UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

312 lines (311 loc) 12 kB
import { VexFlow } from '../src/vexflow.js'; import { MAJOR_KEYS, MINOR_KEYS, VexFlowTests } from './vexflow_test_helpers.js'; import { Element } from '../src/element.js'; import { Glyphs } from '../src/glyphs.js'; import { KeySignature } from '../src/keysignature.js'; import { Stave } from '../src/stave.js'; import { BarlineType } from '../src/stavebarline.js'; const KeySignatureTests = { Start() { QUnit.module('KeySignature'); QUnit.test('Key Parser Test', parser); const run = VexFlowTests.runTests; run('Major Key Test', majorKeys); run('Minor Key Test', minorKeys); run('Stave Helper', staveHelper); run('Cancelled key test', majorKeysCanceled); run('Cancelled key (for each clef) test', keysCanceledForEachClef); run('Altered key test', majorKeysAltered); run('End key with clef test', endKeyWithClef); run('Key Signature Change test', changeKey); }, }; const fontWidths = () => { const sharpWidth = Element.measureWidth(Glyphs.accidentalSharp) + 1; const flatWidth = Element.measureWidth(Glyphs.accidentalFlat) + 1; const naturalWidth = Element.measureWidth(Glyphs.accidentalNatural) + 2; const clefWidth = Element.measureWidth(Glyphs.gClef) * 2; return { sharpWidth, flatWidth, naturalWidth, clefWidth }; }; function parser(assert) { assert.expect(11); function catchError(spec) { assert.throws(() => VexFlow.keySignature(spec), /BadKeySignature/); } catchError('asdf'); catchError('D!'); catchError('E#'); catchError('D#'); catchError('#'); catchError('b'); catchError('Kb'); catchError('Fb'); catchError('Dbm'); catchError('B#m'); VexFlow.keySignature('B'); VexFlow.keySignature('C'); VexFlow.keySignature('Fm'); VexFlow.keySignature('Ab'); VexFlow.keySignature('Abm'); VexFlow.keySignature('F#'); VexFlow.keySignature('G#m'); assert.ok(true, 'all pass'); } function majorKeys(options, contextBuilder) { const w = fontWidths(); const accidentalCount = 28; const casePadding = 10; const testCases = 7; const sharpTestWidth = accidentalCount * w.sharpWidth + casePadding * testCases + Stave.defaultPadding; const flatTestWidth = accidentalCount * w.flatWidth + casePadding * testCases + Stave.defaultPadding; const ctx = contextBuilder(options.elementId, Math.max(sharpTestWidth, flatTestWidth) + 100, 240); const stave1 = new Stave(10, 10, flatTestWidth); const stave2 = new Stave(10, 90, sharpTestWidth); const keys = MAJOR_KEYS; let keySig = null; for (let i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.addToStave(stave1); } for (let n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.addToStave(stave2); } stave1.setContext(ctx); stave1.drawWithStyle(); stave1.getModifiers().forEach((modifier) => { VexFlowTests.drawBoundingBox(ctx, modifier); }); stave2.setContext(ctx); stave2.drawWithStyle(); options.assert.ok(true, 'all pass'); } function majorKeysCanceled(options, contextBuilder) { const scale = 0.9; const w = fontWidths(); const flatPadding = 18; const sharpPadding = 20; const flatTestCases = 8; const sharpTestCases = 7; const sharpTestWidth = 28 * w.sharpWidth + 21 * w.naturalWidth + sharpPadding * sharpTestCases + Stave.defaultPadding + w.clefWidth; const flatTestWidth = 28 * w.flatWidth + 28 * w.naturalWidth + flatPadding * flatTestCases + Stave.defaultPadding + w.clefWidth; const eFlatTestWidth = 28 * w.flatWidth + 32 * w.naturalWidth + flatPadding * flatTestCases + Stave.defaultPadding + w.clefWidth; const eSharpTestWidth = 28 * w.sharpWidth + 28 * w.naturalWidth + sharpPadding * sharpTestCases + Stave.defaultPadding + w.clefWidth; const maxWidth = Math.max(Math.max(sharpTestWidth, flatTestWidth, Math.max(eSharpTestWidth, eFlatTestWidth))); const ctx = contextBuilder(options.elementId, maxWidth + 100, 500); ctx.scale(scale, scale); const stave1 = new Stave(10, 10, flatTestWidth).addClef('treble'); const stave2 = new Stave(10, 90, sharpTestWidth).addClef('treble'); const stave3 = new Stave(10, 170, eFlatTestWidth).addClef('treble'); const stave4 = new Stave(10, 250, eSharpTestWidth).addClef('treble'); const keys = MAJOR_KEYS; let keySig = null; let i; let n; for (i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.cancelKey('Cb'); keySig.setPadding(flatPadding); keySig.addToStave(stave1); } for (n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.cancelKey('C#'); keySig.setPadding(sharpPadding); keySig.addToStave(stave2); } for (i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.cancelKey('E'); keySig.setPadding(flatPadding); keySig.addToStave(stave3); } for (n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.cancelKey('Ab'); keySig.setPadding(sharpPadding); keySig.addToStave(stave4); } stave1.setContext(ctx); stave1.drawWithStyle(); stave2.setContext(ctx); stave2.drawWithStyle(); stave3.setContext(ctx); stave3.drawWithStyle(); stave4.setContext(ctx); stave4.drawWithStyle(); options.assert.ok(true, 'all pass'); } function keysCanceledForEachClef(options, contextBuilder) { const scale = 0.8; const w = fontWidths(); const keyPadding = 10; const keys = ['C#', 'Cb']; const flatsKey = [7, 14]; const sharpsKey = [14, 7]; const natsKey = [7, 7]; const max = 21 * Math.max(w.sharpWidth, w.flatWidth) * 2 + keyPadding * 6 + Stave.defaultPadding + w.clefWidth; const ctx = contextBuilder(options.elementId, max + 100, 380); ctx.scale(scale, scale); const x = 20; let y = 20; let tx = x; ['bass', 'tenor', 'soprano', 'mezzo-soprano', 'baritone-f'].forEach(function (clef) { keys.forEach((key, keyIx) => { const cancelKey = keys[(keyIx + 1) % 2]; const width = flatsKey[keyIx] * w.flatWidth + natsKey[keyIx] * w.naturalWidth + sharpsKey[keyIx] * w.sharpWidth + keyPadding * 3 + w.clefWidth + Stave.defaultPadding; const stave = new Stave(tx, y, width); stave.setClef(clef); stave.addKeySignature(cancelKey); stave.addKeySignature(key, cancelKey); stave.addKeySignature(key); stave.setContext(ctx).drawWithStyle(); tx += width; }); tx = x; y += 80; }); options.assert.ok(true, 'all pass'); } function majorKeysAltered(options, contextBuilder) { const ctx = contextBuilder(options.elementId, 780, 500); ctx.scale(0.9, 0.9); const stave1 = new Stave(10, 10, 750).addClef('treble'); const stave2 = new Stave(10, 90, 750).addClef('treble'); const stave3 = new Stave(10, 170, 750).addClef('treble'); const stave4 = new Stave(10, 250, 750).addClef('treble'); const keys = MAJOR_KEYS; let keySig = null; let i; let n; for (i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.alterKey(['bs', 'bs']); keySig.setPadding(18); keySig.addToStave(stave1); } for (n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.alterKey(['+', '+', '+']); keySig.setPadding(20); keySig.addToStave(stave2); } for (i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.alterKey(['n', 'bs', 'bb']); keySig.setPadding(18); keySig.addToStave(stave3); } for (n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.alterKey(['++', '+', 'n', '+']); keySig.setPadding(20); keySig.addToStave(stave4); } stave1.setContext(ctx); stave1.drawWithStyle(); stave2.setContext(ctx); stave2.drawWithStyle(); stave3.setContext(ctx); stave3.drawWithStyle(); stave4.setContext(ctx); stave4.drawWithStyle(); options.assert.ok(true, 'all pass'); } function minorKeys(options, contextBuilder) { const accidentalCount = 28; const w = fontWidths(); const casePadding = 10; const testCases = 7; const sharpTestWidth = accidentalCount * w.sharpWidth + casePadding * testCases + Stave.defaultPadding; const flatTestWidth = accidentalCount * w.flatWidth + casePadding * testCases + Stave.defaultPadding; const ctx = contextBuilder(options.elementId, Math.max(sharpTestWidth, flatTestWidth) + 100, 240); const stave1 = new Stave(10, 10, flatTestWidth); const stave2 = new Stave(10, 90, sharpTestWidth); const keys = MINOR_KEYS; let keySig = null; for (let i = 0; i < 8; ++i) { keySig = new KeySignature(keys[i]); keySig.addToStave(stave1); } for (let n = 8; n < keys.length; ++n) { keySig = new KeySignature(keys[n]); keySig.addToStave(stave2); } stave1.setContext(ctx); stave1.drawWithStyle(); stave2.setContext(ctx); stave2.drawWithStyle(); options.assert.ok(true, 'all pass'); } function endKeyWithClef(options, contextBuilder) { const ctx = contextBuilder(options.elementId, 400, 200); ctx.scale(0.9, 0.9); const stave1 = new Stave(10, 10, 350); stave1 .setKeySignature('G') .setBegBarType(BarlineType.REPEAT_BEGIN) .setEndBarType(BarlineType.REPEAT_END) .setClef('treble') .addTimeSignature('4/4') .setEndClef('bass') .setEndKeySignature('Cb'); const stave2 = new Stave(10, 90, 350); stave2.setKeySignature('Cb').setClef('bass').setEndClef('treble').setEndKeySignature('G'); stave1.setContext(ctx).drawWithStyle(); stave2.setContext(ctx).drawWithStyle(); options.assert.ok(true, 'all pass'); } function staveHelper(options, contextBuilder) { const w = fontWidths(); const accidentalCount = 28; const casePadding = 10; const testCases = 7; const sharpTestWidth = accidentalCount * w.sharpWidth + casePadding * testCases + Stave.defaultPadding; const flatTestWidth = accidentalCount * w.flatWidth + casePadding * testCases + Stave.defaultPadding; const ctx = contextBuilder(options.elementId, Math.max(sharpTestWidth, flatTestWidth) + 100, 240); const stave1 = new Stave(10, 10, flatTestWidth); const stave2 = new Stave(10, 90, sharpTestWidth); const keys = MAJOR_KEYS; for (let i = 0; i < 8; ++i) { stave1.addKeySignature(keys[i]); } for (let n = 8; n < keys.length; ++n) { stave2.addKeySignature(keys[n]); } stave1.setContext(ctx); stave1.drawWithStyle(); stave2.setContext(ctx); stave2.drawWithStyle(); options.assert.ok(true, 'all pass'); } function changeKey(options) { const f = VexFlowTests.makeFactory(options, 900); const stave = f.Stave({ x: 10, y: 10, width: 800 }).addClef('treble').addTimeSignature('C|'); const voice = f .Voice() .setStrict(false) .addTickables([ f.KeySigNote({ key: 'Bb' }), f.StaveNote({ keys: ['c/4'], duration: '1' }), f.BarNote(), f.KeySigNote({ key: 'D', cancelKey: 'Bb' }), f.StaveNote({ keys: ['c/4'], duration: '1' }), f.BarNote(), f.KeySigNote({ key: 'Bb' }), f.StaveNote({ keys: ['c/4'], duration: '1' }), f.BarNote(), f.KeySigNote({ key: 'D', alterKey: ['b', 'n'] }), f.StaveNote({ keys: ['c/4'], duration: '1' }), ]); f.Formatter().joinVoices([voice]).formatToStave([voice], stave); f.draw(); options.assert.ok(true, 'all pass'); } VexFlowTests.register(KeySignatureTests); export { KeySignatureTests };