audio-mixer-engine 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio-mixer-engine.cjs.js +1 -1
- package/dist/audio-mixer-engine.es.js +134 -134
- package/package.json +1 -1
- package/src/lib/beat-mapper.js +10 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var P=Object.create;var _=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var O=(c,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of M(t))!S.call(c,s)&&s!==e&&_(c,s,{get:()=>t[s],enumerable:!(i=E(t,s))||i.enumerable});return c};var D=(c,t,e)=>(e=c!=null?P(B(c)):{},O(t||!c||!c.__esModule?_(e,"default",{value:c,enumerable:!0}):e,c));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N="data:audio/mpeg;base64,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",z="data:audio/mpeg;base64,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qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//tkxPIADij5M+wwzYmAm6X9hJmwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//s0xPaAClDTI6OxLwCwkeLoEJkoqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sUxNoDwAAB/gAAACAAADSAAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";class p{constructor(t,e={}){if(new.target===p)throw new Error("AudioEngine is abstract and cannot be instantiated directly");this.audioContext=t,this.options=e,this.isInitialized=!1,this.channels=new WeakMap,this.activeChannels=new Set}async initialize(t){throw new Error("initialize() must be implemented by subclass")}createChannel(t,e={}){throw new Error("createChannel() must be implemented by subclass")}allSoundsOff(){throw new Error("allSoundsOff() must be implemented by subclass")}async playMetronomeTick(t,e,i){try{await this._ensureMetronomeBuffersLoaded();const s=e?this.accentTickBuffer:this.regularTickBuffer;if(!s){console.warn("Metronome buffer not available");return}const n=this.audioContext.createBufferSource();n.buffer=s;const a=this.audioContext.createGain();a.gain.value=i,n.connect(a);const r=this.getMetronomeOutput();r?a.connect(r):a.connect(this.audioContext.destination);const q=Math.max(t,this.audioContext.currentTime);n.start(q)}catch(s){console.warn("Buffer metronome playback failed:",s)}}getMetronomeOutput(){return this._metronomeOutput||(this._metronomeOutput=this.audioContext.createGain(),this._metronomeOutput.gain.value=1,this._metronomeOutput.connect(this.audioContext.destination)),this._metronomeOutput}async _ensureMetronomeBuffersLoaded(){if(!(this.regularTickBuffer&&this.accentTickBuffer)){try{if(typeof fetch<"u"){const[t,e]=await Promise.all([fetch(N),fetch(z)]),[i,s]=await Promise.all([t.arrayBuffer(),e.arrayBuffer()]),[n,a]=await Promise.all([this.audioContext.decodeAudioData(i),this.audioContext.decodeAudioData(s)]);this.regularTickBuffer=n,this.accentTickBuffer=a;return}}catch(t){console.warn("Failed to load metronome sounds:",t)}this.regularTickBuffer=this.audioContext.createBuffer(2,1024,this.audioContext.sampleRate),this.accentTickBuffer=this.audioContext.createBuffer(2,1024,this.audioContext.sampleRate)}}getActiveChannels(){return Array.from(this.activeChannels)}destroy(){this.allSoundsOff(),this._metronomeOutput&&(this._metronomeOutput.disconnect(),this._metronomeOutput=null),this.regularTickBuffer=null,this.accentTickBuffer=null,this.activeChannels.clear(),this.isInitialized=!1}_validateInitialized(){if(!this.isInitialized)throw new Error("AudioEngine not initialized. Call initialize() first.")}_registerChannel(t){this.activeChannels.add(t)}_unregisterChannel(t){this.activeChannels.delete(t),this.channels.delete(t)}}class g{constructor(t,e,i={}){if(new.target===g)throw new Error("ChannelHandle is abstract and cannot be instantiated directly");this.engine=t,this.partId=e,this.options={initialVolume:1,...i},this.isDestroyed=!1,this.noteRefCounts=new Map,this.scheduledEvents=new Map,this.activeNotes=new Set}getOutputNode(){throw new Error("getOutputNode() must be implemented by subclass")}noteOn(t,e){this._validateActive();const i=this.noteRefCounts.get(t)||0;this.noteRefCounts.set(t,i+1),this._actualNoteOn(t,e),i===0&&this.activeNotes.add(t)}noteOff(t){this._validateActive();const e=this.noteRefCounts.get(t)||0;if(e<=0)return;const i=e-1;this.noteRefCounts.set(t,i),i===0&&(this._actualNoteOff(t),this.activeNotes.delete(t),this.noteRefCounts.delete(t))}playNote(t,e,i,s){this._validateActive();const n=this.engine.audioContext.currentTime,a=`${this.partId}_${t}_${e}_${Date.now()}`;let r=t,q=s;if(t<n){const d=n-t;r=n,q=Math.max(0,s-d)}if(q<=0)return a;const l=Math.max(0,(r-n)*1e3),o=setTimeout(()=>{this.noteOn(e,i),this.scheduledEvents.delete(`${a}_on`)},l),h=l+q*1e3,u=setTimeout(()=>{this.noteOff(e),this.scheduledEvents.delete(`${a}_off`)},h);return this.scheduledEvents.set(`${a}_on`,o),this.scheduledEvents.set(`${a}_off`,u),a}playPreviewNote(t,e={}){this._validateActive();const i=e.startTime??this.engine.audioContext.currentTime+.01,s=e.duration??.5,n=e.velocity??100;let a=null;e.instrument!==void 0&&(a=this.getInstrument(),this.setInstrument(e.instrument)),this.playNote(i,t,n,s),a!==null&&setTimeout(()=>{this.isDestroyed||this.setInstrument(a)},(s+.1)*1e3)}allNotesOff(){this._validateActive(),this.scheduledEvents.forEach(t=>{clearTimeout(t)}),this.scheduledEvents.clear(),this.activeNotes.forEach(t=>{this._actualNoteOff(t)}),this.noteRefCounts.clear(),this.activeNotes.clear()}_actualNoteOn(t,e){throw new Error("_actualNoteOn() must be implemented by subclass")}_actualNoteOff(t){throw new Error("_actualNoteOff() must be implemented by subclass")}async setInstrument(t){throw new Error("setInstrument() must be implemented by subclass")}getInstrument(){throw new Error("getInstrument() must be implemented by subclass")}setVolume(t){throw new Error("setVolume() must be implemented by subclass")}getVolume(){throw new Error("getVolume() must be implemented by subclass")}getPartId(){return this.partId}isActive(){return!this.isDestroyed&&this.engine.isInitialized&&this.engine.activeChannels.has(this)}destroy(){if(!this.isDestroyed){this.allNotesOff();const t=this.getOutputNode();t&&t.disconnect(),this.noteRefCounts.clear(),this.scheduledEvents.clear(),this.activeNotes.clear(),this.engine._unregisterChannel(this),this.isDestroyed=!0}}_validateActive(){if(this.isDestroyed)throw new Error("Channel has been destroyed");if(!this.engine.isInitialized)throw new Error("AudioEngine is not initialized")}}const I={piano:0,bright_piano:1,electric_grand:2,honky_tonk:3,electric_piano_1:4,electric_piano_2:5,harpsichord:6,clavinet:7,celesta:8,glockenspiel:9,music_box:10,vibraphone:11,marimba:12,xylophone:13,tubular_bells:14,dulcimer:15,drawbar_organ:16,percussive_organ:17,rock_organ:18,church_organ:19,reed_organ:20,accordion:21,harmonica:22,tango_accordion:23,organ:19,nylon_guitar:24,steel_guitar:25,electric_guitar_jazz:26,electric_guitar_clean:27,electric_guitar_muted:28,overdriven_guitar:29,distortion_guitar:30,guitar_harmonics:31,guitar:24,acoustic_bass:32,electric_bass_finger:33,electric_bass_pick:34,fretless_bass:35,slap_bass_1:36,slap_bass_2:37,synth_bass_1:38,synth_bass_2:39,bass:32,violin:40,viola:41,cello:42,contrabass:43,tremolo_strings:44,pizzicato_strings:45,orchestral_harp:46,timpani:47,strings:48,strings_ensemble:48,slow_strings:49,synth_strings_1:50,synth_strings_2:51,choir_aahs:52,voice_oohs:53,synth_voice:54,orchestra_hit:55,trumpet:56,trombone:57,tuba:58,muted_trumpet:59,french_horn:60,brass_section:61,synth_brass_1:62,synth_brass_2:63,soprano_sax:64,alto_sax:65,tenor_sax:66,baritone_sax:67,oboe:68,english_horn:69,bassoon:70,clarinet:71,saxophone:64,piccolo:72,flute:73,recorder:74,pan_flute:75,blown_bottle:76,shakuhachi:77,whistle:78,ocarina:79,lead_1_square:80,lead_2_sawtooth:81,lead_3_calliope:82,lead_4_chiff:83,lead_5_charang:84,lead_6_voice:85,lead_7_fifths:86,lead_8_bass:87,pad_1_new_age:88,pad_2_warm:89,pad_3_polysynth:90,pad_4_choir:91,pad_5_bowed:92,pad_6_metallic:93,pad_7_halo:94,pad_8_sweep:95,fx_1_rain:96,fx_2_soundtrack:97,fx_3_crystal:98,fx_4_atmosphere:99,fx_5_brightness:100,fx_6_goblins:101,fx_7_echoes:102,fx_8_sci_fi:103,sitar:104,banjo:105,shamisen:106,koto:107,kalimba:108,bag_pipe:109,fiddle:110,shanai:111,tinkle_bell:112,agogo:113,steel_drums:114,woodblock:115,taiko_drum:116,melodic_tom:117,synth_drum:118,reverse_cymbal:119,guitar_fret_noise:120,breath_noise:121,seashore:122,bird_tweet:123,telephone_ring:124,helicopter:125,applause:126,gunshot:127},L=Object.entries(I).reduce((c,[t,e])=>(c[e]=t,c),{});class T{static getInstrumentProgram(t){if(typeof t=="number")return t;const e=I[t.toLowerCase()];return e!==void 0?e:0}static getProgramName(t){return L[t]||`Program ${t}`}static generateNoteId(t,e,i){return`${t}_${e}_${Math.round(i)}`}}class k extends g{constructor(t,e,i,s={}){super(t,e,s),this.midiChannel=i,this.currentVolume=s.initialVolume||1,this.currentInstrument=s.instrument||"piano",this.outputGain=null,this._setupOutputNode(),this.setVolume(this.currentVolume),s.instrument&&this.setInstrument(s.instrument)}getOutputNode(){return this.outputGain}_actualNoteOn(t,e){const i=this.engine._getSynthesizer();if(i&&i.noteOn){const s=Math.round(e*this.currentVolume);i.noteOn(this.midiChannel,t,s)}}_actualNoteOff(t){const e=this.engine._getSynthesizer();e&&e.noteOff&&e.noteOff(this.midiChannel,t)}async setInstrument(t){this._validateActive();const e=T.getInstrumentProgram(t);this.currentInstrument=t;const i=this.engine._getSynthesizer();i&&i.programChange?i.programChange(this.midiChannel,e):console.warn("Cannot set instrument: synthesizer not available or no programChange method")}getInstrument(){return this.currentInstrument}setVolume(t){this._validateActive(),t=Math.max(0,Math.min(1,t)),this.currentVolume=t;const e=Math.round(t*127),i=this.engine._getSynthesizer();i&&i.controllerChange&&i.controllerChange(this.midiChannel,7,e)}getVolume(){return this.currentVolume}getMidiChannel(){return this.midiChannel}getActiveNoteCount(){return this.activeNotes.size}playNote(t,e,i,s){this._validateActive();const n=`${this.partId}_${t}_${e}_${Date.now()}`,a=this.engine._getSynthesizer();if(a&&a.post){const r=Math.round(i*this.currentVolume);a.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[144|this.midiChannel,e,r],channelOffset:0,force:!1,options:{time:t}}}),a.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[128|this.midiChannel,e,0],channelOffset:0,force:!1,options:{time:t+s}}})}else return super.playNote(t,e,i,s);return n}allNotesOff(){this._validateActive();const t=this.engine._getSynthesizer();t&&t.post?t.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[176|this.midiChannel,123,0],channelOffset:0,force:!1,options:{time:this.engine.audioContext.currentTime}}}):super.allNotesOff()}destroy(){if(!this.isDestroyed){const t=this.engine._getIndividualOutput(this.midiChannel);this.outputGain&&this.outputGain!==t&&this.outputGain.disconnect(),this.outputGain=null}super.destroy()}_setupOutputNode(){const t=this.engine._getIndividualOutput(this.midiChannel);t?this.outputGain=t:(console.warn(`No individual output available for MIDI channel ${this.midiChannel}, using fallback`),this.outputGain=this.engine.audioContext.createGain(),this.outputGain.gain.value=this.currentVolume)}}class U extends p{constructor(t,e={}){super(t,e),this.synthesizer=null,this.soundfont=null,this.channelCounter=0,this.partToMidiChannel=new Map,this.midiChannelToPart=new Map,this.individualOutputs=[]}async initialize(t){const{WorkletSynthesizer:e}=await import("spessasynth_lib");let i;if(typeof t=="string")i=await this._loadSoundfontFromPath(t);else if(t instanceof ArrayBuffer)i=t;else throw new Error("Invalid soundfont data type. Expected string path or ArrayBuffer.");await this._loadAudioWorkletSafely(),this._setupIndividualOutputs(),this.dummyTarget=this.audioContext.createGain(),await new Promise(s=>setTimeout(s,50)),this.synthesizer=new e(this.audioContext),await this.synthesizer.soundBankManager.addSoundBank(i,"main"),await this.synthesizer.isReady,this._connectIndividualOutputs(),this._initializeMetronomeChannel(),this.isInitialized=!0}createChannel(t,e={}){if(this._validateInitialized(),this.partToMidiChannel.has(t))throw new Error(`Channel for part '${t}' already exists`);const i=this.channelCounter;if(i>=15)throw new Error("Maximum number of musical part channels (15) exceeded. Channel 15 is reserved for metronome.");this.channelCounter++,this.partToMidiChannel.set(t,i),this.midiChannelToPart.set(i,t);const s=new k(this,t,i,e);return this._registerChannel(s),e.instrument&&s.setInstrument(e.instrument),s}allSoundsOff(){this.synthesizer&&this.midiChannelToPart.forEach((t,e)=>{this.synthesizer.controllerChange&&this.synthesizer.controllerChange(e,120,0)})}clearAllChannels(){this.allSoundsOff(),this.partToMidiChannel.clear(),this.midiChannelToPart.clear(),this.channelCounter=0}destroy(){this.allSoundsOff(),this.synthesizer&&typeof this.synthesizer.disconnect=="function"&&this.synthesizer.disconnect(),this.individualOutputs.forEach(t=>{t&&t.disconnect&&t.disconnect()}),this.individualOutputs=[],this.dummyTarget&&(this.dummyTarget.disconnect(),this.dummyTarget=null),this.partToMidiChannel.clear(),this.midiChannelToPart.clear(),this.channelCounter=0,super.destroy(),this.synthesizer=null,this.soundfont=null}getMidiChannelForPart(t){return this.partToMidiChannel.has(t)?this.partToMidiChannel.get(t):null}_getSynthesizer(){return this.synthesizer}_getIndividualOutput(t){return t>=0&&t<this.individualOutputs.length?this.individualOutputs[t]:null}getMetronomeChannel(){const t=this._getIndividualOutput(15);return console.log("Metronome channel 15 output:",t?"Available":"NULL",`(total outputs: ${this.individualOutputs.length})`),t}_setupIndividualOutputs(){this.individualOutputs=[];for(let t=0;t<16;t++){const e=this.audioContext.createGain();e.gain.value=1,this.individualOutputs.push(e)}}_connectIndividualOutputs(){try{this.synthesizer&&this.synthesizer.connectIndividualOutputs?this.synthesizer.connectIndividualOutputs(this.individualOutputs):(console.warn("Synthesizer does not support individual outputs, using master output only"),this.synthesizer&&this.synthesizer.connect&&this.audioContext.destination&&this.synthesizer.connect(this.audioContext.destination))}catch(t){console.warn("Failed to connect individual outputs:",t.message),console.warn("Falling back to master output routing")}}async _loadSoundfontFromPath(t){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load soundfont: ${e.status} ${e.statusText}`);return await e.arrayBuffer()}async _loadAudioWorkletSafely(){const t="/node_modules/spessasynth_lib/dist/spessasynth_processor.min.js";for(let i=1;i<=5;i++)try{await this.audioContext.audioWorklet.addModule(t);return}catch(s){if(console.warn(`AudioWorklet loading failed (attempt ${i}/5):`,s.message),i===5)throw new Error(`AudioWorklet failed after 5 attempts: ${s.message}`);const n=i*500;await new Promise(a=>setTimeout(a,n))}}_initializeMetronomeChannel(){try{const t=this._getSynthesizer();if(!t){console.warn("Cannot initialize metronome channel: synthesizer not available");return}const e=15;t.programChange&&(t.programChange(e,115),console.log("Metronome channel 15 initialized with woodblock instrument (115)")),t.controllerChange&&t.controllerChange(e,7,127)}catch(t){console.warn("Failed to initialize metronome channel:",t)}}async playMetronomeTick(t,e,i){try{const s=this.getMetronomeChannel(),n=this._getSynthesizer();if(!s||!n)return super.playMetronomeTick(t,e,i);const a=15,r=e?86:60,l=Math.round(Math.min(127,Math.max(0,i*(e?127:100)))),o=this.audioContext.currentTime,h=Math.max(t,o),u=h-o;n.post?(n.post({channelNumber:a,type:"midiMessage",data:{messageData:[144|a,r,l],channelOffset:0,force:!1,options:{time:h}}}),n.post({channelNumber:a,type:"midiMessage",data:{messageData:[128|a,r,0],channelOffset:0,force:!1,options:{time:h+.1}}})):u<=.01?(n.noteOn&&n.noteOn(a,r,l),setTimeout(()=>{n.noteOff&&n.noteOff(a,r)},100)):setTimeout(()=>{n.noteOn&&n.noteOn(a,r,l),setTimeout(()=>{n.noteOff&&n.noteOff(a,r)},100)},u*1e3)}catch(s){return console.warn("MIDI metronome failed, falling back to buffers:",s),super.playMetronomeTick(t,e,i)}}getMetronomeOutput(){return!this.individualOutputs||this.individualOutputs.length<16?null:this.individualOutputs[15]}}class C{constructor(){this.partNames=["soprano","alto","tenor","bass","treble","mezzo","baritone","s","a","t","b","satb"],this.parsedData={parts:{},barStructure:[],metadata:{}}}async parse(t,e=null){try{const i=await this._parseMidiBuffer(t);return this.metadataOverrides=e||{},this._normalizeLegacyMetadata(),this._extractMetadata(i),this._extractBarStructure(i),this._extractParts(i),this.parsedData.structureMetadata=this.metadataOverrides,this.parsedData}catch(i){throw console.error("Error parsing MIDI file:",i),i}}_normalizeLegacyMetadata(){if(!this.metadataOverrides||Object.keys(this.metadataOverrides).length===0)return;const t=this.metadataOverrides;if(t.scores&&Array.isArray(t.scores)&&t.scores.length>0){const e=t.scores[0];e.parts&&(t.parts=this._convertLegacyParts(e.parts)),e.bars&&(t.bars=e.bars),delete t.scores}else t.parts&&Array.isArray(t.parts)&&(t.parts=this._convertLegacyParts(t.parts));delete t.type,delete t.version,delete t.subtitle}_convertLegacyParts(t){const e={};for(const i of t){if(!i.name||!i.url)continue;const s=i.name.toLowerCase(),n=this._parseUrlParams(i.url),a={};if(n.track!==void 0&&(a.trackIndex=parseInt(n.track,10)),n.prog!==void 0){const r=parseInt(n.prog,10);r!==0&&(a.instrument=r)}a.trackIndex!==void 0&&(e[s]=a)}return e}_parseUrlParams(t){const e={},i=t.indexOf("?");if(i===-1)return e;const n=t.substring(i+1).split("&");for(const a of n){const[r,q]=a.split("=");r&&q!==void 0&&(e[r]=q)}return e}async _parseMidiBuffer(t){const e=new Uint8Array(t);if(!(e[0]===77&&e[1]===84&&e[2]===104&&e[3]===100))throw new Error("Not a valid MIDI file");const i=this._bytesToNumber(e.slice(4,8)),s=this._bytesToNumber(e.slice(8,10)),n=this._bytesToNumber(e.slice(10,12)),a=this._bytesToNumber(e.slice(12,14)),r=a&32768?null:a,q={format:s,ticksPerBeat:r,tracks:[],duration:0};let l=8+i;for(let o=0;o<n;o++)if(e[l]===77&&e[l+1]===84&&e[l+2]===114&&e[l+3]===107){const h=this._bytesToNumber(e.slice(l+4,l+8)),u=e.slice(l+8,l+8+h),d=this._parseTrack(u);q.tracks.push(d),l+=8+h}else throw new Error(`Invalid track header at position ${l}`);return q}_parseTrack(t){const e={notes:[],name:null,lyrics:[],events:[],duration:0};let i=0,s=0,n=null;for(;i<t.length;){let a=0,r=0;do r=t[i++],a=a<<7|r&127;while(r&128);s+=a,r=t[i++];let q=r;if((r&128)===0){if(n===null)throw new Error("Running status byte encountered before status byte");q=n,i--}else n=q;if(q===255){const l=t[i++],o=this._readVariableLengthValue(t,i);i+=o.bytesRead;const h=t.slice(i,i+o.value);switch(i+=o.value,l){case 3:e.name=this._bytesToString(h);break;case 1:e.events.push({type:"text",text:this._bytesToString(h),tick:s});break;case 5:e.lyrics.push({text:this._bytesToString(h),tick:s});break;case 81:const u=this._bytesToNumber(h),d=Math.round(6e7/u);e.events.push({type:"tempo",bpm:d,tick:s});break;case 88:e.events.push({type:"timeSignature",numerator:h[0],denominator:Math.pow(2,h[1]),tick:s});break;case 47:e.duration=s;break}}else if((q&240)===144){const l=q&15,o=t[i++],h=t[i++];h>0?e.notes.push({type:"noteOn",noteNumber:o,velocity:h,tick:s,channel:l}):e.notes.push({type:"noteOff",noteNumber:o,tick:s,channel:l})}else if((q&240)===128){const l=q&15,o=t[i++];t[i++],e.notes.push({type:"noteOff",noteNumber:o,tick:s,channel:l})}else if(q===240||q===247){const l=this._readVariableLengthValue(t,i);i+=l.bytesRead+l.value}else if((q&240)===176){const l=q&15,o=t[i++],h=t[i++];e.events.push({type:"controller",controllerNumber:o,value:h,channel:l,tick:s})}else if((q&240)===192){const l=q&15,o=t[i++];e.events.push({type:"programChange",programNumber:o,channel:l,tick:s})}else if((q&240)===208){const l=q&15,o=t[i++];e.events.push({type:"channelAftertouch",pressure:o,channel:l,tick:s})}else if((q&240)===224){const l=q&15,o=t[i++],u=(t[i++]<<7|o)-8192;e.events.push({type:"pitchBend",value:u,channel:l,tick:s})}else if((q&240)===160){const l=q&15,o=t[i++],h=t[i++];e.events.push({type:"noteAftertouch",noteNumber:o,pressure:h,channel:l,tick:s})}else console.warn(`Unknown event type: ${q.toString(16)} at position ${i-1}`),i++}return e}_extractMetadata(t){const e={title:null,composer:null,partNames:[],format:t.format,ticksPerBeat:t.ticksPerBeat};t.tracks.forEach((i,s)=>{if(i.name&&!e.title&&(e.title=i.name),i.events.filter(n=>n.type==="text").forEach(n=>{const a=n.text.toLowerCase();(a.includes("compos")||a.includes("by"))&&!e.composer&&(e.composer=n.text)}),i.name){const n=i.name.toLowerCase();for(const a of this.partNames)if(n.includes(a)){e.partNames.push({index:s,name:i.name});break}}}),this.metadataOverrides.title!==void 0&&(e.title=this.metadataOverrides.title),this.metadataOverrides.composer!==void 0&&(e.composer=this.metadataOverrides.composer),this.metadataOverrides.arranger!==void 0&&(e.arranger=this.metadataOverrides.arranger),this.metadataOverrides.copyright!==void 0&&(e.copyright=this.metadataOverrides.copyright),this.parsedData.metadata=e}_extractBarStructure(t){const e=t.ticksPerBeat||480,i=[];t.tracks.forEach(o=>{o.events.forEach(h=>{(h.type==="timeSignature"||h.type==="tempo")&&i.push(h)})}),i.sort((o,h)=>o.tick-h.tick);let s=0;t.tracks.forEach(o=>{o.notes&&o.notes.forEach(h=>{h.type==="noteOff"&&h.tick>s&&(s=h.tick)})}),s===0&&(s=e*8);const n=[],a=i.filter(o=>o.type==="timeSignature").sort((o,h)=>o.tick-h.tick);let r={numerator:4,denominator:4},q=0,l=0;for(;q<s;){for(;l<a.length&&a[l].tick<=q;)r=a[l],l++;let o;o=q+e*4*r.numerator/r.denominator;const h=r.numerator,u=[],d=e*(4/r.denominator);for(let m=0;m<h;m++){const A=q+m*d,y=this._ticksToTime(A,t);u.push(y)}n.push({sig:[r.numerator,r.denominator],beats:u}),q=o}this.parsedData.barStructure=n}_extractParts(t){const e={},i=t.ticksPerBeat;if(this.metadataOverrides.parts)for(const[s,n]of Object.entries(this.metadataOverrides.parts)){if(!n.trackIndex&&n.trackIndex!==0&&!n.trackName)continue;let a=null,r=null;if(n.trackIndex!==void 0&&n.trackIndex!==null)r=n.trackIndex,r>=0&&r<t.tracks.length&&(a=t.tracks[r]);else if(n.trackName){const l=t.tracks.findIndex(o=>o.name===n.trackName);l!==-1&&(a=t.tracks[l],r=l)}if(!a)continue;const q=this._extractPartDataFromTrack(a,r,t,i);n.instrument!==void 0&&n.instrument!==null&&(q.defaultInstrument=this._resolveInstrument(n.instrument)),e[s]=q}else t.tracks.forEach((s,n)=>{if(!s.notes.length)return;let a=null;if(s.name){const l=s.name.toLowerCase();for(const o of this.partNames)if(o.length===1){if(l===o){a=o;break}}else if(l.includes(o)){a=o;break}}a||(a=s.name||`Track ${n+1}`),a==="s"&&(a="soprano"),a==="a"&&(a="alto"),a==="t"&&(a="tenor"),a==="b"&&(a="bass");let r=a,q=2;for(;e[r];)r=`${a} ${q}`,q++;a=r,e[a]=this._extractPartDataFromTrack(s,n,t,i)});this.parsedData.parts=e}_extractPartDataFromTrack(t,e,i,s){const n=[],a={};t.notes.forEach(o=>{if(o.type==="noteOn")a[o.noteNumber]={tick:o.tick,velocity:o.velocity};else if(o.type==="noteOff"&&a[o.noteNumber]){const h=a[o.noteNumber],u=o.tick-h.tick;n.push({pitch:o.noteNumber,name:this._midiNoteToName(o.noteNumber),startTick:h.tick,endTick:o.tick,duration:u,startTime:this._ticksToTime(h.tick,i),endTime:this._ticksToTime(o.tick,i),velocity:h.velocity}),delete a[o.noteNumber]}});const r=t.lyrics.map(o=>({text:o.text,tick:o.tick,time:o.tick/s}));n.sort((o,h)=>o.startTick-h.startTick);const q=t.events.filter(o=>o.type==="programChange").map(o=>({programNumber:o.programNumber,tick:o.tick,time:this._ticksToTime(o.tick,i)})).sort((o,h)=>o.tick-h.tick),l=q.length>0?q[0].programNumber:0;return{notes:n,lyrics:r,trackIndex:e,programChanges:q,defaultInstrument:l}}_resolveInstrument(t){if(typeof t=="number")return t;if(typeof t=="string"){const e={choir_aahs:52,piano:0,acoustic_grand_piano:0,bright_acoustic_piano:1,electric_grand_piano:2,strings:48,string_ensemble_1:48,violin:40,viola:41,cello:42,contrabass:43},i=t.toLowerCase().replace(/ /g,"_");return e[i]!==void 0?e[i]:0}return 0}_midiNoteToName(t){const e=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],i=Math.floor(t/12)-1;return`${e[t%12]}${i}`}_bytesToNumber(t){let e=0;for(let i=0;i<t.length;i++)e=e<<8|t[i];return e}_bytesToString(t){return new TextDecoder().decode(t)}_readVariableLengthValue(t,e){let i=0,s,n=0;do s=t[e+n++],i=i<<7|s&127;while(s&128);return{value:i,bytesRead:n}}_ticksToTime(t,e){const i=e.ticksPerBeat||480,s=[];e.tracks.forEach(q=>{q.events.forEach(l=>{l.type==="tempo"&&s.push(l)})}),s.sort((q,l)=>q.tick-l.tick);let n=0,a=0,r=120;for(const q of s){if(q.tick>t)break;if(q.tick>a){const o=(q.tick-a)/i*(60/r);n+=o,a=q.tick}r=q.bpm}if(t>a){const l=(t-a)/i*(60/r);n+=l}return n}}class v{constructor(){this.barOrder=[],this.beatTable=[]}mapBeats(t,e){try{return e.bars&&!e.sections?this.barOrder=this.generateBarOrderFromLegacyBars(e.bars,t.barStructure):e.sections&&e.order?this.barOrder=this.generateBarOrder(e.sections,e.order):this.barOrder=this.generateLinearBarOrder(t.barStructure),this.beatTable=this.generateBeatTable(this.barOrder,t.barStructure),this.beatTable}catch(i){throw console.error("Error mapping beats:",i),i}}generateBarOrder(t,e){const i=[],s={};for(const n of e){const a=t[n.section];if(!a)throw new Error(`Invalid section index: ${n.section}`);const r=n.section;s[r]||(s[r]=0),s[r]++;const q=s[r],l=n.from!==void 0?n.from:this._getSectionStartBar(t,n.section),o=n.to!==void 0?n.to:a.to,h=n.as||1;for(let u=l;u<=o;u++)this._shouldPlayBar(a,u,h)&&i.push({barNumber:u,repeat:q,sectionIndex:n.section,voltaTime:h})}return i}generateBarOrderFromLegacyBars(t,e){const i=[];let s=1,n=0;for(const a of t){a.from!==void 0&&(s=a.from===-1?0:a.from,n=0);const r=a.repeat||1;let q=a.beats;for(;q>0;){const o=this._getBeatsPerBar(s,e)-n;q>=o?(i.push({barNumber:s,repeat:r,sectionIndex:0,voltaTime:1}),q-=o,n=0,s===0?s=1:s++):(n+=q,q=0)}}return n>0&&i.push({barNumber:s,repeat:1,sectionIndex:0,voltaTime:1}),i}generateLinearBarOrder(t){const e=[];for(let i=0;i<t.length;i++)e.push({barNumber:i+1,repeat:1,sectionIndex:0,voltaTime:1});return e}_getBeatsPerBar(t,e){const i=e.length>0&&e[0].sig&&e[0].sig[0]<=2;let s;if(i?s=t:s=t-1,s<0||s>=e.length)return 4;const n=e[s];return n.sig?n.sig[0]:4}generateBeatTable(t,e){const i=[],s={};let n=0,a=0;const r=[...e];for(;a<t.length&&n<r.length;){const q=t[a],l=q.barNumber;if(s[l]===void 0){const d=r[n];if(!d||!d.sig)throw new Error(`Invalid MIDI bar structure at index ${n}`);s[l]=d.sig[0]}const o=s[l];let h=r[n],u=h.sig[0];for(;u<o&&n+1<r.length;){const d=r[n+1],m=[h.sig[0]+d.sig[0],h.sig[1]],A=[...h.beats||[],...d.beats||[]];h={sig:m,beats:A},r[n]=h,r.splice(n+1,1),u=m[0]}if(u>o){const d=o,m=u-o,A=h.beats?h.beats.slice(0,d):[],y=h.beats?h.beats.slice(d):[],b={sig:[d,h.sig[1]],beats:A},w={sig:[m,h.sig[1]],beats:y};r[n]=b,r.splice(n+1,0,w),h=b}this._generateBeatsForBar(i,q,h,o),n++,a++}if(a<t.length)throw new Error(`Ran out of MIDI bars before completing score. Score bar ${a}/${t.length}, MIDI bar ${n}/${r.length}`);return i}_generateBeatsForBar(t,e,i,s){const{beats:n}=i;if(!n||!Array.isArray(n))throw new Error(`Invalid MIDI bar: missing beats array. Got: ${JSON.stringify(i)}`);const a=n.slice(0,s);for(let r=1;r<=s;r++){const l={time:a[r-1],repeat:e.repeat,bar:e.barNumber,beat:r,timeSig:s};t.push(l)}}_getSectionStartBar(t,e){return t[e].pickup!==void 0?0:e===0?1:t[e-1].to+1}_shouldPlayBar(t,e,i){if(!t.voltas)return!0;const s=t.voltas.indexOf(e);return s===-1?!0:s+1===i}}function x(c){return{all:c=c||new Map,on:function(t,e){var i=c.get(t);i?i.push(e):c.set(t,[e])},off:function(t,e){var i=c.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):c.set(t,[]))},emit:function(t,e){var i=c.get(t);i&&i.slice().map(function(s){s(e)}),(i=c.get("*"))&&i.slice().map(function(s){s(t,e)})}}}class f{constructor(t=null,e,i=null,s=null){if(!e)throw new Error("Parsed MIDI data is required");this.audioEngine=t,this._audioEngineReady=!!(t&&t.isInitialized),this.instrumentMap=i||{},this.parsedData=e,this._isPlaying=!1,this._currentTime=0,this._totalDuration=0,this.playbackSpeed=1,this.partChannels=new Map,this.partOutputs=new Map,this.playbackStartTime=0,this.lookAheadTime=.05,this.scheduleInterval=null,this.partNotePointers=new Map,this.partProgramPointers=new Map,this.eventBus=x(),this.beatMapper=new v,this.beats=[],this._calculateTotalDuration();const n=s||this._createDefaultStructureMetadata();this.beats=this.beatMapper.mapBeats(e,n),this._audioEngineReady&&(this._setupPartChannels(),this._resetNotePointers(),this._resetProgramPointers())}setAudioEngine(t){if(!t||!t.isInitialized)throw new Error("An initialized AudioEngine is required");this.audioEngine=t,this._audioEngineReady=!0,this._setupPartChannels(),this._resetNotePointers(),this._resetProgramPointers()}isAudioEngineReady(){return this._audioEngineReady}play(){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() first.");this._isPlaying||(this._isPlaying=!0,this.playbackStartTime=this.audioEngine.audioContext.currentTime-this._currentTime/this.playbackSpeed,this._resetNotePointers(),this._resetProgramPointers(),this._schedulePlayback(),this._startTimeUpdateLoop())}playAt(t){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() first.");this._isPlaying||(this._isPlaying=!0,this.playbackStartTime=t-this._currentTime/this.playbackSpeed,this._resetNotePointers(),this._resetProgramPointers(),this._schedulePlayback(),this._startTimeUpdateLoop())}pause(){this._isPlaying&&(this._isPlaying=!1,this._stopScheduling(),this._stopTimeUpdateLoop())}stop(){this._isPlaying=!1,this._currentTime=0,this._stopScheduling(),this._stopTimeUpdateLoop(),this._resetNotePointers(),this._resetProgramPointers()}skipToTime(t){t=Math.max(0,Math.min(t,this._totalDuration));const e=this._isPlaying;e&&this.pause(),this._currentTime=t,this._resetNotePointers(),this._resetProgramPointers(),e&&this.play()}setPlaybackSpeed(t,e=!0){if(t<=0)throw new Error("Playback speed must be greater than 0");const i=e&&this._isPlaying;i&&this.pause();const s=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed;this.playbackSpeed=t,i?this.play():this.playbackStartTime=this.audioEngine.audioContext.currentTime-s/this.playbackSpeed}setBar(t,e=0){const i=this.getTimeFromBar(t,e);i!==null&&(this.skipToTime(i),this._emitEvent("barChanged",{bar:t,beat:1,repeat:e,time:i}))}getTimeFromBar(t,e=0){e||(e=1);const i=this.beats.find(s=>s.bar===t&&s.beat===1&&s.repeat===e);return i?i.time:null}getBeatFromTime(t){if(!this.beats.length)return null;let e=null;for(let i=this.beats.length-1;i>=0;i--)if(this.beats[i].time<=t){e=this.beats[i];break}return e}allSoundsOff(){this._audioEngineReady&&this.audioEngine.allSoundsOff()}getPartOutput(t){return this.partOutputs.get(t)||null}getPartChannel(t){return this.partChannels.get(t)||null}getAllNextNotes(t){const e=t??this.getCurrentTime(),i={};for(const[s,n]of Object.entries(this.parsedData.parts)){const a=n.notes.find(r=>r.startTime>=e);i[s]=a?{pitch:a.pitch,startTime:a.startTime}:null}return i}getCurrentTime(){if(this._isPlaying){const t=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed;this._currentTime=Math.min(t,this._totalDuration)}return this._currentTime}getTotalDuration(){return this._totalDuration}isPlaying(){return this._isPlaying}on(t,e){this.eventBus.on(t,e)}off(t,e){this.eventBus.off(t,e)}_setupPartChannels(){Object.keys(this.parsedData.parts).forEach(t=>{const e=this.parsedData.parts[t],i=this.instrumentMap[t]||{},s=i.instrument!==void 0?i.instrument:e.defaultInstrument!==void 0?e.defaultInstrument:0;try{const n=this.audioEngine.createChannel(t,{instrument:s,initialVolume:i.volume||1});this.partChannels.set(t,n);const a=this.audioEngine.audioContext.createGain();a.gain.value=1;const r=n.getOutputNode();r&&r.connect(a),this.partOutputs.set(t,a)}catch(n){console.error(`Failed to create channel for part '${t}':`,n),this._emitEvent("error",n)}})}_calculateTotalDuration(){let t=0;Object.values(this.parsedData.parts).forEach(e=>{e.notes.forEach(i=>{i.endTime>t&&(t=i.endTime)})}),this._totalDuration=t}_schedulePlayback(){this._stopScheduling(),this._startScheduleLoop()}_startScheduleLoop(){this.scheduleInterval||(this.scheduleInterval=setInterval(()=>{if(!this._isPlaying)return;const e=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed,i=e+this.lookAheadTime;for(const[s,n]of this.partChannels){const a=this.parsedData.parts[s];if(a){if(a.programChanges&&a.programChanges.length>0){let r=this.partProgramPointers.get(s)||0;const q=a.programChanges;for(;r<q.length&&q[r].time<e;)r++;for(;r<q.length&&q[r].time<=i;){const l=q[r];n.setInstrument(l.programNumber),r++}this.partProgramPointers.set(s,r)}if(a.notes){let r=this.partNotePointers.get(s)||0;const q=a.notes;for(;r<q.length&&q[r].endTime<e;)r++;for(;r<q.length&&q[r].startTime<=i;){const l=q[r];if(l.endTime-l.startTime>=.01){const o=this.playbackStartTime+l.startTime/this.playbackSpeed,h=(l.endTime-l.startTime)/this.playbackSpeed;n.playNote(o,l.pitch,l.velocity,h)}r++}this.partNotePointers.set(s,r)}}}},50))}_resetNotePointers(){const t=this._currentTime;for(const[e]of this.partChannels){const i=this.parsedData.parts[e];if(!i||!i.notes)continue;let s=0;for(;s<i.notes.length&&i.notes[s].endTime<t;)s++;this.partNotePointers.set(e,s)}}_resetProgramPointers(){const t=this._currentTime;for(const[e,i]of this.partChannels){const s=this.parsedData.parts[e];if(!s||!s.programChanges){this.partProgramPointers.set(e,0);continue}let n=0,a=s.defaultInstrument;for(;n<s.programChanges.length&&s.programChanges[n].time<=t;)a=s.programChanges[n].programNumber,n++;i.setInstrument(a),this.partProgramPointers.set(e,n)}}_stopScheduling(){this.scheduleInterval&&(clearInterval(this.scheduleInterval),this.scheduleInterval=null),this.partChannels.forEach(t=>{t.isActive()&&t.allNotesOff()})}_startTimeUpdateLoop(){this.timeUpdateInterval=setInterval(()=>{const t=this.getCurrentTime();this._emitEvent("timeupdate",{currentTime:t});const e=this.getBeatFromTime(t);e&&this._emitEvent("beatChanged",e),t>=this._totalDuration+.05&&(this.stop(),this._emitEvent("ended",{finalTime:t}))},100)}_stopTimeUpdateLoop(){this.timeUpdateInterval&&(clearInterval(this.timeUpdateInterval),this.timeUpdateInterval=null)}_emitEvent(t,e){(this.eventBus.all.get(t)||[]).forEach(s=>{try{s(e)}catch(n){console.error(`Error in ${t} event listener:`,n)}})}_createDefaultStructureMetadata(){return{sections:[{from:1,to:this.parsedData.barStructure.length}],order:[{section:0}]}}destroy(){this.stop(),this.partChannels.forEach(t=>{t.destroy()}),this.partChannels.clear(),this.partOutputs.forEach(t=>{t.disconnect()}),this.partOutputs.clear(),this.partNotePointers.clear(),this.partProgramPointers.clear(),this.eventBus.all.clear()}}class F{constructor(t=null,e={}){t instanceof f?(this.audioEngine=t.audioEngine,this.midiPlayer=t,this.parsedData=t.parsedData,this._audioEngineReady=!!(this.audioEngine&&this.audioEngine.isInitialized)):(this.audioEngine=t,this._audioEngineReady=!!(t&&t.isInitialized),this.midiPlayer=null,this.parsedData=null),this.eventBus=x(),this._parser=new C,this._partOutputsMap=new Map,this.instrumentMap=null,this.metronomeConfig={enabled:!1,tickInstrument:115,accentInstrument:116,volume:.7,...e.metronome},this.leadInConfig={enabled:!1,bars:1,...e.leadIn},this.startupConfig={delayMs:25,...e.startup},this.state="reset",this.frozenTime=0,this.leadInData=null,this.leadInStartTime=null,this.leadInProgress=null,this.leadInInterval=null,this.timeUpdateInterval=null,this.metronomeScheduleInterval=null,this.nextBeatIndex=0,this._validateConfig(),this.midiPlayer&&this._completeMidiPlayerSetup()}setAudioEngine(t){if(!t||!t.isInitialized)throw new Error("An initialized AudioEngine is required");this.audioEngine=t,this._audioEngineReady=!0,this.parsedData&&!this.midiPlayer&&this._setupPlayerWithAudio()}isAudioEngineReady(){return this._audioEngineReady}async load(t,e=null,i=null){if(this.reset(),t instanceof f)this.parsedData=t.parsedData,this.instrumentMap=i,this._audioEngineReady&&this._setMidiPlayer(t);else if(t instanceof ArrayBuffer)this.parsedData=await this._parser.parse(t,e),this.instrumentMap=i||this._createDefaultInstrumentMap(this.parsedData.parts),this._audioEngineReady&&this._setupPlayerWithAudio();else if(t&&typeof t=="object"&&t.parts)this.parsedData=t,this.instrumentMap=i||this._createDefaultInstrumentMap(t.parts),this._audioEngineReady&&this._setupPlayerWithAudio();else throw new Error("Invalid input type. Expected MidiPlayer, parsed MIDI data, or ArrayBuffer")}reset(){this.stop(),this.midiPlayer&&(this.midiPlayer.destroy(),this.midiPlayer=null),this.parsedData=null,this.instrumentMap=null,this._audioEngineReady&&this.audioEngine.clearAllChannels(),this._partOutputsMap.clear(),this.frozenTime=0,this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this.nextBeatIndex=0,this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this.state="reset"}getPartOutputs(){return this._partOutputsMap.entries()}getPartNames(){return Array.from(this._partOutputsMap.keys())}async play(t={}){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() after user interaction.");if(this.parsedData&&!this.midiPlayer&&this._setupPlayerWithAudio(),!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");if(!(this.state==="playing"||this.state==="lead-in"))try{const e=t.leadIn!==void 0?t.leadIn:this.leadInConfig.enabled,i=t.metronome!==void 0?t.metronome:this.metronomeConfig.enabled;this.frozenTime===0&&(this.frozenTime=this.midiPlayer.getCurrentTime()),e?await this._startLeadIn(i):await this._startMidiPlayback(i)}catch(e){throw this.state="stopped",this._emitEvent("error",e),e}}pause(){if(!this.midiPlayer||this.state==="stopped"||this.state==="paused")return;const t=this.state;this.state="paused",t==="lead-in"?this._pauseLeadIn():t==="playing"&&(this.midiPlayer.pause(),this._stopMetronome()),this._stopTimeUpdateLoop(),this._emitEvent("playbackPaused",{})}resume(){!this.midiPlayer||this.state!=="paused"||(this.leadInData&&this.leadInProgress!==null&&this.leadInProgress<1?this._resumeLeadIn():(this.state="playing",this._resetMetronomeBeatTracking(),this.midiPlayer.play(),this._startMetronomeIfEnabled(),this._startTimeUpdateLoop(),this._emitEvent("playbackStarted",{})))}stop(){if(this.state==="stopped")return;const t=this.state==="playing";this.state="stopped",this.frozenTime=0,this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this._resetMetronomeBeatTracking(),t&&this.midiPlayer.stop(),this._emitEvent("playbackStopped",{})}skipToTime(t){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");this.frozenTime=t,this.state!=="lead-in"&&(this.midiPlayer.skipToTime(t),this.state==="playing"&&this.metronomeConfig.enabled&&this._resetMetronomeBeatTracking())}setBar(t,e=0){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");if(this.state==="lead-in"){const i=this.midiPlayer.getTimeFromBar(t,e);i!==null&&(this.frozenTime=i);return}if(this.midiPlayer.setBar(t,e),this.state==="stopped"){const i=this.midiPlayer.getTimeFromBar(t,e);i!==null&&(this.frozenTime=i)}this.state==="playing"&&this.metronomeConfig.enabled&&this._resetMetronomeBeatTracking()}getCurrentTime(){return this.state==="lead-in"||this.state==="paused"&&this.leadInProgress!==null?this.frozenTime:this.midiPlayer?this.midiPlayer.getCurrentTime():0}getLeadInProgress(){return this.leadInProgress}setMetronomeEnabled(t){const e=this.metronomeConfig.enabled;this.metronomeConfig.enabled=t,this.state==="playing"&&(t&&!e?this._startMetronome():!t&&e&&this._stopMetronome()),this._emitEvent("metronomeEnabledChanged",{enabled:t})}setMetronomeSettings(t){if(t.volume!==void 0&&(t.volume<0||t.volume>1))throw new Error("Metronome volume must be between 0.0 and 1.0");if(Object.assign(this.metronomeConfig,t),t.volume!==void 0){const e=this.audioEngine.getMetronomeOutput();e&&e.gain&&(e.gain.value=t.volume)}this._emitEvent("metronomeSettingsChanged",{...t})}setLeadInEnabled(t){this.leadInConfig.enabled=t,this._emitEvent("leadInSettingsChanged",{enabled:t,bars:this.leadInConfig.bars})}setLeadInBars(t){if(t<1)throw new Error("Lead-in bars must be at least 1");this.leadInConfig.bars=t,this._emitEvent("leadInSettingsChanged",{enabled:this.leadInConfig.enabled,bars:t})}setPlaybackSpeed(t,e=!0){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");this.midiPlayer.setPlaybackSpeed(t,e)}getMetronomeSettings(){return{...this.metronomeConfig}}isMetronomeEnabled(){return this.metronomeConfig.enabled}getLeadInSettings(){return{enabled:this.leadInConfig.enabled,bars:this.leadInConfig.bars}}getStartupSettings(){return{...this.startupConfig}}setStartupDelay(t){if(typeof t!="number"||t<0||t>1e3)throw new Error("Startup delay must be a number between 0 and 1000 milliseconds");this.startupConfig.delayMs=t,this._emitEvent("startupSettingsChanged",{delayMs:t})}getState(){return this.state}isInLeadIn(){return this.state==="lead-in"}isPlaying(){return this.state==="playing"||this.state==="lead-in"}getMetronomeOutput(){return this.audioEngine.getMetronomeOutput()}getPartOutput(t){return this.midiPlayer?this.midiPlayer.getPartOutput(t):null}allSoundsOff(){this.midiPlayer&&this.midiPlayer.allSoundsOff()}previewNextNotes(t={}){if(!this.midiPlayer)throw new Error("No MIDI data loaded");const e=t.delayBetweenParts??.3,i=t.duration??.5,s=t.velocity??100,n=this.midiPlayer.getAllNextNotes(),a=t.partOrder??this.getPartNames();let r=this.audioEngine.audioContext.currentTime+.01;const q=[];for(const l of a){const o=n[l];if(!o)continue;const h=this.midiPlayer.getPartChannel(l);if(!h)continue;const u=this.midiPlayer.getPartOutput(l);u&&u.gain.value===0||(h.playPreviewNote(o.pitch,{startTime:r,duration:i,velocity:s,instrument:t.instrument}),q.push({partName:l,pitch:o.pitch,startTime:r}),r+=e)}return{parts:q,totalDuration:q.length*e}}getTotalDuration(){if(this.midiPlayer)return this.midiPlayer.getTotalDuration();if(this.parsedData&&this.parsedData.parts){let t=0;return Object.values(this.parsedData.parts).forEach(e=>{e.notes&&e.notes.forEach(i=>{i.endTime>t&&(t=i.endTime)})}),t}return 0}on(t,e){this.eventBus.on(t,e)}off(t,e){this.eventBus.off(t,e)}_setupEventDelegation(){this.midiPlayer.on("timeupdate",t=>{this.state==="playing"&&this._emitEvent("timeupdate",{...t,effectiveTime:t.currentTime,leadInProgress:null})}),this.midiPlayer.on("beatChanged",t=>{this.state==="playing"&&this._emitEvent("beatChanged",{...t,isLeadIn:!1})}),this.midiPlayer.on("barChanged",t=>{this.state==="playing"&&this._emitEvent("barChanged",t)}),this.midiPlayer.on("ended",t=>{this.state==="playing"&&(this.state="stopped",this._stopMetronome(),this._stopTimeUpdateLoop(),this._emitEvent("playbackEnded",t))}),this.midiPlayer.on("error",t=>{this._emitEvent("error",t)})}_validateConfig(){if(this.metronomeConfig.volume<0||this.metronomeConfig.volume>1)throw new Error("Metronome volume must be between 0.0 and 1.0");if(this.leadInConfig.bars<1)throw new Error("Lead-in bars must be at least 1")}async _startLeadIn(t){this.state="lead-in";const e=this.startupConfig.delayMs/1e3;this.leadInStartTime=this.audioEngine.audioContext.currentTime+e,this.leadInProgress=0,this.leadInData=this._calculateLeadInBeats(),this._emitEvent("leadInStarted",{totalBeats:this.leadInData.totalBeats,duration:this.leadInData.duration,bars:this.leadInConfig.bars,startupDelayMs:this.startupConfig.delayMs}),setTimeout(()=>{this.state==="lead-in"&&this._startLeadInScheduling(t)},this.startupConfig.delayMs),this._startTimeUpdateLoop()}_calculateLeadInBeats(){if(!this.midiPlayer)return{totalBeats:4,duration:2,beatSequence:[],beatsPerBar:4,startBeat:{bar:1,beat:1,timeSig:4}};const t=this.midiPlayer.beats,e=this.frozenTime,i=this.leadInConfig.bars;let s=t.length-1,n=.5;for(;t[s].time>e;)s--;const a=t[s],r=t[s+1];r?n=r.time-a.time:s>0&&(n=a.time-t[s-1].time);const q=this.midiPlayer&&this.midiPlayer.playbackSpeed||1,l=n/q,o=a.timeSig===1,h=o&&r?r.timeSig:a.timeSig,u=o?h-1:a.beat>1?a.beat-1:0,d=i*h+u;return{totalBeats:d,duration:d*l,beatSequence:this._generateBeatSequence(d,l,h),beatsPerBar:h,startBeat:a}}_generateBeatSequence(t,e,i){const s=[];for(let n=0;n<t;n++){const a=n%i+1;s.push({beat:a,isAccent:a===1,time:n*e,absoluteTime:this.leadInStartTime+n*e})}return s}_startLeadInScheduling(t){this.leadInBeatIndex=0,this.leadInScheduledBeats=new Set;const e=this.leadInData.beatSequence,i=10;this.leadInStartTime=this.audioEngine.audioContext.currentTime,this.leadInInterval=setInterval(()=>{const s=this.audioEngine.audioContext.currentTime-this.leadInStartTime;for(this.leadInProgress=Math.min(1,s/this.leadInData.duration);this.leadInBeatIndex<e.length;){const n=e[this.leadInBeatIndex],a=n.time-s;if(a>.05)break;if(!this.leadInScheduledBeats.has(this.leadInBeatIndex)&&a>=-.05&&a<=.05){const r=a<=0?this.audioEngine.audioContext.currentTime+.01:this.audioEngine.audioContext.currentTime+a;this._scheduleTickAtTime(r,n.isAccent),this._emitEvent("beatChanged",{bar:Math.floor(this.leadInBeatIndex/this.leadInData.beatsPerBar)+1,beat:n.beat,repeat:1,time:this.frozenTime,isLeadIn:!0}),this.leadInScheduledBeats.add(this.leadInBeatIndex)}this.leadInBeatIndex++}this.leadInProgress>=1&&this._completeLeadIn(t)},i)}_completeLeadIn(t){const e=this.leadInStartTime+this.leadInData.duration;this._stopLeadIn(),this._emitEvent("leadInEnded",{}),this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this._startMidiPlaybackAt(e,t,!0)}async _startMidiPlaybackAt(t,e,i=!0){this.state="playing",i&&this._emitEvent("playbackStarted",{startupDelayMs:0,scheduledStartTime:t}),this.midiPlayer.playAt(t),e&&this._startMetronomeAt(t),this.timeUpdateInterval||this._startTimeUpdateLoop()}async _startMidiPlayback(t,e=!0,i=!1){this.state="playing",this._resetMetronomeBeatTracking(),e&&this._emitEvent("playbackStarted",{startupDelayMs:i?0:this.startupConfig.delayMs});const s=()=>{if(this.state==="playing")try{this.midiPlayer.play(),t&&this._startMetronome()}catch(n){this.state="stopped",this._emitEvent("error",n)}};i?s():setTimeout(s,this.startupConfig.delayMs),this.timeUpdateInterval||this._startTimeUpdateLoop()}_startMetronome(){!this.metronomeConfig.enabled||this.state!=="playing"||(this._scheduleMetronomeTicks(),this.metronomeScheduleInterval=setInterval(()=>{this._scheduleMetronomeTicks()},50))}_startMetronomeAt(t){this.metronomeConfig.enabled&&(this.metronomeScheduledStartTime=t,this._resetMetronomeBeatTracking(),this._scheduleMetronomeTicksAt(t),this.metronomeScheduleInterval=setInterval(()=>{this._scheduleMetronomeTicks()},50))}_startMetronomeIfEnabled(){this.metronomeConfig.enabled&&this._startMetronome()}_scheduleMetronomeTicksAt(t){if(!this.metronomeConfig.enabled||!this.midiPlayer)return;const e=this.midiPlayer.beats;if(!e||e.length===0)return;const i=this.midiPlayer.getCurrentTime(),s=.1;for(let n=this.nextBeatIndex;n<e.length;n++){const a=e[n],r=this.midiPlayer.playbackSpeed||1,q=t+(a.time-i)/r;if(q>this.audioEngine.audioContext.currentTime+s)break;if(q>=this.audioEngine.audioContext.currentTime-.01){const l=Math.max(q,this.audioEngine.audioContext.currentTime+.001),o=a.isDownbeat||a.beat===1;this._scheduleTickAtTime(l,o),this.nextBeatIndex=n+1}}}_scheduleMetronomeTicks(){if(!this.metronomeConfig.enabled||!this.midiPlayer)return;const t=this.midiPlayer.getCurrentTime(),e=this.midiPlayer.beats;if(!e||e.length===0)return;for(;this.nextBeatIndex<e.length&&e[this.nextBeatIndex].time<t-.025;)this.nextBeatIndex++;const s=t+.15;for(;this.nextBeatIndex<e.length;){const n=e[this.nextBeatIndex],a=n.time-t;if(n.time>s)break;if(a>=-.025&&a<=.15){const r=this.audioEngine.audioContext.currentTime+.005,q=this.audioEngine.audioContext.currentTime+Math.max(a,.005),l=Math.max(r,q),o=n.beat===1;this._scheduleTickAtTime(l,o)}this.nextBeatIndex++}}async _scheduleTickAtTime(t,e){try{await this.audioEngine.playMetronomeTick(t,e,this.metronomeConfig.volume)}catch(i){console.warn("Failed to schedule metronome tick:",i)}}_resetMetronomeBeatTracking(){if(!this.midiPlayer){this.nextBeatIndex=0;return}const t=this.getCurrentTime(),e=this.midiPlayer.beats;if(!e||e.length===0){this.nextBeatIndex=0;return}for(this.nextBeatIndex=0;this.nextBeatIndex<e.length&&e[this.nextBeatIndex].time<t-.01;)this.nextBeatIndex++}_stopMetronome(){this.metronomeScheduleInterval&&(clearInterval(this.metronomeScheduleInterval),this.metronomeScheduleInterval=null)}_stopLeadIn(){this.leadInInterval&&(clearInterval(this.leadInInterval),this.leadInInterval=null)}_pauseLeadIn(){this._stopLeadIn()}_resumeLeadIn(){if(!this.leadInData||this.leadInProgress===null)return;this.state="lead-in";const t=this.audioEngine.audioContext.currentTime,e=this.leadInProgress*this.leadInData.duration;this.leadInStartTime=t-e,this._startLeadInScheduling(this.metronomeConfig.enabled),this._startTimeUpdateLoop()}_startTimeUpdateLoop(){this.timeUpdateInterval||(this.timeUpdateInterval=setInterval(()=>{this.state==="lead-in"?this._emitEvent("timeupdate",{currentTime:this.frozenTime,effectiveTime:this.frozenTime,leadInProgress:this.leadInProgress||0}):this.state},100))}_stopTimeUpdateLoop(){this.timeUpdateInterval&&(clearInterval(this.timeUpdateInterval),this.timeUpdateInterval=null)}_emitEvent(t,e){(this.eventBus.all.get(t)||[]).forEach(s=>{try{s(e)}catch(n){console.error(`Error in ${t} event listener:`,n)}})}destroy(){this.stop(),this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this.eventBus.all.clear()}_setupPlayerWithAudio(){if(!this._audioEngineReady)throw new Error("Audio engine not ready");if(!this.parsedData)throw new Error("No parsed MIDI data available");const t=this.parsedData.structureMetadata||null,e=new f(this.audioEngine,this.parsedData,this.instrumentMap,t);this._setMidiPlayer(e)}_setMidiPlayer(t){this.midiPlayer=t,this.audioEngine=t.audioEngine,this._audioEngineReady=!0,this._completeMidiPlayerSetup()}_completeMidiPlayerSetup(){this._partOutputsMap.clear(),Object.keys(this.midiPlayer.parsedData.parts).forEach(t=>{const e=this.midiPlayer.getPartOutput(t);e&&this._partOutputsMap.set(t,e)}),this._setupEventDelegation(),this.state="ready"}_createDefaultInstrumentMap(t){const e={},i={soprano:{instrument:"choir_aahs",volume:1},alto:{instrument:"choir_aahs",volume:1},tenor:{instrument:"choir_aahs",volume:1},bass:{instrument:"choir_aahs",volume:1},piano:{instrument:"piano",volume:.8},organ:{instrument:"church_organ",volume:.7},strings:{instrument:"string_ensemble_1",volume:.6},flute:{instrument:"flute",volume:.8},trumpet:{instrument:"trumpet",volume:.7}};return Object.keys(t).forEach(s=>{const n=s.toLowerCase(),a=i[n]||i.piano;e[s]={instrument:a.instrument,volume:a.volume}}),e}}exports.AudioEngine=p;exports.AudioEngineUtils=T;exports.BeatMapper=v;exports.ChannelHandle=g;exports.MidiParser=C;exports.MidiPlayer=f;exports.PlaybackManager=F;exports.SpessaSynthAudioEngine=U;exports.SpessaSynthChannelHandle=k;
|
|
1
|
+
"use strict";var P=Object.create;var _=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var O=(c,t,e,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of M(t))!S.call(c,s)&&s!==e&&_(c,s,{get:()=>t[s],enumerable:!(i=E(t,s))||i.enumerable});return c};var D=(c,t,e)=>(e=c!=null?P(B(c)):{},O(t||!c||!c.__esModule?_(e,"default",{value:c,enumerable:!0}):e,c));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N="data:audio/mpeg;base64,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",z="data:audio/mpeg;base64,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qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//tkxPIADij5M+wwzYmAm6X9hJmwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//s0xPaAClDTI6OxLwCwkeLoEJkoqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//sUxNoDwAAB/gAAACAAADSAAAAEqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq";class p{constructor(t,e={}){if(new.target===p)throw new Error("AudioEngine is abstract and cannot be instantiated directly");this.audioContext=t,this.options=e,this.isInitialized=!1,this.channels=new WeakMap,this.activeChannels=new Set}async initialize(t){throw new Error("initialize() must be implemented by subclass")}createChannel(t,e={}){throw new Error("createChannel() must be implemented by subclass")}allSoundsOff(){throw new Error("allSoundsOff() must be implemented by subclass")}async playMetronomeTick(t,e,i){try{await this._ensureMetronomeBuffersLoaded();const s=e?this.accentTickBuffer:this.regularTickBuffer;if(!s){console.warn("Metronome buffer not available");return}const n=this.audioContext.createBufferSource();n.buffer=s;const a=this.audioContext.createGain();a.gain.value=i,n.connect(a);const r=this.getMetronomeOutput();r?a.connect(r):a.connect(this.audioContext.destination);const l=Math.max(t,this.audioContext.currentTime);n.start(l)}catch(s){console.warn("Buffer metronome playback failed:",s)}}getMetronomeOutput(){return this._metronomeOutput||(this._metronomeOutput=this.audioContext.createGain(),this._metronomeOutput.gain.value=1,this._metronomeOutput.connect(this.audioContext.destination)),this._metronomeOutput}async _ensureMetronomeBuffersLoaded(){if(!(this.regularTickBuffer&&this.accentTickBuffer)){try{if(typeof fetch<"u"){const[t,e]=await Promise.all([fetch(N),fetch(z)]),[i,s]=await Promise.all([t.arrayBuffer(),e.arrayBuffer()]),[n,a]=await Promise.all([this.audioContext.decodeAudioData(i),this.audioContext.decodeAudioData(s)]);this.regularTickBuffer=n,this.accentTickBuffer=a;return}}catch(t){console.warn("Failed to load metronome sounds:",t)}this.regularTickBuffer=this.audioContext.createBuffer(2,1024,this.audioContext.sampleRate),this.accentTickBuffer=this.audioContext.createBuffer(2,1024,this.audioContext.sampleRate)}}getActiveChannels(){return Array.from(this.activeChannels)}destroy(){this.allSoundsOff(),this._metronomeOutput&&(this._metronomeOutput.disconnect(),this._metronomeOutput=null),this.regularTickBuffer=null,this.accentTickBuffer=null,this.activeChannels.clear(),this.isInitialized=!1}_validateInitialized(){if(!this.isInitialized)throw new Error("AudioEngine not initialized. Call initialize() first.")}_registerChannel(t){this.activeChannels.add(t)}_unregisterChannel(t){this.activeChannels.delete(t),this.channels.delete(t)}}class g{constructor(t,e,i={}){if(new.target===g)throw new Error("ChannelHandle is abstract and cannot be instantiated directly");this.engine=t,this.partId=e,this.options={initialVolume:1,...i},this.isDestroyed=!1,this.noteRefCounts=new Map,this.scheduledEvents=new Map,this.activeNotes=new Set}getOutputNode(){throw new Error("getOutputNode() must be implemented by subclass")}noteOn(t,e){this._validateActive();const i=this.noteRefCounts.get(t)||0;this.noteRefCounts.set(t,i+1),this._actualNoteOn(t,e),i===0&&this.activeNotes.add(t)}noteOff(t){this._validateActive();const e=this.noteRefCounts.get(t)||0;if(e<=0)return;const i=e-1;this.noteRefCounts.set(t,i),i===0&&(this._actualNoteOff(t),this.activeNotes.delete(t),this.noteRefCounts.delete(t))}playNote(t,e,i,s){this._validateActive();const n=this.engine.audioContext.currentTime,a=`${this.partId}_${t}_${e}_${Date.now()}`;let r=t,l=s;if(t<n){const d=n-t;r=n,l=Math.max(0,s-d)}if(l<=0)return a;const q=Math.max(0,(r-n)*1e3),o=setTimeout(()=>{this.noteOn(e,i),this.scheduledEvents.delete(`${a}_on`)},q),h=q+l*1e3,u=setTimeout(()=>{this.noteOff(e),this.scheduledEvents.delete(`${a}_off`)},h);return this.scheduledEvents.set(`${a}_on`,o),this.scheduledEvents.set(`${a}_off`,u),a}playPreviewNote(t,e={}){this._validateActive();const i=e.startTime??this.engine.audioContext.currentTime+.01,s=e.duration??.5,n=e.velocity??100;let a=null;e.instrument!==void 0&&(a=this.getInstrument(),this.setInstrument(e.instrument)),this.playNote(i,t,n,s),a!==null&&setTimeout(()=>{this.isDestroyed||this.setInstrument(a)},(s+.1)*1e3)}allNotesOff(){this._validateActive(),this.scheduledEvents.forEach(t=>{clearTimeout(t)}),this.scheduledEvents.clear(),this.activeNotes.forEach(t=>{this._actualNoteOff(t)}),this.noteRefCounts.clear(),this.activeNotes.clear()}_actualNoteOn(t,e){throw new Error("_actualNoteOn() must be implemented by subclass")}_actualNoteOff(t){throw new Error("_actualNoteOff() must be implemented by subclass")}async setInstrument(t){throw new Error("setInstrument() must be implemented by subclass")}getInstrument(){throw new Error("getInstrument() must be implemented by subclass")}setVolume(t){throw new Error("setVolume() must be implemented by subclass")}getVolume(){throw new Error("getVolume() must be implemented by subclass")}getPartId(){return this.partId}isActive(){return!this.isDestroyed&&this.engine.isInitialized&&this.engine.activeChannels.has(this)}destroy(){if(!this.isDestroyed){this.allNotesOff();const t=this.getOutputNode();t&&t.disconnect(),this.noteRefCounts.clear(),this.scheduledEvents.clear(),this.activeNotes.clear(),this.engine._unregisterChannel(this),this.isDestroyed=!0}}_validateActive(){if(this.isDestroyed)throw new Error("Channel has been destroyed");if(!this.engine.isInitialized)throw new Error("AudioEngine is not initialized")}}const I={piano:0,bright_piano:1,electric_grand:2,honky_tonk:3,electric_piano_1:4,electric_piano_2:5,harpsichord:6,clavinet:7,celesta:8,glockenspiel:9,music_box:10,vibraphone:11,marimba:12,xylophone:13,tubular_bells:14,dulcimer:15,drawbar_organ:16,percussive_organ:17,rock_organ:18,church_organ:19,reed_organ:20,accordion:21,harmonica:22,tango_accordion:23,organ:19,nylon_guitar:24,steel_guitar:25,electric_guitar_jazz:26,electric_guitar_clean:27,electric_guitar_muted:28,overdriven_guitar:29,distortion_guitar:30,guitar_harmonics:31,guitar:24,acoustic_bass:32,electric_bass_finger:33,electric_bass_pick:34,fretless_bass:35,slap_bass_1:36,slap_bass_2:37,synth_bass_1:38,synth_bass_2:39,bass:32,violin:40,viola:41,cello:42,contrabass:43,tremolo_strings:44,pizzicato_strings:45,orchestral_harp:46,timpani:47,strings:48,strings_ensemble:48,slow_strings:49,synth_strings_1:50,synth_strings_2:51,choir_aahs:52,voice_oohs:53,synth_voice:54,orchestra_hit:55,trumpet:56,trombone:57,tuba:58,muted_trumpet:59,french_horn:60,brass_section:61,synth_brass_1:62,synth_brass_2:63,soprano_sax:64,alto_sax:65,tenor_sax:66,baritone_sax:67,oboe:68,english_horn:69,bassoon:70,clarinet:71,saxophone:64,piccolo:72,flute:73,recorder:74,pan_flute:75,blown_bottle:76,shakuhachi:77,whistle:78,ocarina:79,lead_1_square:80,lead_2_sawtooth:81,lead_3_calliope:82,lead_4_chiff:83,lead_5_charang:84,lead_6_voice:85,lead_7_fifths:86,lead_8_bass:87,pad_1_new_age:88,pad_2_warm:89,pad_3_polysynth:90,pad_4_choir:91,pad_5_bowed:92,pad_6_metallic:93,pad_7_halo:94,pad_8_sweep:95,fx_1_rain:96,fx_2_soundtrack:97,fx_3_crystal:98,fx_4_atmosphere:99,fx_5_brightness:100,fx_6_goblins:101,fx_7_echoes:102,fx_8_sci_fi:103,sitar:104,banjo:105,shamisen:106,koto:107,kalimba:108,bag_pipe:109,fiddle:110,shanai:111,tinkle_bell:112,agogo:113,steel_drums:114,woodblock:115,taiko_drum:116,melodic_tom:117,synth_drum:118,reverse_cymbal:119,guitar_fret_noise:120,breath_noise:121,seashore:122,bird_tweet:123,telephone_ring:124,helicopter:125,applause:126,gunshot:127},L=Object.entries(I).reduce((c,[t,e])=>(c[e]=t,c),{});class T{static getInstrumentProgram(t){if(typeof t=="number")return t;const e=I[t.toLowerCase()];return e!==void 0?e:0}static getProgramName(t){return L[t]||`Program ${t}`}static generateNoteId(t,e,i){return`${t}_${e}_${Math.round(i)}`}}class k extends g{constructor(t,e,i,s={}){super(t,e,s),this.midiChannel=i,this.currentVolume=s.initialVolume||1,this.currentInstrument=s.instrument||"piano",this.outputGain=null,this._setupOutputNode(),this.setVolume(this.currentVolume),s.instrument&&this.setInstrument(s.instrument)}getOutputNode(){return this.outputGain}_actualNoteOn(t,e){const i=this.engine._getSynthesizer();if(i&&i.noteOn){const s=Math.round(e*this.currentVolume);i.noteOn(this.midiChannel,t,s)}}_actualNoteOff(t){const e=this.engine._getSynthesizer();e&&e.noteOff&&e.noteOff(this.midiChannel,t)}async setInstrument(t){this._validateActive();const e=T.getInstrumentProgram(t);this.currentInstrument=t;const i=this.engine._getSynthesizer();i&&i.programChange?i.programChange(this.midiChannel,e):console.warn("Cannot set instrument: synthesizer not available or no programChange method")}getInstrument(){return this.currentInstrument}setVolume(t){this._validateActive(),t=Math.max(0,Math.min(1,t)),this.currentVolume=t;const e=Math.round(t*127),i=this.engine._getSynthesizer();i&&i.controllerChange&&i.controllerChange(this.midiChannel,7,e)}getVolume(){return this.currentVolume}getMidiChannel(){return this.midiChannel}getActiveNoteCount(){return this.activeNotes.size}playNote(t,e,i,s){this._validateActive();const n=`${this.partId}_${t}_${e}_${Date.now()}`,a=this.engine._getSynthesizer();if(a&&a.post){const r=Math.round(i*this.currentVolume);a.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[144|this.midiChannel,e,r],channelOffset:0,force:!1,options:{time:t}}}),a.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[128|this.midiChannel,e,0],channelOffset:0,force:!1,options:{time:t+s}}})}else return super.playNote(t,e,i,s);return n}allNotesOff(){this._validateActive();const t=this.engine._getSynthesizer();t&&t.post?t.post({channelNumber:this.midiChannel,type:"midiMessage",data:{messageData:[176|this.midiChannel,123,0],channelOffset:0,force:!1,options:{time:this.engine.audioContext.currentTime}}}):super.allNotesOff()}destroy(){if(!this.isDestroyed){const t=this.engine._getIndividualOutput(this.midiChannel);this.outputGain&&this.outputGain!==t&&this.outputGain.disconnect(),this.outputGain=null}super.destroy()}_setupOutputNode(){const t=this.engine._getIndividualOutput(this.midiChannel);t?this.outputGain=t:(console.warn(`No individual output available for MIDI channel ${this.midiChannel}, using fallback`),this.outputGain=this.engine.audioContext.createGain(),this.outputGain.gain.value=this.currentVolume)}}class U extends p{constructor(t,e={}){super(t,e),this.synthesizer=null,this.soundfont=null,this.channelCounter=0,this.partToMidiChannel=new Map,this.midiChannelToPart=new Map,this.individualOutputs=[]}async initialize(t){const{WorkletSynthesizer:e}=await import("spessasynth_lib");let i;if(typeof t=="string")i=await this._loadSoundfontFromPath(t);else if(t instanceof ArrayBuffer)i=t;else throw new Error("Invalid soundfont data type. Expected string path or ArrayBuffer.");await this._loadAudioWorkletSafely(),this._setupIndividualOutputs(),this.dummyTarget=this.audioContext.createGain(),await new Promise(s=>setTimeout(s,50)),this.synthesizer=new e(this.audioContext),await this.synthesizer.soundBankManager.addSoundBank(i,"main"),await this.synthesizer.isReady,this._connectIndividualOutputs(),this._initializeMetronomeChannel(),this.isInitialized=!0}createChannel(t,e={}){if(this._validateInitialized(),this.partToMidiChannel.has(t))throw new Error(`Channel for part '${t}' already exists`);const i=this.channelCounter;if(i>=15)throw new Error("Maximum number of musical part channels (15) exceeded. Channel 15 is reserved for metronome.");this.channelCounter++,this.partToMidiChannel.set(t,i),this.midiChannelToPart.set(i,t);const s=new k(this,t,i,e);return this._registerChannel(s),e.instrument&&s.setInstrument(e.instrument),s}allSoundsOff(){this.synthesizer&&this.midiChannelToPart.forEach((t,e)=>{this.synthesizer.controllerChange&&this.synthesizer.controllerChange(e,120,0)})}clearAllChannels(){this.allSoundsOff(),this.partToMidiChannel.clear(),this.midiChannelToPart.clear(),this.channelCounter=0}destroy(){this.allSoundsOff(),this.synthesizer&&typeof this.synthesizer.disconnect=="function"&&this.synthesizer.disconnect(),this.individualOutputs.forEach(t=>{t&&t.disconnect&&t.disconnect()}),this.individualOutputs=[],this.dummyTarget&&(this.dummyTarget.disconnect(),this.dummyTarget=null),this.partToMidiChannel.clear(),this.midiChannelToPart.clear(),this.channelCounter=0,super.destroy(),this.synthesizer=null,this.soundfont=null}getMidiChannelForPart(t){return this.partToMidiChannel.has(t)?this.partToMidiChannel.get(t):null}_getSynthesizer(){return this.synthesizer}_getIndividualOutput(t){return t>=0&&t<this.individualOutputs.length?this.individualOutputs[t]:null}getMetronomeChannel(){const t=this._getIndividualOutput(15);return console.log("Metronome channel 15 output:",t?"Available":"NULL",`(total outputs: ${this.individualOutputs.length})`),t}_setupIndividualOutputs(){this.individualOutputs=[];for(let t=0;t<16;t++){const e=this.audioContext.createGain();e.gain.value=1,this.individualOutputs.push(e)}}_connectIndividualOutputs(){try{this.synthesizer&&this.synthesizer.connectIndividualOutputs?this.synthesizer.connectIndividualOutputs(this.individualOutputs):(console.warn("Synthesizer does not support individual outputs, using master output only"),this.synthesizer&&this.synthesizer.connect&&this.audioContext.destination&&this.synthesizer.connect(this.audioContext.destination))}catch(t){console.warn("Failed to connect individual outputs:",t.message),console.warn("Falling back to master output routing")}}async _loadSoundfontFromPath(t){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load soundfont: ${e.status} ${e.statusText}`);return await e.arrayBuffer()}async _loadAudioWorkletSafely(){const t="/node_modules/spessasynth_lib/dist/spessasynth_processor.min.js";for(let i=1;i<=5;i++)try{await this.audioContext.audioWorklet.addModule(t);return}catch(s){if(console.warn(`AudioWorklet loading failed (attempt ${i}/5):`,s.message),i===5)throw new Error(`AudioWorklet failed after 5 attempts: ${s.message}`);const n=i*500;await new Promise(a=>setTimeout(a,n))}}_initializeMetronomeChannel(){try{const t=this._getSynthesizer();if(!t){console.warn("Cannot initialize metronome channel: synthesizer not available");return}const e=15;t.programChange&&(t.programChange(e,115),console.log("Metronome channel 15 initialized with woodblock instrument (115)")),t.controllerChange&&t.controllerChange(e,7,127)}catch(t){console.warn("Failed to initialize metronome channel:",t)}}async playMetronomeTick(t,e,i){try{const s=this.getMetronomeChannel(),n=this._getSynthesizer();if(!s||!n)return super.playMetronomeTick(t,e,i);const a=15,r=e?86:60,q=Math.round(Math.min(127,Math.max(0,i*(e?127:100)))),o=this.audioContext.currentTime,h=Math.max(t,o),u=h-o;n.post?(n.post({channelNumber:a,type:"midiMessage",data:{messageData:[144|a,r,q],channelOffset:0,force:!1,options:{time:h}}}),n.post({channelNumber:a,type:"midiMessage",data:{messageData:[128|a,r,0],channelOffset:0,force:!1,options:{time:h+.1}}})):u<=.01?(n.noteOn&&n.noteOn(a,r,q),setTimeout(()=>{n.noteOff&&n.noteOff(a,r)},100)):setTimeout(()=>{n.noteOn&&n.noteOn(a,r,q),setTimeout(()=>{n.noteOff&&n.noteOff(a,r)},100)},u*1e3)}catch(s){return console.warn("MIDI metronome failed, falling back to buffers:",s),super.playMetronomeTick(t,e,i)}}getMetronomeOutput(){return!this.individualOutputs||this.individualOutputs.length<16?null:this.individualOutputs[15]}}class C{constructor(){this.partNames=["soprano","alto","tenor","bass","treble","mezzo","baritone","s","a","t","b","satb"],this.parsedData={parts:{},barStructure:[],metadata:{}}}async parse(t,e=null){try{const i=await this._parseMidiBuffer(t);return this.metadataOverrides=e||{},this._normalizeLegacyMetadata(),this._extractMetadata(i),this._extractBarStructure(i),this._extractParts(i),this.parsedData.structureMetadata=this.metadataOverrides,this.parsedData}catch(i){throw console.error("Error parsing MIDI file:",i),i}}_normalizeLegacyMetadata(){if(!this.metadataOverrides||Object.keys(this.metadataOverrides).length===0)return;const t=this.metadataOverrides;if(t.scores&&Array.isArray(t.scores)&&t.scores.length>0){const e=t.scores[0];e.parts&&(t.parts=this._convertLegacyParts(e.parts)),e.bars&&(t.bars=e.bars),delete t.scores}else t.parts&&Array.isArray(t.parts)&&(t.parts=this._convertLegacyParts(t.parts));delete t.type,delete t.version,delete t.subtitle}_convertLegacyParts(t){const e={};for(const i of t){if(!i.name||!i.url)continue;const s=i.name.toLowerCase(),n=this._parseUrlParams(i.url),a={};if(n.track!==void 0&&(a.trackIndex=parseInt(n.track,10)),n.prog!==void 0){const r=parseInt(n.prog,10);r!==0&&(a.instrument=r)}a.trackIndex!==void 0&&(e[s]=a)}return e}_parseUrlParams(t){const e={},i=t.indexOf("?");if(i===-1)return e;const n=t.substring(i+1).split("&");for(const a of n){const[r,l]=a.split("=");r&&l!==void 0&&(e[r]=l)}return e}async _parseMidiBuffer(t){const e=new Uint8Array(t);if(!(e[0]===77&&e[1]===84&&e[2]===104&&e[3]===100))throw new Error("Not a valid MIDI file");const i=this._bytesToNumber(e.slice(4,8)),s=this._bytesToNumber(e.slice(8,10)),n=this._bytesToNumber(e.slice(10,12)),a=this._bytesToNumber(e.slice(12,14)),r=a&32768?null:a,l={format:s,ticksPerBeat:r,tracks:[],duration:0};let q=8+i;for(let o=0;o<n;o++)if(e[q]===77&&e[q+1]===84&&e[q+2]===114&&e[q+3]===107){const h=this._bytesToNumber(e.slice(q+4,q+8)),u=e.slice(q+8,q+8+h),d=this._parseTrack(u);l.tracks.push(d),q+=8+h}else throw new Error(`Invalid track header at position ${q}`);return l}_parseTrack(t){const e={notes:[],name:null,lyrics:[],events:[],duration:0};let i=0,s=0,n=null;for(;i<t.length;){let a=0,r=0;do r=t[i++],a=a<<7|r&127;while(r&128);s+=a,r=t[i++];let l=r;if((r&128)===0){if(n===null)throw new Error("Running status byte encountered before status byte");l=n,i--}else n=l;if(l===255){const q=t[i++],o=this._readVariableLengthValue(t,i);i+=o.bytesRead;const h=t.slice(i,i+o.value);switch(i+=o.value,q){case 3:e.name=this._bytesToString(h);break;case 1:e.events.push({type:"text",text:this._bytesToString(h),tick:s});break;case 5:e.lyrics.push({text:this._bytesToString(h),tick:s});break;case 81:const u=this._bytesToNumber(h),d=Math.round(6e7/u);e.events.push({type:"tempo",bpm:d,tick:s});break;case 88:e.events.push({type:"timeSignature",numerator:h[0],denominator:Math.pow(2,h[1]),tick:s});break;case 47:e.duration=s;break}}else if((l&240)===144){const q=l&15,o=t[i++],h=t[i++];h>0?e.notes.push({type:"noteOn",noteNumber:o,velocity:h,tick:s,channel:q}):e.notes.push({type:"noteOff",noteNumber:o,tick:s,channel:q})}else if((l&240)===128){const q=l&15,o=t[i++];t[i++],e.notes.push({type:"noteOff",noteNumber:o,tick:s,channel:q})}else if(l===240||l===247){const q=this._readVariableLengthValue(t,i);i+=q.bytesRead+q.value}else if((l&240)===176){const q=l&15,o=t[i++],h=t[i++];e.events.push({type:"controller",controllerNumber:o,value:h,channel:q,tick:s})}else if((l&240)===192){const q=l&15,o=t[i++];e.events.push({type:"programChange",programNumber:o,channel:q,tick:s})}else if((l&240)===208){const q=l&15,o=t[i++];e.events.push({type:"channelAftertouch",pressure:o,channel:q,tick:s})}else if((l&240)===224){const q=l&15,o=t[i++],u=(t[i++]<<7|o)-8192;e.events.push({type:"pitchBend",value:u,channel:q,tick:s})}else if((l&240)===160){const q=l&15,o=t[i++],h=t[i++];e.events.push({type:"noteAftertouch",noteNumber:o,pressure:h,channel:q,tick:s})}else console.warn(`Unknown event type: ${l.toString(16)} at position ${i-1}`),i++}return e}_extractMetadata(t){const e={title:null,composer:null,partNames:[],format:t.format,ticksPerBeat:t.ticksPerBeat};t.tracks.forEach((i,s)=>{if(i.name&&!e.title&&(e.title=i.name),i.events.filter(n=>n.type==="text").forEach(n=>{const a=n.text.toLowerCase();(a.includes("compos")||a.includes("by"))&&!e.composer&&(e.composer=n.text)}),i.name){const n=i.name.toLowerCase();for(const a of this.partNames)if(n.includes(a)){e.partNames.push({index:s,name:i.name});break}}}),this.metadataOverrides.title!==void 0&&(e.title=this.metadataOverrides.title),this.metadataOverrides.composer!==void 0&&(e.composer=this.metadataOverrides.composer),this.metadataOverrides.arranger!==void 0&&(e.arranger=this.metadataOverrides.arranger),this.metadataOverrides.copyright!==void 0&&(e.copyright=this.metadataOverrides.copyright),this.parsedData.metadata=e}_extractBarStructure(t){const e=t.ticksPerBeat||480,i=[];t.tracks.forEach(o=>{o.events.forEach(h=>{(h.type==="timeSignature"||h.type==="tempo")&&i.push(h)})}),i.sort((o,h)=>o.tick-h.tick);let s=0;t.tracks.forEach(o=>{o.notes&&o.notes.forEach(h=>{h.type==="noteOff"&&h.tick>s&&(s=h.tick)})}),s===0&&(s=e*8);const n=[],a=i.filter(o=>o.type==="timeSignature").sort((o,h)=>o.tick-h.tick);let r={numerator:4,denominator:4},l=0,q=0;for(;l<s;){for(;q<a.length&&a[q].tick<=l;)r=a[q],q++;let o;o=l+e*4*r.numerator/r.denominator;const h=r.numerator,u=[],d=e*(4/r.denominator);for(let m=0;m<h;m++){const A=l+m*d,y=this._ticksToTime(A,t);u.push(y)}n.push({sig:[r.numerator,r.denominator],beats:u}),l=o}this.parsedData.barStructure=n}_extractParts(t){const e={},i=t.ticksPerBeat;if(this.metadataOverrides.parts)for(const[s,n]of Object.entries(this.metadataOverrides.parts)){if(!n.trackIndex&&n.trackIndex!==0&&!n.trackName)continue;let a=null,r=null;if(n.trackIndex!==void 0&&n.trackIndex!==null)r=n.trackIndex,r>=0&&r<t.tracks.length&&(a=t.tracks[r]);else if(n.trackName){const q=t.tracks.findIndex(o=>o.name===n.trackName);q!==-1&&(a=t.tracks[q],r=q)}if(!a)continue;const l=this._extractPartDataFromTrack(a,r,t,i);n.instrument!==void 0&&n.instrument!==null&&(l.defaultInstrument=this._resolveInstrument(n.instrument)),e[s]=l}else t.tracks.forEach((s,n)=>{if(!s.notes.length)return;let a=null;if(s.name){const q=s.name.toLowerCase();for(const o of this.partNames)if(o.length===1){if(q===o){a=o;break}}else if(q.includes(o)){a=o;break}}a||(a=s.name||`Track ${n+1}`),a==="s"&&(a="soprano"),a==="a"&&(a="alto"),a==="t"&&(a="tenor"),a==="b"&&(a="bass");let r=a,l=2;for(;e[r];)r=`${a} ${l}`,l++;a=r,e[a]=this._extractPartDataFromTrack(s,n,t,i)});this.parsedData.parts=e}_extractPartDataFromTrack(t,e,i,s){const n=[],a={};t.notes.forEach(o=>{if(o.type==="noteOn")a[o.noteNumber]={tick:o.tick,velocity:o.velocity};else if(o.type==="noteOff"&&a[o.noteNumber]){const h=a[o.noteNumber],u=o.tick-h.tick;n.push({pitch:o.noteNumber,name:this._midiNoteToName(o.noteNumber),startTick:h.tick,endTick:o.tick,duration:u,startTime:this._ticksToTime(h.tick,i),endTime:this._ticksToTime(o.tick,i),velocity:h.velocity}),delete a[o.noteNumber]}});const r=t.lyrics.map(o=>({text:o.text,tick:o.tick,time:o.tick/s}));n.sort((o,h)=>o.startTick-h.startTick);const l=t.events.filter(o=>o.type==="programChange").map(o=>({programNumber:o.programNumber,tick:o.tick,time:this._ticksToTime(o.tick,i)})).sort((o,h)=>o.tick-h.tick),q=l.length>0?l[0].programNumber:0;return{notes:n,lyrics:r,trackIndex:e,programChanges:l,defaultInstrument:q}}_resolveInstrument(t){if(typeof t=="number")return t;if(typeof t=="string"){const e={choir_aahs:52,piano:0,acoustic_grand_piano:0,bright_acoustic_piano:1,electric_grand_piano:2,strings:48,string_ensemble_1:48,violin:40,viola:41,cello:42,contrabass:43},i=t.toLowerCase().replace(/ /g,"_");return e[i]!==void 0?e[i]:0}return 0}_midiNoteToName(t){const e=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],i=Math.floor(t/12)-1;return`${e[t%12]}${i}`}_bytesToNumber(t){let e=0;for(let i=0;i<t.length;i++)e=e<<8|t[i];return e}_bytesToString(t){return new TextDecoder().decode(t)}_readVariableLengthValue(t,e){let i=0,s,n=0;do s=t[e+n++],i=i<<7|s&127;while(s&128);return{value:i,bytesRead:n}}_ticksToTime(t,e){const i=e.ticksPerBeat||480,s=[];e.tracks.forEach(l=>{l.events.forEach(q=>{q.type==="tempo"&&s.push(q)})}),s.sort((l,q)=>l.tick-q.tick);let n=0,a=0,r=120;for(const l of s){if(l.tick>t)break;if(l.tick>a){const o=(l.tick-a)/i*(60/r);n+=o,a=l.tick}r=l.bpm}if(t>a){const q=(t-a)/i*(60/r);n+=q}return n}}class v{constructor(){this.barOrder=[],this.beatTable=[]}mapBeats(t,e){try{return e.bars&&!e.sections?this.barOrder=this.generateBarOrderFromLegacyBars(e.bars,t.barStructure):e.sections&&e.order?this.barOrder=this.generateBarOrder(e.sections,e.order):this.barOrder=this.generateLinearBarOrder(t.barStructure),this.beatTable=this.generateBeatTable(this.barOrder,t.barStructure),this.beatTable}catch(i){throw console.error("Error mapping beats:",i),i}}generateBarOrder(t,e){const i=[],s={};for(const n of e){const a=t[n.section];if(!a)throw new Error(`Invalid section index: ${n.section}`);const r=n.section;s[r]||(s[r]=0),s[r]++;const l=s[r],q=n.from!==void 0?n.from:this._getSectionStartBar(t,n.section),o=n.to!==void 0?n.to:a.to,h=n.as||1;for(let u=q;u<=o;u++)this._shouldPlayBar(a,u,h)&&i.push({barNumber:u,repeat:l,sectionIndex:n.section,voltaTime:h})}return i}generateBarOrderFromLegacyBars(t,e){const i=[];let s=1,n=0,a;for(const r of t){r.from!==void 0&&(s=r.from===-1?0:r.from,n=0),r.timeSig!==void 0&&(a=r.timeSig);const l=r.repeat||1;let q=r.beats;for(;q>0;){const h=(a!==void 0?a:this._getBeatsPerBar(s,e))-n;q>=h?(i.push({barNumber:s,repeat:l,sectionIndex:0,voltaTime:1}),q-=h,n=0,s===0?s=1:s++):(n+=q,q=0)}}return n>0&&i.push({barNumber:s,repeat:1,sectionIndex:0,voltaTime:1}),i}generateLinearBarOrder(t){const e=[];for(let i=0;i<t.length;i++)e.push({barNumber:i+1,repeat:1,sectionIndex:0,voltaTime:1});return e}_getBeatsPerBar(t,e){const i=e.length>0&&e[0].sig&&e[0].sig[0]<=2;let s;if(i?s=t:s=t-1,s<0||s>=e.length)return 4;const n=e[s];return n.sig?n.sig[0]:4}generateBeatTable(t,e){const i=[],s={};let n=0,a=0;const r=[...e];for(;a<t.length&&n<r.length;){const l=t[a],q=l.barNumber;if(s[q]===void 0){const d=r[n];if(!d||!d.sig)throw new Error(`Invalid MIDI bar structure at index ${n}`);s[q]=d.sig[0]}const o=s[q];let h=r[n],u=h.sig[0];for(;u<o&&n+1<r.length;){const d=r[n+1],m=[h.sig[0]+d.sig[0],h.sig[1]],A=[...h.beats||[],...d.beats||[]];h={sig:m,beats:A},r[n]=h,r.splice(n+1,1),u=m[0]}if(u>o){const d=o,m=u-o,A=h.beats?h.beats.slice(0,d):[],y=h.beats?h.beats.slice(d):[],b={sig:[d,h.sig[1]],beats:A},w={sig:[m,h.sig[1]],beats:y};r[n]=b,r.splice(n+1,0,w),h=b}this._generateBeatsForBar(i,l,h,o),n++,a++}if(a<t.length)throw new Error(`Ran out of MIDI bars before completing score. Score bar ${a}/${t.length}, MIDI bar ${n}/${r.length}`);return i}_generateBeatsForBar(t,e,i,s){const{beats:n}=i;if(!n||!Array.isArray(n))throw new Error(`Invalid MIDI bar: missing beats array. Got: ${JSON.stringify(i)}`);const a=n.slice(0,s);for(let r=1;r<=s;r++){const q={time:a[r-1],repeat:e.repeat,bar:e.barNumber,beat:r,timeSig:s};t.push(q)}}_getSectionStartBar(t,e){return t[e].pickup!==void 0?0:e===0?1:t[e-1].to+1}_shouldPlayBar(t,e,i){if(!t.voltas)return!0;const s=t.voltas.indexOf(e);return s===-1?!0:s+1===i}}function x(c){return{all:c=c||new Map,on:function(t,e){var i=c.get(t);i?i.push(e):c.set(t,[e])},off:function(t,e){var i=c.get(t);i&&(e?i.splice(i.indexOf(e)>>>0,1):c.set(t,[]))},emit:function(t,e){var i=c.get(t);i&&i.slice().map(function(s){s(e)}),(i=c.get("*"))&&i.slice().map(function(s){s(t,e)})}}}class f{constructor(t=null,e,i=null,s=null){if(!e)throw new Error("Parsed MIDI data is required");this.audioEngine=t,this._audioEngineReady=!!(t&&t.isInitialized),this.instrumentMap=i||{},this.parsedData=e,this._isPlaying=!1,this._currentTime=0,this._totalDuration=0,this.playbackSpeed=1,this.partChannels=new Map,this.partOutputs=new Map,this.playbackStartTime=0,this.lookAheadTime=.05,this.scheduleInterval=null,this.partNotePointers=new Map,this.partProgramPointers=new Map,this.eventBus=x(),this.beatMapper=new v,this.beats=[],this._calculateTotalDuration();const n=s||this._createDefaultStructureMetadata();this.beats=this.beatMapper.mapBeats(e,n),this._audioEngineReady&&(this._setupPartChannels(),this._resetNotePointers(),this._resetProgramPointers())}setAudioEngine(t){if(!t||!t.isInitialized)throw new Error("An initialized AudioEngine is required");this.audioEngine=t,this._audioEngineReady=!0,this._setupPartChannels(),this._resetNotePointers(),this._resetProgramPointers()}isAudioEngineReady(){return this._audioEngineReady}play(){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() first.");this._isPlaying||(this._isPlaying=!0,this.playbackStartTime=this.audioEngine.audioContext.currentTime-this._currentTime/this.playbackSpeed,this._resetNotePointers(),this._resetProgramPointers(),this._schedulePlayback(),this._startTimeUpdateLoop())}playAt(t){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() first.");this._isPlaying||(this._isPlaying=!0,this.playbackStartTime=t-this._currentTime/this.playbackSpeed,this._resetNotePointers(),this._resetProgramPointers(),this._schedulePlayback(),this._startTimeUpdateLoop())}pause(){this._isPlaying&&(this._isPlaying=!1,this._stopScheduling(),this._stopTimeUpdateLoop())}stop(){this._isPlaying=!1,this._currentTime=0,this._stopScheduling(),this._stopTimeUpdateLoop(),this._resetNotePointers(),this._resetProgramPointers()}skipToTime(t){t=Math.max(0,Math.min(t,this._totalDuration));const e=this._isPlaying;e&&this.pause(),this._currentTime=t,this._resetNotePointers(),this._resetProgramPointers(),e&&this.play()}setPlaybackSpeed(t,e=!0){if(t<=0)throw new Error("Playback speed must be greater than 0");const i=e&&this._isPlaying;i&&this.pause();const s=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed;this.playbackSpeed=t,i?this.play():this.playbackStartTime=this.audioEngine.audioContext.currentTime-s/this.playbackSpeed}setBar(t,e=0){const i=this.getTimeFromBar(t,e);i!==null&&(this.skipToTime(i),this._emitEvent("barChanged",{bar:t,beat:1,repeat:e,time:i}))}getTimeFromBar(t,e=0){e||(e=1);const i=this.beats.find(s=>s.bar===t&&s.beat===1&&s.repeat===e);return i?i.time:null}getBeatFromTime(t){if(!this.beats.length)return null;let e=null;for(let i=this.beats.length-1;i>=0;i--)if(this.beats[i].time<=t){e=this.beats[i];break}return e}allSoundsOff(){this._audioEngineReady&&this.audioEngine.allSoundsOff()}getPartOutput(t){return this.partOutputs.get(t)||null}getPartChannel(t){return this.partChannels.get(t)||null}getAllNextNotes(t){const e=t??this.getCurrentTime(),i={};for(const[s,n]of Object.entries(this.parsedData.parts)){const a=n.notes.find(r=>r.startTime>=e);i[s]=a?{pitch:a.pitch,startTime:a.startTime}:null}return i}getCurrentTime(){if(this._isPlaying){const t=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed;this._currentTime=Math.min(t,this._totalDuration)}return this._currentTime}getTotalDuration(){return this._totalDuration}isPlaying(){return this._isPlaying}on(t,e){this.eventBus.on(t,e)}off(t,e){this.eventBus.off(t,e)}_setupPartChannels(){Object.keys(this.parsedData.parts).forEach(t=>{const e=this.parsedData.parts[t],i=this.instrumentMap[t]||{},s=i.instrument!==void 0?i.instrument:e.defaultInstrument!==void 0?e.defaultInstrument:0;try{const n=this.audioEngine.createChannel(t,{instrument:s,initialVolume:i.volume||1});this.partChannels.set(t,n);const a=this.audioEngine.audioContext.createGain();a.gain.value=1;const r=n.getOutputNode();r&&r.connect(a),this.partOutputs.set(t,a)}catch(n){console.error(`Failed to create channel for part '${t}':`,n),this._emitEvent("error",n)}})}_calculateTotalDuration(){let t=0;Object.values(this.parsedData.parts).forEach(e=>{e.notes.forEach(i=>{i.endTime>t&&(t=i.endTime)})}),this._totalDuration=t}_schedulePlayback(){this._stopScheduling(),this._startScheduleLoop()}_startScheduleLoop(){this.scheduleInterval||(this.scheduleInterval=setInterval(()=>{if(!this._isPlaying)return;const e=(this.audioEngine.audioContext.currentTime-this.playbackStartTime)*this.playbackSpeed,i=e+this.lookAheadTime;for(const[s,n]of this.partChannels){const a=this.parsedData.parts[s];if(a){if(a.programChanges&&a.programChanges.length>0){let r=this.partProgramPointers.get(s)||0;const l=a.programChanges;for(;r<l.length&&l[r].time<e;)r++;for(;r<l.length&&l[r].time<=i;){const q=l[r];n.setInstrument(q.programNumber),r++}this.partProgramPointers.set(s,r)}if(a.notes){let r=this.partNotePointers.get(s)||0;const l=a.notes;for(;r<l.length&&l[r].endTime<e;)r++;for(;r<l.length&&l[r].startTime<=i;){const q=l[r];if(q.endTime-q.startTime>=.01){const o=this.playbackStartTime+q.startTime/this.playbackSpeed,h=(q.endTime-q.startTime)/this.playbackSpeed;n.playNote(o,q.pitch,q.velocity,h)}r++}this.partNotePointers.set(s,r)}}}},50))}_resetNotePointers(){const t=this._currentTime;for(const[e]of this.partChannels){const i=this.parsedData.parts[e];if(!i||!i.notes)continue;let s=0;for(;s<i.notes.length&&i.notes[s].endTime<t;)s++;this.partNotePointers.set(e,s)}}_resetProgramPointers(){const t=this._currentTime;for(const[e,i]of this.partChannels){const s=this.parsedData.parts[e];if(!s||!s.programChanges){this.partProgramPointers.set(e,0);continue}let n=0,a=s.defaultInstrument;for(;n<s.programChanges.length&&s.programChanges[n].time<=t;)a=s.programChanges[n].programNumber,n++;i.setInstrument(a),this.partProgramPointers.set(e,n)}}_stopScheduling(){this.scheduleInterval&&(clearInterval(this.scheduleInterval),this.scheduleInterval=null),this.partChannels.forEach(t=>{t.isActive()&&t.allNotesOff()})}_startTimeUpdateLoop(){this.timeUpdateInterval=setInterval(()=>{const t=this.getCurrentTime();this._emitEvent("timeupdate",{currentTime:t});const e=this.getBeatFromTime(t);e&&this._emitEvent("beatChanged",e),t>=this._totalDuration+.05&&(this.stop(),this._emitEvent("ended",{finalTime:t}))},100)}_stopTimeUpdateLoop(){this.timeUpdateInterval&&(clearInterval(this.timeUpdateInterval),this.timeUpdateInterval=null)}_emitEvent(t,e){(this.eventBus.all.get(t)||[]).forEach(s=>{try{s(e)}catch(n){console.error(`Error in ${t} event listener:`,n)}})}_createDefaultStructureMetadata(){return{sections:[{from:1,to:this.parsedData.barStructure.length}],order:[{section:0}]}}destroy(){this.stop(),this.partChannels.forEach(t=>{t.destroy()}),this.partChannels.clear(),this.partOutputs.forEach(t=>{t.disconnect()}),this.partOutputs.clear(),this.partNotePointers.clear(),this.partProgramPointers.clear(),this.eventBus.all.clear()}}class F{constructor(t=null,e={}){t instanceof f?(this.audioEngine=t.audioEngine,this.midiPlayer=t,this.parsedData=t.parsedData,this._audioEngineReady=!!(this.audioEngine&&this.audioEngine.isInitialized)):(this.audioEngine=t,this._audioEngineReady=!!(t&&t.isInitialized),this.midiPlayer=null,this.parsedData=null),this.eventBus=x(),this._parser=new C,this._partOutputsMap=new Map,this.instrumentMap=null,this.metronomeConfig={enabled:!1,tickInstrument:115,accentInstrument:116,volume:.7,...e.metronome},this.leadInConfig={enabled:!1,bars:1,...e.leadIn},this.startupConfig={delayMs:25,...e.startup},this.state="reset",this.frozenTime=0,this.leadInData=null,this.leadInStartTime=null,this.leadInProgress=null,this.leadInInterval=null,this.timeUpdateInterval=null,this.metronomeScheduleInterval=null,this.nextBeatIndex=0,this._validateConfig(),this.midiPlayer&&this._completeMidiPlayerSetup()}setAudioEngine(t){if(!t||!t.isInitialized)throw new Error("An initialized AudioEngine is required");this.audioEngine=t,this._audioEngineReady=!0,this.parsedData&&!this.midiPlayer&&this._setupPlayerWithAudio()}isAudioEngineReady(){return this._audioEngineReady}async load(t,e=null,i=null){if(this.reset(),t instanceof f)this.parsedData=t.parsedData,this.instrumentMap=i,this._audioEngineReady&&this._setMidiPlayer(t);else if(t instanceof ArrayBuffer)this.parsedData=await this._parser.parse(t,e),this.instrumentMap=i||this._createDefaultInstrumentMap(this.parsedData.parts),this._audioEngineReady&&this._setupPlayerWithAudio();else if(t&&typeof t=="object"&&t.parts)this.parsedData=t,this.instrumentMap=i||this._createDefaultInstrumentMap(t.parts),this._audioEngineReady&&this._setupPlayerWithAudio();else throw new Error("Invalid input type. Expected MidiPlayer, parsed MIDI data, or ArrayBuffer")}reset(){this.stop(),this.midiPlayer&&(this.midiPlayer.destroy(),this.midiPlayer=null),this.parsedData=null,this.instrumentMap=null,this._audioEngineReady&&this.audioEngine.clearAllChannels(),this._partOutputsMap.clear(),this.frozenTime=0,this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this.nextBeatIndex=0,this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this.state="reset"}getPartOutputs(){return this._partOutputsMap.entries()}getPartNames(){return Array.from(this._partOutputsMap.keys())}async play(t={}){if(!this._audioEngineReady)throw new Error("Audio engine not ready. Call setAudioEngine() after user interaction.");if(this.parsedData&&!this.midiPlayer&&this._setupPlayerWithAudio(),!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");if(!(this.state==="playing"||this.state==="lead-in"))try{const e=t.leadIn!==void 0?t.leadIn:this.leadInConfig.enabled,i=t.metronome!==void 0?t.metronome:this.metronomeConfig.enabled;this.frozenTime===0&&(this.frozenTime=this.midiPlayer.getCurrentTime()),e?await this._startLeadIn(i):await this._startMidiPlayback(i)}catch(e){throw this.state="stopped",this._emitEvent("error",e),e}}pause(){if(!this.midiPlayer||this.state==="stopped"||this.state==="paused")return;const t=this.state;this.state="paused",t==="lead-in"?this._pauseLeadIn():t==="playing"&&(this.midiPlayer.pause(),this._stopMetronome()),this._stopTimeUpdateLoop(),this._emitEvent("playbackPaused",{})}resume(){!this.midiPlayer||this.state!=="paused"||(this.leadInData&&this.leadInProgress!==null&&this.leadInProgress<1?this._resumeLeadIn():(this.state="playing",this._resetMetronomeBeatTracking(),this.midiPlayer.play(),this._startMetronomeIfEnabled(),this._startTimeUpdateLoop(),this._emitEvent("playbackStarted",{})))}stop(){if(this.state==="stopped")return;const t=this.state==="playing";this.state="stopped",this.frozenTime=0,this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this._resetMetronomeBeatTracking(),t&&this.midiPlayer.stop(),this._emitEvent("playbackStopped",{})}skipToTime(t){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");this.frozenTime=t,this.state!=="lead-in"&&(this.midiPlayer.skipToTime(t),this.state==="playing"&&this.metronomeConfig.enabled&&this._resetMetronomeBeatTracking())}setBar(t,e=0){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");if(this.state==="lead-in"){const i=this.midiPlayer.getTimeFromBar(t,e);i!==null&&(this.frozenTime=i);return}if(this.midiPlayer.setBar(t,e),this.state==="stopped"){const i=this.midiPlayer.getTimeFromBar(t,e);i!==null&&(this.frozenTime=i)}this.state==="playing"&&this.metronomeConfig.enabled&&this._resetMetronomeBeatTracking()}getCurrentTime(){return this.state==="lead-in"||this.state==="paused"&&this.leadInProgress!==null?this.frozenTime:this.midiPlayer?this.midiPlayer.getCurrentTime():0}getLeadInProgress(){return this.leadInProgress}setMetronomeEnabled(t){const e=this.metronomeConfig.enabled;this.metronomeConfig.enabled=t,this.state==="playing"&&(t&&!e?this._startMetronome():!t&&e&&this._stopMetronome()),this._emitEvent("metronomeEnabledChanged",{enabled:t})}setMetronomeSettings(t){if(t.volume!==void 0&&(t.volume<0||t.volume>1))throw new Error("Metronome volume must be between 0.0 and 1.0");if(Object.assign(this.metronomeConfig,t),t.volume!==void 0){const e=this.audioEngine.getMetronomeOutput();e&&e.gain&&(e.gain.value=t.volume)}this._emitEvent("metronomeSettingsChanged",{...t})}setLeadInEnabled(t){this.leadInConfig.enabled=t,this._emitEvent("leadInSettingsChanged",{enabled:t,bars:this.leadInConfig.bars})}setLeadInBars(t){if(t<1)throw new Error("Lead-in bars must be at least 1");this.leadInConfig.bars=t,this._emitEvent("leadInSettingsChanged",{enabled:this.leadInConfig.enabled,bars:t})}setPlaybackSpeed(t,e=!0){if(!this.midiPlayer)throw new Error("No MIDI data loaded. Call load() first.");this.midiPlayer.setPlaybackSpeed(t,e)}getMetronomeSettings(){return{...this.metronomeConfig}}isMetronomeEnabled(){return this.metronomeConfig.enabled}getLeadInSettings(){return{enabled:this.leadInConfig.enabled,bars:this.leadInConfig.bars}}getStartupSettings(){return{...this.startupConfig}}setStartupDelay(t){if(typeof t!="number"||t<0||t>1e3)throw new Error("Startup delay must be a number between 0 and 1000 milliseconds");this.startupConfig.delayMs=t,this._emitEvent("startupSettingsChanged",{delayMs:t})}getState(){return this.state}isInLeadIn(){return this.state==="lead-in"}isPlaying(){return this.state==="playing"||this.state==="lead-in"}getMetronomeOutput(){return this.audioEngine.getMetronomeOutput()}getPartOutput(t){return this.midiPlayer?this.midiPlayer.getPartOutput(t):null}allSoundsOff(){this.midiPlayer&&this.midiPlayer.allSoundsOff()}previewNextNotes(t={}){if(!this.midiPlayer)throw new Error("No MIDI data loaded");const e=t.delayBetweenParts??.3,i=t.duration??.5,s=t.velocity??100,n=this.midiPlayer.getAllNextNotes(),a=t.partOrder??this.getPartNames();let r=this.audioEngine.audioContext.currentTime+.01;const l=[];for(const q of a){const o=n[q];if(!o)continue;const h=this.midiPlayer.getPartChannel(q);if(!h)continue;const u=this.midiPlayer.getPartOutput(q);u&&u.gain.value===0||(h.playPreviewNote(o.pitch,{startTime:r,duration:i,velocity:s,instrument:t.instrument}),l.push({partName:q,pitch:o.pitch,startTime:r}),r+=e)}return{parts:l,totalDuration:l.length*e}}getTotalDuration(){if(this.midiPlayer)return this.midiPlayer.getTotalDuration();if(this.parsedData&&this.parsedData.parts){let t=0;return Object.values(this.parsedData.parts).forEach(e=>{e.notes&&e.notes.forEach(i=>{i.endTime>t&&(t=i.endTime)})}),t}return 0}on(t,e){this.eventBus.on(t,e)}off(t,e){this.eventBus.off(t,e)}_setupEventDelegation(){this.midiPlayer.on("timeupdate",t=>{this.state==="playing"&&this._emitEvent("timeupdate",{...t,effectiveTime:t.currentTime,leadInProgress:null})}),this.midiPlayer.on("beatChanged",t=>{this.state==="playing"&&this._emitEvent("beatChanged",{...t,isLeadIn:!1})}),this.midiPlayer.on("barChanged",t=>{this.state==="playing"&&this._emitEvent("barChanged",t)}),this.midiPlayer.on("ended",t=>{this.state==="playing"&&(this.state="stopped",this._stopMetronome(),this._stopTimeUpdateLoop(),this._emitEvent("playbackEnded",t))}),this.midiPlayer.on("error",t=>{this._emitEvent("error",t)})}_validateConfig(){if(this.metronomeConfig.volume<0||this.metronomeConfig.volume>1)throw new Error("Metronome volume must be between 0.0 and 1.0");if(this.leadInConfig.bars<1)throw new Error("Lead-in bars must be at least 1")}async _startLeadIn(t){this.state="lead-in";const e=this.startupConfig.delayMs/1e3;this.leadInStartTime=this.audioEngine.audioContext.currentTime+e,this.leadInProgress=0,this.leadInData=this._calculateLeadInBeats(),this._emitEvent("leadInStarted",{totalBeats:this.leadInData.totalBeats,duration:this.leadInData.duration,bars:this.leadInConfig.bars,startupDelayMs:this.startupConfig.delayMs}),setTimeout(()=>{this.state==="lead-in"&&this._startLeadInScheduling(t)},this.startupConfig.delayMs),this._startTimeUpdateLoop()}_calculateLeadInBeats(){if(!this.midiPlayer)return{totalBeats:4,duration:2,beatSequence:[],beatsPerBar:4,startBeat:{bar:1,beat:1,timeSig:4}};const t=this.midiPlayer.beats,e=this.frozenTime,i=this.leadInConfig.bars;let s=t.length-1,n=.5;for(;t[s].time>e;)s--;const a=t[s],r=t[s+1];r?n=r.time-a.time:s>0&&(n=a.time-t[s-1].time);const l=this.midiPlayer&&this.midiPlayer.playbackSpeed||1,q=n/l,o=a.timeSig===1,h=o&&r?r.timeSig:a.timeSig,u=o?h-1:a.beat>1?a.beat-1:0,d=i*h+u;return{totalBeats:d,duration:d*q,beatSequence:this._generateBeatSequence(d,q,h),beatsPerBar:h,startBeat:a}}_generateBeatSequence(t,e,i){const s=[];for(let n=0;n<t;n++){const a=n%i+1;s.push({beat:a,isAccent:a===1,time:n*e,absoluteTime:this.leadInStartTime+n*e})}return s}_startLeadInScheduling(t){this.leadInBeatIndex=0,this.leadInScheduledBeats=new Set;const e=this.leadInData.beatSequence,i=10;this.leadInStartTime=this.audioEngine.audioContext.currentTime,this.leadInInterval=setInterval(()=>{const s=this.audioEngine.audioContext.currentTime-this.leadInStartTime;for(this.leadInProgress=Math.min(1,s/this.leadInData.duration);this.leadInBeatIndex<e.length;){const n=e[this.leadInBeatIndex],a=n.time-s;if(a>.05)break;if(!this.leadInScheduledBeats.has(this.leadInBeatIndex)&&a>=-.05&&a<=.05){const r=a<=0?this.audioEngine.audioContext.currentTime+.01:this.audioEngine.audioContext.currentTime+a;this._scheduleTickAtTime(r,n.isAccent),this._emitEvent("beatChanged",{bar:Math.floor(this.leadInBeatIndex/this.leadInData.beatsPerBar)+1,beat:n.beat,repeat:1,time:this.frozenTime,isLeadIn:!0}),this.leadInScheduledBeats.add(this.leadInBeatIndex)}this.leadInBeatIndex++}this.leadInProgress>=1&&this._completeLeadIn(t)},i)}_completeLeadIn(t){const e=this.leadInStartTime+this.leadInData.duration;this._stopLeadIn(),this._emitEvent("leadInEnded",{}),this.leadInData=null,this.leadInProgress=null,this.leadInStartTime=null,this._startMidiPlaybackAt(e,t,!0)}async _startMidiPlaybackAt(t,e,i=!0){this.state="playing",i&&this._emitEvent("playbackStarted",{startupDelayMs:0,scheduledStartTime:t}),this.midiPlayer.playAt(t),e&&this._startMetronomeAt(t),this.timeUpdateInterval||this._startTimeUpdateLoop()}async _startMidiPlayback(t,e=!0,i=!1){this.state="playing",this._resetMetronomeBeatTracking(),e&&this._emitEvent("playbackStarted",{startupDelayMs:i?0:this.startupConfig.delayMs});const s=()=>{if(this.state==="playing")try{this.midiPlayer.play(),t&&this._startMetronome()}catch(n){this.state="stopped",this._emitEvent("error",n)}};i?s():setTimeout(s,this.startupConfig.delayMs),this.timeUpdateInterval||this._startTimeUpdateLoop()}_startMetronome(){!this.metronomeConfig.enabled||this.state!=="playing"||(this._scheduleMetronomeTicks(),this.metronomeScheduleInterval=setInterval(()=>{this._scheduleMetronomeTicks()},50))}_startMetronomeAt(t){this.metronomeConfig.enabled&&(this.metronomeScheduledStartTime=t,this._resetMetronomeBeatTracking(),this._scheduleMetronomeTicksAt(t),this.metronomeScheduleInterval=setInterval(()=>{this._scheduleMetronomeTicks()},50))}_startMetronomeIfEnabled(){this.metronomeConfig.enabled&&this._startMetronome()}_scheduleMetronomeTicksAt(t){if(!this.metronomeConfig.enabled||!this.midiPlayer)return;const e=this.midiPlayer.beats;if(!e||e.length===0)return;const i=this.midiPlayer.getCurrentTime(),s=.1;for(let n=this.nextBeatIndex;n<e.length;n++){const a=e[n],r=this.midiPlayer.playbackSpeed||1,l=t+(a.time-i)/r;if(l>this.audioEngine.audioContext.currentTime+s)break;if(l>=this.audioEngine.audioContext.currentTime-.01){const q=Math.max(l,this.audioEngine.audioContext.currentTime+.001),o=a.isDownbeat||a.beat===1;this._scheduleTickAtTime(q,o),this.nextBeatIndex=n+1}}}_scheduleMetronomeTicks(){if(!this.metronomeConfig.enabled||!this.midiPlayer)return;const t=this.midiPlayer.getCurrentTime(),e=this.midiPlayer.beats;if(!e||e.length===0)return;for(;this.nextBeatIndex<e.length&&e[this.nextBeatIndex].time<t-.025;)this.nextBeatIndex++;const s=t+.15;for(;this.nextBeatIndex<e.length;){const n=e[this.nextBeatIndex],a=n.time-t;if(n.time>s)break;if(a>=-.025&&a<=.15){const r=this.audioEngine.audioContext.currentTime+.005,l=this.audioEngine.audioContext.currentTime+Math.max(a,.005),q=Math.max(r,l),o=n.beat===1;this._scheduleTickAtTime(q,o)}this.nextBeatIndex++}}async _scheduleTickAtTime(t,e){try{await this.audioEngine.playMetronomeTick(t,e,this.metronomeConfig.volume)}catch(i){console.warn("Failed to schedule metronome tick:",i)}}_resetMetronomeBeatTracking(){if(!this.midiPlayer){this.nextBeatIndex=0;return}const t=this.getCurrentTime(),e=this.midiPlayer.beats;if(!e||e.length===0){this.nextBeatIndex=0;return}for(this.nextBeatIndex=0;this.nextBeatIndex<e.length&&e[this.nextBeatIndex].time<t-.01;)this.nextBeatIndex++}_stopMetronome(){this.metronomeScheduleInterval&&(clearInterval(this.metronomeScheduleInterval),this.metronomeScheduleInterval=null)}_stopLeadIn(){this.leadInInterval&&(clearInterval(this.leadInInterval),this.leadInInterval=null)}_pauseLeadIn(){this._stopLeadIn()}_resumeLeadIn(){if(!this.leadInData||this.leadInProgress===null)return;this.state="lead-in";const t=this.audioEngine.audioContext.currentTime,e=this.leadInProgress*this.leadInData.duration;this.leadInStartTime=t-e,this._startLeadInScheduling(this.metronomeConfig.enabled),this._startTimeUpdateLoop()}_startTimeUpdateLoop(){this.timeUpdateInterval||(this.timeUpdateInterval=setInterval(()=>{this.state==="lead-in"?this._emitEvent("timeupdate",{currentTime:this.frozenTime,effectiveTime:this.frozenTime,leadInProgress:this.leadInProgress||0}):this.state},100))}_stopTimeUpdateLoop(){this.timeUpdateInterval&&(clearInterval(this.timeUpdateInterval),this.timeUpdateInterval=null)}_emitEvent(t,e){(this.eventBus.all.get(t)||[]).forEach(s=>{try{s(e)}catch(n){console.error(`Error in ${t} event listener:`,n)}})}destroy(){this.stop(),this._stopLeadIn(),this._stopMetronome(),this._stopTimeUpdateLoop(),this.eventBus.all.clear()}_setupPlayerWithAudio(){if(!this._audioEngineReady)throw new Error("Audio engine not ready");if(!this.parsedData)throw new Error("No parsed MIDI data available");const t=this.parsedData.structureMetadata||null,e=new f(this.audioEngine,this.parsedData,this.instrumentMap,t);this._setMidiPlayer(e)}_setMidiPlayer(t){this.midiPlayer=t,this.audioEngine=t.audioEngine,this._audioEngineReady=!0,this._completeMidiPlayerSetup()}_completeMidiPlayerSetup(){this._partOutputsMap.clear(),Object.keys(this.midiPlayer.parsedData.parts).forEach(t=>{const e=this.midiPlayer.getPartOutput(t);e&&this._partOutputsMap.set(t,e)}),this._setupEventDelegation(),this.state="ready"}_createDefaultInstrumentMap(t){const e={},i={soprano:{instrument:"choir_aahs",volume:1},alto:{instrument:"choir_aahs",volume:1},tenor:{instrument:"choir_aahs",volume:1},bass:{instrument:"choir_aahs",volume:1},piano:{instrument:"piano",volume:.8},organ:{instrument:"church_organ",volume:.7},strings:{instrument:"string_ensemble_1",volume:.6},flute:{instrument:"flute",volume:.8},trumpet:{instrument:"trumpet",volume:.7}};return Object.keys(t).forEach(s=>{const n=s.toLowerCase(),a=i[n]||i.piano;e[s]={instrument:a.instrument,volume:a.volume}}),e}}exports.AudioEngine=p;exports.AudioEngineUtils=T;exports.BeatMapper=v;exports.ChannelHandle=g;exports.MidiParser=C;exports.MidiPlayer=f;exports.PlaybackManager=F;exports.SpessaSynthAudioEngine=U;exports.SpessaSynthChannelHandle=k;
|
|
@@ -56,8 +56,8 @@ class g {
|
|
|
56
56
|
a.gain.value = i, n.connect(a);
|
|
57
57
|
const r = this.getMetronomeOutput();
|
|
58
58
|
r ? a.connect(r) : a.connect(this.audioContext.destination);
|
|
59
|
-
const
|
|
60
|
-
n.start(
|
|
59
|
+
const l = Math.max(t, this.audioContext.currentTime);
|
|
60
|
+
n.start(l);
|
|
61
61
|
} catch (s) {
|
|
62
62
|
console.warn("Buffer metronome playback failed:", s);
|
|
63
63
|
}
|
|
@@ -182,16 +182,16 @@ class y {
|
|
|
182
182
|
playNote(t, e, i, s) {
|
|
183
183
|
this._validateActive();
|
|
184
184
|
const n = this.engine.audioContext.currentTime, a = `${this.partId}_${t}_${e}_${Date.now()}`;
|
|
185
|
-
let r = t,
|
|
185
|
+
let r = t, l = s;
|
|
186
186
|
if (t < n) {
|
|
187
187
|
const c = n - t;
|
|
188
|
-
r = n,
|
|
188
|
+
r = n, l = Math.max(0, s - c);
|
|
189
189
|
}
|
|
190
|
-
if (
|
|
190
|
+
if (l <= 0)
|
|
191
191
|
return a;
|
|
192
|
-
const
|
|
192
|
+
const q = Math.max(0, (r - n) * 1e3), o = setTimeout(() => {
|
|
193
193
|
this.noteOn(e, i), this.scheduledEvents.delete(`${a}_on`);
|
|
194
|
-
},
|
|
194
|
+
}, q), h = q + l * 1e3, u = setTimeout(() => {
|
|
195
195
|
this.noteOff(e), this.scheduledEvents.delete(`${a}_off`);
|
|
196
196
|
}, h);
|
|
197
197
|
return this.scheduledEvents.set(`${a}_on`, o), this.scheduledEvents.set(`${a}_off`, u), a;
|
|
@@ -786,12 +786,12 @@ class M extends g {
|
|
|
786
786
|
const s = this.getMetronomeChannel(), n = this._getSynthesizer();
|
|
787
787
|
if (!s || !n)
|
|
788
788
|
return super.playMetronomeTick(t, e, i);
|
|
789
|
-
const a = 15, r = e ? 86 : 60,
|
|
789
|
+
const a = 15, r = e ? 86 : 60, q = Math.round(Math.min(127, Math.max(0, i * (e ? 127 : 100)))), o = this.audioContext.currentTime, h = Math.max(t, o), u = h - o;
|
|
790
790
|
n.post ? (n.post({
|
|
791
791
|
channelNumber: a,
|
|
792
792
|
type: "midiMessage",
|
|
793
793
|
data: {
|
|
794
|
-
messageData: [144 | a, r,
|
|
794
|
+
messageData: [144 | a, r, q],
|
|
795
795
|
channelOffset: 0,
|
|
796
796
|
force: !1,
|
|
797
797
|
options: {
|
|
@@ -811,10 +811,10 @@ class M extends g {
|
|
|
811
811
|
// Precise tick duration!
|
|
812
812
|
}
|
|
813
813
|
}
|
|
814
|
-
})) : u <= 0.01 ? (n.noteOn && n.noteOn(a, r,
|
|
814
|
+
})) : u <= 0.01 ? (n.noteOn && n.noteOn(a, r, q), setTimeout(() => {
|
|
815
815
|
n.noteOff && n.noteOff(a, r);
|
|
816
816
|
}, 100)) : setTimeout(() => {
|
|
817
|
-
n.noteOn && n.noteOn(a, r,
|
|
817
|
+
n.noteOn && n.noteOn(a, r, q), setTimeout(() => {
|
|
818
818
|
n.noteOff && n.noteOff(a, r);
|
|
819
819
|
}, 100);
|
|
820
820
|
}, u * 1e3);
|
|
@@ -919,8 +919,8 @@ class P {
|
|
|
919
919
|
return e;
|
|
920
920
|
const n = t.substring(i + 1).split("&");
|
|
921
921
|
for (const a of n) {
|
|
922
|
-
const [r,
|
|
923
|
-
r &&
|
|
922
|
+
const [r, l] = a.split("=");
|
|
923
|
+
r && l !== void 0 && (e[r] = l);
|
|
924
924
|
}
|
|
925
925
|
return e;
|
|
926
926
|
}
|
|
@@ -932,20 +932,20 @@ class P {
|
|
|
932
932
|
const e = new Uint8Array(t);
|
|
933
933
|
if (!(e[0] === 77 && e[1] === 84 && e[2] === 104 && e[3] === 100))
|
|
934
934
|
throw new Error("Not a valid MIDI file");
|
|
935
|
-
const i = this._bytesToNumber(e.slice(4, 8)), s = this._bytesToNumber(e.slice(8, 10)), n = this._bytesToNumber(e.slice(10, 12)), a = this._bytesToNumber(e.slice(12, 14)), r = a & 32768 ? null : a,
|
|
935
|
+
const i = this._bytesToNumber(e.slice(4, 8)), s = this._bytesToNumber(e.slice(8, 10)), n = this._bytesToNumber(e.slice(10, 12)), a = this._bytesToNumber(e.slice(12, 14)), r = a & 32768 ? null : a, l = {
|
|
936
936
|
format: s,
|
|
937
937
|
ticksPerBeat: r,
|
|
938
938
|
tracks: [],
|
|
939
939
|
duration: 0
|
|
940
940
|
};
|
|
941
|
-
let
|
|
941
|
+
let q = 8 + i;
|
|
942
942
|
for (let o = 0; o < n; o++)
|
|
943
|
-
if (e[
|
|
944
|
-
const h = this._bytesToNumber(e.slice(
|
|
945
|
-
|
|
943
|
+
if (e[q] === 77 && e[q + 1] === 84 && e[q + 2] === 114 && e[q + 3] === 107) {
|
|
944
|
+
const h = this._bytesToNumber(e.slice(q + 4, q + 8)), u = e.slice(q + 8, q + 8 + h), c = this._parseTrack(u);
|
|
945
|
+
l.tracks.push(c), q += 8 + h;
|
|
946
946
|
} else
|
|
947
|
-
throw new Error(`Invalid track header at position ${
|
|
948
|
-
return
|
|
947
|
+
throw new Error(`Invalid track header at position ${q}`);
|
|
948
|
+
return l;
|
|
949
949
|
}
|
|
950
950
|
/**
|
|
951
951
|
* Parse a single MIDI track
|
|
@@ -966,18 +966,18 @@ class P {
|
|
|
966
966
|
r = t[i++], a = a << 7 | r & 127;
|
|
967
967
|
while (r & 128);
|
|
968
968
|
s += a, r = t[i++];
|
|
969
|
-
let
|
|
969
|
+
let l = r;
|
|
970
970
|
if ((r & 128) === 0) {
|
|
971
971
|
if (n === null)
|
|
972
972
|
throw new Error("Running status byte encountered before status byte");
|
|
973
|
-
|
|
973
|
+
l = n, i--;
|
|
974
974
|
} else
|
|
975
|
-
n =
|
|
976
|
-
if (
|
|
977
|
-
const
|
|
975
|
+
n = l;
|
|
976
|
+
if (l === 255) {
|
|
977
|
+
const q = t[i++], o = this._readVariableLengthValue(t, i);
|
|
978
978
|
i += o.bytesRead;
|
|
979
979
|
const h = t.slice(i, i + o.value);
|
|
980
|
-
switch (i += o.value,
|
|
980
|
+
switch (i += o.value, q) {
|
|
981
981
|
case 3:
|
|
982
982
|
e.name = this._bytesToString(h);
|
|
983
983
|
break;
|
|
@@ -1014,75 +1014,75 @@ class P {
|
|
|
1014
1014
|
e.duration = s;
|
|
1015
1015
|
break;
|
|
1016
1016
|
}
|
|
1017
|
-
} else if ((
|
|
1018
|
-
const
|
|
1017
|
+
} else if ((l & 240) === 144) {
|
|
1018
|
+
const q = l & 15, o = t[i++], h = t[i++];
|
|
1019
1019
|
h > 0 ? e.notes.push({
|
|
1020
1020
|
type: "noteOn",
|
|
1021
1021
|
noteNumber: o,
|
|
1022
1022
|
velocity: h,
|
|
1023
1023
|
tick: s,
|
|
1024
|
-
channel:
|
|
1024
|
+
channel: q
|
|
1025
1025
|
}) : e.notes.push({
|
|
1026
1026
|
type: "noteOff",
|
|
1027
1027
|
noteNumber: o,
|
|
1028
1028
|
tick: s,
|
|
1029
|
-
channel:
|
|
1029
|
+
channel: q
|
|
1030
1030
|
});
|
|
1031
|
-
} else if ((
|
|
1032
|
-
const
|
|
1031
|
+
} else if ((l & 240) === 128) {
|
|
1032
|
+
const q = l & 15, o = t[i++];
|
|
1033
1033
|
t[i++], e.notes.push({
|
|
1034
1034
|
type: "noteOff",
|
|
1035
1035
|
noteNumber: o,
|
|
1036
1036
|
tick: s,
|
|
1037
|
-
channel:
|
|
1037
|
+
channel: q
|
|
1038
1038
|
});
|
|
1039
|
-
} else if (
|
|
1040
|
-
const
|
|
1041
|
-
i +=
|
|
1042
|
-
} else if ((
|
|
1043
|
-
const
|
|
1039
|
+
} else if (l === 240 || l === 247) {
|
|
1040
|
+
const q = this._readVariableLengthValue(t, i);
|
|
1041
|
+
i += q.bytesRead + q.value;
|
|
1042
|
+
} else if ((l & 240) === 176) {
|
|
1043
|
+
const q = l & 15, o = t[i++], h = t[i++];
|
|
1044
1044
|
e.events.push({
|
|
1045
1045
|
type: "controller",
|
|
1046
1046
|
controllerNumber: o,
|
|
1047
1047
|
value: h,
|
|
1048
|
-
channel:
|
|
1048
|
+
channel: q,
|
|
1049
1049
|
tick: s
|
|
1050
1050
|
});
|
|
1051
|
-
} else if ((
|
|
1052
|
-
const
|
|
1051
|
+
} else if ((l & 240) === 192) {
|
|
1052
|
+
const q = l & 15, o = t[i++];
|
|
1053
1053
|
e.events.push({
|
|
1054
1054
|
type: "programChange",
|
|
1055
1055
|
programNumber: o,
|
|
1056
|
-
channel:
|
|
1056
|
+
channel: q,
|
|
1057
1057
|
tick: s
|
|
1058
1058
|
});
|
|
1059
|
-
} else if ((
|
|
1060
|
-
const
|
|
1059
|
+
} else if ((l & 240) === 208) {
|
|
1060
|
+
const q = l & 15, o = t[i++];
|
|
1061
1061
|
e.events.push({
|
|
1062
1062
|
type: "channelAftertouch",
|
|
1063
1063
|
pressure: o,
|
|
1064
|
-
channel:
|
|
1064
|
+
channel: q,
|
|
1065
1065
|
tick: s
|
|
1066
1066
|
});
|
|
1067
|
-
} else if ((
|
|
1068
|
-
const
|
|
1067
|
+
} else if ((l & 240) === 224) {
|
|
1068
|
+
const q = l & 15, o = t[i++], u = (t[i++] << 7 | o) - 8192;
|
|
1069
1069
|
e.events.push({
|
|
1070
1070
|
type: "pitchBend",
|
|
1071
1071
|
value: u,
|
|
1072
|
-
channel:
|
|
1072
|
+
channel: q,
|
|
1073
1073
|
tick: s
|
|
1074
1074
|
});
|
|
1075
|
-
} else if ((
|
|
1076
|
-
const
|
|
1075
|
+
} else if ((l & 240) === 160) {
|
|
1076
|
+
const q = l & 15, o = t[i++], h = t[i++];
|
|
1077
1077
|
e.events.push({
|
|
1078
1078
|
type: "noteAftertouch",
|
|
1079
1079
|
noteNumber: o,
|
|
1080
1080
|
pressure: h,
|
|
1081
|
-
channel:
|
|
1081
|
+
channel: q,
|
|
1082
1082
|
tick: s
|
|
1083
1083
|
});
|
|
1084
1084
|
} else
|
|
1085
|
-
console.warn(`Unknown event type: ${
|
|
1085
|
+
console.warn(`Unknown event type: ${l.toString(16)} at position ${i - 1}`), i++;
|
|
1086
1086
|
}
|
|
1087
1087
|
return e;
|
|
1088
1088
|
}
|
|
@@ -1136,21 +1136,21 @@ class P {
|
|
|
1136
1136
|
});
|
|
1137
1137
|
}), s === 0 && (s = e * 8);
|
|
1138
1138
|
const n = [], a = i.filter((o) => o.type === "timeSignature").sort((o, h) => o.tick - h.tick);
|
|
1139
|
-
let r = { numerator: 4, denominator: 4 },
|
|
1140
|
-
for (;
|
|
1141
|
-
for (;
|
|
1142
|
-
r = a[
|
|
1139
|
+
let r = { numerator: 4, denominator: 4 }, l = 0, q = 0;
|
|
1140
|
+
for (; l < s; ) {
|
|
1141
|
+
for (; q < a.length && a[q].tick <= l; )
|
|
1142
|
+
r = a[q], q++;
|
|
1143
1143
|
let o;
|
|
1144
|
-
o =
|
|
1144
|
+
o = l + e * 4 * r.numerator / r.denominator;
|
|
1145
1145
|
const h = r.numerator, u = [], c = e * (4 / r.denominator);
|
|
1146
1146
|
for (let m = 0; m < h; m++) {
|
|
1147
|
-
const A =
|
|
1147
|
+
const A = l + m * c, f = this._ticksToTime(A, t);
|
|
1148
1148
|
u.push(f);
|
|
1149
1149
|
}
|
|
1150
1150
|
n.push({
|
|
1151
1151
|
sig: [r.numerator, r.denominator],
|
|
1152
1152
|
beats: u
|
|
1153
|
-
}),
|
|
1153
|
+
}), l = o;
|
|
1154
1154
|
}
|
|
1155
1155
|
this.parsedData.barStructure = n;
|
|
1156
1156
|
}
|
|
@@ -1168,35 +1168,35 @@ class P {
|
|
|
1168
1168
|
if (n.trackIndex !== void 0 && n.trackIndex !== null)
|
|
1169
1169
|
r = n.trackIndex, r >= 0 && r < t.tracks.length && (a = t.tracks[r]);
|
|
1170
1170
|
else if (n.trackName) {
|
|
1171
|
-
const
|
|
1172
|
-
|
|
1171
|
+
const q = t.tracks.findIndex((o) => o.name === n.trackName);
|
|
1172
|
+
q !== -1 && (a = t.tracks[q], r = q);
|
|
1173
1173
|
}
|
|
1174
1174
|
if (!a)
|
|
1175
1175
|
continue;
|
|
1176
|
-
const
|
|
1177
|
-
n.instrument !== void 0 && n.instrument !== null && (
|
|
1176
|
+
const l = this._extractPartDataFromTrack(a, r, t, i);
|
|
1177
|
+
n.instrument !== void 0 && n.instrument !== null && (l.defaultInstrument = this._resolveInstrument(n.instrument)), e[s] = l;
|
|
1178
1178
|
}
|
|
1179
1179
|
else
|
|
1180
1180
|
t.tracks.forEach((s, n) => {
|
|
1181
1181
|
if (!s.notes.length) return;
|
|
1182
1182
|
let a = null;
|
|
1183
1183
|
if (s.name) {
|
|
1184
|
-
const
|
|
1184
|
+
const q = s.name.toLowerCase();
|
|
1185
1185
|
for (const o of this.partNames)
|
|
1186
1186
|
if (o.length === 1) {
|
|
1187
|
-
if (
|
|
1187
|
+
if (q === o) {
|
|
1188
1188
|
a = o;
|
|
1189
1189
|
break;
|
|
1190
1190
|
}
|
|
1191
|
-
} else if (
|
|
1191
|
+
} else if (q.includes(o)) {
|
|
1192
1192
|
a = o;
|
|
1193
1193
|
break;
|
|
1194
1194
|
}
|
|
1195
1195
|
}
|
|
1196
1196
|
a || (a = s.name || `Track ${n + 1}`), a === "s" && (a = "soprano"), a === "a" && (a = "alto"), a === "t" && (a = "tenor"), a === "b" && (a = "bass");
|
|
1197
|
-
let r = a,
|
|
1197
|
+
let r = a, l = 2;
|
|
1198
1198
|
for (; e[r]; )
|
|
1199
|
-
r = `${a} ${
|
|
1199
|
+
r = `${a} ${l}`, l++;
|
|
1200
1200
|
a = r, e[a] = this._extractPartDataFromTrack(s, n, t, i);
|
|
1201
1201
|
});
|
|
1202
1202
|
this.parsedData.parts = e;
|
|
@@ -1235,17 +1235,17 @@ class P {
|
|
|
1235
1235
|
// Time in quarter notes
|
|
1236
1236
|
}));
|
|
1237
1237
|
n.sort((o, h) => o.startTick - h.startTick);
|
|
1238
|
-
const
|
|
1238
|
+
const l = t.events.filter((o) => o.type === "programChange").map((o) => ({
|
|
1239
1239
|
programNumber: o.programNumber,
|
|
1240
1240
|
tick: o.tick,
|
|
1241
1241
|
time: this._ticksToTime(o.tick, i)
|
|
1242
|
-
})).sort((o, h) => o.tick - h.tick),
|
|
1242
|
+
})).sort((o, h) => o.tick - h.tick), q = l.length > 0 ? l[0].programNumber : 0;
|
|
1243
1243
|
return {
|
|
1244
1244
|
notes: n,
|
|
1245
1245
|
lyrics: r,
|
|
1246
1246
|
trackIndex: e,
|
|
1247
|
-
programChanges:
|
|
1248
|
-
defaultInstrument:
|
|
1247
|
+
programChanges: l,
|
|
1248
|
+
defaultInstrument: q
|
|
1249
1249
|
};
|
|
1250
1250
|
}
|
|
1251
1251
|
/**
|
|
@@ -1315,23 +1315,23 @@ class P {
|
|
|
1315
1315
|
*/
|
|
1316
1316
|
_ticksToTime(t, e) {
|
|
1317
1317
|
const i = e.ticksPerBeat || 480, s = [];
|
|
1318
|
-
e.tracks.forEach((
|
|
1319
|
-
|
|
1320
|
-
|
|
1318
|
+
e.tracks.forEach((l) => {
|
|
1319
|
+
l.events.forEach((q) => {
|
|
1320
|
+
q.type === "tempo" && s.push(q);
|
|
1321
1321
|
});
|
|
1322
|
-
}), s.sort((
|
|
1322
|
+
}), s.sort((l, q) => l.tick - q.tick);
|
|
1323
1323
|
let n = 0, a = 0, r = 120;
|
|
1324
|
-
for (const
|
|
1325
|
-
if (
|
|
1326
|
-
if (
|
|
1327
|
-
const o = (
|
|
1328
|
-
n += o, a =
|
|
1324
|
+
for (const l of s) {
|
|
1325
|
+
if (l.tick > t) break;
|
|
1326
|
+
if (l.tick > a) {
|
|
1327
|
+
const o = (l.tick - a) / i * (60 / r);
|
|
1328
|
+
n += o, a = l.tick;
|
|
1329
1329
|
}
|
|
1330
|
-
r =
|
|
1330
|
+
r = l.bpm;
|
|
1331
1331
|
}
|
|
1332
1332
|
if (t > a) {
|
|
1333
|
-
const
|
|
1334
|
-
n +=
|
|
1333
|
+
const q = (t - a) / i * (60 / r);
|
|
1334
|
+
n += q;
|
|
1335
1335
|
}
|
|
1336
1336
|
return n;
|
|
1337
1337
|
}
|
|
@@ -1367,11 +1367,11 @@ class E {
|
|
|
1367
1367
|
throw new Error(`Invalid section index: ${n.section}`);
|
|
1368
1368
|
const r = n.section;
|
|
1369
1369
|
s[r] || (s[r] = 0), s[r]++;
|
|
1370
|
-
const
|
|
1371
|
-
for (let u =
|
|
1370
|
+
const l = s[r], q = n.from !== void 0 ? n.from : this._getSectionStartBar(t, n.section), o = n.to !== void 0 ? n.to : a.to, h = n.as || 1;
|
|
1371
|
+
for (let u = q; u <= o; u++)
|
|
1372
1372
|
this._shouldPlayBar(a, u, h) && i.push({
|
|
1373
1373
|
barNumber: u,
|
|
1374
|
-
repeat:
|
|
1374
|
+
repeat: l,
|
|
1375
1375
|
sectionIndex: n.section,
|
|
1376
1376
|
voltaTime: h
|
|
1377
1377
|
});
|
|
@@ -1386,21 +1386,21 @@ class E {
|
|
|
1386
1386
|
*/
|
|
1387
1387
|
generateBarOrderFromLegacyBars(t, e) {
|
|
1388
1388
|
const i = [];
|
|
1389
|
-
let s = 1, n = 0;
|
|
1390
|
-
for (const
|
|
1391
|
-
|
|
1392
|
-
const
|
|
1393
|
-
let q =
|
|
1389
|
+
let s = 1, n = 0, a;
|
|
1390
|
+
for (const r of t) {
|
|
1391
|
+
r.from !== void 0 && (s = r.from === -1 ? 0 : r.from, n = 0), r.timeSig !== void 0 && (a = r.timeSig);
|
|
1392
|
+
const l = r.repeat || 1;
|
|
1393
|
+
let q = r.beats;
|
|
1394
1394
|
for (; q > 0; ) {
|
|
1395
|
-
const
|
|
1396
|
-
q >=
|
|
1395
|
+
const h = (a !== void 0 ? a : this._getBeatsPerBar(s, e)) - n;
|
|
1396
|
+
q >= h ? (i.push({
|
|
1397
1397
|
barNumber: s,
|
|
1398
|
-
repeat:
|
|
1398
|
+
repeat: l,
|
|
1399
1399
|
sectionIndex: 0,
|
|
1400
1400
|
// Legacy format doesn't have sections
|
|
1401
1401
|
voltaTime: 1
|
|
1402
1402
|
// Legacy format doesn't have voltas
|
|
1403
|
-
}), q -=
|
|
1403
|
+
}), q -= h, n = 0, s === 0 ? s = 1 : s++) : (n += q, q = 0);
|
|
1404
1404
|
}
|
|
1405
1405
|
}
|
|
1406
1406
|
return n > 0 && i.push({
|
|
@@ -1452,14 +1452,14 @@ class E {
|
|
|
1452
1452
|
let n = 0, a = 0;
|
|
1453
1453
|
const r = [...e];
|
|
1454
1454
|
for (; a < t.length && n < r.length; ) {
|
|
1455
|
-
const
|
|
1456
|
-
if (s[
|
|
1455
|
+
const l = t[a], q = l.barNumber;
|
|
1456
|
+
if (s[q] === void 0) {
|
|
1457
1457
|
const c = r[n];
|
|
1458
1458
|
if (!c || !c.sig)
|
|
1459
1459
|
throw new Error(`Invalid MIDI bar structure at index ${n}`);
|
|
1460
|
-
s[
|
|
1460
|
+
s[q] = c.sig[0];
|
|
1461
1461
|
}
|
|
1462
|
-
const o = s[
|
|
1462
|
+
const o = s[q];
|
|
1463
1463
|
let h = r[n], u = h.sig[0];
|
|
1464
1464
|
for (; u < o && n + 1 < r.length; ) {
|
|
1465
1465
|
const c = r[n + 1], m = [
|
|
@@ -1486,7 +1486,7 @@ class E {
|
|
|
1486
1486
|
};
|
|
1487
1487
|
r[n] = b, r.splice(n + 1, 0, T), h = b;
|
|
1488
1488
|
}
|
|
1489
|
-
this._generateBeatsForBar(i,
|
|
1489
|
+
this._generateBeatsForBar(i, l, h, o), n++, a++;
|
|
1490
1490
|
}
|
|
1491
1491
|
if (a < t.length)
|
|
1492
1492
|
throw new Error(`Ran out of MIDI bars before completing score. Score bar ${a}/${t.length}, MIDI bar ${n}/${r.length}`);
|
|
@@ -1502,14 +1502,14 @@ class E {
|
|
|
1502
1502
|
throw new Error(`Invalid MIDI bar: missing beats array. Got: ${JSON.stringify(i)}`);
|
|
1503
1503
|
const a = n.slice(0, s);
|
|
1504
1504
|
for (let r = 1; r <= s; r++) {
|
|
1505
|
-
const
|
|
1505
|
+
const q = {
|
|
1506
1506
|
time: a[r - 1],
|
|
1507
1507
|
repeat: e.repeat,
|
|
1508
1508
|
bar: e.barNumber,
|
|
1509
1509
|
beat: r,
|
|
1510
1510
|
timeSig: s
|
|
1511
1511
|
};
|
|
1512
|
-
t.push(
|
|
1512
|
+
t.push(q);
|
|
1513
1513
|
}
|
|
1514
1514
|
}
|
|
1515
1515
|
/**
|
|
@@ -1807,25 +1807,25 @@ class p {
|
|
|
1807
1807
|
if (a) {
|
|
1808
1808
|
if (a.programChanges && a.programChanges.length > 0) {
|
|
1809
1809
|
let r = this.partProgramPointers.get(s) || 0;
|
|
1810
|
-
const
|
|
1811
|
-
for (; r <
|
|
1810
|
+
const l = a.programChanges;
|
|
1811
|
+
for (; r < l.length && l[r].time < e; )
|
|
1812
1812
|
r++;
|
|
1813
|
-
for (; r <
|
|
1814
|
-
const
|
|
1815
|
-
n.setInstrument(
|
|
1813
|
+
for (; r < l.length && l[r].time <= i; ) {
|
|
1814
|
+
const q = l[r];
|
|
1815
|
+
n.setInstrument(q.programNumber), r++;
|
|
1816
1816
|
}
|
|
1817
1817
|
this.partProgramPointers.set(s, r);
|
|
1818
1818
|
}
|
|
1819
1819
|
if (a.notes) {
|
|
1820
1820
|
let r = this.partNotePointers.get(s) || 0;
|
|
1821
|
-
const
|
|
1822
|
-
for (; r <
|
|
1821
|
+
const l = a.notes;
|
|
1822
|
+
for (; r < l.length && l[r].endTime < e; )
|
|
1823
1823
|
r++;
|
|
1824
|
-
for (; r <
|
|
1825
|
-
const
|
|
1826
|
-
if (
|
|
1827
|
-
const o = this.playbackStartTime +
|
|
1828
|
-
n.playNote(o,
|
|
1824
|
+
for (; r < l.length && l[r].startTime <= i; ) {
|
|
1825
|
+
const q = l[r];
|
|
1826
|
+
if (q.endTime - q.startTime >= 0.01) {
|
|
1827
|
+
const o = this.playbackStartTime + q.startTime / this.playbackSpeed, h = (q.endTime - q.startTime) / this.playbackSpeed;
|
|
1828
|
+
n.playNote(o, q.pitch, q.velocity, h);
|
|
1829
1829
|
}
|
|
1830
1830
|
r++;
|
|
1831
1831
|
}
|
|
@@ -2292,27 +2292,27 @@ class B {
|
|
|
2292
2292
|
throw new Error("No MIDI data loaded");
|
|
2293
2293
|
const e = t.delayBetweenParts ?? 0.3, i = t.duration ?? 0.5, s = t.velocity ?? 100, n = this.midiPlayer.getAllNextNotes(), a = t.partOrder ?? this.getPartNames();
|
|
2294
2294
|
let r = this.audioEngine.audioContext.currentTime + 0.01;
|
|
2295
|
-
const
|
|
2296
|
-
for (const
|
|
2297
|
-
const o = n[
|
|
2295
|
+
const l = [];
|
|
2296
|
+
for (const q of a) {
|
|
2297
|
+
const o = n[q];
|
|
2298
2298
|
if (!o) continue;
|
|
2299
|
-
const h = this.midiPlayer.getPartChannel(
|
|
2299
|
+
const h = this.midiPlayer.getPartChannel(q);
|
|
2300
2300
|
if (!h) continue;
|
|
2301
|
-
const u = this.midiPlayer.getPartOutput(
|
|
2301
|
+
const u = this.midiPlayer.getPartOutput(q);
|
|
2302
2302
|
u && u.gain.value === 0 || (h.playPreviewNote(o.pitch, {
|
|
2303
2303
|
startTime: r,
|
|
2304
2304
|
duration: i,
|
|
2305
2305
|
velocity: s,
|
|
2306
2306
|
instrument: t.instrument
|
|
2307
|
-
}),
|
|
2308
|
-
partName:
|
|
2307
|
+
}), l.push({
|
|
2308
|
+
partName: q,
|
|
2309
2309
|
pitch: o.pitch,
|
|
2310
2310
|
startTime: r
|
|
2311
2311
|
}), r += e);
|
|
2312
2312
|
}
|
|
2313
2313
|
return {
|
|
2314
|
-
parts:
|
|
2315
|
-
totalDuration:
|
|
2314
|
+
parts: l,
|
|
2315
|
+
totalDuration: l.length * e
|
|
2316
2316
|
};
|
|
2317
2317
|
}
|
|
2318
2318
|
// ========================================
|
|
@@ -2427,11 +2427,11 @@ class B {
|
|
|
2427
2427
|
for (; t[s].time > e; ) s--;
|
|
2428
2428
|
const a = t[s], r = t[s + 1];
|
|
2429
2429
|
r ? n = r.time - a.time : s > 0 && (n = a.time - t[s - 1].time);
|
|
2430
|
-
const
|
|
2430
|
+
const l = this.midiPlayer && this.midiPlayer.playbackSpeed || 1, q = n / l, o = a.timeSig === 1, h = o && r ? r.timeSig : a.timeSig, u = o ? h - 1 : a.beat > 1 ? a.beat - 1 : 0, c = i * h + u;
|
|
2431
2431
|
return {
|
|
2432
2432
|
totalBeats: c,
|
|
2433
|
-
duration: c *
|
|
2434
|
-
beatSequence: this._generateBeatSequence(c,
|
|
2433
|
+
duration: c * q,
|
|
2434
|
+
beatSequence: this._generateBeatSequence(c, q, h),
|
|
2435
2435
|
beatsPerBar: h,
|
|
2436
2436
|
startBeat: a
|
|
2437
2437
|
};
|
|
@@ -2573,12 +2573,12 @@ class B {
|
|
|
2573
2573
|
return;
|
|
2574
2574
|
const i = this.midiPlayer.getCurrentTime(), s = 0.1;
|
|
2575
2575
|
for (let n = this.nextBeatIndex; n < e.length; n++) {
|
|
2576
|
-
const a = e[n], r = this.midiPlayer.playbackSpeed || 1,
|
|
2577
|
-
if (
|
|
2576
|
+
const a = e[n], r = this.midiPlayer.playbackSpeed || 1, l = t + (a.time - i) / r;
|
|
2577
|
+
if (l > this.audioEngine.audioContext.currentTime + s)
|
|
2578
2578
|
break;
|
|
2579
|
-
if (
|
|
2580
|
-
const
|
|
2581
|
-
this._scheduleTickAtTime(
|
|
2579
|
+
if (l >= this.audioEngine.audioContext.currentTime - 0.01) {
|
|
2580
|
+
const q = Math.max(l, this.audioEngine.audioContext.currentTime + 1e-3), o = a.isDownbeat || a.beat === 1;
|
|
2581
|
+
this._scheduleTickAtTime(q, o), this.nextBeatIndex = n + 1;
|
|
2582
2582
|
}
|
|
2583
2583
|
}
|
|
2584
2584
|
}
|
|
@@ -2599,8 +2599,8 @@ class B {
|
|
|
2599
2599
|
if (n.time > s)
|
|
2600
2600
|
break;
|
|
2601
2601
|
if (a >= -0.025 && a <= 0.15) {
|
|
2602
|
-
const r = this.audioEngine.audioContext.currentTime + 5e-3,
|
|
2603
|
-
this._scheduleTickAtTime(
|
|
2602
|
+
const r = this.audioEngine.audioContext.currentTime + 5e-3, l = this.audioEngine.audioContext.currentTime + Math.max(a, 5e-3), q = Math.max(r, l), o = n.beat === 1;
|
|
2603
|
+
this._scheduleTickAtTime(q, o);
|
|
2604
2604
|
}
|
|
2605
2605
|
this.nextBeatIndex++;
|
|
2606
2606
|
}
|
package/package.json
CHANGED
package/src/lib/beat-mapper.js
CHANGED
|
@@ -95,6 +95,7 @@ class BeatMapper {
|
|
|
95
95
|
const barOrder = [];
|
|
96
96
|
let currentBar = 1; // Start at bar 1 by default
|
|
97
97
|
let beatsInCurrentBar = 0; // Track accumulated beats in current bar
|
|
98
|
+
let currentTimeSig = undefined; // Track time signature from metadata
|
|
98
99
|
|
|
99
100
|
for (const barEntry of bars) {
|
|
100
101
|
// Handle 'from' field - jump to a specific bar
|
|
@@ -104,6 +105,11 @@ class BeatMapper {
|
|
|
104
105
|
beatsInCurrentBar = 0; // Reset when jumping to a new bar
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
// Update time signature if specified in this entry
|
|
109
|
+
if (barEntry.timeSig !== undefined) {
|
|
110
|
+
currentTimeSig = barEntry.timeSig;
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
// Get repeat number (default to 1 if not specified)
|
|
108
114
|
const repeat = barEntry.repeat || 1;
|
|
109
115
|
|
|
@@ -111,7 +117,10 @@ class BeatMapper {
|
|
|
111
117
|
let remainingBeats = barEntry.beats;
|
|
112
118
|
|
|
113
119
|
while (remainingBeats > 0) {
|
|
114
|
-
|
|
120
|
+
// Use time signature from metadata if available, otherwise get from MIDI
|
|
121
|
+
const beatsPerBar = currentTimeSig !== undefined
|
|
122
|
+
? currentTimeSig
|
|
123
|
+
: this._getBeatsPerBar(currentBar, midiBarStructure);
|
|
115
124
|
const beatsNeeded = beatsPerBar - beatsInCurrentBar;
|
|
116
125
|
|
|
117
126
|
if (remainingBeats >= beatsNeeded) {
|