UNPKG

vexflow

Version:

A JavaScript library for rendering music notation and guitar tablature.

301 lines (300 loc) 13.6 kB
import { VexFlowTests } from './vexflow_test_helpers.js'; import { Accidental } from '../src/accidental.js'; import { Beam } from '../src/beam.js'; import { Dot } from '../src/dot.js'; import { Formatter } from '../src/formatter.js'; import { Glyph } from '../src/glyph.js'; import { Ornament } from '../src/ornament.js'; import { Stave } from '../src/stave.js'; import { StaveNote } from '../src/stavenote.js'; import { Voice, VoiceMode } from '../src/voice.js'; const OrnamentTests = { Start() { QUnit.module('Ornament'); const run = VexFlowTests.runTests; run('Ornaments', drawOrnaments); run('Ornaments Vertically Shifted', drawOrnamentsDisplaced); run('Ornaments - Delayed turns', drawOrnamentsDelayed); run('Ornaments - Delayed turns, Multiple Draws', drawOrnamentsDelayedMultipleDraws); run('Stacked', drawOrnamentsStacked); run('With Upper/Lower Accidentals', drawOrnamentsWithAccidentals); run('Jazz Ornaments', jazzOrnaments); }, }; function drawOrnaments(options, contextBuilder) { options.assert.expect(0); const ctx = contextBuilder(options.elementId, 750, 195); const stave = new Stave(10, 30, 700); stave.setContext(ctx).draw(); const notes = [ new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), ]; notes[0].addModifier(new Ornament('mordent'), 0); notes[1].addModifier(new Ornament('mordent_inverted'), 0); notes[2].addModifier(new Ornament('turn'), 0); notes[3].addModifier(new Ornament('turn_inverted'), 0); notes[4].addModifier(new Ornament('tr'), 0); notes[5].addModifier(new Ornament('upprall'), 0); notes[6].addModifier(new Ornament('downprall'), 0); notes[7].addModifier(new Ornament('prallup'), 0); notes[8].addModifier(new Ornament('pralldown'), 0); notes[9].addModifier(new Ornament('upmordent'), 0); notes[10].addModifier(new Ornament('downmordent'), 0); notes[11].addModifier(new Ornament('lineprall'), 0); notes[12].addModifier(new Ornament('prallprall'), 0); Formatter.FormatAndDraw(ctx, stave, notes); } function drawOrnamentsDisplaced(options, contextBuilder) { options.assert.expect(0); const ctx = contextBuilder(options.elementId, 750, 195); const stave = new Stave(10, 30, 700); stave.setContext(ctx).draw(); const notes = [ new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/5'], duration: '4', stem_direction: -1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), new StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), ]; notes[0].addModifier(new Ornament('mordent'), 0); notes[1].addModifier(new Ornament('mordent_inverted'), 0); notes[1].addModifier(new Ornament('mordent_inverted'), 0); notes[2].addModifier(new Ornament('turn'), 0); notes[3].addModifier(new Ornament('turn_inverted'), 0); notes[4].addModifier(new Ornament('tr'), 0); notes[5].addModifier(new Ornament('upprall'), 0); notes[6].addModifier(new Ornament('downprall'), 0); notes[7].addModifier(new Ornament('prallup'), 0); notes[8].addModifier(new Ornament('pralldown'), 0); notes[9].addModifier(new Ornament('upmordent'), 0); notes[10].addModifier(new Ornament('downmordent'), 0); notes[11].addModifier(new Ornament('lineprall'), 0); notes[12].addModifier(new Ornament('prallprall'), 0); Formatter.FormatAndDraw(ctx, stave, notes); } const addDelayedTurns = (f) => { const context = f.getContext(); const stave = f.Stave({ x: 10, y: 30, width: 500 }); stave.setContext(context).draw(); const notes = [ f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), ]; notes[0].addModifier(f.Ornament('turn', { delayed: true }), 0); notes[1].addModifier(f.Ornament('turn_inverted', { delayed: true }), 0); notes[2].addModifier(f.Ornament('turn_inverted', { delayed: true }), 0); notes[3].addModifier(f.Ornament('turn', { delayed: true }), 0); return { context, stave, notes }; }; function drawOrnamentsDelayed(options) { options.assert.expect(0); const f = VexFlowTests.makeFactory(options, 550, 195); const { context, stave, notes } = addDelayedTurns(f); Formatter.FormatAndDraw(context, stave, notes); } function drawOrnamentsDelayedMultipleDraws(options) { options.assert.expect(0); const f = VexFlowTests.makeFactory(options, 550, 195); const { context, stave, notes } = addDelayedTurns(f); Formatter.FormatAndDraw(context, stave, notes); Formatter.FormatAndDraw(context, stave, notes); } function drawOrnamentsStacked(options) { options.assert.expect(0); const f = VexFlowTests.makeFactory(options, 550, 195); const ctx = f.getContext(); const stave = f.Stave({ x: 10, y: 30, width: 500 }); stave.setContext(ctx).draw(); const notes = [ f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['a/4'], duration: '4', stem_direction: 1 }), ]; notes[0].addModifier(f.Ornament('mordent'), 0); notes[1].addModifier(f.Ornament('turn_inverted'), 0); notes[2].addModifier(f.Ornament('turn'), 0); notes[3].addModifier(f.Ornament('turn_inverted'), 0); notes[0].addModifier(f.Ornament('turn'), 0); notes[1].addModifier(f.Ornament('prallup'), 0); notes[2].addModifier(f.Ornament('upmordent'), 0); notes[3].addModifier(f.Ornament('lineprall'), 0); Formatter.FormatAndDraw(ctx, stave, notes); } function drawOrnamentsWithAccidentals(options) { options.assert.expect(0); const f = VexFlowTests.makeFactory(options, 650, 250); const ctx = f.getContext(); const stave = f.Stave({ x: 10, y: 60, width: 600 }); stave.setContext(ctx).draw(); const notes = [ f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), f.StaveNote({ keys: ['f/4'], duration: '4', stem_direction: 1 }), ]; notes[0].addModifier(f.Ornament('mordent', { lowerAccidental: '#', upperAccidental: '#' }), 0); notes[1].addModifier(f.Ornament('turn_inverted', { lowerAccidental: 'b', upperAccidental: 'b' }), 0); notes[2].addModifier(f.Ornament('turn', { upperAccidental: '##', lowerAccidental: '##' }), 0); notes[3].addModifier(f.Ornament('mordent_inverted', { lowerAccidental: 'db', upperAccidental: 'db' }), 0); notes[4].addModifier(f.Ornament('turn_inverted', { upperAccidental: '++', lowerAccidental: '++' }), 0); notes[5].addModifier(f.Ornament('tr', { upperAccidental: 'n', lowerAccidental: 'n' }), 0); notes[6].addModifier(f.Ornament('prallup', { upperAccidental: 'd', lowerAccidental: 'd' }), 0); notes[7].addModifier(f.Ornament('lineprall', { upperAccidental: 'db', lowerAccidental: 'db' }), 0); notes[8].addModifier(f.Ornament('upmordent', { upperAccidental: 'bbs', lowerAccidental: 'bbs' }), 0); notes[9].addModifier(f.Ornament('prallprall', { upperAccidental: 'bb', lowerAccidental: 'bb' }), 0); notes[10].addModifier(f.Ornament('turn_inverted', { upperAccidental: '+', lowerAccidental: '+' }), 0); Formatter.FormatAndDraw(ctx, stave, notes); } function jazzOrnaments(options) { const clefWidth = Glyph.getWidth('gClef', 38); function draw(modifiers, keys, x, width, y, stemDirection) { const note = (keys, duration, modifier, stemDirection) => { const n = new StaveNote({ keys, duration, stem_direction: stemDirection }) .addModifier(modifier, 0) .addModifier(new Accidental('b'), 0); const dot = duration.indexOf('d') >= 0; if (dot) { Dot.buildAndAttach([n], { all: true }); } return n; }; const stave = new Stave(x, y, width).addClef('treble').setContext(ctx).draw(); const notes = [ note(keys, '4d', modifiers[0], stemDirection), note(keys, '8', modifiers[1], stemDirection), note(keys, '4d', modifiers[2], stemDirection), note(keys, '8', modifiers[3], stemDirection), ]; if (modifiers.length > 4) { notes[3].addModifier(modifiers[4], 0); } Beam.generateBeams(notes); const voice = new Voice({ num_beats: 4, beat_value: 4, }).setMode(VoiceMode.SOFT); voice.addTickables(notes); const formatter = new Formatter().joinVoices([voice]); formatter.format([voice], width - Stave.defaultPadding - clefWidth); stave.setContext(ctx).draw(); voice.draw(ctx, stave); } options.assert.expect(0); const f = VexFlowTests.makeFactory(options, 950, 400); const ctx = f.getContext(); ctx.scale(1, 1); const xStart = 10; const width = 300; const yStart = 50; const staffHeight = 70; let curX = xStart; let curY = yStart; let mods = [ f.Ornament('scoop'), f.Ornament('doit'), f.Ornament('fall'), f.Ornament('doitLong'), ]; draw(mods, ['a/5'], curX, width, curY, -1); curX += width; mods = [ f.Ornament('fallLong'), f.Ornament('bend'), f.Ornament('plungerClosed'), f.Ornament('plungerOpen'), f.Ornament('bend'), ]; draw(mods, ['a/5'], curX, width, curY, -1); curX += width; mods = [ f.Ornament('flip'), f.Ornament('jazzTurn'), f.Ornament('smear'), f.Ornament('doit'), ]; draw(mods, ['a/5'], curX, width, curY, 1); curX = xStart; curY += staffHeight; mods = [ f.Ornament('scoop'), f.Ornament('doit'), f.Ornament('fall'), f.Ornament('doitLong'), ]; draw(mods, ['e/5'], curX, width, curY); curX += width; mods = [ f.Ornament('fallLong'), f.Ornament('bend'), f.Ornament('plungerClosed'), f.Ornament('plungerOpen'), f.Ornament('bend'), ]; draw(mods, ['e/5'], curX, width, curY); curX += width; mods = [ f.Ornament('flip'), f.Ornament('jazzTurn'), f.Ornament('smear'), f.Ornament('doit'), ]; draw(mods, ['e/5'], curX, width, curY); curX = xStart; curY += staffHeight; mods = [ f.Ornament('scoop'), f.Ornament('doit'), f.Ornament('fall'), f.Ornament('doitLong'), ]; draw(mods, ['e/4'], curX, width, curY); curX += width; mods = [ f.Ornament('fallLong'), f.Ornament('bend'), f.Ornament('plungerClosed'), f.Ornament('plungerOpen'), f.Ornament('bend'), ]; draw(mods, ['e/4'], curX, width, curY); curX += width; mods = [ f.Ornament('flip'), f.Ornament('jazzTurn'), f.Ornament('smear'), f.Ornament('doit'), ]; draw(mods, ['e/4'], curX, width, curY); } VexFlowTests.register(OrnamentTests); export { OrnamentTests };