Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mml-optimizer

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mml-optimizer - npm Package Compare versions

Comparing version 0.0.5 to 0.0.6

optimizer-core.js

399

index.js

@@ -1,2 +0,2 @@

var aStar = require('a-star');
var core = require('./optimizer-core');
var extend = require('extend');

@@ -36,366 +36,2 @@

function noteDurationToTicks(duration, options) {
return noteDurationAndDotsToTicks(
parseInt(duration, 10),
/[^.]*([.]*)/.exec(duration)[1].length,
options);
}
function noteDurationAndDotsToTicks(duration, dots, options) {
var ticks = Math.floor(options.tpqn * 4 / duration);
for (var i = 0; i < dots; ++i)
ticks = Math.floor(ticks * 1.5);
return ticks;
}
function ticksToAllNoteDurations(ticks, options) {
var dots = '';
var upperBoundIncl;
var lowerBoundExcl;
var result = [];
while (true) {
// Bounds for the preimage of floor(1.5*floor(1.5*...floor(4*tpqn/ticks)))
upperBoundIncl = Math.pow(1.5,dots.length)*4*options.tpqn / ticks;
lowerBoundExcl = Math.pow(1.5,dots.length)*4*options.tpqn / (ticks + 3*Math.pow(1.5,dots.length) - 2);
if (lowerBoundExcl >= options.minimumNoteDuration)
break;
for (var n = Math.floor(upperBoundIncl); n > lowerBoundExcl; --n) {
if (noteDurationAndDotsToTicks(n, dots.length, options) === ticks) {
result.push(n + dots);
break;
}
}
dots += '.';
}
return result;
}
function relativeDuration(ticks, durationRelativeTo, options) {
var candidates = [];
return ticksToAllNoteDurations(ticks, options)
.map(function (duration) {
if (duration === durationRelativeTo)
return '';
else if (parseInt(duration, 10) === parseInt(durationRelativeTo, 10) &&
duration.length > durationRelativeTo.length)
return duration.slice(durationRelativeTo.length);
return duration;
})
.reduce(function (shortestDuration, duration) {
if (shortestDuration.length > duration.length)
return duration;
return shortestDuration;
});
}
function noteNameToMidiPitch(note, octave) {
var midiMap = {
'c': 0,
'd': 2,
'e': 4,
'f': 5,
'g': 7,
'a': 9,
'b': 11
};
var accidentalMap = {
'+': 1,
'-': -1,
'': 0
};
return 12*octave + midiMap[note[0]] + accidentalMap[note[1] || ''];
}
function validOctaves(pitch) {
var octave = Math.floor(pitch / 12);
if (pitch % 12 === 0 && octave > 0)
return [octave - 1, octave];
if (pitch % 12 === 11)
return [octave, octave + 1];
return [octave];
}
function midiPitchToNoteName(pitch, octave) {
var noteNameMap = {
'-1': 'c-',
'0': 'c',
'1': 'c+',
'2': 'd',
'3': 'd+',
'4': 'e',
'5': 'f',
'6': 'f+',
'7': 'g',
'8': 'g+',
'9': 'a',
'10': 'a+',
'11': 'b',
'12': 'b+'
};
return noteNameMap[pitch - (octave * 12)];
}
function parseMml(mmlString, options) {
var state = extend({ time: 0 }, options.defaultState);
var tokens = [];
while (mmlString.length) {
var result;
var tokenLength;
if (result = /^\/\*[^]*?\*\//.exec(mmlString)) {
tokenLength = result[0].length;
} else if (result = /^([A-Ga-g][+#-]?)([0-9]*[.]*)/.exec(mmlString)) {
var noteName = result[1].toLowerCase().replace(/#/g,'+');
var duration = result[2];
if (!duration)
duration = state.duration;
else if (/^[.]+$/.test(duration)) {
duration = state.duration + duration;
}
var pitch = noteNameToMidiPitch(noteName, state.octave) + options.transpose;
var ticks = noteDurationToTicks(duration, options);
tokens.push({
type: 'note',
pitch: pitch,
ticks: ticks,
volume: state.volume,
time: state.time
});
state.time += ticks;
tokenLength = result[0].length;
} else if (result = /^[Rr]([0-9]*[.]*)/.exec(mmlString)) {
var duration = result[1];
if (!duration)
duration = state.duration;
else if (/^[.]+$/.test(duration)) {
duration = state.duration + duration;
}
var ticks = noteDurationToTicks(duration, options);
tokens.push({
type: 'rest',
ticks: ticks,
time: state.time
});
state.time += ticks;
tokenLength = result[0].length;
} else if (result = /^[Nn]([0-9]+)/.exec(mmlString)) {
var pitch = parseInt(result[1], 10) + options.transpose;
var ticks = noteDurationToTicks(state.duration, options);
tokens.push({
type: 'note',
pitch: pitch,
ticks: ticks,
volume: state.volume,
time: state.time
});
state.time += ticks;
tokenLength = result[0].length;
} else if (result = /^[Ll]([0-9]+[.]*)/.exec(mmlString)) {
state.duration = result[1];
tokenLength = result[0].length;
} else if (result = /^[Oo]([0-9]+)/.exec(mmlString)) {
var octave = parseInt(result[1], 10) + options.octaveOffset;
state.octave = octave;
tokenLength = result[0].length;
} else if (result = /^[Vv]([0-9]+)/.exec(mmlString)) {
var volume = parseInt(result[1], 10) / options.maxVolume;
state.volume = volume;
tokens.push({
type: 'volume',
volume: volume,
time: state.time
});
tokenLength = result[0].length;
} else if (result = /^[Tt]([0-9]+)/.exec(mmlString)) {
var tempo = parseInt(result[1], 10);
state.tempo = tempo;
tokens.push({
type: 'tempo',
tempo: tempo,
time: state.time
});
tokenLength = result[0].length;
} else if (mmlString[0] === '&') {
tokens.push({ type: 'tie' });
tokenLength = 1;
} else if (mmlString[0] === '<') {
--state.octave;
tokenLength = 1;
} else if (mmlString[0] === '>') {
++state.octave;
tokenLength = 1;
} else if (mmlString[0] === ',') {
tokens.push({ type: 'nextVoice' });
if (!options.tracksShareState)
state = extend({}, options.defaultState);
state.time = 0;
tokenLength = 1;
} else {
tokenLength = 1;
}
mmlString = mmlString.slice(tokenLength);
}
return tokens;
}
function tokenText(token, state, options) {
switch (token.type) {
case 'note': return noteText(token.pitch, token.ticks, state.octave, state.duration, options);
case 'rest': return restText(token.ticks, state.duration, options);
case 'duration': return durationText(token.duration);
case 'octave': return octaveText(token.octave, state.octave, options);
case 'volume': return volumeText(token.volume, options);
case 'tempo': return tempoText(token.tempo);
case 'tie': return '&';
case 'nextVoice': return ',';
}
throw new Error('Unexpected token type.');
}
function noteText(pitch, ticks, currentOctave, currentDuration, options) {
return midiPitchToNoteName(pitch, currentOctave) + relativeDuration(ticks, currentDuration, options);
}
function restText(ticks, currentDuration, options) {
return 'r' + relativeDuration(ticks, currentDuration, options);
}
function durationText(duration) {
return 'L' + duration;
}
function octaveText(octave, currentOctave, options) {
if (currentOctave - octave === 1)
return '<';
if (currentOctave - octave === -1)
return '>';
return 'O' + (octave - options.octaveOffset);
}
function volumeText(volume, options) {
return 'V' + Math.round(volume * options.maxVolume);
}
function tempoText(tempo) {
return 'T' + tempo;
}
function tokenNeighbors(token, state, options) {
var neighbors = [];
switch (token.type) {
case 'note':
validOctaves(token.pitch).forEach(function (octave) {
if (octave === state.octave) {
neighbors.push(extend({}, state, { cursor: state.cursor + 1 }));
if (token.ticks !== noteDurationToTicks(state.duration, options)) {
ticksToAllNoteDurations(token.ticks, options)
.forEach(function (duration) {
neighbors.push(extend({}, state, { duration: duration }));
while (duration[duration.length-1] === '.') {
duration = duration.slice(0,-1);
neighbors.push(extend({}, state, { duration: duration }));
}
});
}
} else {
neighbors.push(extend({}, state, { octave: octave }));
}
});
break;
case 'rest':
neighbors.push(extend({}, state, { cursor: state.cursor + 1 }));
if (token.ticks !== noteDurationToTicks(state.duration, options)) {
ticksToAllNoteDurations(token.ticks, options)
.forEach(function (duration) {
neighbors.push(extend({}, state, { duration: duration }));
while (duration[duration.length-1] === '.') {
duration = duration.slice(0,-1);
neighbors.push(extend({}, state, { duration: duration }));
}
});
}
case 'volume':
case 'tempo':
case 'tie':
neighbors.push(extend({}, state, { cursor: state.cursor + 1 }));
case 'nextVoice':
if (options.tracksShareState)
neighbors.push(extend({}, state, { cursor: state.cursor + 1 }));
else
neighbors.push(extend({}, options.defaultState, { cursor: state.cursor + 1 }));
break;
}
return neighbors;
}
function findPath(mmlTokens, options) {
var result = aStar({
start: extend({}, options.defaultState, { cursor: 0 }),
isEnd: function (node) {
return node.cursor === mmlTokens.length;
},
neighbor: function (node) {
return tokenNeighbors(mmlTokens[node.cursor], node, options);
},
distance: function (nodeA, nodeB) {
if (nodeA.cursor !== nodeB.cursor)
return tokenText(mmlTokens[nodeA.cursor], nodeA, options).length;
if (nodeA.duration !== nodeB.duration)
return durationText(nodeB.duration).length;
if (nodeA.octave !== nodeB.octave)
return octaveText(nodeB.octave, nodeA.octave, options).length;
throw new Error('Unexpected node transition.');
},
heuristic: function (node) {
return mmlTokens.length - node.cursor;
},
hash: function (node) {
return JSON.stringify(node);
}
});
if (result.status === 'noPath')
throw new Error('No optimized path found.');
return result.path;
}
function optimizeTokens(mmlTokens, options) {
var path = findPath(mmlTokens, options);
var optimizedTokens = [];
for (var i = 1; i < path.length; ++i) {
if (path[i].cursor !== path[i-1].cursor)
optimizedTokens.push(mmlTokens[path[i-1].cursor]);
else if (path[i].duration !== path[i-1].duration)
optimizedTokens.push({
type: 'duration',
duration: path[i].duration,
time: mmlTokens[path[i].cursor].time
});
else if (path[i].octave !== path[i-1].octave)
optimizedTokens.push({
type: 'octave',
octave: path[i].octave,
time: mmlTokens[path[i].cursor].time
});
else
throw new Error('Unexpected node transition.');
}
return optimizedTokens;
}
function generateMml(tokens, options) {
return tokens.reduce(function (acc, token) {
return extend(acc, {
text: acc.text + tokenText(token, acc, options),
octave: token.type === 'octave' ? token.octave : acc.octave,
tempo: token.type === 'tempo' ? token.tempo : acc.tempo,
volume: token.type === 'volume' ? token.volume : acc.volume,
duration: token.type === 'duration' ? token.duration : acc.duration
});
}, extend({}, options.defaultState, { text: '' })).text;
}
function getOptions(alias) {

@@ -407,5 +43,4 @@ if (!alias)

module.exports = function opt(input, options) {
function parse(mml, options) {
options = options || {};
var outputOptions = getOptions(options.output);
var inputOptions = extend({}, getOptions(options.input), {

@@ -416,18 +51,20 @@ tpqn: outputOptions.tpqn,

});
var parsed = parseMml(input, inputOptions);
var optimized = optimizeTokens(parsed, outputOptions);
var generated = generateMml(optimized, outputOptions);
var parsed = core.parseMml(mml, inputOptions);
return parsed;
}
function generate(tokens, options) {
options = options || {};
var outputOptions = getOptions(options.output);
var optimized = core.optimizeTokens(tokens, outputOptions);
var generated = core.generateMml(optimized, outputOptions);
return generated;
}
module.exports = function opt(mml, options) {
var parsed = parse(mml, options);
var generated = generate(parsed, options);
return generated;
};
module.exports.noteDurationToTicks = noteDurationToTicks;
module.exports.ticksToAllNoteDurations = ticksToAllNoteDurations;
module.exports.relativeDuration = relativeDuration;
module.exports.noteNameToMidiPitch = noteNameToMidiPitch;
module.exports.validOctaves = validOctaves;
module.exports.midiPitchToNoteName = midiPitchToNoteName;
module.exports.parseMml = parseMml;
module.exports.findPath = findPath;
module.exports.optimizeTokens = optimizeTokens;
module.exports.generateMml = generateMml;
module.exports.parse = parse;
module.exports.generate = generate;
{
"name": "mml-optimizer",
"version": "0.0.5",
"version": "0.0.6",
"description": "Optimizer for Music Macro Language (MML)",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -1,2 +0,4 @@

var opt = require('./index.js');
var opt = require('./index');
var core = require('./optimizer-core');
var assert = require('chai').assert;

@@ -17,357 +19,359 @@ var extend = require('extend');

describe('noteDurationToTicks', function () {
var options = { tpqn: 500 };
runCases('should convert {0} to {1}', opt.noteDurationToTicks, [
[['1', options], 2000],
[['1.', options], 3000],
[['1..', options], 4500],
[['1...', options], 6750],
[['3', options], 666],
[['3.', options], 999],
[['4', options], 500],
[['4.', options], 750],
[['5', options], 400],
[['5.', options], 600],
[['7', options], 285],
[['7.', options], 427],
[['64', options], 31],
[['64.', options], 46]
]);
});
describe('optimizer-core', function () {
describe('noteDurationToTicks', function () {
var options = { tpqn: 500 };
runCases('should convert {0} to {1}', core.noteDurationToTicks, [
[['1', options], 2000],
[['1.', options], 3000],
[['1..', options], 4500],
[['1...', options], 6750],
[['3', options], 666],
[['3.', options], 999],
[['4', options], 500],
[['4.', options], 750],
[['5', options], 400],
[['5.', options], 600],
[['7', options], 285],
[['7.', options], 427],
[['64', options], 31],
[['64.', options], 46]
]);
});
describe('ticksToAllNoteDurations', function () {
var options = { tpqn: 500, minimumNoteDuration: 64 };
runCases('should convert {0} to {1}', opt.ticksToAllNoteDurations, [
[[31, options], ['64']],
[[46, options], ['43', '64.']],
[[61, options], ['48.']],
[[111, options], ['18', '27.']],
[[166, options], ['12', '18.', '27..']],
[[285, options], ['7', '35....', '52.....']],
[[333, options], ['6', '9.', '30....', '45.....']],
[[400, options], ['5']],
[[427, options], ['7.', '35.....', '52......']],
[[500, options], ['4']],
[[600, options], ['5.']],
[[666, options], ['3']],
[[750, options], ['4.']],
[[999, options], ['3.']],
[[2000, options], ['1']],
[[3000, options], ['1.']],
[[4500, options], ['1..']],
[[6750, options], ['1...']]
]);
describe('ticksToAllNoteDurations', function () {
var options = { tpqn: 500, minimumNoteDuration: 64 };
runCases('should convert {0} to {1}', core.ticksToAllNoteDurations, [
[[31, options], ['64']],
[[46, options], ['43', '64.']],
[[61, options], ['48.']],
[[111, options], ['18', '27.']],
[[166, options], ['12', '18.', '27..']],
[[285, options], ['7', '35....', '52.....']],
[[333, options], ['6', '9.', '30....', '45.....']],
[[400, options], ['5']],
[[427, options], ['7.', '35.....', '52......']],
[[500, options], ['4']],
[[600, options], ['5.']],
[[666, options], ['3']],
[[750, options], ['4.']],
[[999, options], ['3.']],
[[2000, options], ['1']],
[[3000, options], ['1.']],
[[4500, options], ['1..']],
[[6750, options], ['1...']]
]);
it('should convert ticks to duration and back', function () {
for (var i = 1; i <= 64; ++i) {
for (var dots = ''; dots.length < 3; dots += '.') {
var ticks = opt.noteDurationToTicks(i + dots, options);
var durations = opt.ticksToAllNoteDurations(ticks, options);
durations.forEach(function (duration) {
assert.equal(opt.noteDurationToTicks(duration, options),
ticks,
'Testing ' + i + dots);
});
it('should convert ticks to duration and back', function () {
for (var i = 1; i <= 64; ++i) {
for (var dots = ''; dots.length < 3; dots += '.') {
var ticks = core.noteDurationToTicks(i + dots, options);
var durations = core.ticksToAllNoteDurations(ticks, options);
durations.forEach(function (duration) {
assert.equal(core.noteDurationToTicks(duration, options),
ticks,
'Testing ' + i + dots);
});
}
}
}
});
});
});
describe('relativeDuration', function () {
var options = { tpqn: 500, minimumNoteDuration: 64 };
runCases('should convert {0} to {1}', opt.relativeDuration, [
[[opt.noteDurationToTicks('4', options), '1', options], '4'],
[[opt.noteDurationToTicks('4', options), '4', options], ''],
[[opt.noteDurationToTicks('4', options), '4.', options], '4'],
[[opt.noteDurationToTicks('4.', options), '4', options], '.'],
[[opt.noteDurationToTicks('4..', options), '4.', options], '.'],
[[opt.noteDurationToTicks('4...', options), '4.', options], '..'],
[[opt.noteDurationToTicks('4....', options), '4.', options], '...'],
[[opt.noteDurationToTicks('12', options), '12', options], ''],
[[opt.noteDurationToTicks('12', options), '18', options], '.'],
[[opt.noteDurationToTicks('12', options), '27', options], '12']
]);
});
describe('relativeDuration', function () {
var options = { tpqn: 500, minimumNoteDuration: 64 };
runCases('should convert {0} to {1}', core.relativeDuration, [
[[core.noteDurationToTicks('4', options), '1', options], '4'],
[[core.noteDurationToTicks('4', options), '4', options], ''],
[[core.noteDurationToTicks('4', options), '4.', options], '4'],
[[core.noteDurationToTicks('4.', options), '4', options], '.'],
[[core.noteDurationToTicks('4..', options), '4.', options], '.'],
[[core.noteDurationToTicks('4...', options), '4.', options], '..'],
[[core.noteDurationToTicks('4....', options), '4.', options], '...'],
[[core.noteDurationToTicks('12', options), '12', options], ''],
[[core.noteDurationToTicks('12', options), '18', options], '.'],
[[core.noteDurationToTicks('12', options), '27', options], '12']
]);
});
describe('noteNameToMidiPitch', function () {
runCases('should convert {0} to {1}', opt.noteNameToMidiPitch, [
[['c', 5], 60],
[['c+', 5], 61],
[['c-', 5], 59],
[['c', 4], 48],
[['a', 5], 69]
]);
});
describe('noteNameToMidiPitch', function () {
runCases('should convert {0} to {1}', core.noteNameToMidiPitch, [
[['c', 5], 60],
[['c+', 5], 61],
[['c-', 5], 59],
[['c', 4], 48],
[['a', 5], 69]
]);
});
describe('validOctaves', function () {
runCases('should convert {0} to {1}', opt.validOctaves, [
[opt.noteNameToMidiPitch('g', 4), [4]],
[opt.noteNameToMidiPitch('c', 4), [3, 4]],
[opt.noteNameToMidiPitch('b', 4), [4, 5]],
[opt.noteNameToMidiPitch('c', 0), [0]]
]);
});
describe('validOctaves', function () {
runCases('should convert {0} to {1}', core.validOctaves, [
[core.noteNameToMidiPitch('g', 4), [4]],
[core.noteNameToMidiPitch('c', 4), [3, 4]],
[core.noteNameToMidiPitch('b', 4), [4, 5]],
[core.noteNameToMidiPitch('c', 0), [0]]
]);
});
describe('midiPitchToNoteName', function () {
runCases('should convert {0} to {1}', opt.midiPitchToNoteName, [
[[67, 5], 'g'],
[[68, 5], 'g+'],
[[60, 5], 'c'],
[[59, 5], 'c-'],
[[59, 4], 'b'],
[[60, 4], 'b+']
]);
});
describe('midiPitchToNoteName', function () {
runCases('should convert {0} to {1}', core.midiPitchToNoteName, [
[[67, 5], 'g'],
[[68, 5], 'g+'],
[[60, 5], 'c'],
[[59, 5], 'c-'],
[[59, 4], 'b'],
[[60, 4], 'b+']
]);
});
describe('parseMml', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 100,
volume: 100/127,
duration: '4'
},
maxVolume: 127,
tracksShareState: true,
octaveOffset: -1,
transpose: 1
};
runCases('should parse {0}', opt.parseMml, [
[['ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['cdefgabCDEFGAB', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 51, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 56, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 58, ticks: 500, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 60, ticks: 500, volume: 100/127, time: 3000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 3500 },
{ type: 'note', pitch: 51, ticks: 500, volume: 100/127, time: 4000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 4500 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 5000 },
{ type: 'note', pitch: 56, ticks: 500, volume: 100/127, time: 5500 },
{ type: 'note', pitch: 58, ticks: 500, volume: 100/127, time: 6000 },
{ type: 'note', pitch: 60, ticks: 500, volume: 100/127, time: 6500 },
]],
[['c#d#e#f#g#a#b#c+d+e+f+g+a+b+c-d-e-f-g-a-b-', options], [
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 3000 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 3500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 4000 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 4500 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 5000 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 5500 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 6000 },
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 6500 },
{ type: 'note', pitch: 48, ticks: 500, volume: 100/127, time: 7000 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 7500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 8000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 8500 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 9000 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 9500 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 10000 }
]],
[['c2c4c8c', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1750 }
]],
[['c2c2.c2..c2...', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 2250, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 49, ticks: 3375, volume: 100/127, time: 4750 }
]],
[['cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 750, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 1125, volume: 100/127, time: 1250 },
{ type: 'note', pitch: 49, ticks: 1687, volume: 100/127, time: 2375 }
]],
[['n60n30n90', options], [
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 31, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 91, ticks: 500, volume: 100/127, time: 1000 }
]],
[['r2r4r8r', options], [
{ type: 'rest', ticks: 1000, time: 0 },
{ type: 'rest', ticks: 500, time: 1000 },
{ type: 'rest', ticks: 250, time: 1500 },
{ type: 'rest', ticks: 500, time: 1750 }
]],
[['r2r2.r2..r2...', options], [
{ type: 'rest', ticks: 1000, time: 0 },
{ type: 'rest', ticks: 1500, time: 1000 },
{ type: 'rest', ticks: 2250, time: 2500 },
{ type: 'rest', ticks: 3375, time: 4750 }
]],
[['rr.r..r...', options], [
{ type: 'rest', ticks: 500, time: 0 },
{ type: 'rest', ticks: 750, time: 500 },
{ type: 'rest', ticks: 1125, time: 1250 },
{ type: 'rest', ticks: 1687, time: 2375 }
]],
[['ccc /* this is a comment v64 */ ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2500 }
]],
[['ccc /* this is a\nmulti line\r\ncomment v64 */ ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2500 }
]],
[['ccL8cc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1250 }
]],
[['rrL8rr', options], [
{ type: 'rest', ticks: 500, time: 0 },
{ type: 'rest', ticks: 500, time: 500 },
{ type: 'rest', ticks: 250, time: 1000 },
{ type: 'rest', ticks: 250, time: 1250 }
]],
[['L2cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 2250, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 49, ticks: 3375, volume: 100/127, time: 4750 }
]],
[['L4.cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 750, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1125, volume: 100/127, time: 750 },
{ type: 'note', pitch: 49, ticks: 1687, volume: 100/127, time: 1875 },
{ type: 'note', pitch: 49, ticks: 2530, volume: 100/127, time: 3562 }
]],
[['o3c>c>c<c<c', options], [
{ type: 'note', pitch: 25, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 37, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 37, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 25, ticks: 500, volume: 100/127, time: 2000 }
]],
[['t180ccc', options], [
{ type: 'tempo', tempo: 180, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['v64ccc', options], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 1000 }
]],
[['c&c&c', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'tie' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'tie' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['L8V64O2c,c,c', options], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 }
]],
[['L8V64O2c,c,c', extend({}, options, { tracksShareState: false })], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 }
]],
[['@#$ ccc !|/', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]]
]);
});
describe('parseMml', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 100,
volume: 100/127,
duration: '4'
},
maxVolume: 127,
tracksShareState: true,
octaveOffset: -1,
transpose: 1
};
runCases('should parse {0}', core.parseMml, [
[['ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['cdefgabCDEFGAB', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 51, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 56, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 58, ticks: 500, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 60, ticks: 500, volume: 100/127, time: 3000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 3500 },
{ type: 'note', pitch: 51, ticks: 500, volume: 100/127, time: 4000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 4500 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 5000 },
{ type: 'note', pitch: 56, ticks: 500, volume: 100/127, time: 5500 },
{ type: 'note', pitch: 58, ticks: 500, volume: 100/127, time: 6000 },
{ type: 'note', pitch: 60, ticks: 500, volume: 100/127, time: 6500 },
]],
[['c#d#e#f#g#a#b#c+d+e+f+g+a+b+c-d-e-f-g-a-b-', options], [
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 3000 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 3500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 4000 },
{ type: 'note', pitch: 54, ticks: 500, volume: 100/127, time: 4500 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 5000 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 5500 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 6000 },
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 6500 },
{ type: 'note', pitch: 48, ticks: 500, volume: 100/127, time: 7000 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 7500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 8000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 8500 },
{ type: 'note', pitch: 55, ticks: 500, volume: 100/127, time: 9000 },
{ type: 'note', pitch: 57, ticks: 500, volume: 100/127, time: 9500 },
{ type: 'note', pitch: 59, ticks: 500, volume: 100/127, time: 10000 }
]],
[['c2c4c8c', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1750 }
]],
[['c2c2.c2..c2...', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 2250, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 49, ticks: 3375, volume: 100/127, time: 4750 }
]],
[['cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 750, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 1125, volume: 100/127, time: 1250 },
{ type: 'note', pitch: 49, ticks: 1687, volume: 100/127, time: 2375 }
]],
[['n60n30n90', options], [
{ type: 'note', pitch: 61, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 31, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 91, ticks: 500, volume: 100/127, time: 1000 }
]],
[['r2r4r8r', options], [
{ type: 'rest', ticks: 1000, time: 0 },
{ type: 'rest', ticks: 500, time: 1000 },
{ type: 'rest', ticks: 250, time: 1500 },
{ type: 'rest', ticks: 500, time: 1750 }
]],
[['r2r2.r2..r2...', options], [
{ type: 'rest', ticks: 1000, time: 0 },
{ type: 'rest', ticks: 1500, time: 1000 },
{ type: 'rest', ticks: 2250, time: 2500 },
{ type: 'rest', ticks: 3375, time: 4750 }
]],
[['rr.r..r...', options], [
{ type: 'rest', ticks: 500, time: 0 },
{ type: 'rest', ticks: 750, time: 500 },
{ type: 'rest', ticks: 1125, time: 1250 },
{ type: 'rest', ticks: 1687, time: 2375 }
]],
[['ccc /* this is a comment v64 */ ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2500 }
]],
[['ccc /* this is a\nmulti line\r\ncomment v64 */ ccc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2000 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 2500 }
]],
[['ccL8cc', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 250, volume: 100/127, time: 1250 }
]],
[['rrL8rr', options], [
{ type: 'rest', ticks: 500, time: 0 },
{ type: 'rest', ticks: 500, time: 500 },
{ type: 'rest', ticks: 250, time: 1000 },
{ type: 'rest', ticks: 250, time: 1250 }
]],
[['L2cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 1000, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 49, ticks: 2250, volume: 100/127, time: 2500 },
{ type: 'note', pitch: 49, ticks: 3375, volume: 100/127, time: 4750 }
]],
[['L4.cc.c..c...', options], [
{ type: 'note', pitch: 49, ticks: 750, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 1125, volume: 100/127, time: 750 },
{ type: 'note', pitch: 49, ticks: 1687, volume: 100/127, time: 1875 },
{ type: 'note', pitch: 49, ticks: 2530, volume: 100/127, time: 3562 }
]],
[['o3c>c>c<c<c', options], [
{ type: 'note', pitch: 25, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 37, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 37, ticks: 500, volume: 100/127, time: 1500 },
{ type: 'note', pitch: 25, ticks: 500, volume: 100/127, time: 2000 }
]],
[['t180ccc', options], [
{ type: 'tempo', tempo: 180, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['v64ccc', options], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 64/127, time: 1000 }
]],
[['c&c&c', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'tie' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'tie' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]],
[['L8V64O2c,c,c', options], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 }
]],
[['L8V64O2c,c,c', extend({}, options, { tracksShareState: false })], [
{ type: 'volume', volume: 64/127, time: 0 },
{ type: 'note', pitch: 13, ticks: 250, volume: 64/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'nextVoice' },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 }
]],
[['@#$ ccc !|/', options], [
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 49, ticks: 500, volume: 100/127, time: 1000 }
]]
]);
});
describe('findPath', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 120,
volume: 100/127,
duration: '4'
},
transpose: 0
};
runCases('should find a path given an input token set', opt.findPath, [
[[opt.parseMml('cdef', options), options], [
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 1, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 3, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 4, octave: 4, tempo: 120, volume: 100/127, duration: '4' }
]],
[[opt.parseMml('c16d16e32f32', options), options], [
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 1, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '32' },
{ cursor: 3, octave: 4, tempo: 120, volume: 100/127, duration: '32' },
{ cursor: 4, octave: 4, tempo: 120, volume: 100/127, duration: '32' }
]]
]);
});
describe('findPath', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 120,
volume: 100/127,
duration: '4'
},
transpose: 0
};
runCases('should find a path given an input token set', core.findPath, [
[[core.parseMml('cdef', options), options], [
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 1, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 3, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 4, octave: 4, tempo: 120, volume: 100/127, duration: '4' }
]],
[[core.parseMml('c16d16e32f32', options), options], [
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '4' },
{ cursor: 0, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 1, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '16' },
{ cursor: 2, octave: 4, tempo: 120, volume: 100/127, duration: '32' },
{ cursor: 3, octave: 4, tempo: 120, volume: 100/127, duration: '32' },
{ cursor: 4, octave: 4, tempo: 120, volume: 100/127, duration: '32' }
]]
]);
});
describe('optimizeTokens', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 120,
volume: 100/127,
duration: '4'
},
transpose: 0
};
runCases('should return an optimized token set', opt.optimizeTokens, [
[[opt.parseMml('cdef', options), options], [
{ type: 'note', pitch: 48, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 1500 }
]],
[[opt.parseMml('c16d16e32f32', options), options], [
{ type: 'duration', duration: '16', time: 0 },
{ type: 'note', pitch: 48, ticks: 125, volume: 100/127, time: 0 },
{ type: 'note', pitch: 50, ticks: 125, volume: 100/127, time: 125 },
{ type: 'duration', duration: '32', time: 250 },
{ type: 'note', pitch: 52, ticks: 62, volume: 100/127, time: 250 },
{ type: 'note', pitch: 53, ticks: 62, volume: 100/127, time: 312 }
]]
]);
describe('optimizeTokens', function () {
var options = {
tpqn: 500,
minimumNoteDuration: 64,
defaultState: {
octave: 4,
tempo: 120,
volume: 100/127,
duration: '4'
},
transpose: 0
};
runCases('should return an optimized token set', core.optimizeTokens, [
[[core.parseMml('cdef', options), options], [
{ type: 'note', pitch: 48, ticks: 500, volume: 100/127, time: 0 },
{ type: 'note', pitch: 50, ticks: 500, volume: 100/127, time: 500 },
{ type: 'note', pitch: 52, ticks: 500, volume: 100/127, time: 1000 },
{ type: 'note', pitch: 53, ticks: 500, volume: 100/127, time: 1500 }
]],
[[core.parseMml('c16d16e32f32', options), options], [
{ type: 'duration', duration: '16', time: 0 },
{ type: 'note', pitch: 48, ticks: 125, volume: 100/127, time: 0 },
{ type: 'note', pitch: 50, ticks: 125, volume: 100/127, time: 125 },
{ type: 'duration', duration: '32', time: 250 },
{ type: 'note', pitch: 52, ticks: 62, volume: 100/127, time: 250 },
{ type: 'note', pitch: 53, ticks: 62, volume: 100/127, time: 312 }
]]
]);
});
});

@@ -374,0 +378,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc