( ~transcribe = {arg scoreData, seed; var rawMusicData, timeSigData, sectionData, dir, basePath, scoreFile, maxSize, lineBreakString, openStrings, musicData; rawMusicData = scoreData[0]; timeSigData = scoreData[1]; sectionData = scoreData[2]; basePath = ~dir +/+ ".." +/+ "lilypond" +/+ "seed_" ++ seed; basePath.mkdir; (basePath +/+ "includes").mkdir; scoreFile = File(basePath +/+ "cicc_score.ly".standardizePath,"w"); scoreFile.write(File.readAllString(basePath +/+ ".." +/+ "templates" +/+ "cicc_score_template.ly").replace("seed: xxx", "seed: " ++ seed)); scoreFile.close; scoreFile = File(basePath +/+ "cicc_pseudoindents_def.ly".standardizePath,"w"); scoreFile.write(File.readAllString(basePath +/+ ".." +/+ "templates" +/+ "cicc_pseudoindents_def.ly")); scoreFile.close; openStrings = [1/1, 3/2, 2/1, 5/2, 35/12, 7/2]; maxSize = 0; musicData = rawMusicData.collect({arg partData, p; var res; res = partData.collect({arg item, i; var note, rest; switch(p, 0, { var string, fret, dur, sus; string = item[0]; fret = item[1]; dur = item[2]; sus = item[3]; note = sus.collect({[string, fret, i]}); }, 1, { var freq, dur, sus; freq = item[0]; dur = item[1]; sus = item[2]; note = sus.collect({[freq, i]}); rest = if(p < rawMusicData.size, {(dur - sus).collect({[-1, i]})}, {[]}); }, 2, { var freq1, freq2, dur, sus; freq1 = item[0]; freq2 = item[1]; dur = item[2]; sus = 4; note = sus.collect({[[freq1, freq2 - freq1], i]}); rest = if(p < rawMusicData.size, {(dur - sus).collect({[-1, i]})}, {[]}); } ); note ++ rest }).flatten; if(res.size > maxSize, {maxSize = res.size}); res }); musicData = musicData.collect({arg partData, p; var lastSectionSize, lastSectionSizeTrunc, finalSectionSize, ext; lastSectionSize = (maxSize - sectionData.last[0]); lastSectionSizeTrunc = lastSectionSize.trunc(16); finalSectionSize = if(lastSectionSize != lastSectionSizeTrunc, {lastSectionSizeTrunc + 16}, {lastSectionSize}); ext = finalSectionSize - lastSectionSize; partData.extend((maxSize + ext), if(p == 0, {partData.last}, {[-1, partData.last[1]]})) }); lineBreakString = ""; sectionData.slice(nil, 0).add(musicData[0].size).differentiate.drop(1).clump(4).do({arg section; var remainder, endSec; remainder = 0; section.do({arg len, index; var noFullSystems; //this causes a problem if a section is less than 10 half notes (4 measures) if(remainder % 16 == 0, { lineBreakString = lineBreakString ++ "\\repeat unfold 8 {s2 \\noBreak} \\break \n"; }, { var noBeats; noBeats = ((remainder + (64 - remainder).trunc(16)) / 8).asInteger; lineBreakString = lineBreakString ++ "\\pseudoIndents 0 " ++ (21 * (8 - noBeats)) ++ " \\repeat unfold " ++ noBeats ++ " {s2 \\noBreak} \\break \n"; }); remainder = len - (64 - remainder).trunc(16); noFullSystems = (remainder.trunc(64) / 64).asInteger; if(noFullSystems > 0, { (noFullSystems - 1).do({ lineBreakString = lineBreakString ++ "\\repeat unfold 8 {s2 \\noBreak} \\break \n"; }); if(remainder % 64 != 8, { lineBreakString = lineBreakString ++ "\\repeat unfold 8 {s2 \\noBreak} \\break \n"; remainder = remainder - (noFullSystems * 64); }, { lineBreakString = lineBreakString ++ "\\pseudoIndents 0 42 \\repeat unfold 6 {s2 \\noBreak} \\break \n"; remainder = 24; }); }); }); if(remainder > 0, { lineBreakString = lineBreakString ++ "\\pseudoIndents 0 " ++ (21 * (8 - (remainder / 8).asInteger)) ++ " \\repeat unfold " ++ (remainder / 8).asInteger ++ " {s2 \\noBreak} \\break \n"; }); }); musicData.do({arg part, p; var amps, harm, modi, timeSigIndex, sectionCount, sectionIndex, subSectionIndex, curTimeSig, lilyFile, lilyString, voices, lastVal, lilyNotes, lilyOcts, lilyGString, isHarmonic, measureCount, lilyNote, lilyDur, lilyRest, lilyBeatingMark, curTime = 0, noteTuples, markupSuffixes; //create file lilyFile = switch(p, 0, {File(basePath +/+ "includes" +/+ "cicc_guitar.ly".standardizePath,"w")}, 1, {File(basePath +/+ "includes" +/+ "cicc_high.ly".standardizePath,"w")}, 2, {File(basePath +/+ "includes" +/+ "cicc_low.ly".standardizePath,"w")} ); //start lilypond directives lilyString = ""; lastVal = nil; //start voice lilyString = lilyString ++ "\n{ "; lilyString = lilyString ++ "\n\\set Score.markFormatter = #format-mark-box-numbers "; lilyString = lilyString + "\\tempo \\markup {\\concat {\\smaller \\general-align #Y #DOWN \\note #\"2\" #1 \\normal-text \""; lilyString = lilyString + "= approx. 80 (preferably faster towards 90 and no less than 70)\"}}"; if(p != 1, {lilyString = lilyString + "\\override Staff.TimeSignature #'stencil = ##f"}); lilyString = lilyString + "\\numericTimeSignature \\time 2/2\n"; lilyString = switch(p, 0, {lilyString + "\\clef \"treble_(8)\"\n"}, 1, {lilyString + "\\clef \"treble\"\n"}, 2, {lilyString + "\\clef \"bass_(8)\"\n"} ); lilyNotes = ["c", "cis", "d", "dis","e", "f", "fis", "g", "gis", "a", "ais", "b"]; lilyOcts = [",,", ",", "", "'", "''", "'''", "''''"]; timeSigIndex = 0; sectionCount = 0; sectionIndex = 1; subSectionIndex = 1; curTimeSig = 4; measureCount = 0; part.clump(4).do({arg beat, i; var gSum = 0; beat.separate({arg a, b; ((a[0] != -1) || (b[0] != -1)) && (a != b)}).do({arg group, g; var noteLength, target = 0; noteLength = group.size; gSum = gSum + noteLength; //add ties lilyString = lilyString ++ if((p != 2) && (group[0] == lastVal) && (group[0][0] != -1), {"~ "}, {""}); //add barcheck count lilyString = lilyString ++ if((curTime % curTimeSig == 0) && (i != 0), {measureCount = measureCount + 1; "| "}, {""}); if((i == (sectionData[sectionCount][0] / 4)) && (g == 0),{ var barType, pageBreak; barType = switch(sectionData[sectionCount][1], 0, {"\"||\""}, 1, {"\".|\""}, -1, {"\"|.\" \\set Score.currentBarNumber = #1 "}); pageBreak = switch(sectionData[sectionCount][1], 0, {""}, 1, {""}, -1, {measureCount = 0; "\n\\pageBreak \n \\time 2/2\n"}); isHarmonic = switch(sectionData[sectionCount][1], 0, {false}, 1, {true}, -1, {false}); lilyString = lilyString + " \\bar " ++ barType ++ " \\mark \\markup { \\bold \\box " ++ sectionIndex ++ "." ++ subSectionIndex ++ " }" ++ pageBreak; if(sectionCount < (sectionData.size - 1), {sectionCount = sectionCount + 1}); switch(sectionData[sectionCount][1], 0, {subSectionIndex = subSectionIndex + 1}, 1, {subSectionIndex = subSectionIndex + 1}, -1, {sectionIndex = sectionIndex + 1; subSectionIndex = 1}) }); if((i == (timeSigData[timeSigIndex][0] / 4)) && (g == 0),{ timeSigData[timeSigIndex][0]; curTimeSig = timeSigData[timeSigIndex][1]; if(curTimeSig % 2 == 0, { lilyString = lilyString + "\n\\time " ++ (curTimeSig / 2).asInteger.asString ++ "/2\n"; }, { lilyString = lilyString + "\n\\time " ++ curTimeSig.asString ++ "/4\n"; }); if(timeSigIndex < (timeSigData.size - 1), {timeSigIndex = timeSigIndex + 1}); curTime = 0; }); switch(p, 0, { lilyNote = lilyNotes[(((38.midicps * openStrings[group[0][0]]).cpsmidi + group[0][1]).round(1) % 12)]; lilyNote = lilyNote ++ lilyOcts[(((38.midicps * openStrings[group[0][0]]).cpsmidi + group[0][1]).round(1) / 12).asInteger - 2]; }, 1, { if(group[0][0] != -1, { lilyNote = lilyNotes[((group[0][0].cpsmidi).round(1) % 12)]; lilyNote = lilyNote ++ lilyOcts[(((group[0][0]).cpsmidi).round(1) / 12).asInteger - 2]; },{lilyNote = "r"}); }, 2, { if(group[0][0] != -1, { lilyNote = lilyNotes[((group[0][0][0].cpsmidi).round(1) % 12)];// * 2]; lilyNote = lilyNote ++ lilyOcts[(((group[0][0][0]).cpsmidi).round(1) / 12).asInteger - 2]; lilyBeatingMark = "^ \\markup{ " ++ group[0][0][1].round(0.1) ++ " } "; },{lilyNote = "r"}); } ); //duration lilyDur = switch(noteLength, 1, {"16 "}, 2, {"8 "}, 3, {"8. "}, 4, {"4 "}); //append rest directive //lilyRest = ""; lilyGString = if(((group[0] != lastVal) && (p == 0)), { var stringString, fretString; stringString = ["VI ", "V ", "IV ", "III ", "II ", "I "][group[0][0]]; fretString = group[0][1].asString; if(isHarmonic, {fretString = "\\musicglyph \"noteheads.s0harmonic\""}); "_\\markup{\\concat{ " ++ stringString ++ " \\super " ++ fretString ++ "}} " }, {""}); if((p != 2) || (lilyNote == "r"), { lilyString = lilyString ++ lilyNote ++ lilyDur ++ lilyGString; }, { lilyString = lilyString ++ " <<{ " ++ lilyNote ++ lilyDur ++ " \\laissezVibrer " ++ lilyBeatingMark ++ " }\\\\ {\\new Voice { \\voiceTwo " ++ lilyNote ++ lilyDur ++ " \\laissezVibrer }}>> \\oneVoice " ++ lilyGString; }); //beam group if((p != 2) && (g == 0) && (noteLength != 4), {lilyString = lilyString ++ " [ "}); if((p != 2) && (gSum == 4) && (noteLength != 4), {lilyString = lilyString ++ " ] "}); lastVal = group[0]; curTime = curTime + (noteLength / 4); }); }); //end voice lilyString = lilyString ++ " ] \\bar \"|.\" } \n"; noteTuples = [lilyNotes, lilyOcts].allTuples.collect({arg val; val.join}).join("|"); markupSuffixes = ["VI ", "V ", "IV ", "III ", "II ", "I "].collect({arg stringString; (["\\\\musicglyph \\\"noteheads.s0harmonic\\\""] ++ (0..14)).collect({arg fret; "_\\\\markup{\\\\concat{ " ++ stringString ++ " \\\\super " ++ fret.asString ++ "}}"})}).flatten.join("|"); lilyString.findRegexp( "(" ++ noteTuples ++ ")4 (" ++ markupSuffixes ++ ") ~ " ++ "(" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4" ).clump(8).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "1. " ++ match[2][1])}); lilyString.findRegexp( "(" ++ noteTuples ++ ")4 (" ++ markupSuffixes ++ ") ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4" ).clump(6).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "1 " ++ match[2][1])}); lilyString.findRegexp( "(" ++ noteTuples ++ ")4 (" ++ markupSuffixes ++ ") ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4" ).clump(5).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "2. " ++ match[2][1])}); lilyString.findRegexp("(" ++ noteTuples ++ ")4 (" ++ markupSuffixes ++ ") ~ (" ++ noteTuples ++ ")4").clump(4).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "2 " ++ match[2][1])}); //consolidate notes lilyString.findRegexp( "(" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4" ).clump(7).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "1.")}); lilyString.findRegexp( "(" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4" ).clump(5).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "1")}); lilyString.findRegexp("(" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4").clump(4).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "2.")}); lilyString.findRegexp("(" ++ noteTuples ++ ")4 ~ (" ++ noteTuples ++ ")4").clump(3).do({arg match; lilyString = lilyString.replace(match[0][1], match[1][1] ++ "2")}); //consolidate rests lilyString.findRegexp("r4 r4 r4 r4 r4 r4").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "R1*3/2")}); lilyString.findRegexp("r4 r4 r4 r4 r4").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "r4 r1")}); lilyString.findRegexp("r4 r4 r4 r4").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "r1")}); lilyString.findRegexp("r4 r4 r4").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "r2.")}); lilyString.findRegexp("r4 r4").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "r2")}); lilyString.findRegexp("\\| r1").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "| R1")}); lilyString.findRegexp("4\nr1").clump(2).do({arg match; lilyString = lilyString.replace(match[0][1], "2\n R1")}); //write file lilyFile.write("{\n" ++ lineBreakString ++ "}\n" ++ lilyString); lilyFile.close; }); }; ~genScoreData = {arg guitarSeq, accompLowSeq, accompHighSeq, timeSigInsSeq, sectionSeq; var stringSeq, fretSeq, durSeq, partData, timeSigData, sectionData; stringSeq = guitarSeq.slice(nil, 0); fretSeq = guitarSeq.slice(nil, 1); durSeq = guitarSeq.slice(nil, 2); partData = [ [stringSeq, fretSeq, durSeq, durSeq].flop, accompHighSeq, accompLowSeq ]; timeSigData = timeSigInsSeq; sectionData = sectionSeq; [partData, timeSigData, sectionData] }; )