musicjson-toolbox
Version:
A toolbox for comparing musicjson objects
77 lines (76 loc) • 10.3 kB
JavaScript
!function(){"use strict"
var t={base12:{C:1,D:3,E:5,F:6,G:8,A:10,B:12},base12Inverted:{1:"C",3:"D",5:"E",6:"F",8:"G",10:"A",12:"B"},degreesFromSemitones:{1:1,3:2,5:3,6:4,8:5,10:6,12:7},deg:{0:0,1:.9,2:.2,3:.5,4:.1,5:.35,6:.8},ton:{0:.6,1:2.6,2:2.3,3:1,4:1,5:1.6,6:1.8,7:.8,8:1.3,9:1.3,10:2.2,11:2.5},globalK:.348,globalK1:.3,globalK2:.22,globalK3:.1,abcStep:["C,,,","^C,,,","D,,,","^D,,,","E,,,","F,,,","^F,,,","G,,,","^G,,,","A,,,","^A,,,","B,,,","C,,","^C,,","D,,","^D,,","E,,","F,,","^F,,","G,,","^G,,","A,,","^A,,","B,,","C,","^C,","D,","^D,","E,","F,","^F,","G,","^G,","A,","^A,","B,","C","^C","D","^D","E","F","^F","G","^G","A","^A","B","c","^c","d","^d","e","f","^f","g","^g","a","^a","b","c'","^c'","d'","^d'","e'","f'","^f'","g'","^g'","a'","^a'","b'","c''","^c''","d''","^d''","e''","f''","^f''","g''","^g''","a''","^a''","b''","c'''","^c'''","d'''","^d'''","e'''","f'''","^f'''","g'''","^g'''","a'''","^a'''","b'''"],abcAccidental:{"flat-flat":"__",flat:"_",natural:"=",sharp:"^","sharp-sharp":"^^",undefined:"","":""},notes:function(t,e,i){for(var n=[],r=-1,a=0,s=0;s<t.measures.length;s++){for(var u=0;u<t.measures[s].notes.length;u++)t.measures[s].notes[u].measureNumber=s,t.measures[s].notes[u].noteNumber=u,t.measures[s].notes[u].noteNumberAbsolute=a,a++
if(e&&t.measures[s].attributes.repeat.left&&(r=s),n=n.concat(t.measures[s].notes),e&&t.measures[s].attributes.repeat.right){if(-1!==r)for(;s>=r;)n=n.concat(t.measures[r].notes),r++
r=-1}}if(i===!1)for(var h=0;h<n.length;h++)n[h].rest!==!0&&"true"!==n[h].rest||n.splice(h,1)
return n},intervals:function(t){var e=[]
e.push({value:"*",duration:"*",measureNumber:0,noteNumber:0,noteNumberAbsolute:0})
for(var i=1;i<t.length;i++){var n=this.pitchDifference(t[i-1].pitch,0,t[i].pitch,!0,!1),r=this.durationDifference(t[i-1].duration,t[i].duration,!1),a={value:n,duration:r,measureNumber:t[i].measureNumber,noteNumber:t[i].noteNumber,noteNumberAbsolute:t[i].noteNumberAbsolute}
e.push(a)}return e},parsons:function(t){var e=[]
e.push({value:"*",measureNumber:0,noteNumber:0,noteNumberAbsolute:0})
for(var i=1;i<t.length;i++){var n,r=this.pitchDifference(t[i-1].pitch,0,t[i].pitch,!0,!1)
n=r>0?"u":0>r?"d":"r",e.push({value:n,measureNumber:t[i].measureNumber,noteNumber:t[i].noteNumber,noteNumberAbsolute:t[i].noteNumberAbsolute})}return e},ngrams:function(t,e){for(var i=[],n=0;n<t.length-(e-1);n++){for(var r=[],a=0;e>a;a++)r.push(t[n+a])
i.push(r)}return i},pitchValues:function(t,e){return t.map(function(t){return this.base12Pitch(t.pitch.step,e,t.pitch.octave,t.pitch.alter,!1)}.bind(this))},pitchDurationValues:function(t,e,i,n){return t.map(function(t){var r=this.base12Pitch(t.pitch.step,e,t.pitch.octave,t.pitch.alter,!1)
return{value:r,rest:t.rest,duration:t.duration/i/n*16}}.bind(this))},tempoAdjust:function(t,e){for(var i=[],n=0;n<t.length;n++){var r=t[n]
r.duration=e(r.duration),i.push(r)}return i},valueMapping:function(t){return t.map(function(t){return t.value})},highlightMapping:function(t){return t.map(function(t){return{measure:t.measureNumber,note:t.noteNumber,noteAbsolute:t.noteNumberAbsolute}})},base12Pitch:function(t,e,i,n,r){var a=this.base12[t]
if(n&&(a+=n),0>e)for(a-=12*Math.round(Math.abs(e)/2);0>e;)a+=7,e++
else for(a+=12*Math.round(Math.abs(e)/2);e>0;)a-=7,e--
if(0===a&&(a=12,i--),r)a+=12*i
else{for(;a>12;)a-=12
for(;0>a;)a+=12}return a},interval2AbcStep:function(t,e){return this.abcStep[e+t-13]},pitchDuration2AbcStep:function(t,e){var i=this.abcAccidental[t.pitch.accidental],n=this.abcStep[this.base12Pitch(t.pitch.step,0,t.pitch.octave,0,!0)-13],r=t.duration
null!==e&&e.dot&&(r=2*r)
var a=""
return t.dot&&(r/=1.5,a=">"),t.rest?"z"+r+a:i+n+r+a},pitchDifference:function(t,e,i,n,r){"undefined"==typeof n&&(n=!1),"undefined"==typeof r&&(r=!1)
var a=this.base12Pitch(i.step,e,parseInt(i.octave),parseInt(i.alter),n)-this.base12Pitch(t.step,e,parseInt(t.octave),parseInt(t.alter),n)
return r&&(a=Math.abs(a)),a},durationDifference:function(t,e,i){"undefined"==typeof i&&(i=!1)
var n=e-t
return i&&(n=Math.abs(n)),n},uniques:function(t){for(var e=[],i=0,n=t.length;n>i;i++)-1===e.indexOf(t[i])&&""!==t[i]&&e.push(t[i])
return e},editDistance:function(t,e,i,n){if(0===t.length)return 0
if(0===e.length)return 0
var r,a=[]
for(r=0;r<=e.length;r++)a[r]=[r]
var s
for(s=0;s<=t.length;s++)a[0][s]=s
for(r=1;r<=e.length;r++)for(s=1;s<=t.length;s++)i(r,s)?a[r][s]=a[r-1][s-1]:a[r][s]=Math.min(a[r-1][s-1]+n(r,s),a[r][s-1]+n(r,s),a[r-1][s]+n(r,s))
var u=Math.max(a[e.length][0],a[0][t.length])
return 1-a[e.length][t.length]/u},stringEditDistance:function(t,e){return this.editDistance(t,e,function(i,n){return e.charAt(i-1)===t.charAt(n-1)},function(){return 1})},arrayEditDistance:function(t,e){return this.editDistance(t,e,function(i,n){return e[i-1]===t[n-1]},function(){return 1})},weightedEditDistance:function(t,e,i){if(0===t.length)return 0
if(0===e.length)return 0
var n,r=[]
for(n=0;n<=t.length;n++)n>0?r[n]=[parseFloat(r[n-1])+this.weightDeletion(t,n,i)]:r[n]=[n]
var a
for(a=0;a<=e.length;a++)a>0?r[0][a]=parseFloat(r[0][a-1])+this.weightInsertion(e,a,i):r[0][a]=a
var s=0,u=1/0
for(n=0;n<t.length;n++)s<t[n].duration&&(s=t[n].duration)
for(a=0;a<e.length;a++)u>e[a].duration&&(u=e[a].duration)
var h=s/u,o=0,l=1/0
for(a=0;a<e.length;a++)o<e[a].duration&&(o=e[a].duration)
for(n=0;n<t.length;n++)l>t[n].duration&&(l=t[n].duration)
var f=o/l
for(n=1;n<=t.length;n++)for(a=1;a<=e.length;a++)if(t[n-1].value===e[a-1].value&&t[n-1].rest===e[a-1].rest&&t[n-1].duration===e[a-1].duration)r[n][a]=r[n-1][a-1]
else{var c=r[n-1][a-1]+this.weightSubstitution(t,e,n,a,i),g=r[n][a-1]+this.weightInsertion(e,a,i),p=r[n-1][a]+this.weightDeletion(t,n,i),d=this.weightFragmentation(r,t,e,n,a,h,i),b=this.weightConsolidation(r,t,e,n,a,f,i),v=Math.min(c,g,p,d,b)
r[n][a]=v}var m=-(1/0)
for(n=0;n<r.length;n++){var D=Math.max.apply(null,r[n])
D>m&&(m=D)}return 1-r[t.length][e.length]/m},weightSubstitution:function(t,e,i,n,r){var a=this.weightInterval(t[i-1],e[n-1],r),s=this.weightLength(t[i-1].duration,e[n-1].duration),u=r?this.globalK1:this.globalK,h=a+u*s
return h},weightInsertion:function(t,e,i){var n=i?this.globalK3:this.globalK
return n*parseFloat(t[e-1].duration)},weightDeletion:function(t,e,i){var n=i?this.globalK3:this.globalK
return n*t[e-1].duration},weightFragmentation:function(t,e,i,n,r,a,s){var u,h,o=2,l=Math.min(r-1,a),f=1/0,c=s?this.globalK1:this.globalK
for(u=o;l>=u;u++){h=u
for(var g=t[n-1][r-h],p=0;h>0;){var d=this.weightInterval(e[n-1],i[r-h],s)
g+=d,p+=i[r-h].duration,h--}var b=this.weightLength(e[n-1].duration,p)
g+=c*b,f>g&&(f=g)}return f},weightConsolidation:function(t,e,i,n,r,a,s){var u,h,o=2,l=Math.min(n-1,a),f=1/0,c=s?this.globalK1:this.globalK
for(u=o;l>=u;u++){h=u
for(var g=t[n-h][r-1],p=0;h>0;){var d=this.weightInterval(e[n-h],i[r-1],s)
g+=d,p+=e[n-h].duration,h--}var b=this.weightLength(p,i[r-1].duration)
g+=c*b,f>g&&(f=g)}return f},weightInterval:function(t,e,i){if("true"===t.rest||t.rest===!0||"true"===e.rest||e.rest===!0)return.1
var n=t.value%12
0===n&&(n=12)
var r=e.value%12
if(0===r&&(r=12),i)return Math.abs(r-n)
if("undefined"!=typeof this.base12Inverted[n]&&"undefined"!=typeof this.base12Inverted[r]){var a=this.degreesFromSemitones[n],s=this.degreesFromSemitones[r]
return this.deg[Math.abs(a-s)]}return this.ton[Math.abs(n-r)]},weightLength:function(t,e){return Math.abs(t-e)},distanceParsons:function(t,e){return this.stringEditDistance(this.valueMapping(this.parsons(this.notes(t,!1,!1))).join(""),e)},parsonSimilarity:function(t,e){return this.distanceParsons(t,this.valueMapping(this.parsons(this.notes(e,!1,!1))).join(""))},distancePitch:function(t,e){return this.arrayEditDistance(this.pitchValues(this.notes(t,!1,!1),parseInt(t.attributes.key.fifths)),e)},pitchSimilarity:function(t,e){return this.distancePitch(t,this.pitchValues(this.notes(e,!1,!1),parseInt(e.attributes.key.fifths)))},distanceIntervals:function(t,e){return this.arrayEditDistance(this.valueMapping(this.intervals(this.notes(t,!1,!1))),e)},intervalSimilarity:function(t,e){return this.distanceIntervals(t,this.valueMapping(this.intervals(this.notes(e,!1,!1))))},distancePitchDuration:function(t,e,i){return this.weightedEditDistance(this.pitchDurationValues(this.notes(t,!1,!0),parseInt(t.attributes.key.fifths),parseInt(t.attributes.divisions),parseInt(t.attributes.time["beat-type"])),e,i)},pitchDurationSimilarity:function(t,e,i){return this.distancePitchDuration(t,this.pitchDurationValues(this.notes(e,!1,!0),parseInt(e.attributes.key.fifths),parseInt(e.attributes.divisions),parseInt(e.attributes.time["beat-type"])),i)},parsonsNgramSimilarity:function(t,e){for(var i=this.ngrams(this.parsons(this.notes(t,!1,!1)),e.length),n=[],r=0;r<i.length;r++){for(var a=0;a<i[r].length;a++)0===a&&(i[r][a].value="*")
n.push({similarity:this.stringEditDistance(this.valueMapping(i[r]).join(""),e),highlight:this.highlightMapping(i[r])})}return n},pitchNgramSimilarity:function(t,e){for(var i=parseInt(t.attributes.key.fifths),n=this.ngrams(this.notes(t,!1,!1),e.length),r=[],a=0;a<n.length;a++)r.push({similarity:this.arrayEditDistance(this.pitchValues(n[a],i),e),highlight:this.highlightMapping(n[a])})
return r},intervalNgramSimilarity:function(t,e){for(var i=this.ngrams(this.intervals(this.notes(t,!1,!1)),e.length),n=[],r=0;r<i.length;r++){for(var a=0;a<i[r].length;a++)0===a&&(i[r][a].value="*")
n.push({similarity:this.arrayEditDistance(this.valueMapping(i[r]),e),highlight:this.highlightMapping(i[r])})}return n},pitchDurationNgramSimilarity:function(t,e,i){var n=parseInt(t.attributes.divisions),r=parseInt(t.attributes.time["beat-type"]),a=parseInt(t.attributes.key.fifths),s=this.notes(t,!1,!0),u=this.ngrams(s,e.length)
u=u.concat(this.ngrams(s,Math.floor(1.5*e.length))),u=u.concat(this.ngrams(s,2*e.length))
for(var h=[],o=0;o<u.length;o++)h.push({similarity:this.weightedEditDistance(this.pitchDurationValues(u[o],a,n,r),e,i),highlight:this.highlightMapping(u[o])})
return h}}
"undefined"!=typeof define&&null!==define&&define.amd?define(function(){return t}):"undefined"!=typeof module&&null!==module?module.exports=t:"undefined"!=typeof self&&"function"==typeof self.postMessage&&"function"==typeof self.importScripts?self.MusicJsonToolbox=t:"undefined"!=typeof window&&null!==window&&(window.MusicJsonToolbox=t)}()