jianpurender
Version:
Render music score using SVG on browsers.
1 lines • 11.9 kB
JavaScript
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.jianpu_model=e():t.jianpu_model=e()}(self,(()=>(()=>{"use strict";var t={559:(t,e,s)=>{s.d(e,{MAJOR_SCALE_INTERVALS:()=>r,MAX_QUARTER_DIVISION:()=>i,MIDDLE_C_MIDI:()=>a,MIN_RESOLUTION:()=>n});const n=.0625,i=240,r={0:1,2:2,4:3,5:4,7:5,9:6,11:7},a=60},765:(t,e,s)=>{s.d(e,{JianpuBlock:()=>a});var n=s(559);function i(t){return Math.abs(t)<1e-6}function r(t,e){const s=t.start+t.length;if(e<=t.start||e>=s||i(s-e))return null;const n=s-e;t.length=e-t.start;const r={start:e,length:n,pitch:t.pitch,intensity:t.intensity,jianpuNumber:t.jianpuNumber,octaveDot:t.octaveDot,accidental:0,tiedFrom:t};return t.tiedTo&&(r.tiedTo=t.tiedTo,t.tiedTo.tiedFrom=r),t.tiedTo=r,r}class a{start;length;notes;measureNumber;durationLines;augmentationDots;augmentationDash;beatBegin;beatEnd;isTieStart;isTieEnd;constructor(t=0,e=0,s=[],n=1){this.start=t,this.length=e,this.notes=s,this.measureNumber=n}addNote(t){if(0===this.notes.length)return this.start=t.start,this.length=t.length,this.notes.push(t),!0;if(!i(this.start-t.start))return console.warn(`JianpuBlock: Attempted to add note at ${t.start} to block starting at ${this.start}. Ignoring.`),!1;let e=!1,s=!1;for(let n=0;n<this.notes.length;n++)if(this.notes[n].pitch===t.pitch){s=!0,t.length<this.notes[n].length&&(this.notes[n].tiedFrom&&(t.tiedFrom=this.notes[n].tiedFrom,t.tiedFrom&&(t.tiedFrom.tiedTo=t)),this.notes[n].tiedTo&&(t.tiedTo=this.notes[n].tiedTo,t.tiedTo&&(t.tiedTo.tiedFrom=t)),this.notes[n]=t,e=!0);break}s||this.notes.push(t);let n=1/0;for(const t of this.notes)n=Math.min(n,t.length);return this.length=n,!s||e}split(t,e){const s=this.start+this.length;if(t<=this.start||t>=s||i(s-t))return null;const n=s-t,o=t-this.start,h=new a(t,n,[],e.measureNumberAtQ(t)),u=[];for(const e of this.notes){const s=e.start+e.length;if(s>t+1e-6){const s=r(e,t);s?u.push(s):console.warn("Split failed for note, unexpected state.")}else i(s-t)}return u.forEach((t=>h.addNote(t))),this.length=o,delete this.durationLines,delete this.augmentationDots,delete this.augmentationDash,this.beatEnd&&(h.beatEnd=!0,delete this.beatEnd),this.isTieEnd&&(h.isTieStart=!0,delete this.isTieEnd),h}splitToBeat(t){const e=t.timeSignatureAtQ(this.start);if(!e)return null;const s=t.measureLengthAtQ(this.start),n=t.measureNumberAtQ(this.start),r=this.start-(n-Math.floor(n))*s,a=this.start-r,o=4/e.denominator,h=a/o;this.beatBegin=i(h-Math.round(h));const u=r+(Math.floor(h+1e-6)+1)*o,l=r+s,m=this.start+this.length;let d=null;u<m-1e-6&&u>this.start+1e-6&&(d=u),l<m-1e-6&&l>this.start+1e-6&&(null===d||l<d)&&(d=l);let c=null;if(null!==d)c=this.split(d,t),c&&(this.beatEnd=!0);else{const t=(a+this.length)/o;this.beatEnd=i(t-Math.round(t)),this.beatEnd||(this.beatEnd=i(m-l))}return this.isTieStart=this.notes.some((t=>t.tiedFrom)),this.isTieEnd=this.notes.some((t=>t.tiedTo)),c&&(c.isTieStart=c.notes.some((t=>t.tiedFrom)),c.isTieEnd=c.notes.some((t=>t.tiedTo)),this.notes.some((t=>t.tiedTo&&t.start+t.length>d))&&delete this.isTieEnd),c}calculateRenderProperties(t){delete this.durationLines,delete this.augmentationDots,delete this.augmentationDash;const e=this.length;if(i(e)||e<0)return;if(t.allowDottedRests||this.notes.length>0){if(i(e-1.5))return void(this.augmentationDots=1);if(i(e-.75))return this.durationLines=1,void(this.augmentationDots=1);if(i(e-.375))return this.durationLines=2,void(this.augmentationDots=1);i(e-3)&&(this.augmentationDots=1)}if(this.durationLines=e>=3.999999||e>=1.999999||e>=.999999?0:e>=.499999?1:e>=.249999?2:e>=.124999?3:4,this.augmentationDash=!1,1===this.notes.length){const e=this.notes[0],s=t.timeSignatureAtQ(this.start);if(!s)return;const n=Math.max(4/s.denominator,1);if(!(this.measureNumber%1<=1e-6)&&e.tiedFrom&&i(e.tiedFrom.length-n)&&e.tiedFrom.pitch===e.pitch&&e.length>=1){let s=!0;if(e.tiedTo){const n=e.start+e.length;s=Math.floor(t.measureNumberAtQ(this.start))===Math.floor(t.measureNumberAtQ(n))&&e.tiedTo.length>=1}s&&(this.augmentationDash=!0)}}}splitToStandardSymbol(t){const e=this.length;if(i(e)||e<n.MIN_RESOLUTION-1e-6)return null;const s=[];t.allowDottedRests||this.notes.length>0?(s.push(6),s.push(4),s.push(3),s.push(2),s.push(1.5),s.push(1),s.push(.75),s.push(.5),s.push(.375),s.push(.25),s.push(.125),s.push(.0625)):(s.push(4),s.push(2),s.push(1),s.push(.5),s.push(.25),s.push(.125),s.push(.0625));let r=0;for(const t of s)if(e>=t-1e-6){r=t;break}i(r)&&(r=n.MIN_RESOLUTION,e<r-1e-6&&e>1e-6&&console.warn(`Block length ${e} is too small, rendering as ${r}`));let a=null;return e>r+1e-6?(a=this.split(this.start+r,t),this.length!==r&&(console.warn(`Adjusting block length after split from ${this.length} to ${r}`),this.length=r)):this.length=r,a}mergeToMap(t){const e=t.get(this.start);e?(this.notes.forEach((t=>e.addNote(t))),0!==this.measureNumber&&(e.measureNumber=this.measureNumber)):t.set(this.start,this)}isMeasureBeginning(){return i(this.measureNumber-Math.floor(this.measureNumber))}}},775:(t,e,s)=>{s.d(e,{MeasuresInfo:()=>r});var n=s(830),i=s(559);class r{measuresInfo;allowDottedRests=!0;constructor(t,e){this.measuresInfo=[];let s=0,r=0,a=0,o=t.tempos[0],h=t.keySignatures[0],u=t.timeSignatures[0],l=1,m=(0,n.getMeasureLength)(u),d=u.start;const c=i.MIN_RESOLUTION;for(let i=0;i<e;i+=c){const e={start:i,measureNumber:l+(i-d)/m,measureLength:m,tempo:o,keySignature:h,timeSignature:u};if(s<t.tempos.length&&Math.abs(t.tempos[s].start-i)<c/2&&(o=t.tempos[s++],e.tempo=o,e.tempoChange=!0),r<t.keySignatures.length&&Math.abs(t.keySignatures[r].start-i)<c/2&&(h=t.keySignatures[r++],e.keySignature=h,e.keyChange=!0),a<t.timeSignatures.length&&Math.abs(t.timeSignatures[a].start-i)<c/2){l+=(t.timeSignatures[a].start-d)/m,l=Math.round(1e3*l)/1e3,u=t.timeSignatures[a++],e.timeSignature=u,m=(0,n.getMeasureLength)(u),e.measureLength=m,e.measureNumber=l,e.timeChange=!0,d=e.start}this.measuresInfo.push(e)}}findIndex(t){return Math.max(0,Math.min(this.measuresInfo.length-1,Math.floor(t/i.MIN_RESOLUTION)))}measureNumberAtQ(t){if(0===this.measuresInfo.length)return 1;const e=this.findIndex(t),s=this.measuresInfo[e],n=(t-s.start)/s.measureLength;return s.measureNumber+n+1e-9}measureLengthAtQ(t){if(0===this.measuresInfo.length)return(0,n.getMeasureLength)(n.DEFAULT_TIME_SIGNATURE);const e=this.findIndex(t);return this.measuresInfo[e].measureLength}tempoAtQ(t,e=!1){if(0===this.measuresInfo.length)return n.DEFAULT_TEMPO.qpm;const s=this.findIndex(t),r=this.measuresInfo[s],a=Math.abs(r.start-t)<i.MIN_RESOLUTION/2;return!e||r.tempoChange&&a?r.tempo.qpm:-1}keySignatureAtQ(t,e=!1){if(0===this.measuresInfo.length)return n.DEFAULT_KEY_SIGNATURE.key;const s=this.findIndex(t),r=this.measuresInfo[s],a=Math.abs(r.start-t)<i.MIN_RESOLUTION/2;return!e||r.keyChange&&a?r.keySignature.key:-1}timeSignatureAtQ(t,e=!1){if(0===this.measuresInfo.length)return n.DEFAULT_TIME_SIGNATURE;const s=this.findIndex(t),r=this.measuresInfo[s],a=Math.abs(r.start-t)<i.MIN_RESOLUTION/2;return!e||r.timeChange&&a?r.timeSignature:null}quartersToTime(t,e){const s=this.tempoAtQ(e);return s<=0?0:t/s*60}timeToQuarters(t,e){const s=this.tempoAtQ(e);if(s<=0)return 0;const n=t*s/60;return Math.round(n*i.MAX_QUARTER_DIVISION)/i.MAX_QUARTER_DIVISION}isBeatStart(t){if(0===this.measuresInfo.length)return!1;const e=this.findIndex(t),s=this.measuresInfo[e],n=s.timeSignature,r=(t-(s.start-(s.measureNumber-Math.floor(s.measureNumber))*s.measureLength))/(4/n.denominator);return Math.abs(r-Math.round(r))<i.MIN_RESOLUTION/2}}},830:(t,e,s)=>{s.d(e,{DEFAULT_KEY_SIGNATURE:()=>i,DEFAULT_TEMPO:()=>n,DEFAULT_TIME_SIGNATURE:()=>r,getMeasureLength:()=>a});const n={start:0,qpm:60},i={start:0,key:0},r={start:0,numerator:4,denominator:4};function a(t){return t.numerator*(4/t.denominator)}}},e={};function s(n){var i=e[n];if(void 0!==i)return i.exports;var r=e[n]={exports:{}};return t[n](r,r.exports,s),r.exports}s.d=(t,e)=>{for(var n in e)s.o(e,n)&&!s.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},s.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),s.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var n={};s.r(n),s.d(n,{JianpuModel:()=>h,mapMidiToJianpu:()=>u});var i=s(830),r=s(775),a=s(765),o=s(559);class h{jianpuInfo;measuresInfo;jianpuBlockMap;lastQ;constructor(t,e){this.jianpuInfo=t,this.jianpuBlockMap=new Map,this.lastQ=0,this.update(t,e)}isLastMeasureAtQ(t){return t>=this.lastQ-1e-6}getTotalDuration(){return this.lastQ}update(t,e){this.jianpuInfo=t,t.notes.sort(((t,e)=>t.start-e.start)),this.lastQ=0,t.notes.forEach((t=>{this.lastQ=Math.max(this.lastQ,t.start+t.length)})),this.lastQ+=1e-6,t.tempos=t.tempos&&t.tempos.length?t.tempos:[i.DEFAULT_TEMPO],t.tempos.sort(((t,e)=>t.start-e.start)),t.tempos[0].start>1e-6&&t.tempos.unshift({...i.DEFAULT_TEMPO,start:0});const s=void 0!==e?{start:0,key:e}:{...i.DEFAULT_KEY_SIGNATURE};t.keySignatures=t.keySignatures&&t.keySignatures.length?t.keySignatures:[s],t.keySignatures.sort(((t,e)=>t.start-e.start)),t.keySignatures[0].start>1e-6&&t.keySignatures.unshift({...s,start:0}),t.timeSignatures=t.timeSignatures&&t.timeSignatures.length?t.timeSignatures:[i.DEFAULT_TIME_SIGNATURE],t.timeSignatures.sort(((t,e)=>t.start-e.start)),t.timeSignatures[0].start>1e-6&&t.timeSignatures.unshift({...i.DEFAULT_TIME_SIGNATURE,start:0}),this.measuresInfo=new r.MeasuresInfo(t,this.lastQ),this.infoToBlocks()}infoToBlocks(){const t=new Map;let e=0;if(this.jianpuInfo.notes.forEach((s=>{const n=s.start,i=this.measuresInfo.measureNumberAtQ(n);if(n>e+1e-6){const s=e,i=n-s,r=this.measuresInfo.measureNumberAtQ(s),o=new a.JianpuBlock(s,i,[],r);t.set(s,o)}const r=this.measuresInfo.keySignatureAtQ(n),o=this.createJianpuNote(s,r);let h=t.get(n);h||(h=new a.JianpuBlock(n,0,[],i),t.set(n,h)),h.addNote(o),e=Math.max(e,n+h.length)})),this.lastQ>e+1e-6){const s=e,n=this.lastQ-s;if(n>1e-6){const e=this.measuresInfo.measureNumberAtQ(s),i=new a.JianpuBlock(s,n,[],e);t.set(s,i)}}this.jianpuBlockMap=new Map;const s=Array.from(t.keys()).sort(((t,e)=>t-e));let n=[];s.forEach((e=>{n.push(t.get(e))}));const i=new Set;for(;n.length>0;){let t=n.shift();i.has(t.start)&&this.jianpuBlockMap.has(t.start);let e=t.splitToBeat(this.measuresInfo);if(e){t.mergeToMap(this.jianpuBlockMap),i.add(t.start),n.unshift(e);continue}let s=t,r=null;do{r=s.splitToStandardSymbol(this.measuresInfo),s.mergeToMap(this.jianpuBlockMap),i.add(s.start),r&&(s=r)}while(r)}this.jianpuBlockMap.forEach((t=>{t.calculateRenderProperties(this.measuresInfo)}))}createJianpuNote(t,e){const s=u(t.pitch,e);return{...t,jianpuNumber:s.jianpuNumber,octaveDot:s.octaveDot,accidental:s.accidental}}}function u(t,e){const s=e%12;let n=o.MIDDLE_C_MIDI+s;s>o.MIDDLE_C_MIDI%12&&(n-=12);const i=(t-(n+12*Math.round((t-n)/12))+12)%12;let r=o.MAJOR_SCALE_INTERVALS[i],a=0;if(void 0===r){switch(i){case 1:r=o.MAJOR_SCALE_INTERVALS[0],a=1;break;case 3:r=o.MAJOR_SCALE_INTERVALS[4],a=2;break;case 6:r=o.MAJOR_SCALE_INTERVALS[5],a=1;break;case 8:r=o.MAJOR_SCALE_INTERVALS[9],a=2;break;case 10:r=o.MAJOR_SCALE_INTERVALS[11],a=2;break;default:{console.warn(`Unexpected chromatic interval ${i} in mapMidiToJianpu. Defaulting to sharp of lower valid degree.`);const s=(i-1+12)%12,n=(i+1+12)%12,h=o.MAJOR_SCALE_INTERVALS[s],u=o.MAJOR_SCALE_INTERVALS[n];void 0!==h?(r=h,a=1):void 0!==u?(r=u,a=2):(r=1,a=1,console.error(`Could not determine Jianpu number components for MIDI ${t}, interval ${i} from tonic in key ${e}.`));break}}void 0===r&&(console.error(`Jianpu number became undefined for MIDI ${t} (interval ${i}, key ${e}) after chromatic processing. This indicates a logic error or misconfigured MAJOR_SCALE_INTERVALS.`),r=1,a=1)}return{jianpuNumber:r,octaveDot:Math.floor((t-n)/12),accidental:a}}return n})()));