vexflow
Version:
A JavaScript library for rendering music notation and guitar tablature
583 lines (477 loc) • 15.1 kB
JavaScript
/**
* VexFlow - Tuplet Tests
* Copyright Mohit Muthanna 2010 <mohit@muthanna.com>
*/
VF.Test.Tuplet = (function() {
// Ideally this would be using arrow syntax...
var set = function(key) {
return function(value) {
return function(object) {
object[key] = value;
return object;
};
};
};
var setStemDirection = set('stem_direction');
var setDuration = set('duration');
var stemUp = setStemDirection(VF.Stem.UP);
var stemDown = setStemDirection(VF.Stem.DOWN);
var quarterNote = setDuration('4');
var Tuplet = {
Start: function() {
var runTests = VF.Test.runTests;
QUnit.module('Tuplet');
runTests('Simple Tuplet', Tuplet.simple);
runTests('Beamed Tuplet', Tuplet.beamed);
runTests('Ratioed Tuplet', Tuplet.ratio);
runTests('Bottom Tuplet', Tuplet.bottom);
runTests('Bottom Ratioed Tuplet', Tuplet.bottom_ratio);
runTests('Awkward Tuplet', Tuplet.awkward);
runTests('Complex Tuplet', Tuplet.complex);
runTests('Mixed Stem Direction Tuplet', Tuplet.mixedTop);
runTests('Mixed Stem Direction Bottom Tuplet', Tuplet.mixedBottom);
runTests('Nested Tuplets', Tuplet.nested);
runTests('Single Tuplets', Tuplet.single);
},
simple: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10, width: 350 }).addTimeSignature('3/4');
var notes = [
{ keys: ['g/4'], duration: '4' },
{ keys: ['a/4'], duration: '4' },
{ keys: ['b/4'], duration: '4' },
{ keys: ['b/4'], duration: '8' },
{ keys: ['a/4'], duration: '8' },
{ keys: ['g/4'], duration: '8' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Tuplet({ notes: notes.slice(0, 3) });
vf.Tuplet({ notes: notes.slice(3, 6) });
// 3/4 time
var voice = vf.Voice({ time: { num_beats: 3, beat_value: 4 } })
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Simple Test');
},
beamed: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10, width: 350 }).addTimeSignature('3/8');
var notes = [
{ keys: ['b/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['g/4'], duration: '16' },
{ keys: ['a/4'], duration: '8' },
{ keys: ['f/4'], duration: '8' },
{ keys: ['a/4'], duration: '8' },
{ keys: ['f/4'], duration: '8' },
{ keys: ['a/4'], duration: '8' },
{ keys: ['f/4'], duration: '8' },
{ keys: ['g/4'], duration: '8' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Beam({ notes: notes.slice(0, 3) });
vf.Beam({ notes: notes.slice(3, 10) });
vf.Tuplet({ notes: notes.slice(0, 3) });
vf.Tuplet({ notes: notes.slice(3, 10) });
// 3/8 time
var voice = vf.Voice({ time: { num_beats: 3, beat_value: 8 } })
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Beamed Test');
},
ratio: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10, width: 350 }).addTimeSignature('4/4');
var notes = [
{ keys: ['f/4'], duration: '4' },
{ keys: ['a/4'], duration: '4' },
{ keys: ['b/4'], duration: '4' },
{ keys: ['g/4'], duration: '8' },
{ keys: ['e/4'], duration: '8' },
{ keys: ['g/4'], duration: '8' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Beam({
notes: notes.slice(3, 6),
});
vf.Tuplet({
notes: notes.slice(0, 3),
options: {
ratioed: true,
},
});
vf.Tuplet({
notes: notes.slice(3, 6),
options: {
ratioed: true,
notes_occupied: 4,
},
});
var voice = vf.Voice()
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Ratioed Test');
},
bottom: function(options) {
var vf = VF.Test.makeFactory(options, 350, 160);
var stave = vf.Stave({ x: 10, y: 10 }).addTimeSignature('3/4');
var notes = [
{ keys: ['f/4'], duration: '4' },
{ keys: ['c/4'], duration: '4' },
{ keys: ['g/4'], duration: '4' },
{ keys: ['d/5'], duration: '8' },
{ keys: ['g/3'], duration: '8' },
{ keys: ['b/4'], duration: '8' },
].map(stemDown).map(vf.StaveNote.bind(vf));
vf.Beam({
notes: notes.slice(3, 6),
});
vf.Tuplet({
notes: notes.slice(0, 3),
options: { location: VF.Tuplet.LOCATION_BOTTOM },
});
vf.Tuplet({
notes: notes.slice(3, 6),
options: { location: VF.Tuplet.LOCATION_BOTTOM },
});
var voice = vf.Voice({ time: { num_beats: 3, beat_value: 4 } })
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Bottom Test');
},
bottom_ratio: function(options) {
var vf = VF.Test.makeFactory(options, 350, 160);
var stave = vf.Stave({ x: 10, y: 10 }).addTimeSignature('5/8');
var notes = [
{ keys: ['f/4'], duration: '4' },
{ keys: ['c/4'], duration: '4' },
{ keys: ['d/4'], duration: '4' },
{ keys: ['d/5'], duration: '8' },
{ keys: ['g/5'], duration: '8' },
{ keys: ['b/4'], duration: '8' },
].map(stemDown).map(vf.StaveNote.bind(vf));
vf.Beam({
notes: notes.slice(3, 6),
});
vf.Tuplet({
notes: notes.slice(0, 3),
options: {
location: VF.Tuplet.LOCATION_BOTTOM,
ratioed: true,
},
});
vf.Tuplet({
notes: notes.slice(3, 6),
options: {
location: VF.Tuplet.LOCATION_BOTTOM,
notes_occupied: 1,
},
});
var voice = vf.Voice({ time: { num_beats: 5, beat_value: 8 } })
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Bottom Ratioed Test');
},
awkward: function(options) {
var vf = VF.Test.makeFactory(options, 370, 160);
var stave = vf.Stave({ x: 10, y: 10 });
var notes = [
{ keys: ['g/4'], duration: '16' },
{ keys: ['b/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['g/4'], duration: '16' },
{ keys: ['f/4'], duration: '16' },
{ keys: ['e/4'], duration: '16' },
{ keys: ['c/4'], duration: '16' },
{ keys: ['g/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['f/4'], duration: '16' },
{ keys: ['e/4'], duration: '16' },
{ keys: ['c/4'], duration: '8' },
{ keys: ['d/4'], duration: '8' },
{ keys: ['e/4'], duration: '8' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Beam({ notes: notes.slice(0, 12) });
vf.Tuplet({
notes: notes.slice(0, 12),
options: {
notes_occupied: 142,
ratioed: true,
},
});
vf.Tuplet({
notes: notes.slice(12, 15),
options: {
ratioed: true,
},
}).setBracketed(true);
var voice = vf.Voice()
.setStrict(false)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Awkward Test');
},
complex: function(options) {
var vf = VF.Test.makeFactory(options, 600);
var stave = vf.Stave({ x: 10, y: 10 }).addTimeSignature('4/4');
var notes1 = [
{ keys: ['b/4'], duration: '8d' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['g/4'], duration: '8' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['b/4'], duration: '16r' },
{ keys: ['g/4'], duration: '32' },
{ keys: ['f/4'], duration: '32' },
{ keys: ['g/4'], duration: '32' },
{ keys: ['f/4'], duration: '32' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['f/4'], duration: '8' },
{ keys: ['b/4'], duration: '8' },
{ keys: ['a/4'], duration: '8' },
{ keys: ['g/4'], duration: '8' },
{ keys: ['b/4'], duration: '8' },
{ keys: ['a/4'], duration: '8' },
].map(stemUp).map(vf.StaveNote.bind(vf));
notes1[0].addDotToAll();
var notes2 = [
{ keys: ['c/4'] },
{ keys: ['c/4'] },
{ keys: ['c/4'] },
{ keys: ['c/4'] },
].map(quarterNote).map(stemDown).map(vf.StaveNote.bind(vf));
vf.Beam({ notes: notes1.slice(0, 3) });
vf.Beam({ notes: notes1.slice(5, 9) });
vf.Beam({ notes: notes1.slice(11, 16) });
vf.Tuplet({
notes: notes1.slice(0, 3),
});
vf.Tuplet({
notes: notes1.slice(3, 11),
options: {
num_notes: 7,
notes_occupied: 4,
ratioed: false,
},
});
vf.Tuplet({
notes: notes1.slice(11, 16),
options: {
notes_occupied: 4,
},
});
var voice1 = vf.Voice()
.setStrict(true)
.addTickables(notes1);
var voice2 = vf.Voice()
.setStrict(true)
.addTickables(notes2);
new VF.Formatter()
.joinVoices([voice1, voice2])
.formatToStave([voice1, voice2], stave);
vf.draw();
ok(true, 'Complex Test');
},
mixedTop: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10 });
var notes = [
{ keys: ['a/4'], stem_direction: 1 },
{ keys: ['c/6'], stem_direction: -1 },
{ keys: ['a/4'], stem_direction: 1 },
{ keys: ['f/5'], stem_direction: 1 },
{ keys: ['a/4'], stem_direction: -1 },
{ keys: ['c/6'], stem_direction: -1 },
].map(quarterNote).map(vf.StaveNote.bind(vf));
vf.Tuplet({
notes: notes.slice(0, 2),
options: {
notes_occupied: 3,
},
});
vf.Tuplet({
notes: notes.slice(2, 4),
options: {
notes_occupied: 3,
},
});
vf.Tuplet({
notes: notes.slice(4, 6),
options: {
notes_occupied: 3,
},
});
var voice = vf.Voice()
.setStrict(false)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Mixed Stem Direction Tuplet');
},
mixedBottom: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10 });
var notes = [
{ keys: ['f/3'], stem_direction: 1 },
{ keys: ['a/5'], stem_direction: -1 },
{ keys: ['a/4'], stem_direction: 1 },
{ keys: ['f/3'], stem_direction: 1 },
{ keys: ['a/4'], stem_direction: -1 },
{ keys: ['c/4'], stem_direction: -1 },
].map(quarterNote).map(vf.StaveNote.bind(vf));
vf.Tuplet({
notes: notes.slice(0, 2),
options: {
notes_occupied: 3,
},
});
vf.Tuplet({
notes: notes.slice(2, 4),
options: {
notes_occupied: 3,
},
});
vf.Tuplet({
notes: notes.slice(4, 6),
options: {
notes_occupied: 3,
},
});
var voice = vf.Voice()
.setStrict(false)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Mixed Stem Direction Bottom Tuplet');
},
nested: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10 }).addTimeSignature('4/4');
var notes = [
// Big triplet 1:
{ keys: ['b/4'], duration: '4' },
{ keys: ['a/4'], duration: '4' },
{ keys: ['g/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['f/4'], duration: '16' },
{ keys: ['a/4'], duration: '16' },
{ keys: ['g/4'], duration: '16' },
{ keys: ['b/4'], duration: '2' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Beam({
notes: notes.slice(2, 7),
});
vf.Tuplet({
notes: notes.slice(0, 7),
options: {
notes_occupied: 2,
num_notes: 3,
},
});
vf.Tuplet({
notes: notes.slice(2, 7),
options: {
notes_occupied: 4,
num_notes: 5,
},
});
// 4/4 time
var voice = vf.Voice()
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Nested Tuplets');
},
single: function(options) {
var vf = VF.Test.makeFactory(options);
var stave = vf.Stave({ x: 10, y: 10 }).addTimeSignature('4/4');
var notes = [
// Big triplet 1:
{ keys: ['c/4'], duration: '4' },
{ keys: ['d/4'], duration: '8' },
{ keys: ['e/4'], duration: '8' },
{ keys: ['f/4'], duration: '8' },
{ keys: ['g/4'], duration: '8' },
{ keys: ['a/4'], duration: '2' },
{ keys: ['b/4'], duration: '4' },
].map(stemUp).map(vf.StaveNote.bind(vf));
vf.Beam({
notes: notes.slice(1, 4),
});
// big quartuplet
vf.Tuplet({
notes: notes.slice(0, -1),
options: {
num_notes: 4,
notes_occupied: 3,
ratioed: true,
bracketed: true,
},
});
// first singleton
vf.Tuplet({
notes: notes.slice(0, 1),
options: {
num_notes: 3,
notes_occupied: 2,
ratioed: true,
},
});
// eighth note triplet
vf.Tuplet({
notes: notes.slice(1, 4),
options: {
num_notes: 3,
notes_occupied: 2,
},
});
// second singleton
vf.Tuplet({
notes: notes.slice(4, 5),
options: {
num_notes: 3,
notes_occupied: 2,
ratioed: true,
bracketed: true,
},
});
// 4/4 time
var voice = vf.Voice({ time: { num_beats: 4, beat_value: 4 } })
.setStrict(true)
.addTickables(notes);
new VF.Formatter()
.joinVoices([voice])
.formatToStave([voice], stave);
vf.draw();
ok(true, 'Nested Tuplets');
},
};
return Tuplet;
})();