edo.js
Version:
A set of functions for manipulating musical pitches within a given EDO
1 lines • 73.3 kB
JavaScript
this.edo=this.edo||{},this.edo.js=function(t){"use strict";const e="undefined"==typeof window?"server":"browser";let i,s,r,n,h;"server"==e&&(i=require("fs"),s=require("xml2js").parseString,r=require("midi-parser-js")),n="server"==e?function(t,e,s,r){i.writeFile(e+t,s,(function(t){if(t)return console.log(t)}))}:function(t,e,i,s="text/plain"){const r=new Blob([i],{type:s}),n=document.createElement("a");n.download=t,n.href=window.URL.createObjectURL(r),n.onclick=function(t){setTimeout((()=>{window.URL.revokeObjectURL(this.href)}),1500)},n.click(),n.remove()},h="server"==e?function(t){return i.readFileSync(t)}:function(t,e,i){var s=document.createElement("input");s.setAttribute("type","file");var r=document.createElement("a");r.setAttribute("href",""),r.innerText="Select File",r.onclick=function(){return s.click(),!1},r.click()};class a{constructor(t,e="fast"){for(let e=0;e<t.length;e++)t[e]<0&&(t[e]=0);this.n_init=t,this.N=t.reduce(((t,e)=>e+t)),this.k=t.length,this.initialize(e)}initialize(t){this.occurrence=[...this.n_init],this.word=Array(this.N).fill(0),this.alphabet=Array(this.k).fill(0),this.alphabet=this.alphabet.map(((t,e,i)=>e)),this.run=Array(this.N).fill(0),this.first_letter=0,this.last_letter=this.k-1,this.__set_letter_bounds(t),"simple"!=t&&(this.word=[this.word[0]].concat(Array(this.N-1).fill(this.last_letter)))}__set_letter_bounds(t){let e=!1;for(let i=0;i<this.k;i++)!e&&this.occurrence[i]>0&&(e=!0,this.occurrence[i]-=1,this.word[0]=i,this.first_letter=i),"simple"!=t&&0==this.occurrence[i]&&this.__remove_letter(i);this.last_letter=this.alphabet?Math.max.apply(Math,this.alphabet):0}*execute(t="simple"){this.initialize(t),"simple"==t?yield*this._simple_fixed_content(2,1):"fast"==t&&(yield*this._fast_fixed_content(2,1,2))}*_simple_fixed_content(t,e){if(t>this.N)this.N%e==0&&(yield[...this.word]);else for(let i=this.word[t-e-1];i<this.k;i++)this.occurrence[i]>0&&(this.word[t-1]=i,this.occurrence[i]-=1,i==this.word[t-e-1]?yield*this._simple_fixed_content(t+1,e):yield*this._simple_fixed_content(t+1,t),this.occurrence[i]+=1)}*_fast_fixed_content(t,e,i){let s;if(this.occurrence[this.last_letter]==this.N-t+1)this.occurrence[this.last_letter]==this.run[t-e-1]?this.N%e==0&&(yield[...this.word]):this.occurrence[this.last_letter]>this.run[t-e-1]&&(yield[...this.word]);else if(this.occurrence[this.first_letter]!=this.N-t+1){let r=Math.max.apply(Math,this.alphabet),n=this.alphabet.length-1,h=i;for(;r>=this.word[t-e-1];)this.run[parseInt(i-1)]=parseInt(t-i),this.word[t-1]=r,this.occurrence[r]-=1,this.occurrence[r]||(s=this.__remove_letter(r)),r!=this.last_letter&&(h=t+1),r==this.word[t-e-1]?yield*this._fast_fixed_content(t+1,e,h):yield*this._fast_fixed_content(t+1,t,h),this.occurrence[r]||this.__add_letter(s,r),this.occurrence[r]+=1,n-=1,r=this.__get_letter(n);this.word[t-1]=this.last_letter}}__remove_letter(t){let e=this.alphabet.indexOf(t);return this.alphabet.splice(e,1),e}__add_letter(t,e){this.alphabet.splice(t,0,e)}__get_letter(t){return t<0?-1:this.alphabet[t]}}class o{constructor(t=12){this.edo=t,this.cents_per_step=12/t*100,this.M3s=this.convert.ratio_to_interval(5/4,20),this.m3s=this.convert.ratio_to_interval(1.2,20),this.P5s=this.convert.ratio_to_interval(1.5,5),this.edo_divisors=this.get.divisors(t),this.catalog={}}scale(t,e=this.cache){return new l(t,this,e)}make_DOM_svg(t,e,i,s=!1){let r=document.createElement("div");r.style.width=e+"px",r.style.height=i+"px",r.style.display="inline";let n=r.setAttribute("id","paper_"+Date.now()),h=document.getElementById(t);s&&(h.innerHTML=""),h.appendChild(r);const a=new Raphael(r,e,i);let o=a.rect(0,0,e,i).attr("fill","#000000");return{div_id:n,div:r,container_id:t,container:h,paper:a,background:o,width:e,height:i,cleaned:s}}shuffle_array(t,e=!0){let i;i=e?t:[...t];for(let t=i.length-1;t>0;t--){const e=Math.floor(Math.random()*t),s=i[t];i[t]=i[e],i[e]=s}return i}sort_scales=t=>t=t.sort(((t,e)=>{let i=Math.min(t.pitches.length,e.pitches.length);for(let s=0;s<i;s++){if(t.pitches[s]!=e.pitches[s])return t.pitches[s]-e.pitches[s];if(t.pitches[s]==e.pitches[s]&&s==i-1)return t.pitches.length-e.pitches.length}}));float_to_rat(t,e=.001){let i=1,s=0,r=0,n=1,h=t;do{let t=Math.floor(h),e=i;i=t*i+s,s=e,e=r,r=t*r+n,n=e,h=1/(h-t)}while(Math.abs(t-i/r)>t*e);return i+"/"+r}convert={cents_to_interval:(t,e=!0)=>{let i=t/this.cents_per_step;return e&&(i=Math.round(i)),i},cents_to_ratio:t=>Array.isArray(t)?t.map((t=>this.convert.cents_to_ratio(t))):Math.pow(2,t/1200),cents_to_simple_ratio:(t,e=17)=>{if(Array.isArray(t))return t.map((t=>this.convert.cents_to_simple_ratio(t,e)));if(0==(t=this.mod(t,1200)))return{cents:0,cents_in_octave:0,value:1,diff_in_octave:0,ratio:"1/1",original:0};let i,s=this.get.simple_ratios(e,!0);for(let e of Object.keys(s))if(i){Math.abs(s[e].cents_in_octave-t)<Math.abs(s[i].cents_in_octave-t)&&(i=e)}else i=e;return s[i].diff_in_octave=t-s[i].cents_in_octave,s[i].ratio=i,s[i].original=t,s[i]},freq_to_midi:t=>{let e=12*Math.log2(t/440)+69,i=Math.floor(e),s=e-i,r=Math.round(100*s);return r>50&&(i+=1,r=-1*(100-r)),{midi:i,cents:r}},interval_to_cents:t=>this.cents_per_step*t,interval_to_ratio:t=>Array.isArray(t)?t.map((t=>this.convert.interval_to_ratio(t))):Math.pow(2,t/this.edo),intervals_to_pitches:(t,e=0,i)=>{let s;s=i?[mod(e,i)]:[e];for(let r of t)if(Array.isArray(r)){e=s.flat()[s.flat().length-1];let t=this.convert.intervals_to_pitches(r,e);t=t.slice(1),s.push(t)}else i?s.push(mod(parseInt(s[s.length-1])+parseInt(r)),i):s.push(parseInt(s[s.length-1])+parseInt(r));return s},intervals_to_scale:t=>{let e=[0];return t.forEach((t=>{e.push(t+e[e.length-1])})),this.scale(e,!1).pitches},midi_to_intervals:t=>{let e=[];for(let i=0;i<t.length-1;i++)e.push(t[i+1]-t[i]);return e},midi_to_name:(t,e=0)=>{if(12!=this.edo)return t;if(Array.isArray(t))return t.map((t=>this.convert.midi_to_name(t,e)));{t+=e;let i=Math.floor(t/12)-1;return this.convert.pc_to_name(this.mod(t,12)).trim()+i}},midi_to_freq:(t,e=0,i=440)=>Array.isArray(t)?t.map((t=>this.convert.midi_to_freq(t,e,i))):Math.pow(2,(t+e-69)/12)*i,name_to_scale:t=>{let e=(t=t.split("-"))[0];if(t=t[1],e!=this.edo)return"Wrong edo";let i=[];for(let s=e;s>0;s--){let e=Math.pow(2,s);e>t||(i.push(s),t-=e)}return i.push(0),i.reverse(),this.scale(i,!1)},pc_to_name:t=>12!=this.edo?t:Array.isArray(t)?t.map((t=>this.convert.pc_to_name(t))):{0:"C ",1:"C#",2:"D ",3:"Eb",4:"E ",5:"F ",6:"F#",7:"G ",8:"Ab",9:"A ",10:"Bb",11:"B ","*":"**"}[t].trim(),pitches_to_freq:(t,e=440)=>{let i=this.edo;return t.map((t=>Math.pow(2,t/i)*e))},pitches_to_PCs:t=>t.map((t=>this.mod(t,this.edo))),ratio_to_cents:t=>1200*Math.log2(t),ratio_to_interval:(t,e=10)=>{let i=[],s=this.convert.ratio_to_cents(t);for(let t=0;t<this.edo;t++){let r=this.convert.interval_to_cents(t);if(Math.abs(r-s)<=e)i.push(t);else if(i.length>0)break}return i},to_steps:(t,e=!0)=>{if(t.length<=1)return[];if(this.cat_getset(["to_steps",String(t)]))return this.cat_getset(["to_steps",String(t)]);let i=[];for(let e=0;e<t.length-1;e++)i.push(t[e+1]-t[e]);return e&&this.cat_getset(["to_steps",String(t)],i),i}};count={common_tones:(t,e)=>t.reduce(((t,i)=>t+e.includes(i)),0),differences:(...t)=>{let e=t.map(((t,e,i)=>{if(e!=i.length-1){let t=i[e].length,s=i[e+1].length,r=Math.min(t,s),n=Math.max(t,s)-r;for(let t=0;t<r;t++)i[e][t]!=i[e+1][t]&&n++;return n}}));return e.slice(0,e.length-1)},pitches:t=>{let e=[],i=new Set(t);for(let s of i){let i=t.reduce(((t,e)=>e==s?t+1:t),0);e.push([s,i])}return e.sort(((t,e)=>e[1]-t[1])),e}};export={png:t=>{if("server"==e)return console.log("This is only support when run on client-side");const i=function(e){let i=new MouseEvent("click",{view:window,bubbles:!1,cancelable:!0}),s=document.createElement("a");s.setAttribute("download",t+".png"),s.setAttribute("href",e),s.setAttribute("target","_blank"),s.dispatchEvent(i)};let s=document.getElementById(t).getElementsByTagName("svg");for(let t of s){let e=t.getBBox(),s=e.width,r=e.height,n=document.createElement("canvas");n.width=s,n.height=r;let h=n.getContext("2d"),a=(new XMLSerializer).serializeToString(t),o=window.URL||window.webkitURL||window,l=new Image,c=new Blob([a],{type:"image/svg+xml;charset=utf-8"}),p=o.createObjectURL(c);l.onload=function(){h.drawImage(l,0,0),o.revokeObjectURL(p);var t=n.toDataURL("image/png").replace("image/png","image/octet-stream");i(t)},l.src=p}},svg:t=>{if("server"==e)return console.log("This is only support when run on client-side");let i=document.getElementById(t).getElementsByTagName("svg");for(let e of i){let i='<?xml version="1.0" encoding="utf-8"?>'+e.outerHTML,s=document.createElement("a");s.download=t+".svg",s.type="image/svg+xml";let r=new Blob([i],{type:"image/svg+xml"});s.href=(window.URL||webkitURL).createObjectURL(r),s.click()}}};get={angle:t=>{let e=Math.abs(t[0]-t[1]);e=e>Math.ceil(this.edo/2)?this.edo-e:e;let i=Math.abs(t[1]-t[2]);return i=i>Math.ceil(this.edo/2)?this.edo-i:i,(180-e/12*360)/2+(180-i/12*360)/2},best_edo_from_cents:(t,e=t.length+2,i=24)=>{let s=t,r=1/0,n=1/0;for(let t=e;t<=i;t++){let e=new o(t).get.notes_from_cents(s).reduce(((t,e)=>t+Math.abs(e.diff)),0);e<r&&(r=e,n=t)}let h=new o(n);return h.scale(h.get.notes_from_cents(s).map((t=>t.note)))},coordinates:(t,e=[0,0],i=.56418958354776)=>{if(Array.isArray(t))return t.map((t=>this.get.coordinates(t,e,i)));const s=360/this.edo,r=(t=this.mod(t,this.edo))*s*(Math.PI/180);return[i*Math.sin(r)+e[0],i*Math.cos(r)+e[1]]},contour:(t,e=!1)=>{if(e){let e=[];for(let i=1;i<t.length;i++)t[i]>t[i-1]?e.push(1):t[i]==t[i-1]?e.push(0):e.push(-1);return e}{let e={},i=this.get.unique_elements(t);i=i.sort(((t,e)=>t-e));for(let t=0;t<i.length;t++)e[i[t]]=t;return t.map((t=>e[t]))}},contour_motives:(t,e=!1,i=8)=>{let s=[],r=this.get.subsets(t,e).map((t=>this.get.contour(t))).filter((t=>t.length>1));return r=r.filter((t=>t.length<=i)),s=this.get.unique_elements(r).map((t=>{let e=0;for(let i=0;i<r.length;i++)this.is.same(t,r[i])&&e++;return{motive:t,incidence:e}})),s=s.sort(((t,e)=>e.incidence-t.incidence||e.motive.length-t.motive.length)),s},combinations:(t,e)=>{let i=this.get.n_choose_k(t,e);return i=i.map((t=>this.get.permutations(t))),i=i.flat(),i=this.get.unique_elements(i),i},complementary_interval:t=>this.edo-t,complementary_set:(t,e)=>{let i=Array.from(Array(this.edo).keys());return t.forEach((t=>{-1==i.indexOf(t)||i.splice(i.indexOf(t),1)})),e&&(i=this.scale(i,!1).pitches),i},evenly_split:t=>{let e=[],i=this.edo;if(i<t)return e;if(i%t==0)e=Array.from(Array(t).fill(i/t));else{let s=t-i%t,r=Math.floor(i/t);for(let i=0;i<t;i++)i>=s?e.push(r+1):e.push(r)}return e},harmonic_progression:(t,e,i=4,s=2)=>{let r=[e],n=100;for(;r.length<i&&n>0;){let e=r[r.length-1],i=[];for(let r of t)for(let t=0;t<this.edo;t++){let n=r.map((e=>(e+t)%this.edo)),h=this.count.common_tones(n,e);h>=s&&h!=e.length&&i.push(n)}i=this.get.unique_elements(i),0!=i.length?r.push(this.shuffle_array(i)[0]):n--}for(let t=1;t<r.length;t++)r[t]=this.get.minimal_voice_leading(r[t-1],r[t]);return r},harmonized_melody:(t,e,i,s=1)=>{let r=[],n=[...t],h=i;e=e.map((t=>this.scale(t,!1).get.modes())).flat(),n=n.map(((t,i)=>{let n=e.map((e=>e.map((e=>(e+t)%this.edo)).sort(((t,e)=>t-e))));if(h&&0==i)return r.push(h),h;h&&(n=n.filter((t=>{let e=this.count.common_tones(t,h);return e>=s&&e!=h.length})));let a=this.shuffle_array(n)[0];return r.push(a),h=a,h}));for(let t=1;t<r.length;t++)null!=r[t]&&null!=r[t-1]&&(r[t]=this.get.minimal_voice_leading(r[t-1],r[t]));return console.log(r),r},harp_position_of_quality:(t,e=[0,2,4,5,7,9,11],i=[-1,0,1])=>{let s=[],r=e.map((t=>i.map((e=>this.mod(t+e,this.edo))))),n=this.get.partitioned_subsets(r);return n=n.map((r=>{for(let n=0;n<this.edo;n++){let h=t.map((t=>(t+n)%this.edo));if(this.is.subset(h,r)){let t=[],n=[],a=[];h.forEach((e=>t.push(r.indexOf(e)+1))),t.forEach((t=>{let s=-e[t-1]+r[t-1];i.includes(s)||(s<0?s=this.mod(s+this.edo,this.edo):s>0&&(s-=this.edo)),a.push(r[t-1]),n.push(s)})),s.push({strings:t,pedals:n,pitches:a})}}})),s=this.get.unique_elements(s),s=s.sort(((t,e)=>{let i=t.pitches,s=e.pitches,r=i.length;for(let t=0;t<r;t++)if(i[t]!=s[t])return i[t]-s[t]})),s},harp_pedals_to_pitches:(t,e=[0,2,4,5,7,9,11])=>e.map(((e,i)=>this.mod(e+t[i],this.edo))),harp_least_pedals_passage:(t,e=[0,2,4,5,7,9,11],i=[-1,0,1])=>{let s=e.map((t=>i.map((e=>this.mod(t+e,this.edo))))),r=this.get.partitioned_subsets(s),n=[],h=(t,i=[])=>{let s,a,o;for(let i=0;i<t.length;i++){s=t.slice(0,t.length-i),a=t.slice(t.length-i);let n=this.get.unique_elements(s.map((t=>this.mod(t,this.edo))));if(!(n.length>e.length)&&(o=r.filter((t=>this.is.subset(n,t))),o.length>0))break}o&&o.forEach((t=>{0==a.length?n.push([...i,t]):h(a,[...i,t])}))};h(t);let a=n.map((t=>t.map(((e,i)=>{if(i==t.length-1)return 0;let s=t[i],r=t[i+1],n=0;for(let t=0;t<r.length;t++)s[t]!=r[t]&&n++;return n})))).map((t=>t.reduce(((t,e)=>t+e),0))),o=Math.min(...a),l=[];return a.forEach(((t,e)=>{t==o&&l.push(e)})),n=n.filter(((t,e)=>l.includes(e))),{paths:n,pedals:o}},scale_fragments:({max_length:t=4,min_length:e=1,steps:i=[1,2],span:s=this.edo},r=!0)=>{if(this.cat_getset(["scale_fragments",t,e,i,s]))return this.cat_getset(["scale_fragments",t,e,i,s]);let n=i,h=[];for(let i=e;i<=t;i++){let t=this.get.partitioned_subsets([...Array(i).fill(n)]);for(let e of t)h.push(e)}let a=h.filter((t=>t.reduce(((t,e)=>t+e),0)==s)).map((t=>{let e=this.edo/s;return{fragment:t,cardinality:t.length*e}})).sort(((t,e)=>e.fragment.length-t.fragment.length||t.cardinality-e.cardinality));return r&&this.cat_getset(["scale_fragments",t,e,i,s],a),a},sets_from_mixture:t=>this.get.partitioned_subsets(t).filter((t=>t.length==new Set(t).size)),fill_partial_harp_pedaling:(t,e=[-1,-1,-1,-1,-1,-1,-1],i=[0,2,4,5,7,9,11])=>t=t.map((t=>{let i=[...e];return t.strings.forEach(((e,s)=>{i[e-1]=t.pedals[s]})),t.pedals=i,t})),interval_class:(t,e)=>{let i=Math.abs(t-e);return i<Math.ceil(this.edo/2)?i:this.edo-i},n_choose_k:(t,e=2)=>{let i=[];const s=(t,e,r=0,n=Array(e))=>{if(0!=e)for(let i=r;i<=t.length-e;i++)n[n.length-e]=t[i],s(t,e-1,i+1,n);else i.push([...n])};return s(t,e),i},notes_from_cents:(t=[])=>{let e=1200/this.edo;return t=t.map((t=>this.mod(t,1200))).map((t=>{let i=Math.floor(t/e),s=t-i*e,r=Math.ceil(t/e),n=r*e-t;return s<n?{note:i,diff:-s}:{note:r,diff:n}}))},sine_pair_dissonance:(t,e,i=1,s=1)=>{const r=Math.min(t,e),n=Math.max(t,e),h=Math.min(i,s),a=Math.max(i,s),o=h*a,l=2*h/(h+a),c=.24/(.0207*r+18.96),p=Math.pow(Math.E,-3.5*c*(n-r))-Math.pow(Math.E,-5.75*c*(n-r));return.5*Math.pow(o,.1)*Math.pow(l,3.11)*p},resize_melody:(t,e=2,i="multiply")=>{let s=t[0];return t=this.convert.to_steps(t),"add"==i?t=t.map((t=>t>0?t+e>0?t+e:0:t<0&&t-e<0?t-e:0)):"multiply"==i&&(t=t.map((t=>Math.round(t*e)))),t=this.convert.intervals_to_pitches(t),this.get.transposition(t,s,!1)},generated_scale:(t=7,e=7,i=!1)=>{let s=[];for(let i=0;i<e;i++)s.push(this.mod(t*i,this.edo));return s=this.get.normal_order(s.sort(((t,e)=>t-e))),s},generators:(t=!1)=>{let e=[];for(let t=1;t<Math.ceil(this.edo/2);t++){let i=Array.from(Array(this.edo).keys()).map((e=>this.mod(e*t,this.edo)));i=this.get.unique_elements(i),i.length==this.edo&&e.push(t)}return t&&(e=e.map((t=>[t,this.get.complementary_interval(t)]))),e},intersection:(...t)=>{let e=t[0];for(let i=1;i<t.length;i++)e=e.filter((e=>t[i].includes(e)));return e},interval_traversed:t=>t.reduce(((t,e)=>t+e)),interval_stack:(t,e=3,i=!1)=>{const s=(t,e)=>{if(0==t)return[0];let i=[];for(;t;)i.push(t%e),t=Math.floor(t/e);return i.reverse(),i};let r=[],n=(t=this.get.unique_elements(t)).length,h={},a=[];for(let e=0;e<t.length;e++)h[e]=t[e];let o=n**e;for(let t=0;t<o;t++){let i=s(t,n),h=e-i.length;h=Array(h).fill(0),r.push([...h,...i])}for(let t of r)a.push(t.map((t=>h[t])));if(a.sort(((t,e)=>t.reduce(((t,e)=>t+e))-e.reduce(((t,e)=>t+e)))),i){let t=[];for(let e of a){let i=[0];for(let t of e)i.push(i[i.length-1]+t);t.push(i)}a=t}return a},inversion:(t,e=!0)=>{if(this.cat_getset(["scale_"+t,"inverted"]))return this.cat_getset(["scale_"+t,"inverted"]);let i=[...this.convert.to_steps(t)];i.reverse();let s=this.convert.intervals_to_scale(i);return e&&this.cat_getset(["scale_"+t,"inverted"],s),s},lattice:(t=3,e=4,i=!1)=>{let s="";for(let r=this.edo;r>=-this.edo;r-=e){let e="";for(let s=0;s<this.edo;s++){let n,h=this.mod(r+s*t,this.edo);n=i?this.convert.pc_to_name(h):String(h),e+=n+" ".repeat(3-n.length)}s+=e+"\n\n"}return s},levenshtein:(t,e,i=!1)=>{let s,r,n=t,h=e,a=n.length+1,o=h.length+1,l=Array.from({length:a},(t=>Array(o).fill(0)));for(let t=1;t<a;t++)for(let e=1;e<o;e++)l[t][0]=t,l[0][e]=e;let c=0;for(s=1;s<o;s++)for(r=1;r<a;r++){c=n[r-1]==h[s-1]?0:i?2:1;let t=Math.min.apply(Math,[l[r-1][s]+1,l[r][s-1]+1,l[r-1][s-1]+c]);l[r][s]=t}if(i){return(n.length+h.length-l[r-1][s-1])/(n.length+h.length)}return l[n.length][h.length]},maximal_rahn_difference:t=>t*(t-1)*(t-1)/2,maximal_carey_coherence_failures:t=>t*(t-1)*(t-2)*(3*t-5)/24,minimal_voice_leading:(t,e)=>{let i=this.get.permutations(e),s=i.map((e=>e=e.map(((i,s)=>{let r=Math.abs(e[s]-t[s]);return r=r>Math.ceil(this.edo/2)?this.edo-r:r,r})).reduce(((t,e)=>t+e),0))),r=s.reduce(((t,e)=>e<t?e:t),1/0);return i[s.indexOf(r)]},mixture_in_cardinality:(t,e=!0,i=3,s=!0)=>{if(this.cat_getset(["mixture_in_cardinality",t,e?"collapsed":"uncollapsed",i]))return this.cat_getset(["mixture_in_cardinality",t,e?"collapsed":"uncollapsed",i]);let r,n=this.get.unique_elements(this.get.scales(1,this.edo,1,this.edo,t,t).map((t=>t.get.mixture()))).filter((t=>{for(let e=0;e<t.length;e++){if(t[e].length>3)return!1;for(let i=1;i<t[e].length;i++)if(t[e][i]-t[e][i-1]!=1)return!1}return!0}));return e?(r=[...Array(t)].map((t=>[])),n.forEach((e=>{for(let i=0;i<t;i++)r[i]=[...r[i],...e[i]]})),r=r.map((t=>Array.from(new Set(t)).sort(((t,e)=>t-e)).slice(-i)))):r=n.map((t=>t.map((t=>t.slice(-i))))),this.cat_getset(["mixture_in_cardinality",t,e?"collapsed":"uncollapsed",i],r),r},modes:(t,e=!0,i=!0)=>{if(this.edo,this.cat_getset(["scale_"+t,"modes"]))return this.cat_getset(["scale_"+t,"modes"]);let s=t.length,r=t.concat(t),n=[];for(let t=0;t<s;t++){let e=this.edo-r[t],i=r.slice(t,t+s);i=i.map((t=>(t+e)%this.edo)),n.push(i)}return i&&(n=this.get.unique_elements(n)),e&&this.cat_getset(["scale_"+t,"modes"],n),n},motives:(t,e=!0,i=!1,s=8)=>{let r=[];if(e){let e=this.get.subsets(t,i).filter((t=>t.length<=s)).map((t=>this.convert.to_steps(t))),n=this.get.unique_elements(e);r=n.map((t=>{let i=0;for(let s=0;s<e.length;s++)this.is.same(t,e[s])&&i++;return{motive:t,incidence:i}}))}else{this.get.unique_elements(this.get.subsets(t,i).filter((t=>t.length<=s))).forEach((e=>{let s=this.get.subset_indices(e,t,i).length;r.push({motive:e,incidence:s})}))}return r=r.filter((t=>t.motive.length>0)),r=r.sort(((t,e)=>e.motive.length-t.motive.length||e.incidence-t.incidence)),r},necklace:t=>{let e=[],i=this.get.unique_elements(t),s={},r=[];i.forEach(((e,i)=>{s[i]=e;let n=t.reduce(((t,i)=>i==e?t+1:t),0);r.push(n)}));let n=new a(r);return Array.from(n.execute("fast")).forEach((t=>{let i=t.map((t=>s[t]));e.push(i)})),e},new_pitches:(t,e=!0)=>{let i=[],s=[];for(let r=0;r<t.length;r++)if(e){if(-1==s.indexOf(this.mod(t[r],this.edo))&&(s.push(t[r]),i.push([t[r],r]),s.length==this.edo))break}else-1==s.indexOf(t[r])&&(s.push(t[r]),i.push([t[r],r]));return i},ngrams:(t,e=3)=>{let i={};for(;e>1;e--)for(let s=0;s<t.length-(e-1);s++){let r=[];for(let i=s;i<s+(e-1);i++)r.push(t[i]);r=r.join(" "),Array.isArray(i[r])?i[r].push(t[s+(e-1)]):i[r]=[t[s+(e-1)]]}return i},normal_order:(t,e=!0)=>{if(0==t.length)return[];let i=this.edo;if(this.cat_getset(["scale_"+t,"normal_order"]))return this.cat_getset(["scale_"+t,"normal_order"]);let s=[];t.forEach((t=>{s.push(t%this.edo)})),s=this.get.unique_elements(s),s.sort(((t,e)=>t-e));let r=this.get.modes(s),n=function(t){let e=i,s=[];if(t.forEach((t=>{t[t.length-1]<e&&(e=t[t.length-1])})),t.forEach((t=>{t[t.length-1]==e&&s.push(t)})),1==s.length)return s[0];{let t=s[0][s[0].length-1],e=s.map((t=>t.slice(0,-1))),i=n(e);return i.push(t),i}},h=n(r);return e&&this.cat_getset(["scale_"+t,"normal_order"],h),h},stacked:(t,e,i=!1)=>{let s=this.get.permutations(t),r=[];for(let t=0;t<s.length;t++){let n=s[t];for(let t=0;t<n.length;t++){let i=1;for(;n[t]<n[t-1];)n.splice(t,1,n[t]+this.edo*i),i++;-1!=e.indexOf(n[t]-n[t-1])||0==t||(n=!1)}n&&(i?r.push(this.get.transposition(n,-1*n[0],!1)):r.push(n))}return r},step_maximal_mean_error_in_cardinality:t=>{let e=Array.from(Array(t-1).fill(1));return this.scale(this.convert.intervals_to_scale(e),!1).get.step_mean_error()},step_minimal_mean_error_in_cardinality:t=>{let e=this.get.evenly_split(t);return this.scale(this.convert.intervals_to_scale(e),!1).get.step_mean_error()},step_min_max_mean_error_in_cardinality:t=>({min:this.get.step_minimal_mean_error_in_cardinality(t),max:this.get.step_maximal_mean_error_in_cardinality(t)}),step_min_max_error_in_EDO:(t=!0)=>{if(this.cat_getset(["min_max_error_in_EDO"]))return this.cat_getset(["min_max_error_in_EDO"]);let e=[];for(let t=2;t<=this.edo;t++)e.push(this.get.step_min_max_mean_error_in_cardinality(t));let i={min:e.sort(((t,e)=>t.min-e.min))[0].min,max:e.sort(((t,e)=>e.max-t.max))[0].max};return t&&this.cat_getset(["min_max_error_in_EDO"],i),i},without:(t,e,i=!1)=>{let s=[...t];return e.forEach((t=>{do{var e=s.indexOf(t);-1!=e&&s.splice(e,1)}while(-1!=e)})),i&&(s=this.get.normal_order(s)),s},partitioned_subsets:t=>{t=t.map((t=>Array.isArray(t)?t:[t]));let e=[];const i=function(t){for(let s=0;s<t.length;s++){if(t[s].length>1){t[s].forEach((r=>{if(s<t.length-1){let e=[...t.slice(0,s),[r],...t.slice(s+1)];i(e)}else e.push([...t.slice(0,s),[r]])}));break}s==t.length-1&&e.push(t)}};return i(t),e=e.map((t=>t.map((t=>t[0])))),e},path_n_steps:(t,e=[],i=8)=>{const s=e.filter((t=>this.get.interval_traversed(t)>0)),r=e.filter((t=>this.get.interval_traversed(t)<0)),n=e.filter((t=>0==this.get.interval_traversed(t)));let h=[];const a=function(e=[]){let o=e.flat().reduce(((t,e)=>t+e),0),l=e.flat().length;if(l>i||l==i&&o!=t)return null;if(l==i&&o==t)return e;if(o<t)for(let t=0;t<s.length;t++){let i=a(e.concat([s[t]]));null!=i&&h.push(i)}else if(o>t)for(let t=0;t<r.length;t++){let i=a(e.concat([r[t]]));null!=i&&h.push(i)}for(let t=0;t<n.length;t++){let i=a(e.concat([n[t]]));null!=i&&h.push(i)}};return a(),this.get.unique_elements(h)},path_on_tree:(t,e,i=0)=>{let s=[i];for(let i of e)s.push(s[s.length-1]+t[i]);return s},permutations:(t,e=!0)=>{if(t=t.sort(((t,e)=>t-e)),this.cat_getset(["permutations",String(t)]))return this.cat_getset(["permutations",String(t)]);let i=[];const s=(t,e=[])=>{if(0===t.length)i.push(e);else for(let i=0;i<t.length;i++){let r=t.slice(),n=r.splice(i,1);s(r.slice(),e.concat(n))}};return s(t),e&&this.cat_getset(["permutations",String(t)],i),i},pitch_distribution:(t,e=!1)=>{e&&(t=t.map((t=>this.mod(t,this.edo))));let i=this.get.unique_elements(t).map((e=>({note:e,rate:t.filter((t=>t==e)).length/t.length})));return i=i.sort(((t,e)=>e.rate-t.rate)),i},pitch_fields:(t,e=8,i=!0,s=!1,r=!1)=>{if(s){let s=[];for(let n=0;n<t.length-e;n++){let h=[i?this.mod(t[n],this.edo):t[n]];t:for(let s=n+1;s<t.length&&h.length!=e;s++){let e;e=i?this.mod(t[s],this.edo):t[s],-1==h.indexOf(e)&&h.push(e)}h=h.sort(((t,e)=>t-e)),r&&this.is.same(s[s.length-1],h)||s.push(h)}return s}{let s=[];for(let i=0;i<=t.length-e;i++)s.push(t.slice(i,i+e));return s=s.map((t=>(i&&(t=t.map((t=>this.mod(t,this.edo)))),t=this.get.unique_elements(t).sort(((t,e)=>t-e))))).filter(((t,e,i)=>e+1==i.length||!this.is.same(i[e],i[e+1]))),s}},random_melody:(t=8,e=[0,12],i=4,s,r=5)=>{let n=0,h=[],a=[];for(let t=e[0];t<=e[1];t++)s&&-1==s.indexOf(this.mod(t,this.edo))||a.push(t);for(;h.length<t&&n<1e3;){n++;let t=h.slice(Math.max(h.length-i,0),h.length),e=a.filter((e=>-1==t.indexOf(e)));if(h.length>0){let t=[];do{t=e.filter((t=>Math.abs(t-h[h.length-1])<=r)),r++}while(0==t.length);e=t}let s=Math.floor(Math.random()*e.length);h.push(e[s])}return h},random_melody_from_contour:(t,e=[0,12],i)=>{let s=[],r=[],n=this.get.unique_elements([...t]).sort(((t,e)=>t-e)),h=n.length-r.length;for(let t=e[0];t<=e[1];t++)i?-1!=i.indexOf(this.mod(t,this.edo))&&s.push(t):s.push(t);for(;r.length<h;){let t=Math.floor(Math.random()*s.length),e=s.splice(t,1)[0];r.push(e),h=n.length}r=r.sort(((t,e)=>t-e));let a={};for(let t=0;t<n.length;t++)a[n[t]]=r[t];return t=t.map((t=>a[t]))},random_melody_from_ngram:(t,e=[0],i=16)=>{let s=[...e],r=100+i;for(;s.length<i&r>0;){t:for(let e=s.length;e>0;e--){let i=t[s.slice(s.length-e).join(" ")];if(Array.isArray(i)){let t=i[Math.floor(Math.random()*i.length)];s.push(t);break t}}r--}return s},random_melody_from_distribution:(t,e=8)=>{let i=[];t=t.sort(((t,e)=>t.rate-e.rate));let s=Math.floor(1/t[0].rate);for(t=(t=t.map((t=>[...new Array(Math.ceil(s*t.rate)).fill(t.note)]))).flat();i.length<e;){let e=Math.floor(Math.random()*t.length);i.push(t[e])}return i},ratio_approximation:(t,e=17)=>{let i=0,s="",r=0,n=this.convert.interval_to_cents(t),h=this.get.simple_ratios(e=e);for(let t in h){Math.abs(h[t].cents-n)<Math.abs(n-i)&&(i=h[t].cents,s=t,r=h[t].value)}let a=s.split(":");a[0];let o=a[1];return{ratio:s,cents_offset:n-i,decimal:r,octave:Math.log2(parseInt(o)),log_position:Math.log2(r)}},retrograde:t=>t.reverse(),rotated:(t,e)=>(e=this.mod(e,t.length),[...t.slice(e),...t].slice(0,t.length)),rotations:t=>{let e=[];for(let i=0;i<t.length;i++)e.push([...t.slice(i,t.length),...t.slice(0,i)]);return e},scalar_melodies:(t,e=[1,2],i=!0)=>{e.push(0);let s=[];return t.forEach(((t,r)=>{let n=!1;for(let i=0;i<s.length;i++){let h=s[i],a=h[h.length-1].pitch,o=Math.abs(t-a);this.is.element_of(o,e)&&(s[i].push({pitch:t,index:r}),n=!0)}if(!n){let n=[];if(i){let i=[];e.forEach((e=>{i.push(t+e),i.push(t-e)})),i=this.get.unique_elements(i),i.forEach((e=>{s.map((t=>t.map((t=>t.pitch)))).forEach(((i,s)=>{if(i.includes(e)){let h=i.lastIndexOf(e);n.push([t,r,s,h])}}))})),n=n.map((t=>{let e=s[t[2]].slice(0,t[3]+1);return e=[...e,{pitch:t[0],index:t[1]}],e})),s=[...s,...n]}0==n.length&&s.push([{pitch:t,index:r}])}})),s},scales:(t=1,e=this.edo-1,i=1,s=12,r=this.edo,n=2,h=!1)=>{let a=this;let o=function(t,e,s,r,n=a.edo){let h=[];return function t(n,a,o=Array.from(Array(n.length).fill(0)),l=0){let c=o.reduce(((t,e,i)=>e*n[i]+t),0),p=o.reduce(((t,e)=>e+t),0),_=o.filter((t=>t>0)).length;if(_>e)return;if(p>r)return;if(c==a&&_>=i&&p>=s&&h.push(o),l==o.length)return;let u=c,g=0;for(;u<a;){let e=Array.from(o);e[l]=g,g++,u=e.reduce(((t,e,i)=>e*n[i]+t),0),t(n,a,e,l+1)}}(t,n),h=h.map((e=>e.map(((e,i)=>Array(e).fill(t[i]))).flat())),h}(function(t,e){let i=[];for(let s=e;s!=t-1;s--)i.push(s);return i}(t%=a.edo,e=e>=a.edo?a.edo-1:e),s,n,r),c=function(t){let e=[];for(let i=0;i<t.length;i++){let s=t[i],r=a.get.necklace(s);e=e.concat(r)}return e}(o),p=(t=>{let e=[];return t.forEach((t=>{e.push(a.convert.intervals_to_scale(t))})),e})(c),_=[];return p.forEach((t=>_.push(new l(t,this,h).normal()))),_=this.sort_scales(_),_},shortest_path:(t,e=[5,-3],i=[],s=10)=>{let r=[],n=[];for(let t of e)t>0?r.push(t):t<0&&n.push(t);let h=[];const a=function(t,e=[3,4],i=[-1,-2],s=[],r=10){if(r<0)return null;let n=s.reduce(((t,e)=>t+e),0);if(n==t&&(0==h.length||h.length>s.length))h=[...s];else if(n!=t||!(0!=h.length||h.length<=s.length))if(n<t)for(let n of e)a(t,e,i,s.concat([n]),r-1);else if(n>t)for(let n of i)a(t,e,i,s.concat([n]),r-1)};return a(t,r,n,i,s),h=h.sort(((t,e)=>t-e)),h},simple_ratios:(t=17,e=!0)=>{if(this.cat_getset(["simple_ratios",t]))return this.cat_getset(["simple_ratios",t]);let i=this.get.primes_in_range(t),s={};for(let e=2;e<t+1;e++)for(let t=1;t<e;t++)i.indexOf(e)<0&&i.indexOf(t)<0||e%2==0&&t%2==0||e%t==0&&t>2||(s[String(e)+":"+String(t)]={cents:this.convert.ratio_to_cents(e/t),cents_in_octave:this.mod(this.convert.ratio_to_cents(e/t),1200),value:e/t});return e&&this.cat_getset(["simple_ratios",t],s),s},starting_at:(t,e=0,i=!0)=>{let s=-1*t[0]+e;return t.map((t=>i?this.mod(t+s,this.edo):t+s))},subset_indices:(t,e,i=!0)=>{let s=[];const r=function(t,e,i=[],n=0){if(0==t.length)return i;let h=t[0];for(let a=n;a<e.length;a++)if(e[a]==h){let n=r(t.slice(1),e,[...i,a],a+1);n&&s.push(n)}};return i?r(t,e):function(t,e){t:for(let i=0;i<e.length-(t.length-1);i++)for(let r=0;r<t.length;r++){if(t[r]!=e[i+r])continue t;if(r==t.length-1){let e=new Array(t.length).fill(0);e.forEach(((t,s)=>e[s]=i+s)),s.push(e)}}}(t,e),s},subsets:(t,e=!0,i=!1)=>{if(e)t=t.reduce(((t,e)=>t.concat(t.map((t=>[...t,e])))),[[]]);else{let e=[];for(let i=1;i<t.length+1;i++)for(let s=0;s<t.length-i+1;s++)e.push(t.slice(s,s+i));t=e}return t=t.filter((t=>t.length>0)),i&&(t=t.map((t=>this.get.normal_order(t))),t=this.get.unique_elements(t)),t},transposition:(t,e=0,i=!0)=>(t=t.map((t=>t+e)),i&&(t=t.map((t=>this.mod(t,this.edo)))),t),union:(...t)=>[].concat(...t),unique_elements:t=>{let e=new Set(t.map(JSON.stringify));return e=Array.from(e).map(JSON.parse),e},well_formed_scale:(t=7)=>[...Array(t).keys()].map((e=>Math.floor(e*this.edo/t))),without_chromatic_notes:t=>t=t.filter(((t,e,i)=>{let s=0;return e>0&&(i[e-1]>i[e]?s=-1:i[e-1]<i[e]&&(s=1)),i[e]+s!=i[e+1]})),primes_in_range:(t=17,e=2)=>{let i=[];for(let s=e;s<=t;s++)if(s>1)for(let t=2;t<s&&s%t!=0;t++)i.push(s);return i},divisors:t=>{let e=[];for(let i=2;i<Math.ceil(t/2);i++)t%parseInt(i)==0&&e.push(i);return e}};midi={import:t=>{if("server"!=e)return alert("This is currently supported only on server-side");let i=h(t);return i=r.parse(i),i.track=i.track.map((t=>(t.event=t.event.map(((t,e,i)=>(t.onset=0==e?t.deltaTime:i[e-1].onset+t.deltaTime,t))),t))),i},strip:t=>{let e=t,i=[];e.track=e.track.map((t=>(t.event=t.event.filter((t=>9==t.type)).map((t=>({pitch:t.data[0],onset:t.onset}))).map(((t,e,s)=>{let r=t.onset;return-1==i.indexOf(r)&&i.push(r),s.filter((t=>t.onset==r))})),t.event=this.get.unique_elements(t.event),t))),i.sort(((t,e)=>t-e)),e.track=e.track.map((t=>(t.event=t.event.map((t=>t=t.map((t=>(t.onset=i.indexOf(t.onset),t))))),t))),e.track=e.track.map((t=>t=t.event.reduce(((t,e)=>(e.forEach((e=>{null==t[e.onset]?t[e.onset]=[e.pitch]:t[e.onset].push(e.pitch)})),t)),[]))),e.track=e.track.filter((t=>t.length>0));let s=[];return e.track.forEach((t=>{t.forEach(((t,e)=>{null==s[e]?s[e]=[...t]:s[e]=[...s[e],...t]}))})),s=s.map((t=>1==t.length?t[0]:t)),s},chordify:(t,e=480,i=!0,s=!1,r=!1)=>{let n=t,h=0;return n=n.track.map((t=>(t.event=t.event.filter((t=>9==t.type)),t.event.map((t=>h=t.onset>h?t.onset:h)),[...t.event]))).flat().sort(((t,e)=>t.onset-e.onset)),Array.from(Array(Math.ceil(h/e)).keys()).map((t=>t*e)).map(((t,e,i)=>i.length-1>e?n.filter((t=>t.onset>=i[e]&&t.onset<i[e+1])):n.filter((t=>t.onset>=i[e])))).map((t=>(t=t.map((t=>s?this.mod(t.data[0],this.edo):t.data[0])),r&&t.sort(((t,e)=>t-e)),i&&(t=this.get.unique_elements(t)),t)))}};xml={import:t=>{if("server"!=e)return alert("This is currently supported only on server-side");var i=h(t);let r;return s(i,(function(t,e){r=e})),r}};is={element_of:(t,e)=>{if(0==t.length||0==e.length)return!1;return t=JSON.stringify(t),-1!=JSON.stringify(e).indexOf(t)},rotation:(t,e)=>{let i=[...e,...e];for(let s=0;s<e.length;s++)if(this.is.same(t,i.slice(s,s+e.length)))return!0;return!1},same:(t,e)=>(t=JSON.stringify(t))==(e=JSON.stringify(e)),subset:(t,e,i=!1)=>{if(!i)return t.every((t=>e.includes(t)));for(;t.length>0;){let i=e.indexOf(t[0]);if(-1==i)return!1;t=t.slice(1),e.splice(i,1)}return!0},transposition:(t,e)=>{let i=t,s=e;return this.is.same(i,s.map((t=>this.mod(t-s[0]-i[0],this.edo))))}};show={contour:(t,e,i=!1,s)=>{let r,n,h=document.getElementById(t);s?Array.isArray(s)?(r=s[0],n=s[1]):(r=s,n=s):(r=h.offsetWidth,n=h.offsetHeight);let a=document.createElement("div");a.style.width=r+"px",a.style.height=n+"px",a.style.display="inline",a.setAttribute("id","paper_"+Date.now()),i&&(h.innerHTML=""),h.appendChild(a);const o=new Raphael(a,r,n);o.rect(0,0,r,n).attr("fill","000").attr("stroke","white");let l=Math.max.apply(Math,e),c=Math.min.apply(Math,e),p=15,_=e.map((t=>{return Math.floor((t-(e=c))*(p-(i=n-p))/(l-e)+i);var e,i})),u=p,g=Math.floor((r-30)/(e.length-1)),m="M15,"+_[0],f=o.set(),d=n/45;f.push(o.circle(p,_[0],d));for(let t=1;t<_.length;t++)u+=g,m+="L"+u+","+_[t],f.push(o.circle(u,_[t],d));o.path(m).attr("stroke","red").attr("stroke-width",2),f.attr("fill","white"),f.toFront()},interval_fractal_tree:(t,e=200,i=90,s=[0,2,4,5,7,9,11],r=[-1,1],n=5,h=.7)=>{const a=this,o=document.getElementById(t);o.innerHTML="";const l=this.edo;let c=o.offsetWidth,p=o.offsetWidth;const _=new Raphael(o,c,p),u=function(t=[0,0],e=50,i=90){return i=i*Math.PI/180,[Math.floor(t[0]+e*Math.cos(i)),Math.floor(t[1]+e*Math.sin(i))]};class g{constructor(t=300,e=0,i=0,s=0,r=20,n=90,h=.7,a=5,o=[-1,1],l=0,c=null){this.diatonic=!!c,this.mode=c,this.iterations=a,this.length_mul=h,this.angle_span=n,this.length=t,this.angle=e,this.circle_r=r,this.circle_o=u([i,s],t-r,e-90),this.start=[i,s],this.line_center=u(this.start,(this.length-2*this.circle_r)/2,this.angle-90),this.line_end=u(this.start,this.length-2*this.circle_r,this.angle-90),this.end=u([i,s],t,e-90),this.sub_branches=o.length,this.intervals=o,this.starting_pitch=l}draw_branch(){let t=this.start,e=this.line_end;_.path("M"+t.join(",")+"L"+e.join(",")).attr("stroke","white");let i=this.circle_o,s=Math.floor((this.starting_pitch-(r=0))*(360-(n=0))/(l-1-r)+n);var r,n;let h=Raphael.hsl2rgb(s,100,50);if(_.circle(i[0],i[1],this.circle_r).attr("fill",h),this.text=_.text(i[0],i[1],this.starting_pitch).attr("fill","blue").attr("font-size",25),this.iterations>0){let t=Math.floor(this.angle_span/2)-this.angle_span,e=this.angle_span/(this.sub_branches-1),i=this.length*this.length_mul;for(let s=0;s<this.sub_branches;s++){let r=100;if(this.diatonic){let t=this.mode.indexOf(this.starting_pitch);r=this.mode[a.mod(t+this.intervals[s],this.mode.length)]}else r=mod(this.starting_pitch+this.intervals[s],l);let n=this.angle+t+s*e,h=this.end[0],o=this.end[1];new g(i,n,h,o,this.circle_r,this.angle_span,this.length_mul,this.iterations-1,this.intervals,r,this.mode).draw_branch()}}}}_.clear(),_.rect(0,0,c,p).attr("fill","000"),new g(e=e,0,Math.floor(c/2),p,20,i,h,n,r,0,s).draw_branch()},necklace:t=>{t.cx=t.cx||t.paper.width/2,t.cy=t.cy||t.paper.height/2,t.radius=t.radius||t.paper.width/2-30,t.ring=null==t.ring||t.ring,t.inner_strings=null==t.inner_strings||t.inner_strings,t.outer_strings=null==t.outer_strings||t.outer_strings,t.PC_at_midnight=t.PC_at_midnight||0,t.string_width=t.string_width||1,t.node_color=t.node_color||"black",t.node_radius=t.node_radius||t.paper.height*Math.PI/(4*this.edo)/2-5;class e{constructor(t,e,i,s,r){this.necklace=t,this.radius=e,this.cx=i,this.cy=s,this.name=r}draw(){let t=this.necklace.paper;this.drawing&&(this.drawing.remove(),this.drawing=void 0),this.drawing=t.set(),this.circle=t.circle(this.cx,this.cy,this.radius).attr("stroke","white").attr("fill",this.necklace.node_color),this.drawing.push(this.circle),this.text=t.text(this.cx,this.cy,this.name).attr("fill","white").attr("font-size",this.radius),this.drawing.push(this.text)}}class i{constructor(t,e,i,s,r,n){this.necklace=t,this.x1=e,this.y1=i,this.x2=s,this.y2=r,this.length=Math.sqrt((s-e)**2+(r-i)**2),this.stroke_width=n}draw(){let t=this.necklace.paper;this.drawing&&(this.drawing.remove(),this.drawing=void 0);let e=Math.floor((i=this.length,s=0,r=2*this.necklace.radius,(i-s)*(360-(n=0))/(r-s)+n));var i,s,r,n;let h=Raphael.hsl2rgb(e,100,50);this.drawing=t.path("M"+this.x1+","+this.y1+"L"+this.x2+","+this.y2).attr("stroke",h.hex).attr("stroke-width",this.stroke_width)}}let s=new class{constructor(t,e){this.cx=e.cx,this.cy=e.cy,this.radius=e.radius,this.pitches=e.pitches,this.PC_at_midnight=e.PC_at_midnight,this.show_ring=e.ring,this.show_inner_strings=e.inner_strings,this.show_outer_strings=e.outer_strings,this.parent=t,this.edo=t.edo,this.nodes=[],this.strings=[],this.paper=e.paper,this.node_color=e.node_color,this.node_radius=e.node_radius,this.string_width=e.string_width,this.draw_all()}draw_all(){this.show_ring&&this.draw_ring(),this.draw_nodes(),this.draw_strings(this.string_width);for(let t of this.nodes)t.drawing.toFront(),t.text.toFront()}draw_ring(t="white",e=3){let i=this.paper;this.ring&&(this.ring.remove(),this.ring=void 0),this.ring=i.circle(this.cx,this.cy,this.radius).attr("stroke",t).attr("stroke-width",e)}draw_nodes(){for(let t of this.nodes)t.drawing.remove(),t.text.remove();this.nodes=[];let t=this.node_radius;t=Math.max(t,1);for(let i of this.pitches){let s=(i*(360/this.edo)-90)*Math.PI/180,r=Math.floor(this.cx+this.radius*Math.cos(s)),n=Math.floor(this.cy+this.radius*Math.sin(s)),h=new e(this,t,r,n,(i+this.PC_at_midnight)%this.edo);this.nodes.push(h)}for(let t of this.nodes)t.draw()}draw_strings(t){for(let t of this.strings)t.drawing.remove();if(this.strings=[],this.show_outer_strings)for(let e=0;e<this.nodes.length;e++){let s=this.nodes[e],r=this.nodes[(e+1)%this.nodes.length],n=new i(this,s.cx,s.cy,r.cx,r.cy,t);this.strings.push(n)}if(this.show_inner_strings)for(let e=0;e<this.nodes.length-2;e++)for(let s=2;s<this.nodes.length;s++){let r=this.nodes[e],n=this.nodes[s],h=new i(this,r.cx,r.cy,n.cx,n.cy,t);this.strings.push(h)}for(let t of this.strings)t.draw()}}(this,t);return s},nested_necklaces:(t,e,i=!0,s=600,r=!1,n,h=!0)=>{let a=s,o=s,l=a/2-a/20,c=e.length,p=Math.min(l/c);const _=this.make_DOM_svg(t,o,a,i).paper;let u=Math.min(_.height*Math.PI/(4*this.edo)/2-5,_.height*Math.PI/(c*c*2),_.height*Math.PI/(this.edo*c)/2-5);n&&(u=Math.max(u,n));for(let t of e){let e={paper:_,pitches:t,radius:l,ring:r,inner_strings:!1,node_radius:u,outer_strings:h};this.show.necklace(e),l-=p}},necklace_fractal:t=>{const e=t.container_id,i=t.necklaces,s=t.offset_x,r=t.offset_y||50,n=t.radius_multiplier||.5,h=t.initial_radius||250,a=t.minimum_node_radius||20,o=null==t.ring||t.ring,l=t.canvas_width||900,c=t.canvas_height||900,p=null!=t.replace&&t.replace,_=this.make_DOM_svg(e,l,c,p).paper,u=this,g=function(t,e,i=h){let l=[...t],c=l.splice(0,1)[0];if(e)e.forEach((t=>{let e=u.show.necklace({paper:_,ring:o,radius:i,pitches:c,cx:t.cx,cy:t.cy+i,PC_at_midnight:t.name,node_radius:Math.max(i/8,a)});l.length>0&&g(l,e.nodes,e.radius*n)}));else{let t=u.show.necklace({cx:_.width/2+s,ring:o,paper:_,radius:i,pitches:c,cy:i+r,node_radius:Math.max(i/8,a)});l.length>0&&g(l,t.nodes,t.radius*n)}};g(i)}};mod(t,e=this.edo){return(t%e+e)%e}cat_getset(t,e){if(void 0===e)return function t(e,i,...s){if(void 0!==e)return 0==s.length&&e.hasOwnProperty(i)?(Array.isArray(e[i])&&JSON.parse(JSON.stringify(e[i])),"object"==typeof e[i]?JSON.parse(JSON.stringify(e[i])):e[i]):t(e[i],...s)}(this.catalog,...t);if(Array.isArray(e))e=Array.from(e);else if("object"==typeof e)return JSON.parse(JSON.stringify(e));return function t(e,i,s,...r){return 0==r.length?(e[s]=i,e[s]):(void 0===e[s]&&(e[s]={}),t(e[s],i,...r))}(this.catalog,e,...t)}purge_cache(){this.catalog={}}}class l{constructor(t,e,i=!0){this.parent=e;let s=0-Math.min.apply(Math,t);this.pitches=t.map((t=>t+s)),this.edo=this.parent.edo,this.pitches=this.pitches.map((t=>t%e.edo)),this.pitches=this.parent.get.unique_elements(this.pitches),this.pitches.sort(((t,e)=>t-e)),this.length=this.count.pitches(),this.name=this.get.name(!1),this.cache=i}count={chord_quality:t=>{this.pitches;let e=0;return t=this.parent.get.partitioned_subsets(t),this.parent.get.modes(this.pitches,!1,!1).forEach((i=>{t.forEach((t=>{-1==(t=t.map((t=>-1!=i.indexOf(t)))).indexOf(!1)&&e++}))})),e},consecutive_steps:(t,e=this.cache)=>{if(this.cat_getset(["consecutive_steps",t]))return this.cat_getset(["consecutive_steps",t]);let i=[],s=this.to.steps();if(s=[...s,...s],-1==s.indexOf(t))return 0;let r=0;for(let e of s)e==t?r++:(i.push(r),r=0);i=i.sort(((t,e)=>e-t));let n=i[0];return n=Math.min.apply(Math,[n,this.edo]),e&&this.cat_getset(["consecutive_steps",t],n),n},imperfections:(t=10,e=this.cache)=>{if(this.cat_getset("# imperfections"))return this.cat_getset("# imperfections");let i=this.pitches,s=0,r=[],n=this.parent.convert.ratio_to_cents(1.5);for(let e=1;e<this.edo;e++)if(Math.abs(this.parent.convert.interval_to_cents(e)-n)<=t)r.push(e);else if(r.length>0)break;let h=i.map((t=>t+this.edo)),a=i.concat(h);return i.forEach((t=>{let e=!1;r.forEach((i=>{-1!=a.indexOf(t+i)&&(e=!0)})),e||s++})),e&&this.cat_getset("# imperfections",s),s},interval:t=>{Array.isArray(t)||(t=[t]);let e=this.pitches,i=0;for(let s of e)for(let r of t)-1!=e.indexOf((s+r)%this.edo)&&i++;return i},M3s:()=>this.count.interval(this.parent.M3s),m3s:()=>this.count.interval(this.parent.m3s),min_max_n_chords_in_necklace:(t=this.cache)=>{let e=this.get.necklace_family();if(this.parent.cat_getset(["necklace_family",String(e)]))return this.parent.cat_getset(["necklace_family",String(e)]);let i=1/0,s=0;return this.get.necklace_family_members().map((t=>this.parent.scale(t))).forEach((t=>{let e=t.count.n_chords();e>s&&(s=e),e<i&&(i=e)})),t&&this.parent.cat_getset(["necklace_family",String(e)],{min:i,max:s}),{min:i,max:s}},major_minor_triads:()=>this.count.chord_quality([[...this.parent.M3s],[...this.parent.P5s]])+this.count.chord_quality([[...this.parent.m3s],[...this.parent.P5s]]),modes:()=>this.get.modes().length,n_chords:t=>{if(t=Object.assign({prime_form:!1,n:[2,this.count.pitches()],cache:this.cache},t),this.cat_getset(["n_chords_count",...Object.values(t)]))return this.cat_getset(["n_chords_count",...Object.values(t)]);let e=0;for(let i=t.n[0];i<=t.n[1];i++)e+=this.get.n_chords(i,!0,t.prime_form,!1).length;return t.cache&&this.cat_getset(["n_chords_count",...Object.values(t)],e),e},n_chords_diatonic:(t=this.cache)=>{if(this.cat_getset(["n_chords_diatonic_count"]))return this.cat_getset(["n_chords_diatonic_count"]);let e=0;for(let t=2;t<=this.pitches.length;t++){let i=this.get.n_chords_diatonic(t);i=i.map((t=>t.combos.length)).reduce(((t,e)=>t+e),0),e+=i}return t&&this.cat_getset(["n_chords_diatonic_count"],e),e},P5s:()=>this.count.interval(this.parent.P5s),pitches:()=>this.pitches.length,rahn_differences:()=>{let t=0;for(let e=1;e<this.count.pitches();e++){let i=this.get.generic_intervals(e);i=i.map((t=>t.instances)),t+=this.parent.get.n_choose_k(i,2).map((t=>t[0]*t[1])).reduce(((t,e)=>t+e),0)}return t},rahn_contradictions:(t=this.cache)=>{if(this.cat_getset("rahn_contradictions"))return this.cat_getset("rahn_contradictions");let e=0,i=[...Array(this.pitches.length).keys()],s=this.parent.get.combinations(i,2).sort(((t,e)=>t[0]-e[0]||t[1]-e[1])).map((t=>{let e=this.get.pairwise_generic_specific_intervals(t[0],t[1]);return e.scale_degs=t,e.pitches=[this.pitches[t[0]],this.pitches[t[1]]],e}));for(let t=0;t<s.length-1;t++){let i=s[t];for(let r=t+1;r<s.length;r++){let t=s[r];(i.generic<t.generic&&i.specific>t.specific||t.generic<i.generic&&t.specific>i.specific)&&e++}}return t&&this.cat_getset("rahn_contradictions",e),e},rahn_ambiguities:(t=this.cache)=>{if(this.cat_getset("rahn_ambiguities"))return this.cat_getset("rahn_ambiguities");let e=0,i=[...Array(this.pitches.length).keys()],s=this.parent.get.combinations(i,2).sort(((t,e)=>t[0]-e[0]||t[1]-e[1])).map((t=>{let e=this.get.pairwise_generic_specific_intervals(t[0],t[1]);return e.scale_degs=t,e.pitches=[this.pitches[t[0]],this.pitches[t[1]]],e}));for(let t=0;t<s.length-1;t++){let i=s[t];for(let r=t+1;r<s.length;r++){let t=s[r];i.specific==t.specific&&i.generic!=t.generic&&e++}}return t&&this.cat_getset("rahn_ambiguities",e),e},ratio:(t,e=10)=>{let i=this.parent.convert.ratio_to_interval(t,e);return this.count.interval(i)},rotational_symmetries:()=>this.edo/this.count.transpositions(),simple_ratios:(t=17,e=15)=>{let i=this.parent.get.simple_ratios(t=t),s=0,r=0;for(let t in i){let n=this.count.ratio(i[t].value,e);n>0&&(s++,r+=n)}return{discrete:s,instances:r}},tetrachords:()=>this.get.tetrachords().length,thirds:()=>this.count.interval(this.parent.M3s.concat(this.parent.m3s)),transpositions:(t=this.cache)=>{if(this.cat_getset("# transpositions"))return this.cat_getset("# transpositions");let e=this.pitches,i=[e];for(let t=0;t<this.parent.edo;t++){let s=[];if(e.forEach((e=>{s.push((e+t+1)%this.edo)})),s.sort(((t,e)=>t-e)),this.parent.is.element_of(s,i))return i.length;i.push(s)}let s=i.length;return t&&this.cat_getset("# transpositions",s),s},trichords:()=>this.get.trichords().length,unique_elements:t=>{let e=this.pitches,i=e.length;return e.forEach((e=>{-1!=t.indexOf(e)&&i--})),i}};export={scala:(t,e="scala/")=>{let i=this.get.name(),s="! "+(t=t||i+".scl")+"\n";s+="!\n"+i+" "+JSON.stringify(this.get.pitches())+"\n",s+=String(this.count.pitches()+1)+"\n!\n";let r=this.to.cents();for(let t of r)s+=String(t)+"\n";s+="2/1",n(t,e,s)}};get={area:(t=.56418958354776)=>{this.edo;const e=this.get.coordinates([0,0],t);let i=0,s=0;for(let t=0;t<e.length;t++)i+=e[t][0]*e[(t+1)%e.length][1],s+=e[t][1]*e[(t+1)%e.length][0];return Math.abs((i-s)/2)},binary_unevenness:(t=!0)=>{function e(t,i=1){let s=t.edo/2,r=t.to.steps(),n=new o(t.count.pitches()).get.evenly_split(2),h=[r.slice(0,n[0]),r.slice(n[0])],a=h.map((t=>t.reduce(((t,e)=>t+e),0))).map((t=>Math.abs(t-s))).reduce(((t,e)=>t+e),0)/2,l=[];for(let t=0;t<h.length;t++)if(h[t].length>=2){let s=h[t],r=s.reduce(((t,e)=>t+e),0),n=new o(r),a=e(n.scale(n.convert.intervals_to_scale(s),!1),i+1);l.push(a)}let c=h.map((t=>t.reduce(((t,e)=>t+e),0)));return 0==l.length?{this_level_segments:c,this_level_mean_error:a,level:i}:{this_level_segments:c,this_level_mean_error:a,lower_levels:l,level:i}}let i=[];for(let t=0;t<this.count.pitches();t++){let s=this.mode(t),r=e(s);i.push({mode:s.pitches,level:0,lower_levels:[r]})}return t?function(t){let e={};function s(t){let i=t.level;i in e||(e[i]=[]),e[i].push(t.this_level_mean_error),"lower_levels"in t&&t.lower_levels.forEach((t=>{s(t)}))}i.forEach((t=>{s(t)})),delete e[0];for(let t in e)e[t]=e[t].reduce(((t,e)=>t+e),0)/e[t].length;let r=[];for(let t in e)r.push(e[t]);return r.reduce(((t,e)=>t+e),0)/r.length}():i},cardinality_variety_ratio:()=>{let t=[];for(let e=2;e<this.count.pitches();e++){let i=this.get.n_chords_diatonic(e).map((t=>t.combos.length));i=i.reduce(((t,e)=>t+e))/i.length,t.push(e/i)}return t=t.reduce(((t,e)=>t+e))/t.length,t},diagnostic_combinations:(t=this.cache)=>{if(this.cat_getset("diagnostic_combinations"))return this.cat_getset("diagnostic_combinations");let e=[];for(let t=2;t<this.count.pitches();t++){let i=this.get.n_chords(t,!1);i=i.map((t=>[t,this.get.position_of_quality(t).length])),i.forEach((t=>{1==t[1]&&e.push(t[0])}))}return t&&this.cat_getset("diagnostic_combinations",e),e},minimal_diagnostic_combination:(t=this.cache)=>{if(this.cat_getset("minimal_diagnostic_combination"))return this.cat_getset("diagnostic_combinations");let e=[];for(let t=2;t<this.count.pitches();t++){let i=this.get.n_chords(t,!1);if(i=i.map((t=>[t,this.get.position_of_quality(t).length])),i.forEach((t=>{1==t[1]&&e.push(t[0])})),e.length>0)break}return t&&this.cat_getset("minimal_diagnostic_combination",e),e},diagnostic_intervals:(t=this.cache)=>{if(this.cat_getset("diagnostic_intervals"))return this.cat_getset("diagnostic_intervals");let e=[];for(let t=1;t<=Math.floor(this.edo/2);t++){let i=this.get.specific_intervals(t);if(!i)continue;if(0==i.length)continue;let s=!0;i.forEach((t=>{1!=t.instances&&(s=!1)})),s&&e.push(i[0].specific)}return t&&this.cat_getset("diagnostic_intervals",e),e},edo:()=>this.edo,entropy:t=>{let e=this.count.transpositions(),i=this.get.position_of_quality(t).length/e;return Math.log2(1/i)},evenness_of_spread:()=>{const t=this.pitches.map((t=>t/this.edo)),e=[...Array(t.length).keys()].map((e=>e*(this.edo/t.length/this.edo))),i=[...Array(t.length).keys()].map((t=>0)),s=t.map(((t,i)=>t-e[i]));i.map(((t,i)=>t-e[i]));const r=s.reduce(((t,e)=>t+e))/s.length;return s.map((t=>t-r)).map((t=>Math.pow(t,2))).reduce(((t,e)=>t+e))/s.length},*iterator(t=this.pitches()){let e=0;for(;;){let i=yield t[e%t.length];i=i||1,e+=i}},symmetricalness:({min_n:t=2,max_n:e=this.count.pitches(),verbose:i=!1}={},s=this.cache)=>{if(this.cat_getset(["self_similarity",t,e,i]))return this.cat_getset(["self_similarity",t,e,i]);let r,n=0,h=0,a=[];for(let i=t;i<=e;i++){let t=this.get.n_chords(i);h+=t.length,t=t.map((t=>{let e=this.get.position_of_quality(t).length;return n+=e,{fragment:t,manifestations:e}})),a.push(...t)}return r=i?a:{distinct:h,manifestations:n,ratio:n/h,normalized:(n/h-1)/(this.count.pitches()-1)},s&&this.cat_getset(["self_similarity",t,e,i],r),r},sym2:()=>{const t=(t,e)=>{const i=t=>0==t?1:t*i(t-1);return i(t)/(i(e)*i(t-e))};let e=[];for(let i=2;i<=this.count.pitches()-1;i++){const s=this.get.n_chords(i).length,r=t(this.count.pitches(),i);e.push(s/r)}return e.reduce(((t,e)=>t+e),0)/e.length},set_difference:(t=[0,2,4,5,7,9,11],e=!1,i=1)=>{let s=e?this.count.pitches():1,r=[],n=[],h=[],a=[];for(let e=0;e<s;e++){let s=this.mode(e).pitches,o=[];for(let e=0;e<s.length;e++)o.push(s[e]-t[e]);let l=o.map((t=>Math.abs(t)<=i)).reduce(((t,e)=>t&&e),!0),c=o.reduce(((t,e)=>0!=e?t+1:t),0);r.push(o),n.push(l),a.push(e),h.push(c)}for(let t=n.length-1;t>=0;t--)n[t]||(n.splice(t,1),r.splice(t,1),h.splice(t,1),a.splice(t,1));let o=Math.min(...h),l=h.indexOf(o);return{valid:n[l]||!1,alterations:h[l],delta:r[l],mode:n[l]?this.mode(a[l]).pitches:void 0}},per_note_set_difference:(t=[0,2,4,5,7,9,11])=>this.pitches.map(((e,i)=>t[i]-e)),coordinates:(t=[0,0],e=.56418958354776)=>this.parent.get.coordinates(this.pitches,t,e),common_tone_transpositions:t=>{let e=this.get.modes(),i=[];return this.pitches.forEach((s=>{e.forEach(((e,r)=>{let n=e.map((t=>this.parent.mod(t+s,this.edo)));t&&(n=n.sort(((t,e)=>t-e)));let h=this.parent.count.common_tones(this.pitches,n);i.push({transposition:n,common_tones:h,altered_tones:this.count.pitches()-h,common_tone:s,as_scale_degree:r+1})}))})),i=this.parent.get.unique_elements(i),i},complement:t=>this.parent.get.complementary_set(this.pitches,t),chord_quality_from_shape:(t,e=1)=>(t=t.map((t=>0==(t=this.parent.mod(t,this.pitches.length))?this.pitches.length:t))).map((t=>{let i=this.parent.mod(t+e-2,this.pitches.length);return this.pitches[i]})),in_tally_order:()=>{let t=this.get.step_tally().map((t=>t[0]));console.log(t);let e=[];for(let i=0;i<this.count.modes();i++){let s=Array.from(new Set(this.mode(i).to.steps()));this.parent.is.same(s,t