UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature

800 lines (653 loc) 30.2 kB
/** * VexFlow - Accidental Tests * Copyright Mohit Muthanna 2010 <mohit@muthanna.com> */ Vex.Flow.Test.Accidental = (function() { function hasAccidental(note) { return note.modifiers.reduce(function(hasAcc, modifier) { return hasAcc || modifier.getCategory() === 'accidentals'; }, false); } // newAccid factory function makeNewAccid(factory) { return function(accidType) { return factory.Accidental({ type: accidType }); }; } var Accidental = { Start: function() { QUnit.module('Accidental'); Vex.Flow.Test.runTests('Basic', Vex.Flow.Test.Accidental.basic); Vex.Flow.Test.runTests('Stem Down', Vex.Flow.Test.Accidental.basicStemDown); Vex.Flow.Test.runTests('Cautionary Accidental', Vex.Flow.Test.Accidental.cautionary); Vex.Flow.Test.runTests('Accidental Arrangement Special Cases', Vex.Flow.Test.Accidental.specialCases); Vex.Flow.Test.runTests('Multi Voice', Vex.Flow.Test.Accidental.multiVoice); Vex.Flow.Test.runTests('Microtonal', Vex.Flow.Test.Accidental.microtonal); Vex.Flow.Test.runTests('Microtonal (Iranian)', Vex.Flow.Test.Accidental.microtonal_iranian); test('Automatic Accidentals - Simple Tests', Vex.Flow.Test.Accidental.autoAccidentalWorking); Vex.Flow.Test.runTests('Automatic Accidentals', Vex.Flow.Test.Accidental.automaticAccidentals0); Vex.Flow.Test.runTests('Automatic Accidentals - C major scale in Ab', Vex.Flow.Test.Accidental.automaticAccidentals1); Vex.Flow.Test.runTests('Automatic Accidentals - No Accidentals Necsesary', Vex.Flow.Test.Accidental.automaticAccidentals2); Vex.Flow.Test.runTests('Automatic Accidentals - Multi Voice Inline', Vex.Flow.Test.Accidental.automaticAccidentalsMultiVoiceInline); Vex.Flow.Test.runTests('Automatic Accidentals - Multi Voice Offset', Vex.Flow.Test.Accidental.automaticAccidentalsMultiVoiceOffset); Vex.Flow.Test.runTests('Factory API', Vex.Flow.Test.Accidental.factoryAPI); }, basic: function(options) { var vf = VF.Test.makeFactory(options, 700, 240); var newAccid = makeNewAccid(vf); vf.Stave({ x: 10, y: 10, width: 550 }); var notes = [ vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: '1' }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('#')), vf.StaveNote({ keys: ['d/4', 'e/4', 'f/4', 'a/4', 'c/5', 'e/5', 'g/5'], duration: '2' }) .addAccidental(0, newAccid('##')) .addAccidental(1, newAccid('n')) .addAccidental(2, newAccid('bb')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('#')) .addAccidental(5, newAccid('n')) .addAccidental(6, newAccid('bb')), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'e/5', 'g/5'], duration: '16' }) .addAccidental(0, newAccid('n')) .addAccidental(1, newAccid('#')) .addAccidental(2, newAccid('#')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('bb')) .addAccidental(5, newAccid('##')) .addAccidental(6, newAccid('#')), vf.StaveNote({ keys: ['a/3', 'c/4', 'e/4', 'b/4', 'd/5', 'g/5'], duration: '1' }) .addAccidental(0, newAccid('#')) .addAccidental(1, newAccid('##').setAsCautionary()) .addAccidental(2, newAccid('#').setAsCautionary()) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('bb').setAsCautionary()) .addAccidental(5, newAccid('b').setAsCautionary()), ]; VF.Formatter.SimpleFormat(notes, 10, { paddingBetween: 45 }); notes.forEach(function(note, index) { Vex.Flow.Test.plotNoteWidth(vf.getContext(), note, 140); ok(note.getAccidentals().length > 0, 'Note ' + index + ' has accidentals'); note.getAccidentals().forEach(function(accid, index) { ok(accid.getWidth() > 0, 'Accidental ' + index + ' has set width'); }); }); vf.draw(); Vex.Flow.Test.plotLegendForNoteWidth(vf.getContext(), 480, 140); ok(true, 'Full Accidental'); }, cautionary: function(options) { var vf = VF.Test.makeFactory(options, 800, 240); var stave = vf.Stave({ x: 0, y: 10, width: 780 }); var score = vf.EasyScore(); var accids = Object .keys(VF.accidentalCodes.accidentals) .filter(function(accid) { return accid !== '{' && accid !== '}'; }); var notes = accids .map(function(accid) { return vf .StaveNote({ keys: ['a/4'], duration: '4', stem_direction: VF.Stem.UP }) .addAccidental(0, vf.Accidental({ type: accid })); }); var voice = score.voice(notes, { time: accids.length + '/4' }); voice .getTickables() .forEach(function(tickable) { tickable.modifiers .filter(function(modifier) { return modifier.getAttribute('type') === 'Accidental'; }) .forEach(function(accid) { accid.setAsCautionary(); }); }); vf.Formatter() .joinVoices([voice]) .formatToStave([voice], stave); vf.draw(); ok(true, 'Must successfully render cautionary accidentals'); }, specialCases: function(options) { var vf = VF.Test.makeFactory(options, 700, 240); var newAccid = makeNewAccid(vf); vf.Stave({ x: 10, y: 10, width: 550 }); var notes = [ vf.StaveNote({ keys: ['f/4', 'd/5'], duration: '1' }) .addAccidental(0, newAccid('#')) .addAccidental(1, newAccid('b')), vf.StaveNote({ keys: ['c/4', 'g/4'], duration: '2' }) .addAccidental(0, newAccid('##')) .addAccidental(1, newAccid('##')), vf.StaveNote({ keys: ['b/3', 'd/4', 'f/4'], duration: '16' }) .addAccidental(0, newAccid('#')) .addAccidental(1, newAccid('#')) .addAccidental(2, newAccid('##')), vf.StaveNote({ keys: ['g/4', 'a/4', 'c/5', 'e/5'], duration: '16' }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('b')) .addAccidental(3, newAccid('n')), vf.StaveNote({ keys: ['e/4', 'g/4', 'b/4', 'c/5'], duration: '4' }) .addAccidental(0, newAccid('b').setAsCautionary()) .addAccidental(1, newAccid('b').setAsCautionary()) .addAccidental(2, newAccid('bb')) .addAccidental(3, newAccid('b')), vf.StaveNote({ keys: ['b/3', 'e/4', 'a/4', 'd/5', 'g/5'], duration: '8' }) .addAccidental(0, newAccid('bb')) .addAccidental(1, newAccid('b').setAsCautionary()) .addAccidental(2, newAccid('n').setAsCautionary()) .addAccidental(3, newAccid('#')) .addAccidental(4, newAccid('n').setAsCautionary()), ]; VF.Formatter.SimpleFormat(notes, 0, { paddingBetween: 20 }); notes.forEach(function(note, index) { Vex.Flow.Test.plotNoteWidth(vf.getContext(), note, 140); ok(note.getAccidentals().length > 0, 'Note ' + index + ' has accidentals'); note.getAccidentals().forEach(function(accid, index) { ok(accid.getWidth() > 0, 'Accidental ' + index + ' has set width'); }); }); vf.draw(); Vex.Flow.Test.plotLegendForNoteWidth(vf.getContext(), 480, 140); ok(true, 'Full Accidental'); }, basicStemDown: function(options) { var vf = VF.Test.makeFactory(options, 700, 240); var newAccid = makeNewAccid(vf); vf.Stave({ x: 10, y: 10, width: 550 }); var notes = [ vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: 'w', stem_direction: -1 }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('#')), vf.StaveNote({ keys: ['d/4', 'e/4', 'f/4', 'a/4', 'c/5', 'e/5', 'g/5'], duration: '2', stem_direction: -1 }) .addAccidental(0, newAccid('##')) .addAccidental(1, newAccid('n')) .addAccidental(2, newAccid('bb')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('#')) .addAccidental(5, newAccid('n')) .addAccidental(6, newAccid('bb')), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'e/5', 'g/5'], duration: '16', stem_direction: -1 }) .addAccidental(0, newAccid('n')) .addAccidental(1, newAccid('#')) .addAccidental(2, newAccid('#')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('bb')) .addAccidental(5, newAccid('##')) .addAccidental(6, newAccid('#')), ]; VF.Formatter.SimpleFormat(notes, 0, { paddingBetween: 30 }); notes.forEach(function(note, index) { Vex.Flow.Test.plotNoteWidth(vf.getContext(), note, 140); ok(note.getAccidentals().length > 0, 'Note ' + index + ' has accidentals'); note.getAccidentals().forEach(function(accid, index) { ok(accid.getWidth() > 0, 'Accidental ' + index + ' has set width'); }); }); vf.draw(); Vex.Flow.Test.plotLegendForNoteWidth(vf.getContext(), 480, 140); ok(true, 'Full Accidental'); }, showNotes: function(note1, note2, stave, ctx, x) { var modifierContext = new Vex.Flow.ModifierContext(); note1.addToModifierContext(modifierContext); note2.addToModifierContext(modifierContext); new VF.TickContext() .addTickable(note1) .addTickable(note2) .preFormat() .setX(x); note1.setContext(ctx).draw(); note2.setContext(ctx).draw(); Vex.Flow.Test.plotNoteWidth(ctx, note1, 180); Vex.Flow.Test.plotNoteWidth(ctx, note2, 15); }, multiVoice: function(options) { var vf = VF.Test.makeFactory(options, 460, 250); var newAccid = makeNewAccid(vf); var stave = vf.Stave({ x: 10, y: 45, width: 420 }); var ctx = vf.getContext(); stave.draw(); var note1 = vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: '2', stem_direction: -1 }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('n')) .addAccidental(2, newAccid('#')) .setStave(stave); var note2 = vf.StaveNote({ keys: ['d/5', 'a/5', 'b/5'], duration: '2', stem_direction: 1 }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('bb')) .addAccidental(2, newAccid('##')) .setStave(stave); Vex.Flow.Test.Accidental.showNotes(note1, note2, stave, ctx, 60); note1 = vf.StaveNote({ keys: ['c/4', 'e/4', 'c/5'], duration: '2', stem_direction: -1 }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('n')) .addAccidental(2, newAccid('#')) .setStave(stave); note2 = vf.StaveNote({ keys: ['d/5', 'a/5', 'b/5'], duration: '4', stem_direction: 1 }) .addAccidental(0, newAccid('b')) .setStave(stave); Vex.Flow.Test.Accidental.showNotes(note1, note2, stave, ctx, 150); note1 = vf.StaveNote({ keys: ['d/4', 'c/5', 'd/5'], duration: '2', stem_direction: -1 }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('n')) .addAccidental(2, newAccid('#')) .setStave(stave); note2 = vf.StaveNote({ keys: ['d/5', 'a/5', 'b/5'], duration: '4', stem_direction: 1 }) .addAccidental(0, newAccid('b')) .setStave(stave); Vex.Flow.Test.Accidental.showNotes(note1, note2, stave, ctx, 250); Vex.Flow.Test.plotLegendForNoteWidth(ctx, 350, 150); ok(true, 'Full Accidental'); }, microtonal: function(options) { var assert = options.assert; var vf = VF.Test.makeFactory(options, 700, 240); var newAccid = makeNewAccid(vf); var ctx = vf.getContext(); vf.Stave({ x: 10, y: 10, width: 650 }); var notes = [ vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: '1' }) .addAccidental(0, newAccid('db')) .addAccidental(1, newAccid('d')), vf.StaveNote({ keys: ['d/4', 'e/4', 'f/4', 'a/4', 'c/5', 'e/5', 'g/5'], duration: '2' }) .addAccidental(0, newAccid('bbs')) .addAccidental(1, newAccid('++')) .addAccidental(2, newAccid('+')) .addAccidental(3, newAccid('d')) .addAccidental(4, newAccid('db')) .addAccidental(5, newAccid('+')) .addAccidental(6, newAccid('##')), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'e/5', 'g/5'], duration: '16' }) .addAccidental(0, newAccid('++')) .addAccidental(1, newAccid('bbs')) .addAccidental(2, newAccid('+')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('db')) .addAccidental(5, newAccid('##')) .addAccidental(6, newAccid('#')), vf.StaveNote({ keys: ['a/3', 'c/4', 'e/4', 'b/4', 'd/5', 'g/5'], duration: '1' }) .addAccidental(0, newAccid('#')) .addAccidental(1, newAccid('db').setAsCautionary()) .addAccidental(2, newAccid('bbs').setAsCautionary()) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('++').setAsCautionary()) .addAccidental(5, newAccid('d').setAsCautionary()), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'd/5', 'g/5'], duration: '16' }) .addAccidental(0, newAccid('++-')) .addAccidental(1, newAccid('+-')) .addAccidental(2, newAccid('bs')) .addAccidental(3, newAccid('bss')) .addAccidental(4, newAccid('afhf')) .addAccidental(5, newAccid('ashs')), ]; VF.Formatter.SimpleFormat(notes, 0, { paddingBetween: 35 }); notes.forEach(function(note, index) { Vex.Flow.Test.plotNoteWidth(vf.getContext(), note, 140); assert.ok(note.getAccidentals().length > 0, 'Note ' + index + ' has accidentals'); note.getAccidentals().forEach(function(accid, index) { assert.ok(accid.getWidth() > 0, 'Accidental ' + index + ' has set width'); }); }); vf.draw(); Vex.Flow.Test.plotLegendForNoteWidth(ctx, 580, 140); ok(true, 'Microtonal Accidental'); }, microtonal_iranian: function(options) { var assert = options.assert; var vf = VF.Test.makeFactory(options, 700, 240); var newAccid = makeNewAccid(vf); var ctx = vf.getContext(); vf.Stave({ x: 10, y: 10, width: 650 }); var notes = [ vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: '1' }) .addAccidental(0, newAccid('k')) .addAccidental(1, newAccid('o')), vf.StaveNote({ keys: ['d/4', 'e/4', 'f/4', 'a/4', 'c/5', 'e/5', 'g/5'], duration: '2' }) .addAccidental(0, newAccid('b')) .addAccidental(1, newAccid('k')) .addAccidental(2, newAccid('n')) .addAccidental(3, newAccid('o')) .addAccidental(4, newAccid('#')) .addAccidental(5, newAccid('bb')) .addAccidental(6, newAccid('##')), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'e/5', 'g/5'], duration: '16' }) .addAccidental(0, newAccid('o')) .addAccidental(1, newAccid('k')) .addAccidental(2, newAccid('n')) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('bb')) .addAccidental(5, newAccid('##')) .addAccidental(6, newAccid('#')), vf.StaveNote({ keys: ['a/3', 'c/4', 'e/4', 'b/4', 'd/5', 'g/5'], duration: '1' }) .addAccidental(0, newAccid('#')) .addAccidental(1, newAccid('o').setAsCautionary()) .addAccidental(2, newAccid('n').setAsCautionary()) .addAccidental(3, newAccid('b')) .addAccidental(4, newAccid('k').setAsCautionary()), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4'], duration: '16' }) .addAccidental(0, newAccid('k')) .addAccidental(1, newAccid('k')) .addAccidental(2, newAccid('k')) .addAccidental(3, newAccid('k')), ]; VF.Formatter.SimpleFormat(notes, 0, { paddingBetween: 35 }); notes.forEach(function(note, index) { Vex.Flow.Test.plotNoteWidth(vf.getContext(), note, 140); assert.ok(note.getAccidentals().length > 0, 'Note ' + index + ' has accidentals'); note.getAccidentals().forEach(function(accid, index) { assert.ok(accid.getWidth() > 0, 'Accidental ' + index + ' has set width'); }); }); vf.draw(); Vex.Flow.Test.plotLegendForNoteWidth(ctx, 580, 140); ok(true, 'Microtonal Accidental (Iranian)'); }, automaticAccidentals0: function(options) { var vf = VF.Test.makeFactory(options, 700, 200); var stave = vf.Stave(); const notes = [ { keys: ['c/4', 'c/5'], duration: '4' }, { keys: ['c#/4', 'c#/5'], duration: '4' }, { keys: ['c#/4', 'c#/5'], duration: '4' }, { keys: ['c##/4', 'c##/5'], duration: '4' }, { keys: ['c##/4', 'c##/5'], duration: '4' }, { keys: ['c/4', 'c/5'], duration: '4' }, { keys: ['cn/4', 'cn/5'], duration: '4' }, { keys: ['cbb/4', 'cbb/5'], duration: '4' }, { keys: ['cbb/4', 'cbb/5'], duration: '4' }, { keys: ['cb/4', 'cb/5'], duration: '4' }, { keys: ['cb/4', 'cb/5'], duration: '4' }, { keys: ['c/4', 'c/5'], duration: '4' }, ].map(vf.StaveNote.bind(vf)); const gracenotes = [ { keys: ['d#/4'], duration: '16', slash: true }, ].map(vf.GraceNote.bind(vf)); notes[0].addModifier(0, vf.GraceNoteGroup({ notes: gracenotes }).beamNotes()); const voice = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickable(new Vex.Flow.TimeSigNote('12/4').setStave(stave)) .addTickables(notes); Vex.Flow.Accidental.applyAccidentals([voice], 'C'); new Vex.Flow.Formatter() .joinVoices([voice]) .formatToStave([voice], stave); vf.draw(); ok(true); }, automaticAccidentals1: function(options) { var vf = VF.Test.makeFactory(options, 700, 150); var stave = vf.Stave().addKeySignature('Ab'); var notes = [ { keys: ['c/4'], duration: '4' }, { keys: ['d/4'], duration: '4' }, { keys: ['e/4'], duration: '4' }, { keys: ['f/4'], duration: '4' }, { keys: ['g/4'], duration: '4' }, { keys: ['a/4'], duration: '4' }, { keys: ['b/4'], duration: '4' }, { keys: ['c/5'], duration: '4' }, ].map(vf.StaveNote.bind(vf)); var voice = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes); Vex.Flow.Accidental.applyAccidentals([voice], 'Ab'); new Vex.Flow.Formatter() .joinVoices([voice]) .formatToStave([voice], stave); vf.draw(); ok(true); }, automaticAccidentals2: function(options) { var vf = VF.Test.makeFactory(options, 700, 150); var stave = vf.Stave().addKeySignature('A'); var notes = [ { keys: ['a/4'], duration: '4' }, { keys: ['b/4'], duration: '4' }, { keys: ['c#/5'], duration: '4' }, { keys: ['d/5'], duration: '4' }, { keys: ['e/5'], duration: '4' }, { keys: ['f#/5'], duration: '4' }, { keys: ['g#/5'], duration: '4' }, { keys: ['a/5'], duration: '4' }, ].map(vf.StaveNote.bind(vf)); var voice = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes); Vex.Flow.Accidental.applyAccidentals([voice], 'A'); new Vex.Flow.Formatter() .joinVoices([voice]) .formatToStave([voice], stave); vf.draw(); ok(true); }, automaticAccidentalsMultiVoiceInline: function(options) { var vf = VF.Test.makeFactory(options, 700, 150); var stave = vf.Stave().addKeySignature('Ab'); var notes0 = [ { keys: ['c/4'], duration: '4', stem_direction: -1 }, { keys: ['d/4'], duration: '4', stem_direction: -1 }, { keys: ['e/4'], duration: '4', stem_direction: -1 }, { keys: ['f/4'], duration: '4', stem_direction: -1 }, { keys: ['g/4'], duration: '4', stem_direction: -1 }, { keys: ['a/4'], duration: '4', stem_direction: -1 }, { keys: ['b/4'], duration: '4', stem_direction: -1 }, { keys: ['c/5'], duration: '4', stem_direction: -1 }, ].map(vf.StaveNote.bind(vf)); var notes1 = [ { keys: ['c/5'], duration: '4' }, { keys: ['d/5'], duration: '4' }, { keys: ['e/5'], duration: '4' }, { keys: ['f/5'], duration: '4' }, { keys: ['g/5'], duration: '4' }, { keys: ['a/5'], duration: '4' }, { keys: ['b/5'], duration: '4' }, { keys: ['c/6'], duration: '4' }, ].map(vf.StaveNote.bind(vf)); var voice0 = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes0); var voice1 = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes1); // Ab Major Vex.Flow.Accidental.applyAccidentals([voice0, voice1], 'Ab'); equal(hasAccidental(notes0[0]), false); equal(hasAccidental(notes0[1]), true); equal(hasAccidental(notes0[2]), true); equal(hasAccidental(notes0[3]), false); equal(hasAccidental(notes0[4]), false); equal(hasAccidental(notes0[5]), true); equal(hasAccidental(notes0[6]), true); equal(hasAccidental(notes0[7]), false); equal(hasAccidental(notes1[0]), false); equal(hasAccidental(notes1[1]), true); equal(hasAccidental(notes1[2]), true); equal(hasAccidental(notes1[3]), false); equal(hasAccidental(notes1[4]), false); equal(hasAccidental(notes1[5]), true); equal(hasAccidental(notes1[6]), true); equal(hasAccidental(notes1[7]), false); new Vex.Flow.Formatter() .joinVoices([voice0, voice1]) .formatToStave([voice0, voice1], stave); vf.draw(); ok(true); }, automaticAccidentalsMultiVoiceOffset: function(options) { var vf = VF.Test.makeFactory(options, 700, 150); var stave = vf.Stave().addKeySignature('Cb'); var notes0 = [ { keys: ['c/4'], duration: '4', stem_direction: -1 }, { keys: ['d/4'], duration: '4', stem_direction: -1 }, { keys: ['e/4'], duration: '4', stem_direction: -1 }, { keys: ['f/4'], duration: '4', stem_direction: -1 }, { keys: ['g/4'], duration: '4', stem_direction: -1 }, { keys: ['a/4'], duration: '4', stem_direction: -1 }, { keys: ['b/4'], duration: '4', stem_direction: -1 }, { keys: ['c/5'], duration: '4', stem_direction: -1 }, ].map(vf.StaveNote.bind(vf)); var notes1 = [ { keys: ['c/5'], duration: '8' }, { keys: ['c/5'], duration: '4' }, { keys: ['d/5'], duration: '4' }, { keys: ['e/5'], duration: '4' }, { keys: ['f/5'], duration: '4' }, { keys: ['g/5'], duration: '4' }, { keys: ['a/5'], duration: '4' }, { keys: ['b/5'], duration: '4' }, { keys: ['c/6'], duration: '4' }, ].map(vf.StaveNote.bind(vf)); var voice0 = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes0); var voice1 = vf.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes1); // Cb Major (All flats) Vex.Flow.Accidental.applyAccidentals([voice0, voice1], 'Cb'); equal(hasAccidental(notes0[0]), true); equal(hasAccidental(notes0[1]), true); equal(hasAccidental(notes0[2]), true); equal(hasAccidental(notes0[3]), true); equal(hasAccidental(notes0[4]), true); equal(hasAccidental(notes0[5]), true); equal(hasAccidental(notes0[6]), true); equal(hasAccidental(notes0[7]), false, 'Natural Remembered'); equal(hasAccidental(notes1[0]), true); equal(hasAccidental(notes1[1]), false); equal(hasAccidental(notes1[2]), false); equal(hasAccidental(notes1[3]), false); equal(hasAccidental(notes1[4]), false); equal(hasAccidental(notes1[5]), false); equal(hasAccidental(notes1[6]), false); equal(hasAccidental(notes1[7]), false); new Vex.Flow.Formatter() .joinVoices([voice0, voice1]) .formatToStave([voice0, voice1], stave); vf.draw(); ok(true); }, autoAccidentalWorking: function() { function makeNote(noteStruct) { return new VF.StaveNote(noteStruct); } var notes = [ { keys: ['bb/4'], duration: '4' }, { keys: ['bb/4'], duration: '4' }, { keys: ['g#/4'], duration: '4' }, { keys: ['g/4'], duration: '4' }, { keys: ['b/4'], duration: '4' }, { keys: ['b/4'], duration: '4' }, { keys: ['a#/4'], duration: '4' }, { keys: ['g#/4'], duration: '4' }, ].map(makeNote); var voice = new VF.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes); // F Major (Bb) Vex.Flow.Accidental.applyAccidentals([voice], 'F'); equal(hasAccidental(notes[0]), false, 'No flat because of key signature'); equal(hasAccidental(notes[1]), false, 'No flat because of key signature'); equal(hasAccidental(notes[2]), true, 'Added a sharp'); equal(hasAccidental(notes[3]), true, 'Back to natural'); equal(hasAccidental(notes[4]), true, 'Back to natural'); equal(hasAccidental(notes[5]), false, 'Natural remembered'); equal(hasAccidental(notes[6]), true, 'Added sharp'); equal(hasAccidental(notes[7]), true, 'Added sharp'); notes = [ { keys: ['e#/4'], duration: '4' }, { keys: ['cb/4'], duration: '4' }, { keys: ['fb/4'], duration: '4' }, { keys: ['b#/4'], duration: '4' }, { keys: ['b#/4'], duration: '4' }, { keys: ['cb/5'], duration: '4' }, { keys: ['fb/5'], duration: '4' }, { keys: ['e#/4'], duration: '4' }, ].map(makeNote); voice = new VF.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes); // A Major (F#,G#,C#) Vex.Flow.Accidental.applyAccidentals([voice], 'A'); equal(hasAccidental(notes[0]), true, 'Added sharp'); equal(hasAccidental(notes[1]), true, 'Added flat'); equal(hasAccidental(notes[2]), true, 'Added flat'); equal(hasAccidental(notes[3]), true, 'Added sharp'); equal(hasAccidental(notes[4]), false, 'Sharp remembered'); equal(hasAccidental(notes[5]), false, 'Flat remembered'); equal(hasAccidental(notes[6]), false, 'Flat remembered'); equal(hasAccidental(notes[7]), false, 'sharp remembered'); notes = [ { keys: ['c/4'], duration: '4' }, { keys: ['cb/4'], duration: '4' }, { keys: ['cb/4'], duration: '4' }, { keys: ['c#/4'], duration: '4' }, { keys: ['c#/4'], duration: '4' }, { keys: ['cbb/4'], duration: '4' }, { keys: ['cbb/4'], duration: '4' }, { keys: ['c##/4'], duration: '4' }, { keys: ['c##/4'], duration: '4' }, { keys: ['c/4'], duration: '4' }, { keys: ['c/4'], duration: '4' }, ].map(makeNote); voice = new VF.Voice() .setMode(Vex.Flow.Voice.Mode.SOFT) .addTickables(notes); // C Major (no sharps/flats) Vex.Flow.Accidental.applyAccidentals([voice], 'C'); equal(hasAccidental(notes[0]), false, 'No accidental'); equal(hasAccidental(notes[1]), true, 'Added flat'); equal(hasAccidental(notes[2]), false, 'Flat remembered'); equal(hasAccidental(notes[3]), true, 'Sharp added'); equal(hasAccidental(notes[4]), false, 'Sharp remembered'); equal(hasAccidental(notes[5]), true, 'Added doubled flat'); equal(hasAccidental(notes[6]), false, 'Double flat remembered'); equal(hasAccidental(notes[7]), true, 'Added double sharp'); equal(hasAccidental(notes[8]), false, 'Double sharp rememberd'); equal(hasAccidental(notes[9]), true, 'Added natural'); equal(hasAccidental(notes[10]), false, 'Natural remembered'); }, factoryAPI: function(options) { var assert = options.assert; var vf = VF.Test.makeFactory(options, 700, 240); vf.Stave({ x: 10, y: 10, width: 550 }); function newAcc(type) { return vf.Accidental({ type: type }); } var notes = [ vf.StaveNote({ keys: ['c/4', 'e/4', 'a/4'], duration: 'w' }) .addAccidental(0, newAcc('b')) .addAccidental(1, newAcc('#')), vf.StaveNote({ keys: ['d/4', 'e/4', 'f/4', 'a/4', 'c/5', 'e/5', 'g/5'], duration: 'h' }) .addAccidental(0, newAcc('##')) .addAccidental(1, newAcc('n')) .addAccidental(2, newAcc('bb')) .addAccidental(3, newAcc('b')) .addAccidental(4, newAcc('#')) .addAccidental(5, newAcc('n')) .addAccidental(6, newAcc('bb')), vf.StaveNote({ keys: ['f/4', 'g/4', 'a/4', 'b/4', 'c/5', 'e/5', 'g/5'], duration: '16' }) .addAccidental(0, newAcc('n')) .addAccidental(1, newAcc('#')) .addAccidental(2, newAcc('#')) .addAccidental(3, newAcc('b')) .addAccidental(4, newAcc('bb')) .addAccidental(5, newAcc('##')) .addAccidental(6, newAcc('#')), vf.StaveNote({ keys: ['a/3', 'c/4', 'e/4', 'b/4', 'd/5', 'g/5'], duration: 'w' }) .addAccidental(0, newAcc('#')) .addAccidental(1, newAcc('##').setAsCautionary()) .addAccidental(2, newAcc('#').setAsCautionary()) .addAccidental(3, newAcc('b')) .addAccidental(4, newAcc('bb').setAsCautionary()) .addAccidental(5, newAcc('b').setAsCautionary()), ]; VF.Formatter.SimpleFormat(notes); notes.forEach(function(n, i) { assert.ok(n.getAccidentals().length > 0, 'Note ' + i + ' has accidentals'); n.getAccidentals().forEach(function(accid, i) { assert.ok(accid.getWidth() > 0, 'Accidental ' + i + ' has set width'); }); }); vf.draw(); assert.ok(true, 'Factory API'); }, }; return Accidental; })();