diff --git a/soloanalyser/chordanalyser.js b/soloanalyser/chordanalyser.js index 5a86e65..8ce360e 100644 --- a/soloanalyser/chordanalyser.js +++ b/soloanalyser/chordanalyser.js @@ -28,6 +28,9 @@ /* - 1.2.20: Case-insensitive search for "Aug", "Sus2", ... /* - 1.2.21: Accords "Alt" /* - 1.2.22: b5 and #5 chords wrongly analysed +/* - 1.2.23: Ajout des 7th, 9th, 11th dans les accords 11th et 13th +/* - 1.2.23: Ajout des accords 10th +/* - 1.2.24: bug: mauvaise reconnaissance des accords ## /**********************************************/ // ----------------------------------------------------------------------- // --- Vesionning----------------------------------------- @@ -35,7 +38,7 @@ var default_names = ["1", "b9", "2", "#9", "b11", "4", "#11", "(5)", "m6", "M6", "m7", "M7"]; function checkVersion(expected) { - var version = "1.2.22"; + var version = "1.2.24"; var aV = version.split('.').map(function (v) { return parseInt(v); @@ -59,10 +62,17 @@ function chordFromText(source) { //var text = source.replace(/(\(|\))/g, ''); var text = source.replace(/(^\s*\(\s*|\s*\)\s*$)/g, ''); // on vire les "(" et ")" de début et fin + console.log("chordFromText: source: "+source); + console.log("chordFromText: cleaned: "+text); + var rootbass = text.split("/"); text = rootbass[0]; var bass = (rootbass.length > 1) ? rootbass[1] : null; + console.log("chordFromText: /w bass : "+text); + console.log("chordFromText: bass : "+text); + + // Root var rootacc = getRootAccidental(text); text = rootacc.remaingtext; @@ -98,9 +108,15 @@ function chordFromText(source) { function getRootAccidental(text) { var root = text.slice(0, 1).toUpperCase(); var alt = text.slice(1, 2); + console.log("Searching root and accidental in : "+text); + console.log("Root: "+root); + console.log("Alteration text: "+alt); if ("bb" === text.slice(1, 3)) { alt = 'FLAT2'; text = text.substr(3); + } else if ("##" === text.slice(1, 3)) { + alt = 'SHARP2'; + text = text.substr(3); } else if ("x" === alt) { alt = 'SHARP2'; text = text.substr(2); @@ -115,6 +131,8 @@ function getRootAccidental(text) { text = text.substr(1); } + console.log("Searching for tp for root="+root+", accidental="+alt); + var ftpcs = NoteHelper.tpcs.filter(function (e) { return ((e.raw === root) && (e.accidental === alt)); }); @@ -306,6 +324,9 @@ function scaleFromText(text, bass) { if (n3 !== null) { pushToKeys(keys, n3, "n3"); pushToNotes(chordnotes, n3, "3"); + } else if (text.includes("10")) { + pushToKeys(keys, 4, "10"); + pushToNotes(chordnotes, 4, "10"); } else if (def3 !== null) { pushToKeys(keys, def3, "def3"); } @@ -372,8 +393,9 @@ function scaleFromText(text, bass) { } // Adding an explicit 7 if a 9 is present - if ((n9 !== null) && (n7 === null) && (def7 !== null)) { + //if ((n9 !== null) && (n7 === null) && (def7 !== null)) { // n7 = def7; + if ((n9 !== null) && (n7 === null)) { n7 = 10; } @@ -411,6 +433,21 @@ function scaleFromText(text, bass) { if (getNote(chordnotes, def4) === undefined) pushToNotes(allnotes, def4, "4"); } + + // Adding an explicit 7 and 9 if a 11 is present + console.log("---Adding 7 in 11 chord :"+n11+"/"+n7+"/"+def7); + if ((n11 !== null) && (n7 === null)) { + console.log("...Ajouté"); + n7 = 10; + } + + if ((n11 !== null) && (n9 === null)) { + n9 = 2; + pushToKeys(keys, n9, "9"); + pushToNotes(chordnotes, n9, "9"); + } + + // ..6/13.. if (n6===null) { @@ -451,12 +488,33 @@ function scaleFromText(text, bass) { if (getNote(chordnotes, def6) === undefined) pushToNotes(allnotes, def6, "6"); } + + // Adding an explicit 7, 9, 11 if a 13 is present + if ((n13 !== null) && (n7 === null)) { + n7 = 10; + } + + if ((n13 !== null) && (n9 === null)) { + n9 = 2; + pushToKeys(keys, n9, "9"); + pushToNotes(chordnotes, n9, "9"); + } + + if ((n13 !== null) && (n11 === null)) { + n11 = 5; + pushToKeys(keys, n11, "(11)"); + pushToNotes(chordnotes, n11, "11"); + } + + //..7.. if (n7 !== null) { + console.log("found 7 as explicit ("+n7+")"); pushToKeys(keys, n7, "n7"); pushToNotes(chordnotes, n7, "7"); } else if ((at = [10, 11].indexOf(bass)) >= 0) { + console.log("found 7 as bass ("+bass+")"); n7 = bass; pushToKeys(keys, bass, "bass as 7"); pushToNotes(chordnotes, bass, ["m", "M"][at] + "7"); diff --git a/soloanalyser/core.js b/soloanalyser/core.js index 4b4008e..c752879 100644 --- a/soloanalyser/core.js +++ b/soloanalyser/core.js @@ -19,7 +19,8 @@ /* - 1.2.5: Don't analyse drum staves /* - 1.2.6: New option for not using chords preceeding the selection /* - 1.2.7: new "unknown symbol" "✗" -/* - 1.2.8: Starting Chord Symbol not used in the analyse when the track 0 has no segmennt at the tick +/* - 1.2.8: A Chord Symbol is not used in the analyse when the track 0 has nothing defined at that segment's tick. +/* - 1.2.9: Better treatment of lack of chord symbols and uparsable chord symbols (e.g. chord symbols for files just imported from MusicXML does not work unless the chords are manually edited). /**********************************************/ var degrees = '1;2;3;4;5;6;7;8;9;11;13'; @@ -129,11 +130,21 @@ function doAnalyse() { for (var j = 0; j < annotations.length; j++) { var ann = annotations[j]; //console.log(" (" + i + ") " + ann.userName() + " / " + ann.text + " / " + ann.harmonyType); - if (ann.type !== Element.HARMONY || ann.harmonyType!== HarmonyType.STANDARD ) { // Not using the Roman and Nashvill Harmony types + if ( + (ann.type !== Element.HARMONY || ann.harmonyType!== HarmonyType.STANDARD ) // Not using the Roman and Nashvill Harmony types + && (ann.type !==Element.FRET_DIAGRAM) // Not a Fretboard diagram (that includes chord name) + ) { console.log(segment.tick+": rejecting non relevant annotation: "+ann.userName()); continue; } + + debugO("elements: ",ann.elements); + if (!ann.text) { + console.log(segment.tick+": rejecting relevant annotation without text: "+ann.userName()); + continue; + } + if (ignoreBrackettedChords && (ann.text.search(/^\(.+\)$/g)!==-1)) { console.log(segment.tick+": rejecting chord name with parentheses: "+ann.text); continue; @@ -144,22 +155,27 @@ function doAnalyse() { console.log(segment.tick+": rejecting annotation on out of range track"); continue; } - - count++; - - if (byTrack[ann.track] === undefined) - byTrack[ann.track] = []; + + console.log(segment.tick+": going forward with analyse of "+ann.text); + var chord = ChordHelper.chordFromText(ann.text); if (chord !== null) { console.log(segment.tick+": adding "+ann.text+" to track "+ann.track); // If the chord is correctly analyzed, add it (to avoid invalid chord names, or "%" chord names) + + if (byTrack[ann.track] === undefined) + byTrack[ann.track] = []; + + count++; + byTrack[ann.track].push({ tick: segment.tick, chord: chord }); } else { - console.log(segment.tick+": rejecting invalid chord name: "+ann.text); + console.log(segment.tick+": rejecting invalid chord name: \""+ann.text+"\""); + //debugO("Empty annotation at "+segment.tick,ann); // fait planter le système quand on lit des accords chargés depuis MusicXML:-( } } } @@ -220,6 +236,8 @@ function doAnalyse() { cursor.rewindToTick(segMin); var segment = cursor.segment; var values = (byTrack[track] !== undefined) ? byTrack[track] : []; + debugO("Chords at track "+track,values); + console.log("Chords found at track=+"+track+": "+values.length); var curChord = null; var check=null; var step = lookAhead?0:-1; // if we lookAhead, we start from the first chord, even if it is further that start segment. @@ -233,7 +251,7 @@ function doAnalyse() { // curChord = ChordHelper.chordFromText(values[step].text); } - if(step>=0) { + if((step>=0) && (step<=(values.length-1))) { curChord = values[step].chord; check = values[step].tick; } @@ -453,4 +471,80 @@ function getSelection() { return chords; -} \ No newline at end of file +} + + function debugO(label, element, excludes, isinclude) { + + if (typeof isinclude === 'undefined') { + isinclude = false; // by default the exclude is an exclude list.otherwise it is an include + } + if (!Array.isArray(excludes)) { + excludes = []; + } + + try { + if (typeof element === 'undefined') { + console.log(label + ": undefined"); + return; + } + } catch (error) { + console.log("!! "+label+": failed to check for undefined"); + console.log(error); + return; + } + + try { + if (element === null) { + console.log(label + ": null"); + return; + } + } catch (error) { + console.log("!! "+label+": failed to check for null"); + console.log(error); + return; + } + + + try { + if (Array.isArray(element)) { + for (var i = 0; i < element.length; i++) { + debugO(label + "-" + i, element[i], excludes, isinclude); + } + return; + } + } catch (error) { + console.log("!! "+label+": failed to check for isArray"); + console.log(error); + return; + } + + + try { + if (typeof element === 'object') { + + var kys = Object.keys(element); + for (var i = 0; i < kys.length; i++) { + if ((excludes.indexOf(kys[i]) == -1) ^ isinclude) { + debugO(label + ": " + kys[i], element[kys[i]], excludes, isinclude); + } + } + return; + } + } catch (error) { + console.log("!! "+label+": failed to check for undefined"); + console.log(error); + return; + } + + + try { + console.log(label + ": " + element); + return; + } catch (error) { + console.log("!! "+label+": failed to check for undefined"); + console.log(error); + return; + } + + + } diff --git a/soloanalyser/notehelper.js b/soloanalyser/notehelper.js index 40bb06d..7bcd203 100644 --- a/soloanalyser/notehelper.js +++ b/soloanalyser/notehelper.js @@ -1,6 +1,8 @@ /********************** /* Parking B - MuseScore - Note helper -/* v1.0.5 +/* +/* Rem: Notes heads and Accidentals representation requires the use of the font 'Bravura Text' +/* /* ChangeLog: /* - 22/7/21: Added restToNote and changeNote function /* - 25/7/21: Managing of transposing instruments @@ -8,6 +10,18 @@ /* - 13/03/22: v1.0.4 Extra parameter to keep the rest duration when adding notes and chords. /* - 13/03/22: v1.0.4 New restToChords function. /* - 18/03/22: v1.0.5 restToNote and New restToChords accept now tpc1 and tpc2 values. +/* - 15/2/23: v2.0.0 using unicode for accidentals and heads instead of images +/* - 26/2/23: v2.0.1 protection of methods +/* - 26/2/23: v2.0.1 documentation +/* - 5/3/23: v2.0.2 correct length across bars +/* - 6/3/23: v2.0.2 some refactoring and documentation +/* - 15/3/23: v2.0.2 changeNote: set the pitch note (I guess I assumed it was already set by the calling function, but this is more generic now). +/* - 7/4/23: v2.0.2 buildPitchedNote: accepts note name with accidentals. +/* - 7/4/23: v2.0.2 buildPitchedNote: adds names to the built note in the `extname` object (so similar to #enrichNote). +/* - 5/07/23: v2.0.3 changeNote: better behaviour if we provide pitch and 1 tpc (tpc1 or tpc2) : deduce the other tpc. +/* - 26/08/23: v2.0.3 set TPC by note name (originally 1.0.6 in workoutbuilder) +/* - 03/06/24: v2.0.3 buildPitchedNote: allow for "b","#" as valid alteration signs (along with the unicode versiosns). + /**********************************************/ // ----------------------------------------------------------------------- // --- Vesionning----------------------------------------- @@ -17,7 +31,7 @@ function checktVersion(expected) { return checkVersion(expected); } function checkVersion(expected) { - var version = "1.0.5"; + var version = "2.0.3"; var aV = version.split('.').map(function (v) { return parseInt(v); @@ -42,6 +56,9 @@ function checkVersion(expected) { * Add some propeprties to the note. Among others, the name of the note, in the format "C4" and "C#4", ... * The added properties: * - note.accidentalName : the name of the accidental + * - note.accidentalText : the unicode representation of the accidental character + * - note.headName = the name of the head; + * - note.headText = the unicode representation of the head character; * - note.extname.fullname : "C#4" * - note.extname.name : "C4" * - note.extname.raw : "C" @@ -50,13 +67,48 @@ function checkVersion(expected) { * @return / */ function enrichNote(note) { + if(!note) { + console.warn("enrichNote: null arguments"); + return; + } + + if (note.type != Element.NOTE) { + var label; + try{ + label=note.userName() + } catch (error) { + label=typeof note; + } + console.warn("enrichNote: invalid note type. Expecting 'Note'. Received "+label); + return; + } + // accidental var id = note.accidentalType; + console.log("SEARCHING FOR ACCIDENTAL TYPE = "+id); note.accidentalName = "UNKOWN"; for (var i = 0; i < accidentals.length; i++) { var acc = accidentals[i]; - if (id == eval("Accidental." + acc.name)) { + var val=eval("Accidental." + acc.name); + console.log("checking "+acc.name + " = "+val +" ("+acc.text+")"); + if (id == val) { + note.accidentalName = acc.name; + note.accidentalText = acc.text; + console.log("FOUND "+acc.name+", text: "+acc.text); + break; + } + } + + // head + var grp = note.headGroup ? note.headGroup : 0; + note.headName = heads[0].name; + note.headText = heads[0].text; + for (var i = 1; i < heads.length; i++) { // starting at 1 because 0 is the generic one ("--") + var head = heads[i]; + if (grp == eval("NoteHeadGroup." + head.name)) { + note.headName = head.name; + note.headText = head.text; break; } } @@ -70,6 +122,10 @@ function enrichNote(note) { } +/** +* Compose a note names based on pitch and a provided tpc. +* This result can typically found in the `note.extname` object +*/ function pitchToName(npitch, ntpc) { var tpc = { 'tpc': 14, @@ -80,7 +136,7 @@ function pitchToName(npitch, ntpc) { var pitchnote = pitchnotes[npitch % 12]; var noteOctave = Math.floor(npitch / 12) - 1; - + for (var i = 0; i < tpcs.length; i++) { var t = tpcs[i]; if (ntpc == t.tpc) { @@ -108,23 +164,71 @@ function pitchToName(npitch, ntpc) { * Reconstructed a note pitch information based on the note name and its accidental * @param noteName the name of the note, without alteration. Eg "C4", and not "C#4" * @param accidental the name of the accidental to use. Eg "SHARP2" + + * - OR - + + * @param accidental empty + * @param noteName the name of the note, *with* alteration. Eg "C#4" + Recognized alterations are ♭♭, ♭, ♯♯, ♯ + * @return a structure with pitch/tpc information -ret.pitch : the pitch of the note -ret.tpc: the value for the note tpc1 and tpc2 + ret.pitch : the pitch of the note + ret.tpc2: the value for the note tpc1 and tpc2extname + ret.extname: the note name */ function buildPitchedNote(noteName, accidental) { - var name = noteName.substr(0, 1); - var octave = parseInt(noteName.substr(1, 3)); + if(!noteName) { + console.warn("buildPitchedNote: null arguments"); + return; + } - var a = accidental; - for (var i = 0; i < equivalences.length; i++) { - for (var j = 1; j < equivalences[i].length; j++) { - if (accidental == equivalences[i][j]) { - a = equivalences[i][0]; + + var octave = parseInt(noteName.slice(-1)); + //console.log("OCTAVE: "+octave+" ("+noteName +" => "+noteName.slice(-1)+")"); + var name = noteName.substr(0, 1); + var a; + if (typeof accidental === "undefined" && noteName.length>2) { + var sa=noteName.slice(1,-1); + switch (sa) { + case "\u266D\u266D": + case "bb": + a="FLAT2"; + break; + case "\u266D": + case "b": + a="FLAT"; + break; + case "\u266F": + case "#": + a="SHARP"; + break; + case "\u266F\u266F": + case "##": + case "x": + a="SHARP2"; + break; + default : + a="NONE"; break; + } + //console.log("SA: "+noteName+" => "+sa+ " => "+a); + } else { + a = accidental; + + if (!accidental || accidental=="") { + a="NONE"; + } else { + for (var i = 0; i < equivalences.length; i++) { + for (var j = 1; j < equivalences[i].length; j++) { + if (accidental == equivalences[i][j]) { + a = equivalences[i][0]; + break; + } + } } } + } // tpc @@ -154,6 +258,7 @@ function buildPitchedNote(noteName, accidental) { } if (tpc.tpc == -1) { + console.warn("fail to find a tpc"); // not found. Shouldn't occur tpc.tpc = 0; } @@ -162,95 +267,156 @@ function buildPitchedNote(noteName, accidental) { //console.log("--" + tpc.pitch + "--"); var pitch = (octave + 1) * 12 + ((tpc.pitch !== undefined) ? tpc.pitch : 0); + var extname = pitchToName(pitch, tpc.tpc); + + var recompose = { "pitch": pitch, // we store the note as a label ("C4"), we want that note to *look* like a "C4" more than to *sound* like "C4". - // ==> we force the representation mode by steiing tpc1 to undefined and specifying tpc2 + // ==> we force the representation mode by specifying tpc1 to undefined and specifying tpc2 //"tpc1" : tpc.tpc, - "tpc2": tpc.tpc + "tpc2": tpc.tpc, + + "extname": extname }; return recompose; } /** - * keepRestDuration: duration|boolean|undefined + * Transform a rest into a single note. + * @param rest: an element of type Element.REST to transform into a note + * @param toNote: a note definition: int|note definition + * * int: a pitch + * * note definition: @see #changeNote + * @param keepRestDuration: duration|boolean|undefined * * duration: on the form of duration.numerator, duration.denominator : the duration to force * * boolean==true: keep the rest duration * * boolean==false | undefined: the duration will be quarter - */ + * + * @return an element of type Element.NOTE created on that rest + * IMPORTANT REMARK: the returned element can be on the same segment's tick than the rest element or *after* + * if the the requested duration for the note was larger than the available duration in the measure. + * In that case, the function creates tied notes. The returned element is the last of those tied notes. +*/ function restToNote(rest, toNote, keepRestDuration) { - if (rest.type != Element.REST) + if(!rest || !toNote) { + console.warn("restToNote: null arguments"); return; + } + + if (rest.type != Element.REST) { + console.warn("restToNote: invalid note type. Expecting 'Rest'. Received "+rest.userName()); + return; + } + var duration; - if (toNote === parseInt(toNote)) - toNote = { + var notes=[]; + notes.push((toNote === parseInt(toNote))? + { "pitch": toNote, "concertPitch": false, "sharp_mode": true - }; + }:toNote); + + + var chord=restToChord(rest, notes, keepRestDuration); + + if(chord.notes && chord.notes.length>0) return chord.notes[0]; + else return undefined; - // For compatibility - if (typeof keepRestDuration === 'undefined') +} + +/** + * Transform a rest into a serie of notes (i.e. a chord). + * @param rest: an element of type Element.REST to transform into a note + * @param toNotes: an array of note definitions, defined by : int|note definition + * * int: a pitch + * * note definition: @see #changeNote + * @param keepRestDuration: duration|boolean|undefined + * * duration: on the form of duration.numerator, duration.denominator : the duration to force + * * boolean==true: keep the rest duration + * * boolean==false | undefined: the duration will be quarter + * + * @return an element of type Element.CHORD created on that rest + * IMPORTANT REMARK: the returned element can be on the same segment's tick than the rest element or *after* + * if the the requested duration for the chord was larger than the available duration in the measure. + * In that case, the function creates tied chords. The returned element is the last of those tied chords. + */ +function restToChord(rest, toNotes, keepRestDuration) { + // checks + if(!rest || !toNotes) { + console.warn("restToChord: null arguments"); + return; + } + + if (rest.type != Element.REST) { + console.warn("restToChord: invalid note type. Expecting 'Rest'. Received "+rest.userName()); + return; + } + + // notes to add + var notes = toNotes.map(function (n) { + if (n === parseInt(n)) { + return { + "pitch": n, + "concertPitch": false, + "sharp_mode": true + }; + } else { + return n; + } + }); + + // duration to use + var duration=undefined; + if (typeof keepRestDuration === 'undefined') { + console.log("keepRestDuration=undefined"); duration = undefined; + } else if (typeof keepRestDuration === 'boolean') { + console.log("keepRestDuration=boolean: "+keepRestDuration); if (keepRestDuration) { duration = rest.duration; } - } else + } else { + console.log("keepRestDuration provided. Using "+keepRestDuration); duration = keepRestDuration; + } + if (!duration) { + duration=fraction(1,4); + console.log("keepRestDuration undefined. Forcing a value"); + } + console.log("Ending up with duration = "+(duration.str?duration.str:duration)); + + // Adding the first note + var toNote=toNotes[0]; //console.log("==ON A REST=="); var cur_time = rest.parent.tick; // getting rest's segment's tick var oCursor = curScore.newCursor(); oCursor.track = rest.track; - if (duration) { - oCursor.setDuration(duration.numerator, duration.denominator); - } + oCursor.setDuration(duration.numerator, duration.denominator); oCursor.rewindToTick(cur_time); oCursor.addNote(toNote.pitch); oCursor.rewindToTick(cur_time); + var chord = oCursor.element; var note = chord.notes[0]; - //debugPitch(level_DEBUG,"Added note",note); + console.log("Expected duration: %1, current duration %2".arg(duration?duration.str:"??").arg(chord.duration?chord.duration.str:"??")); changeNote(note, toNote); - //debugPitch(level_DEBUG,"Corrected note",note); - - - return note; -} - -function restToChord(rest, toNotes, keepRestDuration) { - if (rest.type != Element.REST) - return; - - var notes = toNotes.map(function (n) { - if (n === parseInt(n)) { - return { - "pitch": n, - "concertPitch": false, - "sharp_mode": true - }; - } else { - return n; - } - }); - - //console.log("Dealing with note "+0+": "+notes[0].pitch); - restToNote(rest, notes[0], keepRestDuration); - + + // adding the other notes for (var i = 1; i < notes.length; i++) { var dest = notes[i]; //console.log("Dealing with note "+i+": "+dest.pitch); var cur_time = rest.parent.tick; // getting rest's segment's tick - var oCursor = curScore.newCursor(); - oCursor.track = rest.track; oCursor.rewindToTick(cur_time); oCursor.addNote(dest.pitch, true); // addToChord=true oCursor.rewindToTick(cur_time); @@ -261,35 +427,74 @@ function restToChord(rest, toNotes, keepRestDuration) { //debugPitch(level_DEBUG,"Added note",note); NoteHelper.changeNote(note, dest); - } - return note; + var remaining=durationTo64(duration)-durationTo64(chord.duration); + console.log("- expected: %1, actual: %2, remaining: %3".arg(durationTo64(duration)).arg(durationTo64(chord.duration)).arg(remaining)); + + var success=true; + while(success && remaining > 0) { + var durG=fraction(remaining,64).str; + success=oCursor.next(); + if(!success) { + console.warn("Unable to move to the next element while searching for the remaining %1 duration".arg(durG)); + break; + } + var element = oCursor.element; + if (element.type!=Element.CHORD) { + console.warn("Could not find a valid Element.CHORD element while searching for the remaining %1 duration (found %2)".arg(durG).arg(element.userName())); + break; + } + chord=element; + cur_time = oCursor.tick; + remaining=remaining-durationTo64(chord.duration); + console.log("- expected: %1, last: %2, remaining: %3".arg(durationTo64(duration)).arg(durationTo64(chord.duration)).arg(remaining)); + } + + return chord; } /** * @param toNote.pitch: the target pitch, - - * @param toNote.tpc1, toNote.tpc2 : the target tpc, if known beforehand - - * -- OR -- - - * @param toNote.concertPitch: true|false, false means the note must be dispalyed as having that pitch. + * + * @param toNote.tpc1, toNote.tpc2 -- OR -- toNote.concertPitch, toNote.sharp_mode + * * toNote.tpc1, toNote.tpc2 : the target tpc, if known beforehand + * * toNote.concertPitch: true|false, false means the note must be dispalyed as having that pitch. * For a Bb instrument, a pitch=60 (C), with concertPitch=false will be displayed as a C but be played as Bb. * With concertPitch=true, it will be played as a C and therefor displayed as a D. - * @param toNote.sharp_mode: true|false The preference goes to sharp accidentals (true) or flat accidentals (false) + * * toNote.sharp_mode: true|false The preference goes to sharp accidentals (true) or flat accidentals (false) */ function changeNote(note, toNote) { + if(!note || !toNote) { + console.warn("changeNote: null arguments"); + return; + } + if (note.type != Element.NOTE) { - debug(level_INFO, "! Changing Note of a non-Note element"); + console.warn("changeNote: invalid note type. Expecting 'Note'. Received "+note.userName()); return; } + + note.pitch=toNote.pitch; if (toNote.tpc1 !== undefined && toNote.tpc1 !== undefined) { // tpc1 and tpc2 are defined ==> using them note.tpc1 = toNote.tpc1; note.tpc2 = toNote.tpc2; + + } else if (toNote.tpc1 !== undefined) { + // tpc1 is defined ==> using it and align tpc2 + var dtpc = note.tpc2 - note.tpc1; + note.tpc1 = toNote.tpc1; + note.tpc2 = toNote.tpc1 + dtpc; + + } else if (toNote.tpc2 !== undefined) { + // tpc2 is defined ==> using it and align tpc1 + var dtpc = note.tpc2 - note.tpc1; + note.tpc1 = toNote.tpc2 - dtpc; + note.tpc2 = toNote.tpc2 + dtpc; + } else { // tpc1 and tpc2 are not defined ==> computing them @@ -313,14 +518,24 @@ function changeNote(note, toNote) { } - var tpc = getPreferredTpc(note.tpc1, sharp_mode); - if (tpc !== null) - note.tpc1 = tpc; + var tpc1=null; + if (toNote.name) + tpc1=getPreferredTpcForName(note.tpc1,toNote.name); + if (tpc1 === null) + tpc1 = getPreferredTpc(note.tpc1, sharp_mode); + + if (tpc1 !== null) + note.tpc1 = tpc1; + + var tpc2=null; //delta = toNote.pitch - 60; - var tpc = getPreferredTpc(note.tpc2, sharp_mode); - if (tpc !== null) - note.tpc2 = tpc; + if (toNote.name) + tpc2=getPreferredTpcForName(note.tpc2,toNote.name); + if (tpc2 === null) + tpc2 = getPreferredTpc(note.tpc2, sharp_mode); + if (tpc2 !== null) + note.tpc2 = tpc2; } @@ -346,22 +561,43 @@ function getPreferredTpc(tpc, sharp_mode) { } +function getPreferredTpcForName(tpc, noteName) { + var delta = tpcToPitch(tpc); + + console.log("-->Searching tpc pitch "+delta+" and note "+noteName); + + + // On ne garde que les tpcs correspondant au nom de la note souhaitée + for (var i = 0; i < tpcs.length; i++) { + if (tpcs[i].raw === noteName) { + console.log(" analysing "+JSON.stringify(tpcs[i])); + if (tpcs[i].pitch === delta) { + return tpcs[i].tpc; + } + } + } + + return null; + +} + + var pitchnotes = ['C', 'C', 'D', 'D', 'E', 'F', 'F', 'G', 'G', 'A', 'A', 'B']; -var tpcs = [new tpcClass(-1, 'F♭♭'), - new tpcClass(0, 'C♭♭'), - new tpcClass(1, 'G♭♭'), - new tpcClass(2, 'D♭♭'), - new tpcClass(3, 'A♭♭'), - new tpcClass(4, 'E♭♭'), - new tpcClass(5, 'B♭♭'), - new tpcClass(6, 'F♭'), - new tpcClass(7, 'C♭'), - new tpcClass(8, 'G♭'), - new tpcClass(9, 'D♭'), - new tpcClass(10, 'A♭'), - new tpcClass(11, 'E♭'), - new tpcClass(12, 'B♭'), +var tpcs = [new tpcClass(-1, 'F\u266D\u266D'), + new tpcClass(0, 'C\u266D\u266D'), + new tpcClass(1, 'G\u266D\u266D'), + new tpcClass(2, 'D\u266D\u266D'), + new tpcClass(3, 'A\u266D\u266D'), + new tpcClass(4, 'E\u266D\u266D'), + new tpcClass(5, 'B\u266D\u266D'), + new tpcClass(6, 'F\u266D'), + new tpcClass(7, 'C\u266D'), + new tpcClass(8, 'G\u266D'), + new tpcClass(9, 'D\u266D'), + new tpcClass(10, 'A\u266D'), + new tpcClass(11, 'E\u266D'), + new tpcClass(12, 'B\u266D'), new tpcClass(13, 'F'), new tpcClass(14, 'C'), new tpcClass(15, 'G'), @@ -369,20 +605,20 @@ var tpcs = [new tpcClass(-1, 'F♭♭'), new tpcClass(17, 'A'), new tpcClass(18, 'E'), new tpcClass(19, 'B'), - new tpcClass(20, 'F♯'), - new tpcClass(21, 'C♯'), - new tpcClass(22, 'G♯'), - new tpcClass(23, 'D♯'), - new tpcClass(24, 'A♯'), - new tpcClass(25, 'E♯'), - new tpcClass(26, 'B♯'), - new tpcClass(27, 'F♯♯'), - new tpcClass(28, 'C♯♯'), - new tpcClass(29, 'G♯♯'), - new tpcClass(30, 'D♯♯'), - new tpcClass(31, 'A♯♯'), - new tpcClass(32, 'E♯♯'), - new tpcClass(33, 'B♯♯'), + new tpcClass(20, 'F\u266F'), + new tpcClass(21, 'C\u266F'), + new tpcClass(22, 'G\u266F'), + new tpcClass(23, 'D\u266F'), + new tpcClass(24, 'A\u266F'), + new tpcClass(25, 'E\u266F'), + new tpcClass(26, 'B\u266F'), + new tpcClass(27, 'F\u266F\u266F'), + new tpcClass(28, 'C\u266F\u266F'), + new tpcClass(29, 'G\u266F\u266F'), + new tpcClass(30, 'D\u266F\u266F'), + new tpcClass(31, 'A\u266F\u266F'), + new tpcClass(32, 'E\u266F\u266F'), + new tpcClass(33, 'B\u266F\u266F'), ]; function filterTpcs(sharp_mode) { @@ -417,156 +653,451 @@ var sharpTpcs = filterTpcs(true); var flatTpcs = filterTpcs(false); var accidentals = [{ - 'name': 'NONE', + "name": "NONE", + "text": '' + }, { + "name": "FLAT", + "text": '\uE260' + }, { + "name": "NATURAL", + "text": '\uE261' + }, { + "name": "SHARP", + "text": '\uE262' + }, { + "name": "SHARP2", + "text": '\uE263' + }, { + "name": "FLAT2", + "text": '\uE264' + }, { + "name": "SHARP3", + "text": '\uE265' + }, { + "name": "FLAT3", + "text": '\uE266' + }, { + "name": "NATURAL_FLAT", + "text": '\uE267' + }, { + "name": "NATURAL_SHARP", + "text": '\uE268' + }, { + "name": "SHARP_SHARP", + "text": '\uE269' + }, { + "name": "FLAT_ARROW_UP", + "text": '\uE270' + }, { + "name": "FLAT_ARROW_DOWN", + "text": '\uE271' + }, { + "name": "NATURAL_ARROW_UP", + "text": '\uE272' + }, { + "name": "NATURAL_ARROW_DOWN", + "text": '\uE273' + }, { + "name": "SHARP_ARROW_UP", + "text": '\uE274' + }, { + "name": "SHARP_ARROW_DOWN", + "text": '\uE275' + }, { + "name": "SHARP2_ARROW_UP", + "text": '\uE276' + }, { + "name": "SHARP2_ARROW_DOWN", + "text": '\uE277' + }, { + "name": "FLAT2_ARROW_UP", + "text": '\uE278' + }, { + "name": "FLAT2_ARROW_DOWN", + "text": '\uE279' + }, { + "name": "ARROW_DOWN", + "text": '\uE27B' + }, { + "name": "ARROW_UP", + "text": '\uE27A' + }, { + "name": "MIRRORED_FLAT", + "text": '\uE280' + }, { + "name": "MIRRORED_FLAT2", + "text": '\uE281' + }, { + "name": "SHARP_SLASH", + "text": '\uE282' + }, { + "name": "SHARP_SLASH4", + "text": '\uE283' + }, { + "name": "FLAT_SLASH2", + "text": '\uE440' + }, { + "name": "FLAT_SLASH", + "text": '\uE442' + }, { + "name": "SHARP_SLASH3", + "text": '\uE446' + }, { + "name": "SHARP_SLASH2", + "text": '\uE447' + }, { + "name": "DOUBLE_FLAT_ONE_ARROW_DOWN", + "text": '\uE2C0' + }, { + "name": "FLAT_ONE_ARROW_DOWN", + "text": '\uE2C1' }, { - 'name': 'FLAT', + "name": "NATURAL_ONE_ARROW_DOWN", + "text": '\uE2C2' }, { - 'name': 'NATURAL', + "name": "SHARP_ONE_ARROW_DOWN", + "text": '\uE2C3' }, { - 'name': 'SHARP', + "name": "DOUBLE_SHARP_ONE_ARROW_DOWN", + "text": '\uE2C4' }, { - 'name': 'SHARP2', + "name": "DOUBLE_FLAT_ONE_ARROW_UP", + "text": '\uE2C5' }, { - 'name': 'FLAT2', + "name": "FLAT_ONE_ARROW_UP", + "text": '\uE2C6' }, { - 'name': 'NATURAL_FLAT', + "name": "NATURAL_ONE_ARROW_UP", + "text": '\uE2C7' }, { - 'name': 'NATURAL_SHARP', + "name": "SHARP_ONE_ARROW_UP", + "text": '\uE2C8' }, { - 'name': 'SHARP_SHARP', + "name": "DOUBLE_SHARP_ONE_ARROW_UP", + "text": '\uE2C9' }, { - 'name': 'FLAT_ARROW_UP', + "name": "DOUBLE_FLAT_TWO_ARROWS_DOWN", + "text": '\uE2CA' }, { - 'name': 'FLAT_ARROW_DOWN', + "name": "FLAT_TWO_ARROWS_DOWN", + "text": '\uE2CB' }, { - 'name': 'NATURAL_ARROW_UP', + "name": "NATURAL_TWO_ARROWS_DOWN", + "text": '\uE2CC' }, { - 'name': 'NATURAL_ARROW_DOWN', + "name": "SHARP_TWO_ARROWS_DOWN", + "text": '\uE2CD' }, { - 'name': 'SHARP_ARROW_UP', + "name": "DOUBLE_SHARP_TWO_ARROWS_DOWN", + "text": '\uE2CE' }, { - 'name': 'SHARP_ARROW_DOWN', + "name": "DOUBLE_FLAT_TWO_ARROWS_UP", + "text": '\uE2CF' }, { - 'name': 'SHARP2_ARROW_UP', + "name": "FLAT_TWO_ARROWS_UP", + "text": '\uE2D0' }, { - 'name': 'SHARP2_ARROW_DOWN', + "name": "NATURAL_TWO_ARROWS_UP", + "text": '\uE2D1' }, { - 'name': 'FLAT2_ARROW_UP', + "name": "SHARP_TWO_ARROWS_UP", + "text": '\uE2D2' }, { - 'name': 'FLAT2_ARROW_DOWN', + "name": "DOUBLE_SHARP_TWO_ARROWS_UP", + "text": '\uE2D3' }, { - 'name': 'MIRRORED_FLAT', + "name": "DOUBLE_FLAT_THREE_ARROWS_DOWN", + "text": '\uE2D4' }, { - 'name': 'MIRRORED_FLAT2', + "name": "FLAT_THREE_ARROWS_DOWN", + "text": '\uE2D5' }, { - 'name': 'SHARP_SLASH', + "name": "NATURAL_THREE_ARROWS_DOWN", + "text": '\uE2D6' }, { - 'name': 'SHARP_SLASH4', + "name": "SHARP_THREE_ARROWS_DOWN", + "text": '\uE2D7' }, { - 'name': 'FLAT_SLASH2', + "name": "DOUBLE_SHARP_THREE_ARROWS_DOWN", + "text": '\uE2D8' }, { - 'name': 'FLAT_SLASH', + "name": "DOUBLE_FLAT_THREE_ARROWS_UP", + "text": '\uE2D9' }, { - 'name': 'SHARP_SLASH3', + "name": "FLAT_THREE_ARROWS_UP", + "text": '\uE2DA' }, { - 'name': 'SHARP_SLASH2', + "name": "NATURAL_THREE_ARROWS_UP", + "text": '\uE2DB' }, { - 'name': 'DOUBLE_FLAT_ONE_ARROW_DOWN', + "name": "SHARP_THREE_ARROWS_UP", + "text": '\uE2DC' }, { - 'name': 'FLAT_ONE_ARROW_DOWN', + "name": "DOUBLE_SHARP_THREE_ARROWS_UP", + "text": '\uE2DD' }, { - 'name': 'NATURAL_ONE_ARROW_DOWN', + "name": "LOWER_ONE_SEPTIMAL_COMMA", + "text": '\uE2DE' }, { - 'name': 'SHARP_ONE_ARROW_DOWN', + "name": "RAISE_ONE_SEPTIMAL_COMMA", + "text": '\uE2DF' }, { - 'name': 'DOUBLE_SHARP_ONE_ARROW_DOWN', + "name": "LOWER_TWO_SEPTIMAL_COMMAS", + "text": '\uE2E0' }, { - 'name': 'DOUBLE_FLAT_ONE_ARROW_UP', + "name": "RAISE_TWO_SEPTIMAL_COMMAS", + "text": '\uE2E1' }, { - 'name': 'FLAT_ONE_ARROW_UP', + "name": "LOWER_ONE_UNDECIMAL_QUARTERTONE", + "text": '\uE2E2' }, { - 'name': 'NATURAL_ONE_ARROW_UP', + "name": "RAISE_ONE_UNDECIMAL_QUARTERTONE", + "text": '\uE2E3' }, { - 'name': 'SHARP_ONE_ARROW_UP', + "name": "LOWER_ONE_TRIDECIMAL_QUARTERTONE", + "text": '\uE2E4' }, { - 'name': 'DOUBLE_SHARP_ONE_ARROW_UP', + "name": "RAISE_ONE_TRIDECIMAL_QUARTERTONE", + "text": '\uE2E5' }, { - 'name': 'DOUBLE_FLAT_TWO_ARROWS_DOWN', + "name": "DOUBLE_FLAT_EQUAL_TEMPERED", + "text": '\uE2F0' }, { - 'name': 'FLAT_TWO_ARROWS_DOWN', + "name": "FLAT_EQUAL_TEMPERED", + "text": '\uE2F1' }, { - 'name': 'NATURAL_TWO_ARROWS_DOWN', + "name": "NATURAL_EQUAL_TEMPERED", + "text": '\uE2F2' }, { - 'name': 'SHARP_TWO_ARROWS_DOWN', + "name": "SHARP_EQUAL_TEMPERED", + "text": '\uE2F3' }, { - 'name': 'DOUBLE_SHARP_TWO_ARROWS_DOWN', + "name": "DOUBLE_SHARP_EQUAL_TEMPERED", + "text": '\uE2F4' }, { - 'name': 'DOUBLE_FLAT_TWO_ARROWS_UP', + "name": "QUARTER_FLAT_EQUAL_TEMPERED", + "text": '\uE2F5' }, { - 'name': 'FLAT_TWO_ARROWS_UP', + "name": "QUARTER_SHARP_EQUAL_TEMPERED", + "text": '\uE2F6' }, { - 'name': 'NATURAL_TWO_ARROWS_UP', + "name": "FLAT_17", + "text": '\uE2E6' }, { - 'name': 'SHARP_TWO_ARROWS_UP', + "name": "SHARP_17", + "text": '\uE2E7' }, { - 'name': 'DOUBLE_SHARP_TWO_ARROWS_UP', + "name": "FLAT_19", + "text": '\uE2E8' }, { - 'name': 'DOUBLE_FLAT_THREE_ARROWS_DOWN', + "name": "SHARP_19", + "text": '\uE2E9' }, { - 'name': 'FLAT_THREE_ARROWS_DOWN', + "name": "FLAT_23", + "text": '\uE2EA' }, { - 'name': 'NATURAL_THREE_ARROWS_DOWN', + "name": "SHARP_23", + "text": '\uE2EB' }, { - 'name': 'SHARP_THREE_ARROWS_DOWN', + "name": "FLAT_31", + "text": '\uE2EC' }, { - 'name': 'DOUBLE_SHARP_THREE_ARROWS_DOWN', + "name": "SHARP_31", + "text": '\uE2ED' }, { - 'name': 'DOUBLE_FLAT_THREE_ARROWS_UP', + "name": "FLAT_53", + "text": '\uE2F7' }, { - 'name': 'FLAT_THREE_ARROWS_UP', + "name": "SHARP_53", + "text": '\uE2F8' }, { - 'name': 'NATURAL_THREE_ARROWS_UP', + "name": "//EQUALS_ALMOST", + "text": '\uE2FA' }, { - 'name': 'SHARP_THREE_ARROWS_UP', + "name": "//EQUALS", + "text": '\uE2FB' }, { - 'name': 'DOUBLE_SHARP_THREE_ARROWS_UP', + "name": "//TILDE", + "text": '\uE2F9' }, { - 'name': 'LOWER_ONE_SEPTIMAL_COMMA', + "name": "SORI", + "text": '\uE461' }, { - 'name': 'RAISE_ONE_SEPTIMAL_COMMA', + "name": "KORON", + "text": '\uE460' }, { - 'name': 'LOWER_TWO_SEPTIMAL_COMMAS', + "name": "TEN_TWELFTH_FLAT", + "text": '\uE434' }, { - 'name': 'RAISE_TWO_SEPTIMAL_COMMAS', + "name": "TEN_TWELFTH_SHARP", + "text": '\uE429' }, { - 'name': 'LOWER_ONE_UNDECIMAL_QUARTERTONE', + "name": "ELEVEN_TWELFTH_FLAT", + "text": '\uE435' }, { - 'name': 'RAISE_ONE_UNDECIMAL_QUARTERTONE', + "name": "ELEVEN_TWELFTH_SHARP", + "text": '\uE42A' }, { - 'name': 'LOWER_ONE_TRIDECIMAL_QUARTERTONE', + "name": "ONE_TWELFTH_FLAT", + "text": '\uE42B' }, { - 'name': 'RAISE_ONE_TRIDECIMAL_QUARTERTONE', + "name": "ONE_TWELFTH_SHARP", + "text": '\uE420' }, { - 'name': 'DOUBLE_FLAT_EQUAL_TEMPERED', + "name": "TWO_TWELFTH_FLAT", + "text": '\uE42C' }, { - 'name': 'FLAT_EQUAL_TEMPERED', + "name": "TWO_TWELFTH_SHARP", + "text": '\uE421' }, { - 'name': 'NATURAL_EQUAL_TEMPERED', + "name": "THREE_TWELFTH_FLAT", + "text": '\uE42D' }, { - 'name': 'SHARP_EQUAL_TEMPERED', + "name": "THREE_TWELFTH_SHARP", + "text": '\uE422' }, { - 'name': 'DOUBLE_SHARP_EQUAL_TEMPERED', + "name": "FOUR_TWELFTH_FLAT", + "text": '\uE42E' }, { - 'name': 'QUARTER_FLAT_EQUAL_TEMPERED', + "name": "FOUR_TWELFTH_SHARP", + "text": '\uE423' }, { - 'name': 'QUARTER_SHARP_EQUAL_TEMPERED', + "name": "FIVE_TWELFTH_FLAT", + "text": '\uE42F' }, { - 'name': 'SORI', + "name": "FIVE_TWELFTH_SHARP", + "text": '\uE424' }, { - 'name': 'KORON', + "name": "SIX_TWELFTH_FLAT", + "text": '\uE430' + }, { + "name": "SIX_TWELFTH_SHARP", + "text": '\uE425' + }, { + "name": "SEVEN_TWELFTH_FLAT", + "text": '\uE431' + }, { + "name": "SEVEN_TWELFTH_SHARP", + "text": '\uE426' + }, { + "name": "EIGHT_TWELFTH_FLAT", + "text": '\uE432' + }, { + "name": "EIGHT_TWELFTH_SHARP", + "text": '\uE427' + }, { + "name": "NINE_TWELFTH_FLAT", + "text": '\uE433' + }, { + "name": "NINE_TWELFTH_SHARP", + "text": '\uE428' + }, { + "name": "SAGITTAL_5V7KD", + "text": '\uE301' + }, { + "name": "SAGITTAL_5V7KU", + "text": '\uE300' + }, { + "name": "SAGITTAL_5CD", + "text": '\uE303' + }, { + "name": "SAGITTAL_5CU", + "text": '\uE302' + }, { + "name": "SAGITTAL_7CD", + "text": '\uE305' + }, { + "name": "SAGITTAL_7CU", + "text": '\uE304' + }, { + "name": "SAGITTAL_25SDD", + "text": '\uE307' + }, { + "name": "SAGITTAL_25SDU", + "text": '\uE306' + }, { + "name": "SAGITTAL_35MDD", + "text": '\uE309' + }, { + "name": "SAGITTAL_35MDU", + "text": '\uE308' + }, { + "name": "SAGITTAL_11MDD", + "text": '\uE30B' + }, { + "name": "SAGITTAL_11MDU", + "text": '\uE30A' + }, { + "name": "SAGITTAL_11LDD", + "text": '\uE30D' + }, { + "name": "SAGITTAL_11LDU", + "text": '\uE30C' + }, { + "name": "SAGITTAL_35LDD", + "text": '\uE30F' + }, { + "name": "SAGITTAL_35LDU", + "text": '\uE30E' + }, { + "name": "SAGITTAL_FLAT25SU", + "text": '\uE311' + }, { + "name": "SAGITTAL_SHARP25SD", + "text": '\uE310' + }, { + "name": "SAGITTAL_FLAT7CU", + "text": '\uE313' + }, { + "name": "SAGITTAL_SHARP7CD", + "text": '\uE312' + }, { + "name": "SAGITTAL_FLAT5CU", + "text": '\uE315' + }, { + "name": "SAGITTAL_SHARP5CD", + "text": '\uE314' + }, { + "name": "SAGITTAL_FLAT5V7KU", + "text": '\uE317' + }, { + "name": "SAGITTAL_SHARP5V7KD", + "text": '\uE316' + }, { + "name": "SAGITTAL_FLAT", + "text": '\uE319' + }, { + "name": "SAGITTAL_SHARP", + "text": '\uE318' + }, { + "name": "ONE_COMMA_FLAT", + "text": '\uE454' + }, { + "name": "ONE_COMMA_SHARP", + "text": '\uE450' + }, { + "name": "TWO_COMMA_FLAT", + "text": '\uE455' + }, { + "name": "TWO_COMMA_SHARP", + "text": '\uE451' + }, { + "name": "THREE_COMMA_FLAT", + "text": '\uE456' + }, { + "name": "THREE_COMMA_SHARP", + "text": '\uE452' + }, { + "name": "FOUR_COMMA_FLAT", + "text": '\uE457' + }, { + "name": "//FOUR_COMMA_SHARP", + "text": '\uE262' + }, { + "name": "FIVE_COMMA_SHARP", + "text": '\uE453' } - //,{ 'name': 'UNKNOWN', } -]; +] var equivalences = [ ['SHARP', 'NATURAL_SHARP'], @@ -584,6 +1115,199 @@ function isEquivAccidental(a1, a2) { return false; } +var heads = [{ + 'name': 'HEAD_NORMAL', + 'text': '\uE0a3' + }, { + 'name': 'HEAD_CROSS', + 'text': '\uE0a7' + }, { + 'name': 'HEAD_PLUS', + 'text': '\uE0ad' + }, { + 'name': 'HEAD_XCIRCLE', + 'text': '\uE0b3' + }, { + 'name': 'HEAD_WITHX', + 'text': '\uE0b7' + }, { + 'name': 'HEAD_TRIANGLE_UP', + 'text': '\uE0bd' + }, { + 'name': 'HEAD_TRIANGLE_DOWN', + 'text': '\uE0c6' + }, { + 'name': 'HEAD_SLASHED1', + 'text': '\uE0d1' + }, { + 'name': 'HEAD_SLASHED2', + 'text': '\uE0d2' + }, { + 'name': 'HEAD_DIAMOND', + 'text': '\uE0de' + }, { + 'name': 'HEAD_DIAMOND_OLD', + 'text': '\uE0e1' + }, { + 'name': 'HEAD_CIRCLED', + 'text': '\uE0e5' + }, { + 'name': 'HEAD_CIRCLED_LARGE', + 'text': '\uE0e9' + }, { + 'name': 'HEAD_LARGE_ARROW', + 'text': '\uE0ef' + }, { + 'name': 'HEAD_BREVIS_ALT', + 'text': '\uE0a1' + }, { + 'name': 'HEAD_SLASH', + 'text': '\uE101' + }, { + 'name': 'HEAD_SOL', + 'text': '\uE1b0' + }, { + 'name': 'HEAD_LA', + 'text': '\uE1b2' + }, { + 'name': 'HEAD_FA', + 'text': '\uE1b4' + }, { + 'name': 'HEAD_MI', + 'text': '\uE1b8' + }, { + 'name': 'HEAD_DO', + 'text': '\uE1ba' + }, { + 'name': 'HEAD_RE', + 'text': '\uE1bc' + }, { + 'name': 'HEAD_TI', + 'text': '\uE1be' + }, /*{ + 'name': 'HEAD_DO_WALKER', + 'text': '\uE' + }, { + 'name': 'HEAD_RE_WALKER', + 'text': '\uE' + }, { + 'name': 'HEAD_TI_WALKER', + 'text': '\uE' + }, { + 'name': 'HEAD_DO_FUNK', + 'text': '\uE' + }, { + 'name': 'HEAD_RE_FUNK', + 'text': '\uE' + }, { + 'name': 'HEAD_TI_FUNK', + 'text': '\uE' + }, { + 'name': 'HEAD_DO_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_RE_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_MI_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_FA_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_SOL_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_LA_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_TI_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_SI_NAME', + 'text': '\uE' + }, { + 'name': 'HEAD_A_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_A', + 'text': '\uE' + }, { + 'name': 'HEAD_A_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_B_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_B', + 'text': '\uE' + }, { + 'name': 'HEAD_B_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_C_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_C', + 'text': '\uE' + }, { + 'name': 'HEAD_C_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_D_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_D', + 'text': '\uE' + }, { + 'name': 'HEAD_D_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_E_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_E', + 'text': '\uE' + }, { + 'name': 'HEAD_E_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_F_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_F', + 'text': '\uE' + }, { + 'name': 'HEAD_F_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_G_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_G', + 'text': '\uE' + }, { + 'name': 'HEAD_G_FLAT', + 'text': '\uE' + }, { + 'name': 'HEAD_H', + 'text': '\uE' + }, { + 'name': 'HEAD_H_SHARP', + 'text': '\uE' + }, { + 'name': 'HEAD_CUSTOM', + 'text': '\uE' + }, { + 'name': 'HEAD_GROUPS', + 'text': '\uE' + },*/ { + 'name': 'HEAD_INVALID', + 'text': '?' + } + ]; + + /* 'tpc': 33, 'name': 'B♯♯', @@ -606,16 +1330,21 @@ function tpcClass(tpc, name, accidental) { var a = name.substring(1, name.len); switch (a) { - case '♯♯': + case '\u266F\u266F': + case '##': + case 'x': this.accidental = 'SHARP2'; break; - case '♯': + case '\u266F': + case '#': this.accidental = 'SHARP'; break; - case '♭♭': + case '\u266D\u266D': + case 'bb': this.accidental = 'FLAT2'; break; - case '♭': + case '\u266D': + case 'b': this.accidental = 'FLAT'; break; default: @@ -640,4 +1369,8 @@ function deltaTpcToPitch(tpc1, tpc2) { if (d < 0) d += 12; return d; -} \ No newline at end of file +} + +function durationTo64(duration) { + return 64 * duration.numerator / duration.denominator; +} diff --git a/soloanalyser/soloanalyser-interactive.qml b/soloanalyser/soloanalyser-interactive.qml index 5220303..9f5582d 100644 --- a/soloanalyser/soloanalyser-interactive.qml +++ b/soloanalyser/soloanalyser-interactive.qml @@ -35,12 +35,13 @@ import "core.js" as Core /* - 1.4.9: loopBack option not correctly saved to the settings /* - 1.4.10: (see Core.js log 1.2.8) /* - 1.4.10: (see ChordAnalyser.js log 1.2.22) +/* - 1.4.11: (see ChordAnalyser.js log 1.2.23+24) /**********************************************/ MuseScore { menuPath: "Plugins.Solo Analyser." + pluginName description: "Colors and names the notes based on their role if chords/harmonies." - version: "1.4.10" + version: "1.4.11" readonly property var pluginName: qsTr("Interactive") diff --git a/soloanalyser/soloanalyser.qml b/soloanalyser/soloanalyser.qml index 2401254..0f9c222 100644 --- a/soloanalyser/soloanalyser.qml +++ b/soloanalyser/soloanalyser.qml @@ -33,13 +33,14 @@ import "core.js" as Core /* - 1.4.8: New option for not using chords preceeding the selection /* - 1.4.8: (see Core.js log 1.2.8) /* - 1.4.8: (see ChordAnalyser.js log 1.2.22) +/* - 1.4.9: (see ChordAnalyser.js log 1.2.23+24) /**********************************************/ MuseScore { menuPath: "Plugins.Solo Analyser." + pluginName description: "Colors and names the notes based on their role if chords/harmonies." - version: "1.4.8" + version: "1.4.9" readonly property var pluginName: "Analyse" id: mainWindow