not really known
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

494 lines
24 KiB

// Copyright (c) 2014-2016 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA
// This header is prepended to the Lilypond output.
const LILYPONDHEADER = '\\version "2.18.2"\n\n% ****************************************************************\n% \n% WHAT IS THIS? -- This is a LilyPond file generated from Music\n% Blocks software (Read about it at www.musicblocks.net).\n% \n% DOWNLOAD LILYPOND -- In order to create notation with this file,\n% you will need to download and install LilyPond software onto your\n% computer (http://lilypond.org/download.html). Frescobaldi\n% software is also handy for editing LilyPond files\n% (http://frescobaldi.org/download).\n% \n% LILYPOND INSTRUCTIONS -- For instructions on how to further\n% manipulate musical notation using LilyPond software, please\n% read the Introduction (http://lilypond.org/text-input.html) and\n% the Manual\n% (http://lilypond.org/doc/v2.18/Documentation/learning/index.html).\n% \n% GLOSSARY -- A glossary with helpful examples may be found here\n% (http://www.lilypond.org/doc/v2.19/Documentation/music-glossary/).\n% \n% MUTOPIA -- You may also benefit from studying scores from the\n% Mutopia Project website, which has freely sharable music notation\n% generated with LilyPond (http://www.mutopiaproject.org/).\n% \n% LILYBIN -- You can explore your Lilypond output in a web browser at\n% (http://lilybin.com/).\n% \n% COMMENTS -- Some of the code below is commented out. You can\n% enable it by deleting the % that precedes the text or, in the\n% case of a commented section, deleting the %{ and %} that surrounds\n% the section.\n% \n% ****************************************************************\n\n% Please add your own name, the title of your musical creation,\n% and the intended copyright below.\n% The copyright is great for sharing (and re-sharing)!\n% Read more about it here (http://creativecommons.org/licenses/by-sa/4.0/).\n% Of course, you can use any copyright you like -- you made it!\n\\header {\n dedication = \\markup {\n \\abs-fontsize #8 \\sans "Made with LilyPond and Music Blocks" \\with-url #"http://walterbender.github.io/musicblocks/" {\n \\abs-fontsize #8 \\sans "(http://walterbender.github.io/musicblocks/)"\n }\n }\n title = "My Music Blocks Creation"\n% subtitle = "Subtitle"\n% instrument = "Instrument"\n composer = "Mr. Mouse"\n% arranger = "Arranger"\n copyright = "Mr. Mouse (c) 2015 -- CC-BY-SA"\n tagline = "Made from Music Blocks v.0.9"\n footer = \\markup {\n \\with-url #"http://walterbender.github.io/musicblocks/" "Made with Music Blocks Software v.0.9." Engraved on \\simple #(strftime "%Y-%m-%d" (localtime (current-time)))\n }\n currentYear = \\markup {\n \\simple #(strftime "%Y" (localtime (current-time)))\n }\n copyTag = " free to distribute, modify, and perform"\n copyType = \\markup {\n \\with-url #"http://creativecommons.org/licenses/by-sa/3.0/" "Creative Commons Attribution ShareAlike 3.0 (Unported) License "\n }\n copyright = \\markup {\n \\override #\'(baseline-skip . 0 ) \\right-column {\n \\sans \\bold \\with-url #"http://musicblocks.net" {\n \\abs-fontsize #9 "Music " \\concat {\n \\abs-fontsize #12 \\with-color #white \\char ##x01C0 \\abs-fontsize #9 "Blocks "\n }\n }\n }\n \\override #\'(baseline-skip . 0 ) \\center-column {\n \\abs-fontsize #11.9 \\with-color #grey \\bold {\n \\char ##x01C0 \\char ##x01C0\n }\n }\n \\override #\'(baseline-skip . 0 ) \\column {\n \\abs-fontsize #8 \\sans \\concat {\n " Typeset using " \\with-url #"http://www.lilypond.org" "LilyPond software " \\char ##x00A9 " " \\currentYear " by " \\composer " " \\char ##x2014 " " \\footer\n }\n \\concat {\n \\concat {\n \\abs-fontsize #8 \\sans {\n " " \\copyType \\char ##x2014 \\copyTag\n }\n }\n \\abs-fontsize #13 \\with-color #white \\char ##x01C0\n }\n }\n }\n tagline = ##f\n}\n\n% To change the meter make adjustments in the following section.\n% You must also delete the % before \\meter everywhere it appears below.\nmeter = {\n \\time 3/4\n \\key c \\minor\n \\numericTimeSignature\n \\partial 4 \n \\tempo "Andante" 4=90\n}\n\n';
//.TRANS Animal names used in Lilypond output
const RODENTS = [_('mouse'), _('brown rat'), _('mole'), _('chipmunk'), _('red squirrel'), _('guinea pig'), _('capybara'), _('coypu'), _('black rat'), _('grey squirrel'), _('flying squirrel'), _('bat')];
const RODENTSEN = ['mouse', 'brown rat', 'mole', 'chipmunk', 'red squirrel', 'guinea pig', 'capybara', 'coypu', 'black rat', 'grey squirrel', 'flying squirrel', 'bat'];
//.TRANS Abbreviations for names used in Lilypind output, e.g., m for mouse
const RODENTSSHORT = [_('m'), _('br'), _('ml'), _('ch'), _('rs'), _('gp'), _('cb'), _('cp'), _('bk'), _('gs'), _('fs'), _('bt')];
const RODENTSSHORTEN = ['m', 'br', 'ml', 'ch', 'rs', 'gp', 'cb', 'cp', 'bk', 'gs', 'fs', 'bt'];
const LYNOTE = 0;
const LYDURATION = 1;
const LYDOTCOUNT = 2;
const LYTUPLETVALUE = 3;
const LYROUNDDOWN = 4;
const LYINSIDECHORD = 5;
const LYSTACCATO = 6;
const CLEFS = ['treble', 'bass', 'bass_8', 'percussion'];
getLilypondHeader = function () {
return LILYPONDHEADER;
}
updateLilypondNotation = function (logo, note, duration, turtle, insideChord) {
var obj = durationToNoteValue(duration);
if (!(turtle in logo.lilypondStaging)) {
logo.lilypondStaging[turtle] = [];
}
if (logo.turtles.turtleList[turtle].drum) {
note = "c'";
}
logo.lilypondStaging[turtle].push([note, obj[0], obj[1], obj[2], obj[3], insideChord, logo.staccato[turtle].length > 0 && last(logo.staccato[turtle]) > 0]);
};
processLilypondNotes = function (logo, turtle) {
// obj = [instructions] or
// obj = [note, duration, dotCount, tupletValue, roundDown, insideChord, staccato, tie]
logo.lilypondNotes[turtle] = '';
function __toLilynote (note) {
// Lilypond notes use is for sharp, es for flat,
// , and ' for shifts in octave.
// Also, notes must be lowercase.
// And the octave bounday is at C, not A.
// Convert frequencies here.
if (typeof(note) === 'number') {
var pitchObj = frequencyToPitch(note);
note = pitchObj[0] + pitchObj[1];
}
return note.replace(/♯/g, 'is').replace(/♭/g, 'es').replace(/10/g, "''''''''").replace(/1/g, ',,').replace(/2/g, ',').replace(/3/g, '').replace(/4/g, "'").replace(/5/g, "''").replace(/6/g, "'''").replace(/7/g, "''''").replace(/8/g, "''''''").replace(/9/g, "'''''''").toLowerCase();
};
var counter = 0;
var queueSlur = false;
var articulation = false;
var targetDuration = 0;
var tupletDuration = 0;
for (var i = 0; i < logo.lilypondStaging[turtle].length; i++) {
obj = logo.lilypondStaging[turtle][i];
if (typeof(obj) === 'string') {
if (obj === 'break') {
if (i > 0) {
logo.lilypondNotes[turtle] += '\n';
}
counter = 0;
} else {
if (obj === '(') {
// The ( is added after the first note.
queueSlur = true;
} else if (obj === 'begin articulation') {
articulation = true;
} else if (obj === 'end articulation') {
articulation = false;
} else {
logo.lilypondNotes[turtle] += obj;
}
}
} else {
if (counter % 8 === 0 && counter > 0) {
logo.lilypondNotes[turtle] += '\n';
}
counter += 1;
var note = __toLilynote(obj[LYNOTE]);
var incompleteTuplet = 0; // An incomplete tuplet
// If it is a tuplet, look ahead to see if it is complete.
// While you are at it, add up the durations.
if (obj[LYTUPLETVALUE] != null) {
targetDuration = (1 / logo.lilypondStaging[turtle][i][LYDURATION]);
tupletDuration = (1 / logo.lilypondStaging[turtle][i][LYROUNDDOWN]);
var j = 1;
var k = 1;
while (k < obj[LYTUPLETVALUE]) {
if (i + j >= logo.lilypondStaging[turtle].length) {
incompleteTuplet = j;
break;
}
if (logo.lilypondStaging[turtle][i + j][LYINSIDECHORD] > 0 && logo.lilypondStaging[turtle][i + j][LYINSIDECHORD] === logo.lilypondStaging[turtle][i + j - 1][LYINSIDECHORD]) {
// In a chord, so jump to next note.
j++;
} else if (logo.lilypondStaging[turtle][i + j][LYTUPLETVALUE] !== obj[LYTUPLETVALUE]) {
incompleteTuplet = j;
break;
} else {
targetDuration += (1 / logo.lilypondStaging[turtle][i + j][LYDURATION]);
tupletDuration += (1 / logo.lilypondStaging[turtle][i + j][LYROUNDDOWN]);
j++; // Jump to next note.
k++; // Increment notes in tuplet.
}
}
}
function __processTuplet(logo, turtle, i, count) {
var j = 0;
var k = 0;
while (k < count) {
var tupletDuration = 2 * logo.lilypondStaging[turtle][i + j][LYDURATION];
// Are we in a chord?
if (logo.lilypondStaging[turtle][i + j][LYINSIDECHORD] > 0) {
// Is logo the first note in the chord?
if ((i === 0 && j === 0) || logo.lilypondStaging[turtle][i + j - 1][LYINSIDECHORD] !== logo.lilypondStaging[turtle][i + j][LYINSIDECHORD]) {
logo.lilypondNotes[turtle] += '<';
}
logo.lilypondNotes[turtle] += __toLilynote(logo.lilypondStaging[turtle][i + j][LYNOTE]);
if (obj[LYSTACCATO]) {
logo.lilypondNotes[turtle] += '\\staccato';
}
logo.lilypondNotes[turtle] += ' ';
// Is logo the last note in the chord?
if (i + j === logo.lilypondStaging[turtle].length - 1 || logo.lilypondStaging[turtle][i + j + 1][LYINSIDECHORD] !== logo.lilypondStaging[turtle][i + j][LYINSIDECHORD]) {
logo.lilypondNotes[turtle] += '>' + logo.lilypondStaging[turtle][i + j + 1][LYROUNDDOWN] + ' ';
k++; // Increment notes in tuplet.
}
j++;
} else {
logo.lilypondNotes[turtle] += __toLilynote(logo.lilypondStaging[turtle][i + j][LYNOTE]) + logo.lilypondStaging[turtle][i + j][LYROUNDDOWN];
if (obj[LYSTACCATO]) {
logo.lilypondNotes[turtle] += '\\staccato';
}
logo.lilypondNotes[turtle] += ' ';
j++; // Jump to next note.
k++; // Increment notes in tuplet.
}
}
// Workaround to a Lilypond "feature": if a slur
// ends on a tuplet, the closing ) must be inside
// the closing } of the tuplet.
if (i + j - 1 < logo.lilypondStaging[turtle].length - 1) {
var nextObj = logo.lilypondStaging[turtle][i + j];
if (typeof(nextObj) === 'string' && nextObj === ')') {
logo.lilypondNotes[turtle] += ')} ';
i += 1;
} else {
logo.lilypondNotes[turtle] += '} ';
}
} else {
logo.lilypondNotes[turtle] += '} ';
}
return j;
};
if (obj[LYTUPLETVALUE] > 0) {
// lilypond tuplets look like logo: \tuplet 3/2 { f8 g a }
// multiplier = tupletDuration / targetDuration
// e.g., (3/8) / (1/4) = (3/8) * 4 = 12/8 = 3/2
// There may be chords embedded.
if (incompleteTuplet === 0) {
var tupletFraction = toFraction(tupletDuration / targetDuration);
logo.lilypondNotes[turtle] += '\\tuplet ' + tupletFraction[0] + '/' + tupletFraction[1] + ' { ';
i += __processTuplet(logo, turtle, i, obj[LYTUPLETVALUE]) - 1;
} else {
var tupletFraction = toFraction(obj[LYTUPLETVALUE] / incompleteTuplet);
logo.lilypondNotes[turtle] += '\\tuplet ' + tupletFraction[0] + '/' + tupletFraction[1] + ' { ';
i += __processTuplet(logo, turtle, i, incompleteTuplet) - 1;
}
targetDuration = 0;
tupletDuration = 0;
} else {
if (obj[LYINSIDECHORD] > 0) {
// Is logo the first note in the chord?
if (i === 0 || logo.lilypondStaging[turtle][i - 1][LYINSIDECHORD] !== obj[LYINSIDECHORD]) {
// Open the chord.
logo.lilypondNotes[turtle] += '<';
}
logo.lilypondNotes[turtle] += (note);
// Is logo the last note in the chord?
if (i === logo.lilypondStaging[turtle].length - 1 || logo.lilypondStaging[turtle][i + 1][LYINSIDECHORD] !== obj[LYINSIDECHORD]) {
// Close the chord and add note duration.
logo.lilypondNotes[turtle] += '>';
logo.lilypondNotes[turtle] += obj[LYDURATION];
for (var d = 0; d < obj[LYDOTCOUNT]; d++) {
logo.lilypondNotes[turtle] += '.';
}
if (articulation) {
logo.lilypondNotes[turtle] += '->';
}
logo.lilypondNotes[turtle] += ' ';
}
} else {
logo.lilypondNotes[turtle] += (note + obj[LYDURATION]);
for (var d = 0; d < obj[LYDOTCOUNT]; d++) {
logo.lilypondNotes[turtle] += '.';
}
if (articulation) {
logo.lilypondNotes[turtle] += '->';
}
}
if (obj[LYSTACCATO]) {
logo.lilypondNotes[turtle] += '\\staccato';
}
targetDuration = 0;
tupletDuration = 0;
}
logo.lilypondNotes[turtle] += ' ';
if (queueSlur) {
queueSlur = false;
logo.lilypondNotes[turtle] += '(';
}
}
}
};
lilypondLineBreak = function(logo, turtle) {
if (logo.lilypondStaging[turtle] == undefined) {
logo.lilypondStaging[turtle] = [];
}
logo.lilypondStaging[turtle].push('break');
};
lilypondBeginArticulation = function(logo, turtle) {
if (logo.lilypondStaging[turtle] == undefined) {
logo.lilypondStaging[turtle] = [];
}
logo.lilypondStaging[turtle].push('begin articulation');
};
lilypondEndArticulation = function(logo, turtle) {
logo.lilypondStaging[turtle].push('end articulation');
};
lilypondBeginCrescendo = function(logo, turtle, factor) {
if (logo.lilypondStaging[turtle] == undefined) {
logo.lilypondStaging[turtle] = [];
}
if (factor > 0) {
logo.lilypondStaging[turtle].push('\\< ');
} else {
logo.lilypondStaging[turtle].push('\\> ');
}
};
lilypondEndCrescendo = function(logo, turtle) {
logo.lilypondStaging[turtle].push('\\! ');
};
lilypondBeginSlur = function(logo, turtle) {
if (logo.lilypondStaging[turtle] == undefined) {
logo.lilypondStaging[turtle] = [];
}
logo.lilypondStaging[turtle].push('(');
};
lilypondEndSlur = function(logo, turtle) {
logo.lilypondStaging[turtle].push(') ');
};
lilypondInsertTie = function(logo, turtle) {
if (logo.lilypondStaging[turtle] == undefined) {
logo.lilypondStaging[turtle] = [];
}
logo.lilypondStaging[turtle].push('~');
};
lilypondRemoveTie = function(logo, turtle) {
logo.lilypondStaging[turtle].pop();
};
saveLilypondOutput = function(logo, saveName) {
var turtleCount = 0;
var clef = [];
for (var t in logo.lilypondStaging) {
turtleCount += 1;
}
console.log('saving as lilypond: ' + turtleCount);
logo.lilypondOutput += '% You can change the MIDI instruments below to anything on logo list:\n% (http://lilypond.org/doc/v2.18/documentation/notation/midi-instruments)\n\n';
var c = 0;
for (var t in logo.lilypondStaging) {
if (logo.lilypondStaging[t].length > 0) {
var octaveTotal = 0;
var noteCount = 0;
for (var i = 0; i < logo.lilypondStaging[t].length; i++) {
obj = logo.lilypondStaging[t][i];
if (typeof(obj) === 'object') {
if (obj[0].length < 2) {
// Test for rests
} else {
if (typeof(obj[0]) === 'string') {
octaveTotal += Number(obj[0].substr(-1));
} else {
var pitchObj = frequencyToPitch(obj[0]);
octaveTotal += pitchObj[1];
}
noteCount += 1;
}
}
}
if (logo.turtles.turtleList[t].drum) {
clef.push('percussion');
} else if (noteCount > 0) {
// console.log(t + ': ' + octaveTotal + ' ' + noteCount);
switch (Math.floor(octaveTotal / noteCount)) {
case 0:
case 1:
case 2:
clef.push('bass_8');
break;
case 3:
clef.push('bass');
break;
default:
clef.push('treble');
break;
}
} else {
clef.push('treble');
}
processLilypondNotes(logo, t);
var instrumentName = logo.turtles.turtleList[t].name;
if (instrumentName === _('start') || instrumentName === _('start drum')) {
instrumentName = RODENTS[t % 12];
} else if (instrumentName === t.toString()) {
instrumentName = RODENTS[t % 12];
}
if (instrumentName === "") {
instrumentName = RODENTSEN[t % 12];
}
instrumentName = instrumentName.replace(/ /g, '_');
logo.lilypondOutput += instrumentName + ' = {\n';
logo.lilypondOutput += '% \\meter\n';
logo.lilypondOutput += logo.lilypondNotes[t];
// Add bar to last turtle's output.
if (c === turtleCount - 1) {
logo.lilypondOutput += ' \\bar "|."'
}
logo.lilypondOutput += '\n}\n\n';
var shortInstrumentName = RODENTSSHORT[t % 12];
if (shortInstrumentName === "") {
shortInstrumentName = RODENTSSHORTEN[t % 12];
}
logo.lilypondOutput += instrumentName.replace(/ /g, '_') + 'Voice = ';
if (logo.turtles.turtleList[t].drum) {
logo.lilypondOutput += '\\new DrumStaff \\with {\n';
// logo.lilypondOutput += ' \\drummode {\n hihat4 hh bassdrum bd\n }\n';
} else {
logo.lilypondOutput += '\\new Staff \\with {\n';
}
logo.lilypondOutput += ' \\clef "' + last(clef) + '"\n';
logo.lilypondOutput += ' instrumentName = "' + instrumentName + '"\n';
logo.lilypondOutput += ' shortInstrumentName = "' + shortInstrumentName + '"\n';
logo.lilypondOutput += ' midiInstrument = "acoustic grand"\n';
// Automatic note splitting
logo.lilypondOutput += '\n \\remove "Note_heads_engraver"\n \\consists "Completion_heads_engraver"\n \\remove "Rest_engraver"\n \\consists "Completion_rest_engraver"\n'
logo.lilypondOutput += '} { \\clef "' + last(clef) + '" \\' + instrumentName.replace(/ /g, '_') + ' }\n\n';
}
c += 1;
}
// Begin the SCORE section.
logo.lilypondOutput += '\n\\score {\n';
logo.lilypondOutput += ' <<\n';
// Sort the staffs, treble on top, bass_8 on the bottom.
for (var c = 0; c < CLEFS.length; c++) {
var i = 0;
for (var t in logo.lilypondNotes) {
if (clef[i] === CLEFS[c]) {
if (logo.lilypondStaging[t].length > 0) {
var instrumentName = logo.turtles.turtleList[t].name;
if (instrumentName === _('start') || instrumentName === _('start drum')) {
instrumentName = RODENTS[t % 12];
} else if (instrumentName === t.toString()) {
instrumentName = RODENTS[t % 12];
}
instrumentName = instrumentName.replace(/ /g, '_');
logo.lilypondOutput += ' \\' + instrumentName + 'Voice\n';
}
}
}
}
// Add GUITAR TAB in comments.
logo.lilypondOutput += '\n\n% GUITAR TAB SECTION\n% Delete the %{ and %} below to include guitar tablature output.\n%{\n \\new TabStaff = "guitar tab" \n <<\n \\clef moderntab\n';
for (var c = 0; c < CLEFS.length; c++) {
var i = 0;
for (var t in logo.lilypondNotes) {
if (clef[i] === CLEFS[c]) {
if (logo.lilypondStaging[t].length > 0) {
var instrumentName = logo.turtles.turtleList[t].name;
if (instrumentName === _('start') || instrumentName === _('start drum')) {
instrumentName = RODENTS[t % 12]
} else if (instrumentName === t.toString()) {
instrumentName = RODENTS[t % 12];
}
instrumentName = instrumentName.replace(/ /g, '_');
logo.lilypondOutput += ' \\context TabVoice = "'+ instrumentName + '" \\' + instrumentName.replace(/ /g, '_') + '\n';
}
}
}
}
// Close the SCORE sections.
logo.lilypondOutput += ' >>\n%}\n';
logo.lilypondOutput += '\n >>\n \\layout {}\n\n';
// Add MIDI OUTPUT in comments.
logo.lilypondOutput += '% MIDI SECTION\n% Delete the %{ and %} below to include MIDI output.\n%{\n\\midi {\n \\tempo 4=90\n}\n%}\n\n}\n\n';
// ADD TURTLE BLOCKS CODE HERE
logo.lilypondOutput += '% MUSIC BLOCKS CODE\n';
logo.lilypondOutput += '% Below is the code for the Music Blocks project that generated logo Lilypond file.\n%{\n\n';
// prepareExport() returns json-encoded project data.
var projectData = prepareExport();
logo.lilypondOutput += projectData.replace(/]],/g, ']],\n');
logo.lilypondOutput += '\n%}\n\n';
doSaveLilypond(logo, saveName);
};