@al8b/audio 0.1.12 → 0.1.14
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/core/audio-core.js +24 -9
- package/dist/core/audio-core.js.map +1 -1
- package/dist/core/audio-core.mjs +24 -11
- package/dist/core/audio-core.mjs.map +1 -1
- package/dist/core/index.js +24 -11
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.mjs +24 -11
- package/dist/core/index.mjs.map +1 -1
- package/dist/devices/index.js +12 -5
- package/dist/devices/index.js.map +1 -1
- package/dist/devices/index.mjs +12 -5
- package/dist/devices/index.mjs.map +1 -1
- package/dist/devices/sound.d.mts +4 -0
- package/dist/devices/sound.d.ts +4 -0
- package/dist/devices/sound.js +12 -5
- package/dist/devices/sound.js.map +1 -1
- package/dist/devices/sound.mjs +12 -5
- package/dist/devices/sound.mjs.map +1 -1
- package/dist/index.js +36 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -16
- package/dist/index.mjs.map +1 -1
- package/package.json +33 -35
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/audio-core.ts","../src/constants.ts","../src/devices/beeper.ts","../src/core/audio-worklet.ts","../src/devices/music.ts","../src/devices/sound.ts"],"sourcesContent":["/**\n * @al8b/audio - Audio subsystem\n *\n * Architecture:\n * - core/: Audio orchestrator (context + VM interface)\n * - devices/: Beeper, Sound, Music implementations\n */\n\nexport { AudioCore } from \"./core\";\nexport * from \"./devices\";\n","/**\n * AudioCore - Web Audio API wrapper\n * Manages audio context, beeper, and sound/music playback\n */\n\nimport { APIErrorCode, reportRuntimeError } from \"@al8b/diagnostics\";\nimport { Beeper } from \"../devices/beeper\";\nimport { AUDIO_WORKLET_CODE } from \"./audio-worklet\";\n\n/** An actively playing sound/music that can be stopped */\ninterface PlayingHandle {\n\tstop: () => void;\n}\n\n/** Item that can be woken up on audio context activation */\ninterface WakeUpItem {\n\twakeUp: () => void;\n}\n\nexport class AudioCore {\n\tpublic context!: AudioContext;\n\tprivate buffer: string[] = [];\n\tprivate playing: PlayingHandle[] = [];\n\tprivate wakeupList: WakeUpItem[] = [];\n\tprivate workletNode?: AudioWorkletNode;\n\tprivate beeper?: Beeper;\n\tprivate runtime: any;\n\tprivate masterVolume: number = 1;\n\n\tconstructor(runtime: any) {\n\t\tthis.runtime = runtime;\n\t\tthis.getContext();\n\t}\n\n\t/**\n\t * Check if audio context is running\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this.context.state === \"running\";\n\t}\n\n\t/**\n\t * Add item to wakeup list (for mobile audio activation)\n\t */\n\tpublic addToWakeUpList(item: WakeUpItem): void {\n\t\tthis.wakeupList.push(item);\n\t}\n\n\tprivate interfaceCache: Record<string, any> | null = null;\n\n\t/**\n\t * Set master volume (0-1). Applied as a multiplier to all sound/music playback.\n\t */\n\tpublic setVolume(volume: number): void {\n\t\tthis.masterVolume = Math.max(0, Math.min(1, volume));\n\t}\n\n\t/**\n\t * Get current master volume (0-1)\n\t */\n\tpublic getVolume(): number {\n\t\treturn this.masterVolume;\n\t}\n\n\t/**\n\t * Get interface for game code\n\t */\n\tpublic getInterface() {\n\t\tif (this.interfaceCache) {\n\t\t\treturn this.interfaceCache;\n\t\t}\n\t\tthis.interfaceCache = {\n\t\t\tbeep: (sequence: string) => this.beep(sequence),\n\t\t\tcancelBeeps: () => this.cancelBeeps(),\n\t\t\tplaySound: (sound: any, volume?: number, pitch?: number, pan?: number, loopit?: boolean) =>\n\t\t\t\tthis.playSound(sound, volume, pitch, pan, loopit),\n\t\t\tplayMusic: (music: any, volume?: number, loopit?: boolean) => this.playMusic(music, volume, loopit),\n\t\t\tsetVolume: (volume: number) => this.setVolume(volume),\n\t\t\tgetVolume: () => this.getVolume(),\n\t\t\tstopAll: () => this.stopAll(),\n\t\t};\n\t\treturn this.interfaceCache;\n\t}\n\n\t/**\n\t * Play sound effect\n\t */\n\tpublic playSound(sound: any, volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): number {\n\t\tif (typeof sound === \"string\") {\n\t\t\tconst soundName = sound.replace(/\\//g, \"-\");\n\t\t\tconst s = this.runtime.sounds[soundName];\n\t\t\tif (!s) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7013, { soundName });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn s.play(volume * this.masterVolume, pitch, pan, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Play music\n\t */\n\tpublic playMusic(music: any, volume: number = 1, loopit: boolean = false): number {\n\t\tif (typeof music === \"string\") {\n\t\t\tconst musicName = music.replace(/\\//g, \"-\");\n\t\t\tconst m = this.runtime.music[musicName];\n\t\t\tif (!m) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7014, { musicName });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn m.play(volume * this.masterVolume, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Get or create audio context (lazy initialization - created on first use)\n\t * Note: Browser may suspend context until user interaction, which is handled automatically\n\t */\n\tpublic getContext(): AudioContext {\n\t\tif (!this.context) {\n\t\t\tconst AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;\n\t\t\t// Create context - browser may suspend until user interaction\n\t\t\tthis.context = new AudioContextClass();\n\n\t\t\t// If context is suspended, set up activation listeners\n\t\t\tif (this.context.state !== \"running\") {\n\t\t\t\tconst activate = () => {\n\t\t\t\t\tif (this.context && this.context.state !== \"running\") {\n\t\t\t\t\t\tthis.context.resume();\n\t\t\t\t\t\tif (this.beeper) {\n\t\t\t\t\t\t\tthis.start();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const item of this.wakeupList) {\n\t\t\t\t\t\t\titem.wakeUp();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clean up listeners\n\t\t\t\t\t\tdocument.body.removeEventListener(\"touchend\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"mouseup\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"click\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"keydown\", activate);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Add multiple event listeners for better compatibility\n\t\t\t\tdocument.body.addEventListener(\"touchend\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"mouseup\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"click\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"keydown\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t} else if (this.beeper) {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Start audio processor\n\t */\n\tpublic async start(): Promise<void> {\n\t\tif (this.workletNode) return;\n\n\t\ttry {\n\t\t\tconst blob = new Blob([AUDIO_WORKLET_CODE], {\n\t\t\t\ttype: \"application/javascript\",\n\t\t\t});\n\t\t\tconst url = URL.createObjectURL(blob);\n\n\t\t\tawait this.context.audioWorklet.addModule(url);\n\n\t\t\tthis.workletNode = new AudioWorkletNode(this.context, \"l8b-audio-processor\");\n\t\t\tthis.workletNode.connect(this.context.destination);\n\n\t\t\tthis.flushBuffer();\n\t\t} catch (e) {\n\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7012, { error: String(e) });\n\t\t}\n\t}\n\n\t/**\n\t * Flush buffered messages\n\t */\n\tprivate flushBuffer(): void {\n\t\tif (!this.workletNode) return;\n\n\t\twhile (this.buffer.length > 0) {\n\t\t\tthis.workletNode.port.postMessage(this.buffer.splice(0, 1)[0]);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create beeper\n\t */\n\tpublic getBeeper(): Beeper {\n\t\tif (!this.beeper) {\n\t\t\t// Create Beeper instance\n\t\t\tthis.beeper = new Beeper(this);\n\n\t\t\tif (this.context.state === \"running\") {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\t\treturn this.beeper;\n\t}\n\n\t/**\n\t * Play beep sequence\n\t */\n\tpublic beep(sequence: string): void {\n\t\tthis.getBeeper().beep(sequence);\n\t}\n\n\t/**\n\t * Add beeps to audio processor\n\t */\n\tpublic addBeeps(beeps: any[]): void {\n\t\tfor (const b of beeps) {\n\t\t\tb.duration *= this.context.sampleRate;\n\t\t\tb.increment = b.frequency / this.context.sampleRate;\n\t\t}\n\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel all beeps\n\t */\n\tpublic cancelBeeps(): void {\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tthis.stopAll();\n\t}\n\n\t/**\n\t * Add playing sound/music to list\n\t */\n\tpublic addPlaying(item: PlayingHandle): void {\n\t\tthis.playing.push(item);\n\t}\n\n\t/**\n\t * Remove playing sound/music from list\n\t */\n\tpublic removePlaying(item: PlayingHandle): void {\n\t\tconst index = this.playing.indexOf(item);\n\t\tif (index >= 0) {\n\t\t\tthis.playing.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Stop all playing sounds/music\n\t */\n\tpublic stopAll(): void {\n\t\tfor (const p of this.playing) {\n\t\t\ttry {\n\t\t\t\tp.stop();\n\t\t\t} catch (err) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7016, { error: String(err) });\n\t\t\t}\n\t\t}\n\t\tthis.playing = [];\n\t}\n}\n","/** A4 reference frequency in Hz (concert pitch) */\nexport const A4_FREQUENCY = 440;\n\n/** Ratio between adjacent semitones in equal temperament */\nexport const SEMITONE_RATIO = 2 ** (1 / 12);\n\n/** MIDI note number for A4 */\nexport const A4_MIDI_NOTE = 69;\n","/**\n * Beeper - Procedural sound generation from text sequences\n * Converts music notation strings into beep sequences\n * Example: \"square tempo 120 C4 D4 E4 F4\"\n */\nimport { A4_FREQUENCY, A4_MIDI_NOTE, SEMITONE_RATIO } from \"../constants\";\nexport class Beeper {\n\tprivate audio: any;\n\tprivate notes: Record<string | number, number> = {};\n\tprivate plainNotes: Record<string, number> = {};\n\tprivate currentOctave = 5;\n\tprivate currentDuration = 0.5;\n\tprivate currentVolume = 0.5;\n\tprivate currentSpan = 1;\n\tprivate currentWaveform = \"square\";\n\n\tconstructor(audio: any) {\n\t\tthis.audio = audio;\n\t\tthis.initializeNotes();\n\t}\n\n\t/**\n\t * Initialize note mappings\n\t */\n\tprivate initializeNotes(): void {\n\t\tconst noteNames = [\n\t\t\t[\"C\", \"DO\"],\n\t\t\t[\"C#\", \"DO#\", \"Db\", \"REb\"],\n\t\t\t[\"D\", \"RE\"],\n\t\t\t[\"D#\", \"RE#\", \"Eb\", \"MIb\"],\n\t\t\t[\"E\", \"MI\"],\n\t\t\t[\"F\", \"FA\"],\n\t\t\t[\"F#\", \"FA#\", \"Gb\", \"SOLb\"],\n\t\t\t[\"G\", \"SOL\"],\n\t\t\t[\"G#\", \"SOL#\", \"Ab\", \"LAb\"],\n\t\t\t[\"A\", \"LA\"],\n\t\t\t[\"A#\", \"LA#\", \"Bb\", \"SIb\"],\n\t\t\t[\"B\", \"SI\"],\n\t\t];\n\n\t\tfor (let i = 0; i <= 127; i++) {\n\t\t\tthis.notes[i] = i;\n\t\t\tconst oct = Math.floor(i / 12) - 1;\n\n\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\tthis.notes[n + oct] = i;\n\t\t\t}\n\n\t\t\tif (oct === -1) {\n\t\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\t\tthis.plainNotes[n] = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse and play beep sequence\n\t */\n\tpublic beep(input: string): void {\n\t\tlet status: string = \"normal\";\n\t\tconst sequence: any[] = [];\n\t\tconst loops: any[] = [];\n\t\tlet note: number | undefined;\n\n\t\tconst parsed = input.split(\" \");\n\n\t\tfor (const t of parsed) {\n\t\t\tif (t === \"\") continue;\n\n\t\t\tswitch (status) {\n\t\t\t\tcase \"normal\":\n\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t// Full note with octave (e.g., \"C4\")\n\t\t\t\t\t\tnote = this.notes[t];\n\t\t\t\t\t\tthis.currentOctave = Math.floor(note / 12);\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t// Note without octave (e.g., \"C\")\n\t\t\t\t\t\tnote = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if ([\"square\", \"sine\", \"saw\", \"noise\"].includes(t)) {\n\t\t\t\t\t\t// Waveform\n\t\t\t\t\t\tthis.currentWaveform = t;\n\t\t\t\t\t} else if ([\"tempo\", \"duration\", \"volume\", \"span\", \"loop\", \"to\"].includes(t)) {\n\t\t\t\t\t\t// Commands\n\t\t\t\t\t\tstatus = t;\n\t\t\t\t\t} else if (t === \"-\") {\n\t\t\t\t\t\t// Rest/silence\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (t === \"end\") {\n\t\t\t\t\t\t// End loop\n\t\t\t\t\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\t\t\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\t\t\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"tempo\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst tempo = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(tempo) && tempo > 0) {\n\t\t\t\t\t\tthis.currentDuration = 60 / tempo;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"duration\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst duration = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(duration) && duration > 0) {\n\t\t\t\t\t\tthis.currentDuration = duration / 1000;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"volume\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst volume = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(volume)) {\n\t\t\t\t\t\tthis.currentVolume = volume / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst span = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(span)) {\n\t\t\t\t\t\tthis.currentSpan = span / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"loop\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tloops.push({\n\t\t\t\t\t\tstart: sequence.length,\n\t\t\t\t\t});\n\t\t\t\t\tconst repeats = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(repeats)) {\n\t\t\t\t\t\tloops[loops.length - 1].repeats = repeats;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"to\":\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tif (note !== undefined) {\n\t\t\t\t\t\tlet n: number | undefined;\n\n\t\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.notes[t];\n\t\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (n !== undefined && n !== note) {\n\t\t\t\t\t\t\t// Generate slide from note to n\n\t\t\t\t\t\t\tconst step = n > note ? 1 : -1;\n\t\t\t\t\t\t\tfor (let i = note + step; step > 0 ? i <= n : i >= n; i += step) {\n\t\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (i - A4_MIDI_NOTE),\n\t\t\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnote = n;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Close any remaining loops\n\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\tsequence.push({\n\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\tvolume: 0,\n\t\t\t\tspan: this.currentSpan,\n\t\t\t\tduration: 0,\n\t\t\t\twaveform: this.currentWaveform,\n\t\t\t});\n\n\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t}\n\n\t\tthis.audio.addBeeps(sequence);\n\t}\n}\n","export const AUDIO_WORKLET_CODE = `\nclass L8bAudioProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.beeps = [];\n this.last = 0;\n this.port.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.name === \"cancel_beeps\") {\n this.beeps = [];\n } else if (data.name === \"beep\") {\n const seq = data.sequence;\n // Link sequence notes together\n for (let i = 0; i < seq.length; i++) {\n const note = seq[i];\n if (i > 0) {\n seq[i - 1].next = note;\n }\n // Resolve loopto index to actual note reference\n if (note.loopto != null) {\n note.loopto = seq[note.loopto];\n }\n // Initialize phase and time\n note.phase = 0;\n note.time = 0;\n }\n // Add first note to beeps queue\n if (seq.length > 0) {\n this.beeps.push(seq[0]);\n }\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n \n for (let i = 0; i < output.length; i++) {\n const channel = output[i];\n \n if (i > 0) {\n // Copy first channel to other channels\n for (let j = 0; j < channel.length; j++) {\n channel[j] = output[0][j];\n }\n } else {\n // Generate audio for first channel\n for (let j = 0; j < channel.length; j++) {\n let sig = 0;\n \n for (let k = this.beeps.length - 1; k >= 0; k--) {\n const b = this.beeps[k];\n let volume = b.volume;\n \n if (b.time / b.duration > b.span) {\n volume = 0;\n }\n \n // Generate waveform\n switch (b.waveform) {\n case \"square\":\n sig += b.phase > 0.5 ? volume : -volume;\n break;\n case \"saw\":\n sig += (b.phase * 2 - 1) * volume;\n break;\n case \"noise\":\n sig += (Math.random() * 2 - 1) * volume;\n break;\n default: // sine\n sig += Math.sin(b.phase * Math.PI * 2) * volume;\n }\n \n b.phase = (b.phase + b.increment) % 1;\n b.time += 1;\n \n if (b.time >= b.duration) {\n b.time = 0;\n \n if (b.loopto != null) {\n if (b.repeats != null && b.repeats > 0) {\n if (b.loopcount == null) {\n b.loopcount = 0;\n }\n b.loopcount++;\n \n if (b.loopcount >= b.repeats) {\n b.loopcount = 0;\n if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n }\n }\n \n this.last = this.last * 0.9 + sig * 0.1;\n channel[j] = this.last;\n }\n }\n }\n \n return true;\n }\n}\n\nregisterProcessor(\"l8b-audio-processor\", L8bAudioProcessor);\n`;\n","/**\n * Music - Music streaming and playback using HTML5 Audio\n * L8B Music class for LootiScript\n */\nexport class Music {\n\tpublic ready: number = 1;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tpublic tag: HTMLAudioElement;\n\tpublic playing: boolean = false;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string) {\n\t\tthis.audio = audio;\n\t\tthis.url = url;\n\t\tthis.tag = new Audio(this.url);\n\t\tthis.ready = 1;\n\t}\n\n\t/**\n\t * Play music with volume and loop (HTML5 Audio implementation)\n\t */\n\tpublic play(volume: number = 1, loopit: boolean = false): any {\n\t\tthis.playing = true;\n\t\tthis.tag.loop = !!loopit;\n\t\tthis.tag.volume = Math.max(0, Math.min(1, volume));\n\n\t\tif (this.audio.isStarted()) {\n\t\t\tthis.tag.play();\n\t\t} else {\n\t\t\tthis.audio.addToWakeUpList(this);\n\t\t}\n\n\t\tthis.audio.addPlaying(this);\n\n\t\treturn {\n\t\t\tplay: () => {\n\t\t\t\treturn this.tag.play();\n\t\t\t},\n\t\t\tstop: () => {\n\t\t\t\tthis.playing = false;\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.audio.removePlaying(this);\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tthis.tag.volume = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tgetPosition: () => {\n\t\t\t\treturn this.tag.currentTime;\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn this.tag.duration;\n\t\t\t},\n\t\t\tsetPosition: (pos: number) => {\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.tag.currentTime = Math.max(0, Math.min(this.tag.duration, pos));\n\t\t\t\tif (this.playing) {\n\t\t\t\t\tthis.tag.play();\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Wake up audio (for autoplay policy)\n\t */\n\tpublic wakeUp(): void {\n\t\tif (this.playing) {\n\t\t\tthis.tag.play();\n\t\t}\n\t}\n\n\t/**\n\t * Stop music\n\t */\n\tpublic stop(): void {\n\t\tthis.playing = false;\n\t\tthis.tag.pause();\n\t\tthis.audio.removePlaying(this);\n\t}\n}\n","/**\n * Sound - Sound effect playback\n * Handles loading and playing audio buffers\n */\nimport { APIErrorCode, reportRuntimeError } from \"@al8b/diagnostics\";\n\nexport class Sound {\n\tpublic ready: number = 0;\n\tpublic buffer?: AudioBuffer;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string | AudioBuffer) {\n\t\tthis.audio = audio;\n\n\t\tif (url instanceof AudioBuffer) {\n\t\t\tthis.buffer = url;\n\t\t\tthis.url = \"\";\n\t\t\tthis.ready = 1;\n\t\t} else {\n\t\t\tthis.url = url;\n\t\t\tthis.loadSound(url);\n\t\t}\n\t}\n\n\t/**\n\t * Load sound from URL\n\t */\n\tprivate loadSound(url: string): void {\n\t\tconst request = new XMLHttpRequest();\n\t\trequest.open(\"GET\", url, true);\n\t\trequest.responseType = \"arraybuffer\";\n\n\t\trequest.onload = () => {\n\t\t\tthis.audio.context.decodeAudioData(\n\t\t\t\trequest.response,\n\t\t\t\t(buffer: AudioBuffer) => {\n\t\t\t\t\tthis.buffer = buffer;\n\t\t\t\t\tthis.ready = 1;\n\t\t\t\t},\n\t\t\t\t(err: any) => {\n\t\t\t\t\treportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {\n\t\t\t\t\t\terror: `Audio decoding failed: ${String(err)}`,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\n\t\trequest.onerror = () => {\n\t\t\treportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {\n\t\t\t\terror: `Failed to load sound: ${url}`,\n\t\t\t});\n\t\t};\n\n\t\trequest.send();\n\t}\n\n\t/**\n\t * Play sound with volume, pitch, pan, and loop\n\t */\n\tpublic play(volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): any {\n\t\tif (!this.buffer)\n\t\t\treturn {\n\t\t\t\tstop: () => {},\n\t\t\t\tfinished: true,\n\t\t\t};\n\n\t\tconst context = this.audio.context;\n\n\t\t// Create source\n\t\tconst source = context.createBufferSource();\n\t\tsource.playbackRate.value = pitch;\n\t\tsource.buffer = this.buffer;\n\t\tif (loopit) source.loop = true;\n\n\t\t// Create gain node\n\t\tconst gain = context.createGain();\n\t\tgain.gain.value = volume;\n\n\t\t// Create panner\n\t\tconst panner: any = context.createPanner();\n\t\tpanner.panningModel = \"equalpower\";\n\t\tpanner.setPan = (p: number) => {\n\t\t\tpanner.setPosition(p, 0, 1 - Math.abs(p));\n\t\t};\n\t\tpanner.setPan(pan);\n\n\t\t// Connect nodes\n\t\tsource.connect(gain);\n\t\tgain.connect(panner);\n\t\tpanner.connect(context.destination);\n\n\t\t// Start playback\n\t\tsource.start();\n\n\t\t// Track playing sounds for looping\n\t\tlet playing: any = null;\n\t\tif (loopit) {\n\t\t\tplaying = {\n\t\t\t\tstop: () => {\n\t\t\t\t\tsource.stop();\n\t\t\t\t},\n\t\t\t};\n\t\t\tthis.audio.addPlaying(playing);\n\t\t}\n\n\t\t// Return control interface\n\t\tconst res = {\n\t\t\tstop: () => {\n\t\t\t\tsource.stop();\n\t\t\t\tif (playing) this.audio.removePlaying(playing);\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tgain.gain.value = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tsetPitch: (p: number) => {\n\t\t\t\tsource.playbackRate.value = Math.max(0.001, Math.min(1000, p));\n\t\t\t},\n\t\t\tsetPan: (p: number) => {\n\t\t\t\tpanner.setPan(Math.max(-1, Math.min(1, p)));\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn source.buffer ? source.buffer.duration : 0;\n\t\t\t},\n\t\t\tfinished: false,\n\t\t};\n\n\t\tsource.onended = () => {\n\t\t\tres.finished = true;\n\t\t};\n\n\t\treturn res;\n\t}\n\n\t/**\n\t * Create MicroSound class for procedural sound generation\n\t */\n\tpublic static createSoundClass(audiocore: any): any {\n\t\treturn class MicroSound {\n\t\t\tpublic static classname = \"Sound\";\n\t\t\tpublic channels: number;\n\t\t\tpublic length: number;\n\t\t\tpublic sampleRate: number;\n\t\t\tprivate sound: Sound;\n\t\t\tprivate buffer: AudioBuffer;\n\n\t\t\tconstructor(channels: number, length: number, sampleRate: number = 44100) {\n\t\t\t\t// Validate parameters\n\t\t\t\tchannels = channels === 1 ? 1 : 2;\n\t\t\t\tif (!(length > 1 && length < 44100 * 1000)) {\n\t\t\t\t\tlength = 44100;\n\t\t\t\t}\n\t\t\t\tif (!(sampleRate >= 8000 && sampleRate <= 96000)) {\n\t\t\t\t\tsampleRate = 44100;\n\t\t\t\t}\n\n\t\t\t\tthis.channels = channels;\n\t\t\t\tthis.length = length;\n\t\t\t\tthis.sampleRate = sampleRate;\n\n\t\t\t\t// Create audio buffer\n\t\t\t\tthis.buffer = audiocore.context.createBuffer(channels, length, sampleRate);\n\t\t\t\tthis.sound = new Sound(audiocore, this.buffer);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Play the sound\n\t\t\t */\n\t\t\tpublic play(volume?: number, pitch?: number, pan?: number, loopit?: boolean): any {\n\t\t\t\treturn this.sound.play(volume, pitch, pan, loopit);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Write sample value to buffer\n\t\t\t */\n\t\t\tpublic write(channel: number, position: number, value: number): void {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\tch1[position] = value;\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\tch2[position] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Read sample value from buffer\n\t\t\t */\n\t\t\tpublic read(channel: number, position: number): number {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\treturn ch1[position];\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\treturn ch2[position];\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;ACKA,yBAAiD;;;ACJ1C,IAAMA,eAAe;AAGrB,IAAMC,iBAAiB,MAAM,IAAI;AAGjC,IAAMC,eAAe;;;ACDrB,IAAMC,SAAN,MAAMA;EANb,OAMaA;;;EACJC;EACAC,QAAyC,CAAC;EAC1CC,aAAqC,CAAC;EACtCC,gBAAgB;EAChBC,kBAAkB;EAClBC,gBAAgB;EAChBC,cAAc;EACdC,kBAAkB;EAE1B,YAAYP,OAAY;AACvB,SAAKA,QAAQA;AACb,SAAKQ,gBAAe;EACrB;;;;EAKQA,kBAAwB;AAC/B,UAAMC,YAAY;MACjB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAQ;QAAM;;MACrB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;;AAGP,aAASC,IAAI,GAAGA,KAAK,KAAKA,KAAK;AAC9B,WAAKT,MAAMS,CAAAA,IAAKA;AAChB,YAAMC,MAAMC,KAAKC,MAAMH,IAAI,EAAA,IAAM;AAEjC,iBAAWI,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,aAAKT,MAAMa,IAAIH,GAAAA,IAAOD;MACvB;AAEA,UAAIC,QAAQ,IAAI;AACf,mBAAWG,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,eAAKR,WAAWY,CAAAA,IAAKJ;QACtB;MACD;IACD;EACD;;;;EAKOK,KAAKC,OAAqB;AAChC,QAAIC,SAAiB;AACrB,UAAMC,WAAkB,CAAA;AACxB,UAAMC,QAAe,CAAA;AACrB,QAAIC;AAEJ,UAAMC,SAASL,MAAMM,MAAM,GAAA;AAE3B,eAAWC,KAAKF,QAAQ;AACvB,UAAIE,MAAM,GAAI;AAEd,cAAQN,QAAAA;QACP,KAAK;AACJ,cAAI,KAAKhB,MAAMsB,CAAAA,MAAOC,QAAW;AAEhCJ,mBAAO,KAAKnB,MAAMsB,CAAAA;AAClB,iBAAKpB,gBAAgBS,KAAKC,MAAMO,OAAO,EAAA;AACvCF,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW,KAAKL,WAAWqB,CAAAA,MAAOC,QAAW;AAE5CJ,mBAAO,KAAKlB,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;AACjDe,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW;YAAC;YAAU;YAAQ;YAAO;YAAS2B,SAASX,CAAAA,GAAI;AAE1D,iBAAKhB,kBAAkBgB;UACxB,WAAW;YAAC;YAAS;YAAY;YAAU;YAAQ;YAAQ;YAAMW,SAASX,CAAAA,GAAI;AAE7EN,qBAASM;UACV,WAAWA,MAAM,KAAK;AAErBL,qBAASO,KAAK;cACbC,WAAWC;cACXG,QAAQ;cACRC,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAWgB,MAAM,OAAO;AAEvB,gBAAIJ,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5CjB,uBAASO,KAAK;gBACbC,WAAWC;gBACXG,QAAQ;gBACRC,MAAM,KAAKzB;gBACX0B,UAAU;gBACVC,UAAU,KAAK1B;cAChB,CAAA;AAEA,oBAAM6B,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,uBAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,uBAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;YAC7C;UACD;AACA;QAED,KAAK,SAAS;AACbvB,mBAAS;AACT,gBAAMwB,QAAQC,OAAOC,WAAWpB,CAAAA;AAChC,cAAI,CAACmB,OAAOE,MAAMH,KAAAA,KAAUA,QAAQ,GAAG;AACtC,iBAAKrC,kBAAkB,KAAKqC;UAC7B;AACA;QACD;QAEA,KAAK,YAAY;AAChBxB,mBAAS;AACT,gBAAMe,WAAWU,OAAOC,WAAWpB,CAAAA;AACnC,cAAI,CAACmB,OAAOE,MAAMZ,QAAAA,KAAaA,WAAW,GAAG;AAC5C,iBAAK5B,kBAAkB4B,WAAW;UACnC;AACA;QACD;QAEA,KAAK,UAAU;AACdf,mBAAS;AACT,gBAAMa,SAASY,OAAOC,WAAWpB,CAAAA;AACjC,cAAI,CAACmB,OAAOE,MAAMd,MAAAA,GAAS;AAC1B,iBAAKzB,gBAAgByB,SAAS;UAC/B;AACA;QACD;QAEA,KAAK,QAAQ;AACZb,mBAAS;AACT,gBAAMc,OAAOW,OAAOC,WAAWpB,CAAAA;AAC/B,cAAI,CAACmB,OAAOE,MAAMb,IAAAA,GAAO;AACxB,iBAAKzB,cAAcyB,OAAO;UAC3B;AACA;QACD;QAEA,KAAK,QAAQ;AACZd,mBAAS;AACTE,gBAAMM,KAAK;YACVc,OAAOrB,SAASiB;UACjB,CAAA;AACA,gBAAMK,UAAUE,OAAOC,WAAWpB,CAAAA;AAClC,cAAI,CAACmB,OAAOE,MAAMJ,OAAAA,GAAU;AAC3BrB,kBAAMA,MAAMgB,SAAS,CAAA,EAAGK,UAAUA;UACnC;AACA;QACD;QAEA,KAAK;AACJvB,mBAAS;AACT,cAAIG,SAASI,QAAW;AACvB,gBAAIV;AAEJ,gBAAI,KAAKb,MAAMsB,CAAAA,MAAOC,QAAW;AAChCV,kBAAI,KAAKb,MAAMsB,CAAAA;YAChB,WAAW,KAAKrB,WAAWqB,CAAAA,MAAOC,QAAW;AAC5CV,kBAAI,KAAKZ,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;YAC/C;AAEA,gBAAIW,MAAMU,UAAaV,MAAMM,MAAM;AAElC,oBAAMyB,OAAO/B,IAAIM,OAAO,IAAI;AAC5B,uBAASV,IAAIU,OAAOyB,MAAMA,OAAO,IAAInC,KAAKI,IAAIJ,KAAKI,GAAGJ,KAAKmC,MAAM;AAChE3B,yBAASO,KAAK;kBACbC,WAAWC,eAAeC,mBAAmBlB,IAAImB;kBACjDC,QAAQ,KAAKzB;kBACb0B,MAAM,KAAKzB;kBACX0B,UAAU,KAAK5B;kBACf6B,UAAU,KAAK1B;gBAChB,CAAA;cACD;AACAa,qBAAON;YACR;UACD;AACA;MACF;IACD;AAGA,QAAIK,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5C,YAAMC,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,eAASO,KAAK;QACbC,WAAWC;QACXG,QAAQ;QACRC,MAAM,KAAKzB;QACX0B,UAAU;QACVC,UAAU,KAAK1B;MAChB,CAAA;AAEAW,eAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,eAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;IAC7C;AAEA,SAAKxC,MAAM8C,SAAS5B,QAAAA;EACrB;AACD;;;AC7NO,IAAM6B,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AHmB3B,IAAMC,YAAN,MAAMA;EAnBb,OAmBaA;;;EACLC;EACCC,SAAmB,CAAA;EACnBC,UAA2B,CAAA;EAC3BC,aAA2B,CAAA;EAC3BC;EACAC;EACAC;EACAC,eAAuB;EAE/B,YAAYD,SAAc;AACzB,SAAKA,UAAUA;AACf,SAAKE,WAAU;EAChB;;;;EAKOC,YAAqB;AAC3B,WAAO,KAAKT,QAAQU,UAAU;EAC/B;;;;EAKOC,gBAAgBC,MAAwB;AAC9C,SAAKT,WAAWU,KAAKD,IAAAA;EACtB;EAEQE,iBAA6C;;;;EAK9CC,UAAUC,QAAsB;AACtC,SAAKT,eAAeU,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGH,MAAAA,CAAAA;EAC7C;;;;EAKOI,YAAoB;AAC1B,WAAO,KAAKb;EACb;;;;EAKOc,eAAe;AACrB,QAAI,KAAKP,gBAAgB;AACxB,aAAO,KAAKA;IACb;AACA,SAAKA,iBAAiB;MACrBQ,MAAM,wBAACC,aAAqB,KAAKD,KAAKC,QAAAA,GAAhC;MACNC,aAAa,6BAAM,KAAKA,YAAW,GAAtB;MACbC,WAAW,wBAACC,OAAYV,QAAiBW,OAAgBC,KAAcC,WACtE,KAAKJ,UAAUC,OAAOV,QAAQW,OAAOC,KAAKC,MAAAA,GADhC;MAEXC,WAAW,wBAACC,OAAYf,QAAiBa,WAAqB,KAAKC,UAAUC,OAAOf,QAAQa,MAAAA,GAAjF;MACXd,WAAW,wBAACC,WAAmB,KAAKD,UAAUC,MAAAA,GAAnC;MACXI,WAAW,6BAAM,KAAKA,UAAS,GAApB;MACXY,SAAS,6BAAM,KAAKA,QAAO,GAAlB;IACV;AACA,WAAO,KAAKlB;EACb;;;;EAKOW,UAAUC,OAAYV,SAAiB,GAAGW,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAe;AACrH,QAAI,OAAOH,UAAU,UAAU;AAC9B,YAAMO,YAAYP,MAAMQ,QAAQ,OAAO,GAAA;AACvC,YAAMC,IAAI,KAAK7B,QAAQ8B,OAAOH,SAAAA;AAC9B,UAAI,CAACE,GAAG;AACPE,mDAAmB,KAAK/B,SAASgC,UAAUC,gCAAaC,OAAO;UAAEP;QAAU,CAAA;AAC3E,eAAO;MACR;AACA,aAAOE,EAAEM,KAAKzB,SAAS,KAAKT,cAAcoB,OAAOC,KAAKC,MAAAA;IACvD;AACA,WAAO;EACR;;;;EAKOC,UAAUC,OAAYf,SAAiB,GAAGa,SAAkB,OAAe;AACjF,QAAI,OAAOE,UAAU,UAAU;AAC9B,YAAMW,YAAYX,MAAMG,QAAQ,OAAO,GAAA;AACvC,YAAMS,IAAI,KAAKrC,QAAQyB,MAAMW,SAAAA;AAC7B,UAAI,CAACC,GAAG;AACPN,mDAAmB,KAAK/B,SAASgC,UAAUC,gCAAaK,OAAO;UAAEF;QAAU,CAAA;AAC3E,eAAO;MACR;AACA,aAAOC,EAAEF,KAAKzB,SAAS,KAAKT,cAAcsB,MAAAA;IAC3C;AACA,WAAO;EACR;;;;;EAMOrB,aAA2B;AACjC,QAAI,CAAC,KAAKR,SAAS;AAClB,YAAM6C,oBAAqBC,OAAeC,gBAAiBD,OAAeE;AAE1E,WAAKhD,UAAU,IAAI6C,kBAAAA;AAGnB,UAAI,KAAK7C,QAAQU,UAAU,WAAW;AACrC,cAAMuC,WAAW,6BAAA;AAChB,cAAI,KAAKjD,WAAW,KAAKA,QAAQU,UAAU,WAAW;AACrD,iBAAKV,QAAQkD,OAAM;AACnB,gBAAI,KAAK7C,QAAQ;AAChB,mBAAK8C,MAAK;YACX;AACA,uBAAWvC,QAAQ,KAAKT,YAAY;AACnCS,mBAAKwC,OAAM;YACZ;AAEAC,qBAASC,KAAKC,oBAAoB,YAAYN,QAAAA;AAC9CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;AAC7CI,qBAASC,KAAKC,oBAAoB,SAASN,QAAAA;AAC3CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;UAC9C;QACD,GAfiB;AAkBjBI,iBAASC,KAAKE,iBAAiB,YAAYP,UAAU;UACpDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,SAASP,UAAU;UACjDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;MACD,WAAW,KAAKpD,QAAQ;AACvB,aAAK8C,MAAK;MACX;IACD;AAEA,WAAO,KAAKnD;EACb;;;;EAKA,MAAamD,QAAuB;AACnC,QAAI,KAAK/C,YAAa;AAEtB,QAAI;AACH,YAAMsD,OAAO,IAAIC,KAAK;QAACC;SAAqB;QAC3CC,MAAM;MACP,CAAA;AACA,YAAMC,MAAMC,IAAIC,gBAAgBN,IAAAA;AAEhC,YAAM,KAAK1D,QAAQiE,aAAaC,UAAUJ,GAAAA;AAE1C,WAAK1D,cAAc,IAAI+D,iBAAiB,KAAKnE,SAAS,qBAAA;AACtD,WAAKI,YAAYgE,QAAQ,KAAKpE,QAAQqE,WAAW;AAEjD,WAAKC,YAAW;IACjB,SAASC,GAAG;AACXlC,iDAAmB,KAAK/B,SAASgC,UAAUC,gCAAaiC,OAAO;QAAEC,OAAOC,OAAOH,CAAAA;MAAG,CAAA;IACnF;EACD;;;;EAKQD,cAAoB;AAC3B,QAAI,CAAC,KAAKlE,YAAa;AAEvB,WAAO,KAAKH,OAAO0E,SAAS,GAAG;AAC9B,WAAKvE,YAAYwE,KAAKC,YAAY,KAAK5E,OAAO6E,OAAO,GAAG,CAAA,EAAG,CAAA,CAAE;IAC9D;EACD;;;;EAKOC,YAAoB;AAC1B,QAAI,CAAC,KAAK1E,QAAQ;AAEjB,WAAKA,SAAS,IAAI2E,OAAO,IAAI;AAE7B,UAAI,KAAKhF,QAAQU,UAAU,WAAW;AACrC,aAAKyC,MAAK;MACX;IACD;AACA,WAAO,KAAK9C;EACb;;;;EAKOiB,KAAKC,UAAwB;AACnC,SAAKwD,UAAS,EAAGzD,KAAKC,QAAAA;EACvB;;;;EAKO0D,SAASC,OAAoB;AACnC,eAAWC,KAAKD,OAAO;AACtBC,QAAEC,YAAY,KAAKpF,QAAQqF;AAC3BF,QAAEG,YAAYH,EAAEI,YAAY,KAAKvF,QAAQqF;IAC1C;AAEA,QAAI,KAAKjF,aAAa;AACrB,WAAKA,YAAYwE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;QACNnE,UAAU2D;MACX,CAAA,CAAA;IAEF,OAAO;AACN,WAAKjF,OAAOY,KACX2E,KAAKC,UAAU;QACdC,MAAM;QACNnE,UAAU2D;MACX,CAAA,CAAA;IAEF;EACD;;;;EAKO1D,cAAoB;AAC1B,QAAI,KAAKpB,aAAa;AACrB,WAAKA,YAAYwE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF,OAAO;AACN,WAAKzF,OAAOY,KACX2E,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF;AAEA,SAAK1D,QAAO;EACb;;;;EAKO2D,WAAW/E,MAA2B;AAC5C,SAAKV,QAAQW,KAAKD,IAAAA;EACnB;;;;EAKOgF,cAAchF,MAA2B;AAC/C,UAAMiF,QAAQ,KAAK3F,QAAQ4F,QAAQlF,IAAAA;AACnC,QAAIiF,SAAS,GAAG;AACf,WAAK3F,QAAQ4E,OAAOe,OAAO,CAAA;IAC5B;EACD;;;;EAKO7D,UAAgB;AACtB,eAAW+D,KAAK,KAAK7F,SAAS;AAC7B,UAAI;AACH6F,UAAEC,KAAI;MACP,SAASC,KAAK;AACb5D,mDAAmB,KAAK/B,SAASgC,UAAUC,gCAAa2D,OAAO;UAAEzB,OAAOC,OAAOuB,GAAAA;QAAK,CAAA;MACrF;IACD;AACA,SAAK/F,UAAU,CAAA;EAChB;AACD;;;AIvSO,IAAMiG,QAAN,MAAMA;EAJb,OAIaA;;;EACLC,QAAgB;EAChBC,OAAe;EACfC;EACAC;EACAC,UAAmB;EAClBC;EAER,YAAYA,OAAYH,KAAa;AACpC,SAAKG,QAAQA;AACb,SAAKH,MAAMA;AACX,SAAKC,MAAM,IAAIG,MAAM,KAAKJ,GAAG;AAC7B,SAAKF,QAAQ;EACd;;;;EAKOO,KAAKC,SAAiB,GAAGC,SAAkB,OAAY;AAC7D,SAAKL,UAAU;AACf,SAAKD,IAAIO,OAAO,CAAC,CAACD;AAClB,SAAKN,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGL,MAAAA,CAAAA;AAE1C,QAAI,KAAKH,MAAMS,UAAS,GAAI;AAC3B,WAAKX,IAAII,KAAI;IACd,OAAO;AACN,WAAKF,MAAMU,gBAAgB,IAAI;IAChC;AAEA,SAAKV,MAAMW,WAAW,IAAI;AAE1B,WAAO;MACNT,MAAM,6BAAA;AACL,eAAO,KAAKJ,IAAII,KAAI;MACrB,GAFM;MAGNU,MAAM,6BAAA;AACL,aAAKb,UAAU;AACf,aAAKD,IAAIe,MAAK;AACd,aAAKb,MAAMc,cAAc,IAAI;MAC9B,GAJM;MAKNC,WAAW,wBAACC,MAAAA;AACX,aAAKlB,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGQ,CAAAA,CAAAA;MAC3C,GAFW;MAGXC,aAAa,6BAAA;AACZ,eAAO,KAAKnB,IAAIoB;MACjB,GAFa;MAGbC,aAAa,6BAAA;AACZ,eAAO,KAAKrB,IAAIsB;MACjB,GAFa;MAGbC,aAAa,wBAACC,QAAAA;AACb,aAAKxB,IAAIe,MAAK;AACd,aAAKf,IAAIoB,cAAcZ,KAAKC,IAAI,GAAGD,KAAKE,IAAI,KAAKV,IAAIsB,UAAUE,GAAAA,CAAAA;AAC/D,YAAI,KAAKvB,SAAS;AACjB,eAAKD,IAAII,KAAI;QACd;MACD,GANa;IAOd;EACD;;;;EAKOqB,SAAe;AACrB,QAAI,KAAKxB,SAAS;AACjB,WAAKD,IAAII,KAAI;IACd;EACD;;;;EAKOU,OAAa;AACnB,SAAKb,UAAU;AACf,SAAKD,IAAIe,MAAK;AACd,SAAKb,MAAMc,cAAc,IAAI;EAC9B;AACD;;;AC5EA,IAAAU,sBAAiD;AAE1C,IAAMC,QAAN,MAAMA,OAAAA;EANb,OAMaA;;;EACLC,QAAgB;EAChBC;EACAC,OAAe;EACfC;EACCC;EAER,YAAYA,OAAYD,KAA2B;AAClD,SAAKC,QAAQA;AAEb,QAAID,eAAeE,aAAa;AAC/B,WAAKJ,SAASE;AACd,WAAKA,MAAM;AACX,WAAKH,QAAQ;IACd,OAAO;AACN,WAAKG,MAAMA;AACX,WAAKG,UAAUH,GAAAA;IAChB;EACD;;;;EAKQG,UAAUH,KAAmB;AACpC,UAAMI,UAAU,IAAIC,eAAAA;AACpBD,YAAQE,KAAK,OAAON,KAAK,IAAA;AACzBI,YAAQG,eAAe;AAEvBH,YAAQI,SAAS,MAAA;AAChB,WAAKP,MAAMQ,QAAQC,gBAClBN,QAAQO,UACR,CAACb,WAAAA;AACA,aAAKA,SAASA;AACd,aAAKD,QAAQ;MACd,GACA,CAACe,QAAAA;AACAC,oDAAmB,KAAKZ,OAAOa,SAASC,UAAUC,iCAAaC,OAAO;UACrEC,OAAO,0BAA0BC,OAAOP,GAAAA,CAAAA;QACzC,CAAA;MACD,CAAA;IAEF;AAEAR,YAAQgB,UAAU,MAAA;AACjBP,kDAAmB,KAAKZ,OAAOa,SAASC,UAAUC,iCAAaC,OAAO;QACrEC,OAAO,yBAAyBlB,GAAAA;MACjC,CAAA;IACD;AAEAI,YAAQiB,KAAI;EACb;;;;EAKOC,KAAKC,SAAiB,GAAGC,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAY;AACjG,QAAI,CAAC,KAAK5B,OACT,QAAO;MACN6B,MAAM,6BAAA;MAAO,GAAP;MACNC,UAAU;IACX;AAED,UAAMnB,UAAU,KAAKR,MAAMQ;AAG3B,UAAMoB,SAASpB,QAAQqB,mBAAkB;AACzCD,WAAOE,aAAaC,QAAQR;AAC5BK,WAAO/B,SAAS,KAAKA;AACrB,QAAI4B,OAAQG,QAAOI,OAAO;AAG1B,UAAMC,OAAOzB,QAAQ0B,WAAU;AAC/BD,SAAKA,KAAKF,QAAQT;AAGlB,UAAMa,SAAc3B,QAAQ4B,aAAY;AACxCD,WAAOE,eAAe;AACtBF,WAAOG,SAAS,CAACC,MAAAA;AAChBJ,aAAOK,YAAYD,GAAG,GAAG,IAAIE,KAAKC,IAAIH,CAAAA,CAAAA;IACvC;AACAJ,WAAOG,OAAOd,GAAAA;AAGdI,WAAOe,QAAQV,IAAAA;AACfA,SAAKU,QAAQR,MAAAA;AACbA,WAAOQ,QAAQnC,QAAQoC,WAAW;AAGlChB,WAAOiB,MAAK;AAGZ,QAAIC,UAAe;AACnB,QAAIrB,QAAQ;AACXqB,gBAAU;QACTpB,MAAM,6BAAA;AACLE,iBAAOF,KAAI;QACZ,GAFM;MAGP;AACA,WAAK1B,MAAM+C,WAAWD,OAAAA;IACvB;AAGA,UAAME,MAAM;MACXtB,MAAM,6BAAA;AACLE,eAAOF,KAAI;AACX,YAAIoB,QAAS,MAAK9C,MAAMiD,cAAcH,OAAAA;AACtC,eAAO;MACR,GAJM;MAKNI,WAAW,wBAACC,MAAAA;AACXlB,aAAKA,KAAKF,QAAQU,KAAKW,IAAI,GAAGX,KAAKY,IAAI,GAAGF,CAAAA,CAAAA;MAC3C,GAFW;MAGXG,UAAU,wBAACf,MAAAA;AACVX,eAAOE,aAAaC,QAAQU,KAAKW,IAAI,MAAOX,KAAKY,IAAI,KAAMd,CAAAA,CAAAA;MAC5D,GAFU;MAGVD,QAAQ,wBAACC,MAAAA;AACRJ,eAAOG,OAAOG,KAAKW,IAAI,IAAIX,KAAKY,IAAI,GAAGd,CAAAA,CAAAA,CAAAA;MACxC,GAFQ;MAGRgB,aAAa,6BAAA;AACZ,eAAO3B,OAAO/B,SAAS+B,OAAO/B,OAAO2D,WAAW;MACjD,GAFa;MAGb7B,UAAU;IACX;AAEAC,WAAO6B,UAAU,MAAA;AAChBT,UAAIrB,WAAW;IAChB;AAEA,WAAOqB;EACR;;;;EAKA,OAAcU,iBAAiBC,WAAqB;AACnD,WAAO,MAAMC,WAAAA;MA5If,OA4IeA;;;MACZ,OAAcC,YAAY;MACnBC;MACAC;MACAC;MACCC;MACApE;MAER,YAAYiE,UAAkBC,QAAgBC,aAAqB,OAAO;AAEzEF,mBAAWA,aAAa,IAAI,IAAI;AAChC,YAAI,EAAEC,SAAS,KAAKA,SAAS,QAAQ,MAAO;AAC3CA,mBAAS;QACV;AACA,YAAI,EAAEC,cAAc,OAAQA,cAAc,OAAQ;AACjDA,uBAAa;QACd;AAEA,aAAKF,WAAWA;AAChB,aAAKC,SAASA;AACd,aAAKC,aAAaA;AAGlB,aAAKnE,SAAS8D,UAAUnD,QAAQ0D,aAAaJ,UAAUC,QAAQC,UAAAA;AAC/D,aAAKC,QAAQ,IAAItE,OAAMgE,WAAW,KAAK9D,MAAM;MAC9C;;;;MAKOwB,KAAKC,QAAiBC,OAAgBC,KAAcC,QAAuB;AACjF,eAAO,KAAKwC,MAAM5C,KAAKC,QAAQC,OAAOC,KAAKC,MAAAA;MAC5C;;;;MAKO0C,MAAMC,SAAiBC,UAAkBtC,OAAqB;AACpE,YAAIqC,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAKzE,OAAO0E,eAAe,CAAA;AACvCD,cAAID,QAAAA,IAAYtC;QACjB,WAAW,KAAK+B,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK3E,OAAO0E,eAAe,CAAA;AACvCC,cAAIH,QAAAA,IAAYtC;QACjB;MACD;;;;MAKO0C,KAAKL,SAAiBC,UAA0B;AACtD,YAAID,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAKzE,OAAO0E,eAAe,CAAA;AACvC,iBAAOD,IAAID,QAAAA;QACZ,WAAW,KAAKP,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK3E,OAAO0E,eAAe,CAAA;AACvC,iBAAOC,IAAIH,QAAAA;QACZ;AACA,eAAO;MACR;IACD;EACD;AACD;","names":["A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","Beeper","audio","notes","plainNotes","currentOctave","currentDuration","currentVolume","currentSpan","currentWaveform","initializeNotes","noteNames","i","oct","Math","floor","n","beep","input","status","sequence","loops","note","parsed","split","t","undefined","push","frequency","A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","volume","span","duration","waveform","includes","length","lop","splice","loopto","start","repeats","tempo","Number","parseFloat","isNaN","step","addBeeps","AUDIO_WORKLET_CODE","AudioCore","context","buffer","playing","wakeupList","workletNode","beeper","runtime","masterVolume","getContext","isStarted","state","addToWakeUpList","item","push","interfaceCache","setVolume","volume","Math","max","min","getVolume","getInterface","beep","sequence","cancelBeeps","playSound","sound","pitch","pan","loopit","playMusic","music","stopAll","soundName","replace","s","sounds","reportRuntimeError","listener","APIErrorCode","E7013","play","musicName","m","E7014","AudioContextClass","window","AudioContext","webkitAudioContext","activate","resume","start","wakeUp","document","body","removeEventListener","addEventListener","once","blob","Blob","AUDIO_WORKLET_CODE","type","url","URL","createObjectURL","audioWorklet","addModule","AudioWorkletNode","connect","destination","flushBuffer","e","E7012","error","String","length","port","postMessage","splice","getBeeper","Beeper","addBeeps","beeps","b","duration","sampleRate","increment","frequency","JSON","stringify","name","addPlaying","removePlaying","index","indexOf","p","stop","err","E7016","Music","ready","name","url","tag","playing","audio","Audio","play","volume","loopit","loop","Math","max","min","isStarted","addToWakeUpList","addPlaying","stop","pause","removePlaying","setVolume","v","getPosition","currentTime","getDuration","duration","setPosition","pos","wakeUp","import_diagnostics","Sound","ready","buffer","name","url","audio","AudioBuffer","loadSound","request","XMLHttpRequest","open","responseType","onload","context","decodeAudioData","response","err","reportRuntimeError","runtime","listener","APIErrorCode","E7016","error","String","onerror","send","play","volume","pitch","pan","loopit","stop","finished","source","createBufferSource","playbackRate","value","loop","gain","createGain","panner","createPanner","panningModel","setPan","p","setPosition","Math","abs","connect","destination","start","playing","addPlaying","res","removePlaying","setVolume","v","max","min","setPitch","getDuration","duration","onended","createSoundClass","audiocore","MicroSound","classname","channels","length","sampleRate","sound","createBuffer","write","channel","position","ch1","getChannelData","ch2","read"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/devices/beeper.ts","../src/core/audio-worklet.ts","../src/core/audio-core.ts","../src/devices/music.ts","../src/devices/sound.ts"],"sourcesContent":["/**\n * @al8b/audio - Audio subsystem\n *\n * Architecture:\n * - core/: Audio orchestrator (context + VM interface)\n * - devices/: Beeper, Sound, Music implementations\n */\n\nexport { AudioCore } from \"./core\";\nexport * from \"./devices\";\n","/** A4 reference frequency in Hz (concert pitch) */\nexport const A4_FREQUENCY = 440;\n\n/** Ratio between adjacent semitones in equal temperament */\nexport const SEMITONE_RATIO = 2 ** (1 / 12);\n\n/** MIDI note number for A4 */\nexport const A4_MIDI_NOTE = 69;\n","/**\n * Beeper - Procedural sound generation from text sequences\n * Converts music notation strings into beep sequences\n * Example: \"square tempo 120 C4 D4 E4 F4\"\n */\nimport { A4_FREQUENCY, A4_MIDI_NOTE, SEMITONE_RATIO } from \"../constants\";\nexport class Beeper {\n\tprivate audio: any;\n\tprivate notes: Record<string | number, number> = {};\n\tprivate plainNotes: Record<string, number> = {};\n\tprivate currentOctave = 5;\n\tprivate currentDuration = 0.5;\n\tprivate currentVolume = 0.5;\n\tprivate currentSpan = 1;\n\tprivate currentWaveform = \"square\";\n\n\tconstructor(audio: any) {\n\t\tthis.audio = audio;\n\t\tthis.initializeNotes();\n\t}\n\n\t/**\n\t * Initialize note mappings\n\t */\n\tprivate initializeNotes(): void {\n\t\tconst noteNames = [\n\t\t\t[\"C\", \"DO\"],\n\t\t\t[\"C#\", \"DO#\", \"Db\", \"REb\"],\n\t\t\t[\"D\", \"RE\"],\n\t\t\t[\"D#\", \"RE#\", \"Eb\", \"MIb\"],\n\t\t\t[\"E\", \"MI\"],\n\t\t\t[\"F\", \"FA\"],\n\t\t\t[\"F#\", \"FA#\", \"Gb\", \"SOLb\"],\n\t\t\t[\"G\", \"SOL\"],\n\t\t\t[\"G#\", \"SOL#\", \"Ab\", \"LAb\"],\n\t\t\t[\"A\", \"LA\"],\n\t\t\t[\"A#\", \"LA#\", \"Bb\", \"SIb\"],\n\t\t\t[\"B\", \"SI\"],\n\t\t];\n\n\t\tfor (let i = 0; i <= 127; i++) {\n\t\t\tthis.notes[i] = i;\n\t\t\tconst oct = Math.floor(i / 12) - 1;\n\n\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\tthis.notes[n + oct] = i;\n\t\t\t}\n\n\t\t\tif (oct === -1) {\n\t\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\t\tthis.plainNotes[n] = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse and play beep sequence\n\t */\n\tpublic beep(input: string): void {\n\t\tlet status: string = \"normal\";\n\t\tconst sequence: any[] = [];\n\t\tconst loops: any[] = [];\n\t\tlet note: number | undefined;\n\n\t\tconst parsed = input.split(\" \");\n\n\t\tfor (const t of parsed) {\n\t\t\tif (t === \"\") continue;\n\n\t\t\tswitch (status) {\n\t\t\t\tcase \"normal\":\n\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t// Full note with octave (e.g., \"C4\")\n\t\t\t\t\t\tnote = this.notes[t];\n\t\t\t\t\t\tthis.currentOctave = Math.floor(note / 12);\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t// Note without octave (e.g., \"C\")\n\t\t\t\t\t\tnote = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if ([\"square\", \"sine\", \"saw\", \"noise\"].includes(t)) {\n\t\t\t\t\t\t// Waveform\n\t\t\t\t\t\tthis.currentWaveform = t;\n\t\t\t\t\t} else if ([\"tempo\", \"duration\", \"volume\", \"span\", \"loop\", \"to\"].includes(t)) {\n\t\t\t\t\t\t// Commands\n\t\t\t\t\t\tstatus = t;\n\t\t\t\t\t} else if (t === \"-\") {\n\t\t\t\t\t\t// Rest/silence\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (t === \"end\") {\n\t\t\t\t\t\t// End loop\n\t\t\t\t\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\t\t\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\t\t\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"tempo\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst tempo = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(tempo) && tempo > 0) {\n\t\t\t\t\t\tthis.currentDuration = 60 / tempo;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"duration\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst duration = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(duration) && duration > 0) {\n\t\t\t\t\t\tthis.currentDuration = duration / 1000;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"volume\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst volume = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(volume)) {\n\t\t\t\t\t\tthis.currentVolume = volume / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst span = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(span)) {\n\t\t\t\t\t\tthis.currentSpan = span / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"loop\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tloops.push({\n\t\t\t\t\t\tstart: sequence.length,\n\t\t\t\t\t});\n\t\t\t\t\tconst repeats = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(repeats)) {\n\t\t\t\t\t\tloops[loops.length - 1].repeats = repeats;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"to\":\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tif (note !== undefined) {\n\t\t\t\t\t\tlet n: number | undefined;\n\n\t\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.notes[t];\n\t\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (n !== undefined && n !== note) {\n\t\t\t\t\t\t\t// Generate slide from note to n\n\t\t\t\t\t\t\tconst step = n > note ? 1 : -1;\n\t\t\t\t\t\t\tfor (let i = note + step; step > 0 ? i <= n : i >= n; i += step) {\n\t\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (i - A4_MIDI_NOTE),\n\t\t\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnote = n;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Close any remaining loops\n\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\tsequence.push({\n\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\tvolume: 0,\n\t\t\t\tspan: this.currentSpan,\n\t\t\t\tduration: 0,\n\t\t\t\twaveform: this.currentWaveform,\n\t\t\t});\n\n\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t}\n\n\t\tthis.audio.addBeeps(sequence);\n\t}\n}\n","export const AUDIO_WORKLET_CODE = `\nclass L8bAudioProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.beeps = [];\n this.last = 0;\n this.port.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.name === \"cancel_beeps\") {\n this.beeps = [];\n } else if (data.name === \"beep\") {\n const seq = data.sequence;\n // Link sequence notes together\n for (let i = 0; i < seq.length; i++) {\n const note = seq[i];\n if (i > 0) {\n seq[i - 1].next = note;\n }\n // Resolve loopto index to actual note reference\n if (note.loopto != null) {\n note.loopto = seq[note.loopto];\n }\n // Initialize phase and time\n note.phase = 0;\n note.time = 0;\n }\n // Add first note to beeps queue\n if (seq.length > 0) {\n this.beeps.push(seq[0]);\n }\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n \n for (let i = 0; i < output.length; i++) {\n const channel = output[i];\n \n if (i > 0) {\n // Copy first channel to other channels\n for (let j = 0; j < channel.length; j++) {\n channel[j] = output[0][j];\n }\n } else {\n // Generate audio for first channel\n for (let j = 0; j < channel.length; j++) {\n let sig = 0;\n \n for (let k = this.beeps.length - 1; k >= 0; k--) {\n const b = this.beeps[k];\n let volume = b.volume;\n \n if (b.time / b.duration > b.span) {\n volume = 0;\n }\n \n // Generate waveform\n switch (b.waveform) {\n case \"square\":\n sig += b.phase > 0.5 ? volume : -volume;\n break;\n case \"saw\":\n sig += (b.phase * 2 - 1) * volume;\n break;\n case \"noise\":\n sig += (Math.random() * 2 - 1) * volume;\n break;\n default: // sine\n sig += Math.sin(b.phase * Math.PI * 2) * volume;\n }\n \n b.phase = (b.phase + b.increment) % 1;\n b.time += 1;\n \n if (b.time >= b.duration) {\n b.time = 0;\n \n if (b.loopto != null) {\n if (b.repeats != null && b.repeats > 0) {\n if (b.loopcount == null) {\n b.loopcount = 0;\n }\n b.loopcount++;\n \n if (b.loopcount >= b.repeats) {\n b.loopcount = 0;\n if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n }\n }\n \n this.last = this.last * 0.9 + sig * 0.1;\n channel[j] = this.last;\n }\n }\n }\n \n return true;\n }\n}\n\nregisterProcessor(\"l8b-audio-processor\", L8bAudioProcessor);\n`;\n","/**\n * AudioCore - Web Audio API wrapper\n * Manages audio context, beeper, and sound/music playback\n */\n\nimport { Beeper } from \"../devices/beeper\";\nimport { AUDIO_WORKLET_CODE } from \"./audio-worklet\";\n\n/** An actively playing sound/music that can be stopped */\ninterface PlayingHandle {\n\tstop: () => void;\n}\n\n/** Item that can be woken up on audio context activation */\ninterface WakeUpItem {\n\twakeUp: () => void;\n}\n\nexport class AudioCore {\n\tpublic context!: AudioContext;\n\tprivate buffer: string[] = [];\n\tprivate playing: PlayingHandle[] = [];\n\tprivate wakeupList: WakeUpItem[] = [];\n\tprivate workletNode?: AudioWorkletNode;\n\tprivate beeper?: Beeper;\n\tprivate runtime: any;\n\tprivate masterVolume: number = 1;\n\n\tconstructor(runtime: any) {\n\t\tthis.runtime = runtime;\n\t\tthis.getContext();\n\t}\n\n\t/**\n\t * Check if audio context is running\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this.context.state === \"running\";\n\t}\n\n\t/**\n\t * Add item to wakeup list (for mobile audio activation)\n\t */\n\tpublic addToWakeUpList(item: WakeUpItem): void {\n\t\tthis.wakeupList.push(item);\n\t}\n\n\tprivate interfaceCache: Record<string, any> | null = null;\n\n\t/**\n\t * Set master volume (0-1). Applied as a multiplier to all sound/music playback.\n\t */\n\tpublic setVolume(volume: number): void {\n\t\tthis.masterVolume = Math.max(0, Math.min(1, volume));\n\t}\n\n\t/**\n\t * Get current master volume (0-1)\n\t */\n\tpublic getVolume(): number {\n\t\treturn this.masterVolume;\n\t}\n\n\t/**\n\t * Get interface for game code\n\t */\n\tpublic getInterface() {\n\t\tif (this.interfaceCache) {\n\t\t\treturn this.interfaceCache;\n\t\t}\n\t\tthis.interfaceCache = {\n\t\t\tbeep: (sequence: string) => this.beep(sequence),\n\t\t\tcancelBeeps: () => this.cancelBeeps(),\n\t\t\tplaySound: (sound: any, volume?: number, pitch?: number, pan?: number, loopit?: boolean) =>\n\t\t\t\tthis.playSound(sound, volume, pitch, pan, loopit),\n\t\t\tplayMusic: (music: any, volume?: number, loopit?: boolean) => this.playMusic(music, volume, loopit),\n\t\t\tsetVolume: (volume: number) => this.setVolume(volume),\n\t\t\tgetVolume: () => this.getVolume(),\n\t\t\tstopAll: () => this.stopAll(),\n\t\t};\n\t\treturn this.interfaceCache;\n\t}\n\n\t/**\n\t * Play sound effect\n\t */\n\tpublic playSound(sound: any, volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): number {\n\t\tif (typeof sound === \"string\") {\n\t\t\tconst soundName = sound.replace(/\\//g, \"-\");\n\t\t\tconst s = this.runtime.sounds[soundName];\n\t\t\tif (!s) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7013\", message: \"Sound not found\", data: { soundName } });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn s.play(volume * this.masterVolume, pitch, pan, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Play music\n\t */\n\tpublic playMusic(music: any, volume: number = 1, loopit: boolean = false): number {\n\t\tif (typeof music === \"string\") {\n\t\t\tconst musicName = music.replace(/\\//g, \"-\");\n\t\t\tconst m = this.runtime.music[musicName];\n\t\t\tif (!m) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7014\", message: \"Music not found\", data: { musicName } });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn m.play(volume * this.masterVolume, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Get or create audio context (lazy initialization - created on first use)\n\t * Note: Browser may suspend context until user interaction, which is handled automatically\n\t */\n\tpublic getContext(): AudioContext {\n\t\tif (!this.context) {\n\t\t\tconst AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;\n\t\t\t// Create context - browser may suspend until user interaction\n\t\t\tthis.context = new AudioContextClass();\n\n\t\t\t// If context is suspended, set up activation listeners\n\t\t\tif (this.context.state !== \"running\") {\n\t\t\t\tconst activate = () => {\n\t\t\t\t\tif (this.context && this.context.state !== \"running\") {\n\t\t\t\t\t\tthis.context.resume();\n\t\t\t\t\t\tif (this.beeper) {\n\t\t\t\t\t\t\tthis.start();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const item of this.wakeupList) {\n\t\t\t\t\t\t\titem.wakeUp();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clean up listeners\n\t\t\t\t\t\tdocument.body.removeEventListener(\"touchend\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"mouseup\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"click\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"keydown\", activate);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Add multiple event listeners for better compatibility\n\t\t\t\tdocument.body.addEventListener(\"touchend\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"mouseup\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"click\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"keydown\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t} else if (this.beeper) {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Start audio processor\n\t */\n\tpublic async start(): Promise<void> {\n\t\tif (this.workletNode) return;\n\n\t\ttry {\n\t\t\tconst blob = new Blob([AUDIO_WORKLET_CODE], {\n\t\t\t\ttype: \"application/javascript\",\n\t\t\t});\n\t\t\tconst url = URL.createObjectURL(blob);\n\n\t\t\tawait this.context.audioWorklet.addModule(url);\n\n\t\t\tthis.workletNode = new AudioWorkletNode(this.context, \"l8b-audio-processor\");\n\t\t\tthis.workletNode.connect(this.context.destination);\n\n\t\t\tthis.flushBuffer();\n\t\t} catch (e) {\n\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7012\", message: \"Audio worklet error\", data: { error: String(e) } });\n\t\t}\n\t}\n\n\t/**\n\t * Flush buffered messages\n\t */\n\tprivate flushBuffer(): void {\n\t\tif (!this.workletNode) return;\n\n\t\twhile (this.buffer.length > 0) {\n\t\t\tthis.workletNode.port.postMessage(this.buffer.splice(0, 1)[0]);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create beeper\n\t */\n\tpublic getBeeper(): Beeper {\n\t\tif (!this.beeper) {\n\t\t\t// Create Beeper instance\n\t\t\tthis.beeper = new Beeper(this);\n\n\t\t\tif (this.context.state === \"running\") {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\t\treturn this.beeper;\n\t}\n\n\t/**\n\t * Play beep sequence\n\t */\n\tpublic beep(sequence: string): void {\n\t\tthis.getBeeper().beep(sequence);\n\t}\n\n\t/**\n\t * Add beeps to audio processor\n\t */\n\tpublic addBeeps(beeps: any[]): void {\n\t\tfor (const b of beeps) {\n\t\t\tb.duration *= this.context.sampleRate;\n\t\t\tb.increment = b.frequency / this.context.sampleRate;\n\t\t}\n\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel all beeps\n\t */\n\tpublic cancelBeeps(): void {\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tthis.stopAll();\n\t}\n\n\t/**\n\t * Add playing sound/music to list\n\t */\n\tpublic addPlaying(item: PlayingHandle): void {\n\t\tthis.playing.push(item);\n\t}\n\n\t/**\n\t * Remove playing sound/music from list\n\t */\n\tpublic removePlaying(item: PlayingHandle): void {\n\t\tconst index = this.playing.indexOf(item);\n\t\tif (index >= 0) {\n\t\t\tthis.playing.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Stop all playing sounds/music\n\t */\n\tpublic stopAll(): void {\n\t\tfor (const p of this.playing) {\n\t\t\ttry {\n\t\t\t\tp.stop();\n\t\t\t} catch (err) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7016\", message: \"Audio error\", data: { error: String(err) } });\n\t\t\t}\n\t\t}\n\t\tthis.playing = [];\n\t}\n}\n","/**\n * Music - Music streaming and playback using HTML5 Audio\n * L8B Music class for LootiScript\n */\nexport class Music {\n\tpublic ready: number = 1;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tpublic tag: HTMLAudioElement;\n\tpublic playing: boolean = false;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string) {\n\t\tthis.audio = audio;\n\t\tthis.url = url;\n\t\tthis.tag = new Audio(this.url);\n\t\tthis.ready = 1;\n\t}\n\n\t/**\n\t * Play music with volume and loop (HTML5 Audio implementation)\n\t */\n\tpublic play(volume: number = 1, loopit: boolean = false): any {\n\t\tthis.playing = true;\n\t\tthis.tag.loop = !!loopit;\n\t\tthis.tag.volume = Math.max(0, Math.min(1, volume));\n\n\t\tif (this.audio.isStarted()) {\n\t\t\tthis.tag.play();\n\t\t} else {\n\t\t\tthis.audio.addToWakeUpList(this);\n\t\t}\n\n\t\tthis.audio.addPlaying(this);\n\n\t\treturn {\n\t\t\tplay: () => {\n\t\t\t\treturn this.tag.play();\n\t\t\t},\n\t\t\tstop: () => {\n\t\t\t\tthis.playing = false;\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.audio.removePlaying(this);\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tthis.tag.volume = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tgetPosition: () => {\n\t\t\t\treturn this.tag.currentTime;\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn this.tag.duration;\n\t\t\t},\n\t\t\tsetPosition: (pos: number) => {\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.tag.currentTime = Math.max(0, Math.min(this.tag.duration, pos));\n\t\t\t\tif (this.playing) {\n\t\t\t\t\tthis.tag.play();\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Wake up audio (for autoplay policy)\n\t */\n\tpublic wakeUp(): void {\n\t\tif (this.playing) {\n\t\t\tthis.tag.play();\n\t\t}\n\t}\n\n\t/**\n\t * Stop music\n\t */\n\tpublic stop(): void {\n\t\tthis.playing = false;\n\t\tthis.tag.pause();\n\t\tthis.audio.removePlaying(this);\n\t}\n}\n","/**\n * Sound - Sound effect playback\n * Handles loading and playing audio buffers\n */\n\nexport class Sound {\n\tpublic ready: number = 0;\n\tpublic buffer?: AudioBuffer;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string | AudioBuffer) {\n\t\tthis.audio = audio;\n\n\t\tif (url instanceof AudioBuffer) {\n\t\t\tthis.buffer = url;\n\t\t\tthis.url = \"\";\n\t\t\tthis.ready = 1;\n\t\t} else {\n\t\t\tthis.url = url;\n\t\t\tthis.loadSound(url);\n\t\t}\n\t}\n\n\t/**\n\t * Load sound from URL\n\t */\n\tprivate loadSound(url: string): void {\n\t\tconst request = new XMLHttpRequest();\n\t\trequest.open(\"GET\", url, true);\n\t\trequest.responseType = \"arraybuffer\";\n\n\t\trequest.onload = () => {\n\t\t\tthis.audio.context.decodeAudioData(\n\t\t\t\trequest.response,\n\t\t\t\t(buffer: AudioBuffer) => {\n\t\t\t\t\tthis.buffer = buffer;\n\t\t\t\t\tthis.ready = 1;\n\t\t\t\t},\n\t\t\t\t(err: any) => {\n\t\t\t\t\tthis.audio?.runtime?.listener?.reportError?.({\n\t\t\t\t\t\tcode: \"E7016\",\n\t\t\t\t\t\tmessage: \"Audio decoding failed\",\n\t\t\t\t\t\tdata: { error: `Audio decoding failed: ${String(err)}` },\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\n\t\trequest.onerror = () => {\n\t\t\tthis.audio?.runtime?.listener?.reportError?.({\n\t\t\t\tcode: \"E7016\",\n\t\t\t\tmessage: \"Failed to load sound\",\n\t\t\t\tdata: { error: `Failed to load sound: ${url}` },\n\t\t\t});\n\t\t};\n\n\t\trequest.send();\n\t}\n\n\t/**\n\t * Play sound with volume, pitch, pan, and loop\n\t */\n\tpublic play(volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): any {\n\t\tif (!this.buffer)\n\t\t\treturn {\n\t\t\t\tstop: () => {},\n\t\t\t\tfinished: true,\n\t\t\t};\n\n\t\tconst context = this.audio.context;\n\n\t\t// Create source\n\t\tconst source = context.createBufferSource();\n\t\tsource.playbackRate.value = pitch;\n\t\tsource.buffer = this.buffer;\n\t\tif (loopit) source.loop = true;\n\n\t\t// Create gain node\n\t\tconst gain = context.createGain();\n\t\tgain.gain.value = volume;\n\n\t\t// Create panner\n\t\tconst panner: any = context.createPanner();\n\t\tpanner.panningModel = \"equalpower\";\n\t\tpanner.setPan = (p: number) => {\n\t\t\tpanner.setPosition(p, 0, 1 - Math.abs(p));\n\t\t};\n\t\tpanner.setPan(pan);\n\n\t\t// Connect nodes\n\t\tsource.connect(gain);\n\t\tgain.connect(panner);\n\t\tpanner.connect(context.destination);\n\n\t\t// Start playback\n\t\tsource.start();\n\n\t\t// Track playing sounds for looping\n\t\tlet playing: any = null;\n\t\tif (loopit) {\n\t\t\tplaying = {\n\t\t\t\tstop: () => {\n\t\t\t\t\tsource.stop();\n\t\t\t\t},\n\t\t\t};\n\t\t\tthis.audio.addPlaying(playing);\n\t\t}\n\n\t\t// Return control interface\n\t\tconst res = {\n\t\t\tstop: () => {\n\t\t\t\tsource.stop();\n\t\t\t\tif (playing) this.audio.removePlaying(playing);\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tgain.gain.value = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tsetPitch: (p: number) => {\n\t\t\t\tsource.playbackRate.value = Math.max(0.001, Math.min(1000, p));\n\t\t\t},\n\t\t\tsetPan: (p: number) => {\n\t\t\t\tpanner.setPan(Math.max(-1, Math.min(1, p)));\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn source.buffer ? source.buffer.duration : 0;\n\t\t\t},\n\t\t\tfinished: false,\n\t\t};\n\n\t\tsource.onended = () => {\n\t\t\tres.finished = true;\n\t\t};\n\n\t\treturn res;\n\t}\n\n\t/**\n\t * Create MicroSound class for procedural sound generation\n\t */\n\tpublic static createSoundClass(audiocore: any): any {\n\t\treturn class MicroSound {\n\t\t\tpublic static classname = \"Sound\";\n\t\t\tpublic channels: number;\n\t\t\tpublic length: number;\n\t\t\tpublic sampleRate: number;\n\t\t\tprivate sound: Sound;\n\t\t\tprivate buffer: AudioBuffer;\n\n\t\t\tconstructor(channels: number, length: number, sampleRate: number = 44100) {\n\t\t\t\t// Validate parameters\n\t\t\t\tchannels = channels === 1 ? 1 : 2;\n\t\t\t\tif (!(length > 1 && length < 44100 * 1000)) {\n\t\t\t\t\tlength = 44100;\n\t\t\t\t}\n\t\t\t\tif (!(sampleRate >= 8000 && sampleRate <= 96000)) {\n\t\t\t\t\tsampleRate = 44100;\n\t\t\t\t}\n\n\t\t\t\tthis.channels = channels;\n\t\t\t\tthis.length = length;\n\t\t\t\tthis.sampleRate = sampleRate;\n\n\t\t\t\t// Create audio buffer\n\t\t\t\tthis.buffer = audiocore.context.createBuffer(channels, length, sampleRate);\n\t\t\t\tthis.sound = new Sound(audiocore, this.buffer);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Play the sound\n\t\t\t */\n\t\t\tpublic play(volume?: number, pitch?: number, pan?: number, loopit?: boolean): any {\n\t\t\t\treturn this.sound.play(volume, pitch, pan, loopit);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Write sample value to buffer\n\t\t\t */\n\t\t\tpublic write(channel: number, position: number, value: number): void {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\tch1[position] = value;\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\tch2[position] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Read sample value from buffer\n\t\t\t */\n\t\t\tpublic read(channel: number, position: number): number {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\treturn ch1[position];\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\treturn ch2[position];\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":"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","names":["A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","Beeper","audio","notes","plainNotes","currentOctave","currentDuration","currentVolume","currentSpan","currentWaveform","initializeNotes","noteNames","i","oct","Math","floor","n","beep","input","status","sequence","loops","note","parsed","split","t","undefined","push","frequency","A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","volume","span","duration","waveform","includes","length","lop","splice","loopto","start","repeats","tempo","Number","parseFloat","isNaN","step","addBeeps","AUDIO_WORKLET_CODE","AudioCore","context","buffer","playing","wakeupList","workletNode","beeper","runtime","masterVolume","getContext","isStarted","state","addToWakeUpList","item","push","interfaceCache","setVolume","volume","Math","max","min","getVolume","getInterface","beep","sequence","cancelBeeps","playSound","sound","pitch","pan","loopit","playMusic","music","stopAll","soundName","replace","s","sounds","listener","reportError","code","message","data","play","musicName","m","AudioContextClass","window","AudioContext","webkitAudioContext","activate","resume","start","wakeUp","document","body","removeEventListener","addEventListener","once","blob","Blob","AUDIO_WORKLET_CODE","type","url","URL","createObjectURL","audioWorklet","addModule","AudioWorkletNode","connect","destination","flushBuffer","e","error","String","length","port","postMessage","splice","getBeeper","Beeper","addBeeps","beeps","b","duration","sampleRate","increment","frequency","JSON","stringify","name","addPlaying","removePlaying","index","indexOf","p","stop","err","Music","ready","name","url","tag","playing","audio","Audio","play","volume","loopit","loop","Math","max","min","isStarted","addToWakeUpList","addPlaying","stop","pause","removePlaying","setVolume","v","getPosition","currentTime","getDuration","duration","setPosition","pos","wakeUp","Sound","ready","buffer","name","url","audio","AudioBuffer","loadSound","request","XMLHttpRequest","open","responseType","onload","context","decodeAudioData","response","err","runtime","listener","reportError","code","message","data","error","String","onerror","send","play","volume","pitch","pan","loopit","stop","finished","source","createBufferSource","playbackRate","value","loop","gain","createGain","panner","createPanner","panningModel","setPan","p","setPosition","Math","abs","connect","destination","start","playing","addPlaying","res","removePlaying","setVolume","v","max","min","setPitch","getDuration","duration","onended","createSoundClass","audiocore","MicroSound","classname","channels","length","sampleRate","sound","createBuffer","write","channel","position","ch1","getChannelData","ch2","read"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
-
// src/core/audio-core.ts
|
|
5
|
-
import { APIErrorCode, reportRuntimeError } from "@al8b/diagnostics";
|
|
6
|
-
|
|
7
4
|
// src/constants.ts
|
|
8
5
|
var A4_FREQUENCY = 440;
|
|
9
6
|
var SEMITONE_RATIO = 2 ** (1 / 12);
|
|
@@ -452,8 +449,12 @@ var AudioCore = class {
|
|
|
452
449
|
const soundName = sound.replace(/\//g, "-");
|
|
453
450
|
const s = this.runtime.sounds[soundName];
|
|
454
451
|
if (!s) {
|
|
455
|
-
|
|
456
|
-
|
|
452
|
+
this.runtime?.listener?.reportError?.({
|
|
453
|
+
code: "E7013",
|
|
454
|
+
message: "Sound not found",
|
|
455
|
+
data: {
|
|
456
|
+
soundName
|
|
457
|
+
}
|
|
457
458
|
});
|
|
458
459
|
return 0;
|
|
459
460
|
}
|
|
@@ -469,8 +470,12 @@ var AudioCore = class {
|
|
|
469
470
|
const musicName = music.replace(/\//g, "-");
|
|
470
471
|
const m = this.runtime.music[musicName];
|
|
471
472
|
if (!m) {
|
|
472
|
-
|
|
473
|
-
|
|
473
|
+
this.runtime?.listener?.reportError?.({
|
|
474
|
+
code: "E7014",
|
|
475
|
+
message: "Music not found",
|
|
476
|
+
data: {
|
|
477
|
+
musicName
|
|
478
|
+
}
|
|
474
479
|
});
|
|
475
480
|
return 0;
|
|
476
481
|
}
|
|
@@ -537,8 +542,12 @@ var AudioCore = class {
|
|
|
537
542
|
this.workletNode.connect(this.context.destination);
|
|
538
543
|
this.flushBuffer();
|
|
539
544
|
} catch (e) {
|
|
540
|
-
|
|
541
|
-
|
|
545
|
+
this.runtime?.listener?.reportError?.({
|
|
546
|
+
code: "E7012",
|
|
547
|
+
message: "Audio worklet error",
|
|
548
|
+
data: {
|
|
549
|
+
error: String(e)
|
|
550
|
+
}
|
|
542
551
|
});
|
|
543
552
|
}
|
|
544
553
|
}
|
|
@@ -627,8 +636,12 @@ var AudioCore = class {
|
|
|
627
636
|
try {
|
|
628
637
|
p.stop();
|
|
629
638
|
} catch (err) {
|
|
630
|
-
|
|
631
|
-
|
|
639
|
+
this.runtime?.listener?.reportError?.({
|
|
640
|
+
code: "E7016",
|
|
641
|
+
message: "Audio error",
|
|
642
|
+
data: {
|
|
643
|
+
error: String(err)
|
|
644
|
+
}
|
|
632
645
|
});
|
|
633
646
|
}
|
|
634
647
|
}
|
|
@@ -712,7 +725,6 @@ var Music = class {
|
|
|
712
725
|
};
|
|
713
726
|
|
|
714
727
|
// src/devices/sound.ts
|
|
715
|
-
import { APIErrorCode as APIErrorCode2, reportRuntimeError as reportRuntimeError2 } from "@al8b/diagnostics";
|
|
716
728
|
var Sound = class _Sound {
|
|
717
729
|
static {
|
|
718
730
|
__name(this, "Sound");
|
|
@@ -745,14 +757,22 @@ var Sound = class _Sound {
|
|
|
745
757
|
this.buffer = buffer;
|
|
746
758
|
this.ready = 1;
|
|
747
759
|
}, (err) => {
|
|
748
|
-
|
|
749
|
-
|
|
760
|
+
this.audio?.runtime?.listener?.reportError?.({
|
|
761
|
+
code: "E7016",
|
|
762
|
+
message: "Audio decoding failed",
|
|
763
|
+
data: {
|
|
764
|
+
error: `Audio decoding failed: ${String(err)}`
|
|
765
|
+
}
|
|
750
766
|
});
|
|
751
767
|
});
|
|
752
768
|
};
|
|
753
769
|
request.onerror = () => {
|
|
754
|
-
|
|
755
|
-
|
|
770
|
+
this.audio?.runtime?.listener?.reportError?.({
|
|
771
|
+
code: "E7016",
|
|
772
|
+
message: "Failed to load sound",
|
|
773
|
+
data: {
|
|
774
|
+
error: `Failed to load sound: ${url}`
|
|
775
|
+
}
|
|
756
776
|
});
|
|
757
777
|
};
|
|
758
778
|
request.send();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/audio-core.ts","../src/constants.ts","../src/devices/beeper.ts","../src/core/audio-worklet.ts","../src/devices/music.ts","../src/devices/sound.ts"],"sourcesContent":["/**\n * AudioCore - Web Audio API wrapper\n * Manages audio context, beeper, and sound/music playback\n */\n\nimport { APIErrorCode, reportRuntimeError } from \"@al8b/diagnostics\";\nimport { Beeper } from \"../devices/beeper\";\nimport { AUDIO_WORKLET_CODE } from \"./audio-worklet\";\n\n/** An actively playing sound/music that can be stopped */\ninterface PlayingHandle {\n\tstop: () => void;\n}\n\n/** Item that can be woken up on audio context activation */\ninterface WakeUpItem {\n\twakeUp: () => void;\n}\n\nexport class AudioCore {\n\tpublic context!: AudioContext;\n\tprivate buffer: string[] = [];\n\tprivate playing: PlayingHandle[] = [];\n\tprivate wakeupList: WakeUpItem[] = [];\n\tprivate workletNode?: AudioWorkletNode;\n\tprivate beeper?: Beeper;\n\tprivate runtime: any;\n\tprivate masterVolume: number = 1;\n\n\tconstructor(runtime: any) {\n\t\tthis.runtime = runtime;\n\t\tthis.getContext();\n\t}\n\n\t/**\n\t * Check if audio context is running\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this.context.state === \"running\";\n\t}\n\n\t/**\n\t * Add item to wakeup list (for mobile audio activation)\n\t */\n\tpublic addToWakeUpList(item: WakeUpItem): void {\n\t\tthis.wakeupList.push(item);\n\t}\n\n\tprivate interfaceCache: Record<string, any> | null = null;\n\n\t/**\n\t * Set master volume (0-1). Applied as a multiplier to all sound/music playback.\n\t */\n\tpublic setVolume(volume: number): void {\n\t\tthis.masterVolume = Math.max(0, Math.min(1, volume));\n\t}\n\n\t/**\n\t * Get current master volume (0-1)\n\t */\n\tpublic getVolume(): number {\n\t\treturn this.masterVolume;\n\t}\n\n\t/**\n\t * Get interface for game code\n\t */\n\tpublic getInterface() {\n\t\tif (this.interfaceCache) {\n\t\t\treturn this.interfaceCache;\n\t\t}\n\t\tthis.interfaceCache = {\n\t\t\tbeep: (sequence: string) => this.beep(sequence),\n\t\t\tcancelBeeps: () => this.cancelBeeps(),\n\t\t\tplaySound: (sound: any, volume?: number, pitch?: number, pan?: number, loopit?: boolean) =>\n\t\t\t\tthis.playSound(sound, volume, pitch, pan, loopit),\n\t\t\tplayMusic: (music: any, volume?: number, loopit?: boolean) => this.playMusic(music, volume, loopit),\n\t\t\tsetVolume: (volume: number) => this.setVolume(volume),\n\t\t\tgetVolume: () => this.getVolume(),\n\t\t\tstopAll: () => this.stopAll(),\n\t\t};\n\t\treturn this.interfaceCache;\n\t}\n\n\t/**\n\t * Play sound effect\n\t */\n\tpublic playSound(sound: any, volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): number {\n\t\tif (typeof sound === \"string\") {\n\t\t\tconst soundName = sound.replace(/\\//g, \"-\");\n\t\t\tconst s = this.runtime.sounds[soundName];\n\t\t\tif (!s) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7013, { soundName });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn s.play(volume * this.masterVolume, pitch, pan, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Play music\n\t */\n\tpublic playMusic(music: any, volume: number = 1, loopit: boolean = false): number {\n\t\tif (typeof music === \"string\") {\n\t\t\tconst musicName = music.replace(/\\//g, \"-\");\n\t\t\tconst m = this.runtime.music[musicName];\n\t\t\tif (!m) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7014, { musicName });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn m.play(volume * this.masterVolume, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Get or create audio context (lazy initialization - created on first use)\n\t * Note: Browser may suspend context until user interaction, which is handled automatically\n\t */\n\tpublic getContext(): AudioContext {\n\t\tif (!this.context) {\n\t\t\tconst AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;\n\t\t\t// Create context - browser may suspend until user interaction\n\t\t\tthis.context = new AudioContextClass();\n\n\t\t\t// If context is suspended, set up activation listeners\n\t\t\tif (this.context.state !== \"running\") {\n\t\t\t\tconst activate = () => {\n\t\t\t\t\tif (this.context && this.context.state !== \"running\") {\n\t\t\t\t\t\tthis.context.resume();\n\t\t\t\t\t\tif (this.beeper) {\n\t\t\t\t\t\t\tthis.start();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const item of this.wakeupList) {\n\t\t\t\t\t\t\titem.wakeUp();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clean up listeners\n\t\t\t\t\t\tdocument.body.removeEventListener(\"touchend\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"mouseup\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"click\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"keydown\", activate);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Add multiple event listeners for better compatibility\n\t\t\t\tdocument.body.addEventListener(\"touchend\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"mouseup\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"click\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"keydown\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t} else if (this.beeper) {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Start audio processor\n\t */\n\tpublic async start(): Promise<void> {\n\t\tif (this.workletNode) return;\n\n\t\ttry {\n\t\t\tconst blob = new Blob([AUDIO_WORKLET_CODE], {\n\t\t\t\ttype: \"application/javascript\",\n\t\t\t});\n\t\t\tconst url = URL.createObjectURL(blob);\n\n\t\t\tawait this.context.audioWorklet.addModule(url);\n\n\t\t\tthis.workletNode = new AudioWorkletNode(this.context, \"l8b-audio-processor\");\n\t\t\tthis.workletNode.connect(this.context.destination);\n\n\t\t\tthis.flushBuffer();\n\t\t} catch (e) {\n\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7012, { error: String(e) });\n\t\t}\n\t}\n\n\t/**\n\t * Flush buffered messages\n\t */\n\tprivate flushBuffer(): void {\n\t\tif (!this.workletNode) return;\n\n\t\twhile (this.buffer.length > 0) {\n\t\t\tthis.workletNode.port.postMessage(this.buffer.splice(0, 1)[0]);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create beeper\n\t */\n\tpublic getBeeper(): Beeper {\n\t\tif (!this.beeper) {\n\t\t\t// Create Beeper instance\n\t\t\tthis.beeper = new Beeper(this);\n\n\t\t\tif (this.context.state === \"running\") {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\t\treturn this.beeper;\n\t}\n\n\t/**\n\t * Play beep sequence\n\t */\n\tpublic beep(sequence: string): void {\n\t\tthis.getBeeper().beep(sequence);\n\t}\n\n\t/**\n\t * Add beeps to audio processor\n\t */\n\tpublic addBeeps(beeps: any[]): void {\n\t\tfor (const b of beeps) {\n\t\t\tb.duration *= this.context.sampleRate;\n\t\t\tb.increment = b.frequency / this.context.sampleRate;\n\t\t}\n\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel all beeps\n\t */\n\tpublic cancelBeeps(): void {\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tthis.stopAll();\n\t}\n\n\t/**\n\t * Add playing sound/music to list\n\t */\n\tpublic addPlaying(item: PlayingHandle): void {\n\t\tthis.playing.push(item);\n\t}\n\n\t/**\n\t * Remove playing sound/music from list\n\t */\n\tpublic removePlaying(item: PlayingHandle): void {\n\t\tconst index = this.playing.indexOf(item);\n\t\tif (index >= 0) {\n\t\t\tthis.playing.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Stop all playing sounds/music\n\t */\n\tpublic stopAll(): void {\n\t\tfor (const p of this.playing) {\n\t\t\ttry {\n\t\t\t\tp.stop();\n\t\t\t} catch (err) {\n\t\t\t\treportRuntimeError(this.runtime?.listener, APIErrorCode.E7016, { error: String(err) });\n\t\t\t}\n\t\t}\n\t\tthis.playing = [];\n\t}\n}\n","/** A4 reference frequency in Hz (concert pitch) */\nexport const A4_FREQUENCY = 440;\n\n/** Ratio between adjacent semitones in equal temperament */\nexport const SEMITONE_RATIO = 2 ** (1 / 12);\n\n/** MIDI note number for A4 */\nexport const A4_MIDI_NOTE = 69;\n","/**\n * Beeper - Procedural sound generation from text sequences\n * Converts music notation strings into beep sequences\n * Example: \"square tempo 120 C4 D4 E4 F4\"\n */\nimport { A4_FREQUENCY, A4_MIDI_NOTE, SEMITONE_RATIO } from \"../constants\";\nexport class Beeper {\n\tprivate audio: any;\n\tprivate notes: Record<string | number, number> = {};\n\tprivate plainNotes: Record<string, number> = {};\n\tprivate currentOctave = 5;\n\tprivate currentDuration = 0.5;\n\tprivate currentVolume = 0.5;\n\tprivate currentSpan = 1;\n\tprivate currentWaveform = \"square\";\n\n\tconstructor(audio: any) {\n\t\tthis.audio = audio;\n\t\tthis.initializeNotes();\n\t}\n\n\t/**\n\t * Initialize note mappings\n\t */\n\tprivate initializeNotes(): void {\n\t\tconst noteNames = [\n\t\t\t[\"C\", \"DO\"],\n\t\t\t[\"C#\", \"DO#\", \"Db\", \"REb\"],\n\t\t\t[\"D\", \"RE\"],\n\t\t\t[\"D#\", \"RE#\", \"Eb\", \"MIb\"],\n\t\t\t[\"E\", \"MI\"],\n\t\t\t[\"F\", \"FA\"],\n\t\t\t[\"F#\", \"FA#\", \"Gb\", \"SOLb\"],\n\t\t\t[\"G\", \"SOL\"],\n\t\t\t[\"G#\", \"SOL#\", \"Ab\", \"LAb\"],\n\t\t\t[\"A\", \"LA\"],\n\t\t\t[\"A#\", \"LA#\", \"Bb\", \"SIb\"],\n\t\t\t[\"B\", \"SI\"],\n\t\t];\n\n\t\tfor (let i = 0; i <= 127; i++) {\n\t\t\tthis.notes[i] = i;\n\t\t\tconst oct = Math.floor(i / 12) - 1;\n\n\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\tthis.notes[n + oct] = i;\n\t\t\t}\n\n\t\t\tif (oct === -1) {\n\t\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\t\tthis.plainNotes[n] = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse and play beep sequence\n\t */\n\tpublic beep(input: string): void {\n\t\tlet status: string = \"normal\";\n\t\tconst sequence: any[] = [];\n\t\tconst loops: any[] = [];\n\t\tlet note: number | undefined;\n\n\t\tconst parsed = input.split(\" \");\n\n\t\tfor (const t of parsed) {\n\t\t\tif (t === \"\") continue;\n\n\t\t\tswitch (status) {\n\t\t\t\tcase \"normal\":\n\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t// Full note with octave (e.g., \"C4\")\n\t\t\t\t\t\tnote = this.notes[t];\n\t\t\t\t\t\tthis.currentOctave = Math.floor(note / 12);\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t// Note without octave (e.g., \"C\")\n\t\t\t\t\t\tnote = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if ([\"square\", \"sine\", \"saw\", \"noise\"].includes(t)) {\n\t\t\t\t\t\t// Waveform\n\t\t\t\t\t\tthis.currentWaveform = t;\n\t\t\t\t\t} else if ([\"tempo\", \"duration\", \"volume\", \"span\", \"loop\", \"to\"].includes(t)) {\n\t\t\t\t\t\t// Commands\n\t\t\t\t\t\tstatus = t;\n\t\t\t\t\t} else if (t === \"-\") {\n\t\t\t\t\t\t// Rest/silence\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (t === \"end\") {\n\t\t\t\t\t\t// End loop\n\t\t\t\t\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\t\t\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\t\t\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"tempo\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst tempo = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(tempo) && tempo > 0) {\n\t\t\t\t\t\tthis.currentDuration = 60 / tempo;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"duration\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst duration = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(duration) && duration > 0) {\n\t\t\t\t\t\tthis.currentDuration = duration / 1000;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"volume\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst volume = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(volume)) {\n\t\t\t\t\t\tthis.currentVolume = volume / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst span = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(span)) {\n\t\t\t\t\t\tthis.currentSpan = span / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"loop\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tloops.push({\n\t\t\t\t\t\tstart: sequence.length,\n\t\t\t\t\t});\n\t\t\t\t\tconst repeats = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(repeats)) {\n\t\t\t\t\t\tloops[loops.length - 1].repeats = repeats;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"to\":\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tif (note !== undefined) {\n\t\t\t\t\t\tlet n: number | undefined;\n\n\t\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.notes[t];\n\t\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (n !== undefined && n !== note) {\n\t\t\t\t\t\t\t// Generate slide from note to n\n\t\t\t\t\t\t\tconst step = n > note ? 1 : -1;\n\t\t\t\t\t\t\tfor (let i = note + step; step > 0 ? i <= n : i >= n; i += step) {\n\t\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (i - A4_MIDI_NOTE),\n\t\t\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnote = n;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Close any remaining loops\n\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\tsequence.push({\n\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\tvolume: 0,\n\t\t\t\tspan: this.currentSpan,\n\t\t\t\tduration: 0,\n\t\t\t\twaveform: this.currentWaveform,\n\t\t\t});\n\n\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t}\n\n\t\tthis.audio.addBeeps(sequence);\n\t}\n}\n","export const AUDIO_WORKLET_CODE = `\nclass L8bAudioProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.beeps = [];\n this.last = 0;\n this.port.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.name === \"cancel_beeps\") {\n this.beeps = [];\n } else if (data.name === \"beep\") {\n const seq = data.sequence;\n // Link sequence notes together\n for (let i = 0; i < seq.length; i++) {\n const note = seq[i];\n if (i > 0) {\n seq[i - 1].next = note;\n }\n // Resolve loopto index to actual note reference\n if (note.loopto != null) {\n note.loopto = seq[note.loopto];\n }\n // Initialize phase and time\n note.phase = 0;\n note.time = 0;\n }\n // Add first note to beeps queue\n if (seq.length > 0) {\n this.beeps.push(seq[0]);\n }\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n \n for (let i = 0; i < output.length; i++) {\n const channel = output[i];\n \n if (i > 0) {\n // Copy first channel to other channels\n for (let j = 0; j < channel.length; j++) {\n channel[j] = output[0][j];\n }\n } else {\n // Generate audio for first channel\n for (let j = 0; j < channel.length; j++) {\n let sig = 0;\n \n for (let k = this.beeps.length - 1; k >= 0; k--) {\n const b = this.beeps[k];\n let volume = b.volume;\n \n if (b.time / b.duration > b.span) {\n volume = 0;\n }\n \n // Generate waveform\n switch (b.waveform) {\n case \"square\":\n sig += b.phase > 0.5 ? volume : -volume;\n break;\n case \"saw\":\n sig += (b.phase * 2 - 1) * volume;\n break;\n case \"noise\":\n sig += (Math.random() * 2 - 1) * volume;\n break;\n default: // sine\n sig += Math.sin(b.phase * Math.PI * 2) * volume;\n }\n \n b.phase = (b.phase + b.increment) % 1;\n b.time += 1;\n \n if (b.time >= b.duration) {\n b.time = 0;\n \n if (b.loopto != null) {\n if (b.repeats != null && b.repeats > 0) {\n if (b.loopcount == null) {\n b.loopcount = 0;\n }\n b.loopcount++;\n \n if (b.loopcount >= b.repeats) {\n b.loopcount = 0;\n if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n }\n }\n \n this.last = this.last * 0.9 + sig * 0.1;\n channel[j] = this.last;\n }\n }\n }\n \n return true;\n }\n}\n\nregisterProcessor(\"l8b-audio-processor\", L8bAudioProcessor);\n`;\n","/**\n * Music - Music streaming and playback using HTML5 Audio\n * L8B Music class for LootiScript\n */\nexport class Music {\n\tpublic ready: number = 1;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tpublic tag: HTMLAudioElement;\n\tpublic playing: boolean = false;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string) {\n\t\tthis.audio = audio;\n\t\tthis.url = url;\n\t\tthis.tag = new Audio(this.url);\n\t\tthis.ready = 1;\n\t}\n\n\t/**\n\t * Play music with volume and loop (HTML5 Audio implementation)\n\t */\n\tpublic play(volume: number = 1, loopit: boolean = false): any {\n\t\tthis.playing = true;\n\t\tthis.tag.loop = !!loopit;\n\t\tthis.tag.volume = Math.max(0, Math.min(1, volume));\n\n\t\tif (this.audio.isStarted()) {\n\t\t\tthis.tag.play();\n\t\t} else {\n\t\t\tthis.audio.addToWakeUpList(this);\n\t\t}\n\n\t\tthis.audio.addPlaying(this);\n\n\t\treturn {\n\t\t\tplay: () => {\n\t\t\t\treturn this.tag.play();\n\t\t\t},\n\t\t\tstop: () => {\n\t\t\t\tthis.playing = false;\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.audio.removePlaying(this);\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tthis.tag.volume = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tgetPosition: () => {\n\t\t\t\treturn this.tag.currentTime;\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn this.tag.duration;\n\t\t\t},\n\t\t\tsetPosition: (pos: number) => {\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.tag.currentTime = Math.max(0, Math.min(this.tag.duration, pos));\n\t\t\t\tif (this.playing) {\n\t\t\t\t\tthis.tag.play();\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Wake up audio (for autoplay policy)\n\t */\n\tpublic wakeUp(): void {\n\t\tif (this.playing) {\n\t\t\tthis.tag.play();\n\t\t}\n\t}\n\n\t/**\n\t * Stop music\n\t */\n\tpublic stop(): void {\n\t\tthis.playing = false;\n\t\tthis.tag.pause();\n\t\tthis.audio.removePlaying(this);\n\t}\n}\n","/**\n * Sound - Sound effect playback\n * Handles loading and playing audio buffers\n */\nimport { APIErrorCode, reportRuntimeError } from \"@al8b/diagnostics\";\n\nexport class Sound {\n\tpublic ready: number = 0;\n\tpublic buffer?: AudioBuffer;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string | AudioBuffer) {\n\t\tthis.audio = audio;\n\n\t\tif (url instanceof AudioBuffer) {\n\t\t\tthis.buffer = url;\n\t\t\tthis.url = \"\";\n\t\t\tthis.ready = 1;\n\t\t} else {\n\t\t\tthis.url = url;\n\t\t\tthis.loadSound(url);\n\t\t}\n\t}\n\n\t/**\n\t * Load sound from URL\n\t */\n\tprivate loadSound(url: string): void {\n\t\tconst request = new XMLHttpRequest();\n\t\trequest.open(\"GET\", url, true);\n\t\trequest.responseType = \"arraybuffer\";\n\n\t\trequest.onload = () => {\n\t\t\tthis.audio.context.decodeAudioData(\n\t\t\t\trequest.response,\n\t\t\t\t(buffer: AudioBuffer) => {\n\t\t\t\t\tthis.buffer = buffer;\n\t\t\t\t\tthis.ready = 1;\n\t\t\t\t},\n\t\t\t\t(err: any) => {\n\t\t\t\t\treportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {\n\t\t\t\t\t\terror: `Audio decoding failed: ${String(err)}`,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\n\t\trequest.onerror = () => {\n\t\t\treportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {\n\t\t\t\terror: `Failed to load sound: ${url}`,\n\t\t\t});\n\t\t};\n\n\t\trequest.send();\n\t}\n\n\t/**\n\t * Play sound with volume, pitch, pan, and loop\n\t */\n\tpublic play(volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): any {\n\t\tif (!this.buffer)\n\t\t\treturn {\n\t\t\t\tstop: () => {},\n\t\t\t\tfinished: true,\n\t\t\t};\n\n\t\tconst context = this.audio.context;\n\n\t\t// Create source\n\t\tconst source = context.createBufferSource();\n\t\tsource.playbackRate.value = pitch;\n\t\tsource.buffer = this.buffer;\n\t\tif (loopit) source.loop = true;\n\n\t\t// Create gain node\n\t\tconst gain = context.createGain();\n\t\tgain.gain.value = volume;\n\n\t\t// Create panner\n\t\tconst panner: any = context.createPanner();\n\t\tpanner.panningModel = \"equalpower\";\n\t\tpanner.setPan = (p: number) => {\n\t\t\tpanner.setPosition(p, 0, 1 - Math.abs(p));\n\t\t};\n\t\tpanner.setPan(pan);\n\n\t\t// Connect nodes\n\t\tsource.connect(gain);\n\t\tgain.connect(panner);\n\t\tpanner.connect(context.destination);\n\n\t\t// Start playback\n\t\tsource.start();\n\n\t\t// Track playing sounds for looping\n\t\tlet playing: any = null;\n\t\tif (loopit) {\n\t\t\tplaying = {\n\t\t\t\tstop: () => {\n\t\t\t\t\tsource.stop();\n\t\t\t\t},\n\t\t\t};\n\t\t\tthis.audio.addPlaying(playing);\n\t\t}\n\n\t\t// Return control interface\n\t\tconst res = {\n\t\t\tstop: () => {\n\t\t\t\tsource.stop();\n\t\t\t\tif (playing) this.audio.removePlaying(playing);\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tgain.gain.value = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tsetPitch: (p: number) => {\n\t\t\t\tsource.playbackRate.value = Math.max(0.001, Math.min(1000, p));\n\t\t\t},\n\t\t\tsetPan: (p: number) => {\n\t\t\t\tpanner.setPan(Math.max(-1, Math.min(1, p)));\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn source.buffer ? source.buffer.duration : 0;\n\t\t\t},\n\t\t\tfinished: false,\n\t\t};\n\n\t\tsource.onended = () => {\n\t\t\tres.finished = true;\n\t\t};\n\n\t\treturn res;\n\t}\n\n\t/**\n\t * Create MicroSound class for procedural sound generation\n\t */\n\tpublic static createSoundClass(audiocore: any): any {\n\t\treturn class MicroSound {\n\t\t\tpublic static classname = \"Sound\";\n\t\t\tpublic channels: number;\n\t\t\tpublic length: number;\n\t\t\tpublic sampleRate: number;\n\t\t\tprivate sound: Sound;\n\t\t\tprivate buffer: AudioBuffer;\n\n\t\t\tconstructor(channels: number, length: number, sampleRate: number = 44100) {\n\t\t\t\t// Validate parameters\n\t\t\t\tchannels = channels === 1 ? 1 : 2;\n\t\t\t\tif (!(length > 1 && length < 44100 * 1000)) {\n\t\t\t\t\tlength = 44100;\n\t\t\t\t}\n\t\t\t\tif (!(sampleRate >= 8000 && sampleRate <= 96000)) {\n\t\t\t\t\tsampleRate = 44100;\n\t\t\t\t}\n\n\t\t\t\tthis.channels = channels;\n\t\t\t\tthis.length = length;\n\t\t\t\tthis.sampleRate = sampleRate;\n\n\t\t\t\t// Create audio buffer\n\t\t\t\tthis.buffer = audiocore.context.createBuffer(channels, length, sampleRate);\n\t\t\t\tthis.sound = new Sound(audiocore, this.buffer);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Play the sound\n\t\t\t */\n\t\t\tpublic play(volume?: number, pitch?: number, pan?: number, loopit?: boolean): any {\n\t\t\t\treturn this.sound.play(volume, pitch, pan, loopit);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Write sample value to buffer\n\t\t\t */\n\t\t\tpublic write(channel: number, position: number, value: number): void {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\tch1[position] = value;\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\tch2[position] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Read sample value from buffer\n\t\t\t */\n\t\t\tpublic read(channel: number, position: number): number {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\treturn ch1[position];\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\treturn ch2[position];\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":";;;;AAKA,SAASA,cAAcC,0BAA0B;;;ACJ1C,IAAMC,eAAe;AAGrB,IAAMC,iBAAiB,MAAM,IAAI;AAGjC,IAAMC,eAAe;;;ACDrB,IAAMC,SAAN,MAAMA;EANb,OAMaA;;;EACJC;EACAC,QAAyC,CAAC;EAC1CC,aAAqC,CAAC;EACtCC,gBAAgB;EAChBC,kBAAkB;EAClBC,gBAAgB;EAChBC,cAAc;EACdC,kBAAkB;EAE1B,YAAYP,OAAY;AACvB,SAAKA,QAAQA;AACb,SAAKQ,gBAAe;EACrB;;;;EAKQA,kBAAwB;AAC/B,UAAMC,YAAY;MACjB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAQ;QAAM;;MACrB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;;AAGP,aAASC,IAAI,GAAGA,KAAK,KAAKA,KAAK;AAC9B,WAAKT,MAAMS,CAAAA,IAAKA;AAChB,YAAMC,MAAMC,KAAKC,MAAMH,IAAI,EAAA,IAAM;AAEjC,iBAAWI,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,aAAKT,MAAMa,IAAIH,GAAAA,IAAOD;MACvB;AAEA,UAAIC,QAAQ,IAAI;AACf,mBAAWG,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,eAAKR,WAAWY,CAAAA,IAAKJ;QACtB;MACD;IACD;EACD;;;;EAKOK,KAAKC,OAAqB;AAChC,QAAIC,SAAiB;AACrB,UAAMC,WAAkB,CAAA;AACxB,UAAMC,QAAe,CAAA;AACrB,QAAIC;AAEJ,UAAMC,SAASL,MAAMM,MAAM,GAAA;AAE3B,eAAWC,KAAKF,QAAQ;AACvB,UAAIE,MAAM,GAAI;AAEd,cAAQN,QAAAA;QACP,KAAK;AACJ,cAAI,KAAKhB,MAAMsB,CAAAA,MAAOC,QAAW;AAEhCJ,mBAAO,KAAKnB,MAAMsB,CAAAA;AAClB,iBAAKpB,gBAAgBS,KAAKC,MAAMO,OAAO,EAAA;AACvCF,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW,KAAKL,WAAWqB,CAAAA,MAAOC,QAAW;AAE5CJ,mBAAO,KAAKlB,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;AACjDe,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW;YAAC;YAAU;YAAQ;YAAO;YAAS2B,SAASX,CAAAA,GAAI;AAE1D,iBAAKhB,kBAAkBgB;UACxB,WAAW;YAAC;YAAS;YAAY;YAAU;YAAQ;YAAQ;YAAMW,SAASX,CAAAA,GAAI;AAE7EN,qBAASM;UACV,WAAWA,MAAM,KAAK;AAErBL,qBAASO,KAAK;cACbC,WAAWC;cACXG,QAAQ;cACRC,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAWgB,MAAM,OAAO;AAEvB,gBAAIJ,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5CjB,uBAASO,KAAK;gBACbC,WAAWC;gBACXG,QAAQ;gBACRC,MAAM,KAAKzB;gBACX0B,UAAU;gBACVC,UAAU,KAAK1B;cAChB,CAAA;AAEA,oBAAM6B,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,uBAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,uBAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;YAC7C;UACD;AACA;QAED,KAAK,SAAS;AACbvB,mBAAS;AACT,gBAAMwB,QAAQC,OAAOC,WAAWpB,CAAAA;AAChC,cAAI,CAACmB,OAAOE,MAAMH,KAAAA,KAAUA,QAAQ,GAAG;AACtC,iBAAKrC,kBAAkB,KAAKqC;UAC7B;AACA;QACD;QAEA,KAAK,YAAY;AAChBxB,mBAAS;AACT,gBAAMe,WAAWU,OAAOC,WAAWpB,CAAAA;AACnC,cAAI,CAACmB,OAAOE,MAAMZ,QAAAA,KAAaA,WAAW,GAAG;AAC5C,iBAAK5B,kBAAkB4B,WAAW;UACnC;AACA;QACD;QAEA,KAAK,UAAU;AACdf,mBAAS;AACT,gBAAMa,SAASY,OAAOC,WAAWpB,CAAAA;AACjC,cAAI,CAACmB,OAAOE,MAAMd,MAAAA,GAAS;AAC1B,iBAAKzB,gBAAgByB,SAAS;UAC/B;AACA;QACD;QAEA,KAAK,QAAQ;AACZb,mBAAS;AACT,gBAAMc,OAAOW,OAAOC,WAAWpB,CAAAA;AAC/B,cAAI,CAACmB,OAAOE,MAAMb,IAAAA,GAAO;AACxB,iBAAKzB,cAAcyB,OAAO;UAC3B;AACA;QACD;QAEA,KAAK,QAAQ;AACZd,mBAAS;AACTE,gBAAMM,KAAK;YACVc,OAAOrB,SAASiB;UACjB,CAAA;AACA,gBAAMK,UAAUE,OAAOC,WAAWpB,CAAAA;AAClC,cAAI,CAACmB,OAAOE,MAAMJ,OAAAA,GAAU;AAC3BrB,kBAAMA,MAAMgB,SAAS,CAAA,EAAGK,UAAUA;UACnC;AACA;QACD;QAEA,KAAK;AACJvB,mBAAS;AACT,cAAIG,SAASI,QAAW;AACvB,gBAAIV;AAEJ,gBAAI,KAAKb,MAAMsB,CAAAA,MAAOC,QAAW;AAChCV,kBAAI,KAAKb,MAAMsB,CAAAA;YAChB,WAAW,KAAKrB,WAAWqB,CAAAA,MAAOC,QAAW;AAC5CV,kBAAI,KAAKZ,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;YAC/C;AAEA,gBAAIW,MAAMU,UAAaV,MAAMM,MAAM;AAElC,oBAAMyB,OAAO/B,IAAIM,OAAO,IAAI;AAC5B,uBAASV,IAAIU,OAAOyB,MAAMA,OAAO,IAAInC,KAAKI,IAAIJ,KAAKI,GAAGJ,KAAKmC,MAAM;AAChE3B,yBAASO,KAAK;kBACbC,WAAWC,eAAeC,mBAAmBlB,IAAImB;kBACjDC,QAAQ,KAAKzB;kBACb0B,MAAM,KAAKzB;kBACX0B,UAAU,KAAK5B;kBACf6B,UAAU,KAAK1B;gBAChB,CAAA;cACD;AACAa,qBAAON;YACR;UACD;AACA;MACF;IACD;AAGA,QAAIK,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5C,YAAMC,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,eAASO,KAAK;QACbC,WAAWC;QACXG,QAAQ;QACRC,MAAM,KAAKzB;QACX0B,UAAU;QACVC,UAAU,KAAK1B;MAChB,CAAA;AAEAW,eAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,eAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;IAC7C;AAEA,SAAKxC,MAAM8C,SAAS5B,QAAAA;EACrB;AACD;;;AC7NO,IAAM6B,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AHmB3B,IAAMC,YAAN,MAAMA;EAnBb,OAmBaA;;;EACLC;EACCC,SAAmB,CAAA;EACnBC,UAA2B,CAAA;EAC3BC,aAA2B,CAAA;EAC3BC;EACAC;EACAC;EACAC,eAAuB;EAE/B,YAAYD,SAAc;AACzB,SAAKA,UAAUA;AACf,SAAKE,WAAU;EAChB;;;;EAKOC,YAAqB;AAC3B,WAAO,KAAKT,QAAQU,UAAU;EAC/B;;;;EAKOC,gBAAgBC,MAAwB;AAC9C,SAAKT,WAAWU,KAAKD,IAAAA;EACtB;EAEQE,iBAA6C;;;;EAK9CC,UAAUC,QAAsB;AACtC,SAAKT,eAAeU,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGH,MAAAA,CAAAA;EAC7C;;;;EAKOI,YAAoB;AAC1B,WAAO,KAAKb;EACb;;;;EAKOc,eAAe;AACrB,QAAI,KAAKP,gBAAgB;AACxB,aAAO,KAAKA;IACb;AACA,SAAKA,iBAAiB;MACrBQ,MAAM,wBAACC,aAAqB,KAAKD,KAAKC,QAAAA,GAAhC;MACNC,aAAa,6BAAM,KAAKA,YAAW,GAAtB;MACbC,WAAW,wBAACC,OAAYV,QAAiBW,OAAgBC,KAAcC,WACtE,KAAKJ,UAAUC,OAAOV,QAAQW,OAAOC,KAAKC,MAAAA,GADhC;MAEXC,WAAW,wBAACC,OAAYf,QAAiBa,WAAqB,KAAKC,UAAUC,OAAOf,QAAQa,MAAAA,GAAjF;MACXd,WAAW,wBAACC,WAAmB,KAAKD,UAAUC,MAAAA,GAAnC;MACXI,WAAW,6BAAM,KAAKA,UAAS,GAApB;MACXY,SAAS,6BAAM,KAAKA,QAAO,GAAlB;IACV;AACA,WAAO,KAAKlB;EACb;;;;EAKOW,UAAUC,OAAYV,SAAiB,GAAGW,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAe;AACrH,QAAI,OAAOH,UAAU,UAAU;AAC9B,YAAMO,YAAYP,MAAMQ,QAAQ,OAAO,GAAA;AACvC,YAAMC,IAAI,KAAK7B,QAAQ8B,OAAOH,SAAAA;AAC9B,UAAI,CAACE,GAAG;AACPE,2BAAmB,KAAK/B,SAASgC,UAAUC,aAAaC,OAAO;UAAEP;QAAU,CAAA;AAC3E,eAAO;MACR;AACA,aAAOE,EAAEM,KAAKzB,SAAS,KAAKT,cAAcoB,OAAOC,KAAKC,MAAAA;IACvD;AACA,WAAO;EACR;;;;EAKOC,UAAUC,OAAYf,SAAiB,GAAGa,SAAkB,OAAe;AACjF,QAAI,OAAOE,UAAU,UAAU;AAC9B,YAAMW,YAAYX,MAAMG,QAAQ,OAAO,GAAA;AACvC,YAAMS,IAAI,KAAKrC,QAAQyB,MAAMW,SAAAA;AAC7B,UAAI,CAACC,GAAG;AACPN,2BAAmB,KAAK/B,SAASgC,UAAUC,aAAaK,OAAO;UAAEF;QAAU,CAAA;AAC3E,eAAO;MACR;AACA,aAAOC,EAAEF,KAAKzB,SAAS,KAAKT,cAAcsB,MAAAA;IAC3C;AACA,WAAO;EACR;;;;;EAMOrB,aAA2B;AACjC,QAAI,CAAC,KAAKR,SAAS;AAClB,YAAM6C,oBAAqBC,OAAeC,gBAAiBD,OAAeE;AAE1E,WAAKhD,UAAU,IAAI6C,kBAAAA;AAGnB,UAAI,KAAK7C,QAAQU,UAAU,WAAW;AACrC,cAAMuC,WAAW,6BAAA;AAChB,cAAI,KAAKjD,WAAW,KAAKA,QAAQU,UAAU,WAAW;AACrD,iBAAKV,QAAQkD,OAAM;AACnB,gBAAI,KAAK7C,QAAQ;AAChB,mBAAK8C,MAAK;YACX;AACA,uBAAWvC,QAAQ,KAAKT,YAAY;AACnCS,mBAAKwC,OAAM;YACZ;AAEAC,qBAASC,KAAKC,oBAAoB,YAAYN,QAAAA;AAC9CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;AAC7CI,qBAASC,KAAKC,oBAAoB,SAASN,QAAAA;AAC3CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;UAC9C;QACD,GAfiB;AAkBjBI,iBAASC,KAAKE,iBAAiB,YAAYP,UAAU;UACpDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,SAASP,UAAU;UACjDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;MACD,WAAW,KAAKpD,QAAQ;AACvB,aAAK8C,MAAK;MACX;IACD;AAEA,WAAO,KAAKnD;EACb;;;;EAKA,MAAamD,QAAuB;AACnC,QAAI,KAAK/C,YAAa;AAEtB,QAAI;AACH,YAAMsD,OAAO,IAAIC,KAAK;QAACC;SAAqB;QAC3CC,MAAM;MACP,CAAA;AACA,YAAMC,MAAMC,IAAIC,gBAAgBN,IAAAA;AAEhC,YAAM,KAAK1D,QAAQiE,aAAaC,UAAUJ,GAAAA;AAE1C,WAAK1D,cAAc,IAAI+D,iBAAiB,KAAKnE,SAAS,qBAAA;AACtD,WAAKI,YAAYgE,QAAQ,KAAKpE,QAAQqE,WAAW;AAEjD,WAAKC,YAAW;IACjB,SAASC,GAAG;AACXlC,yBAAmB,KAAK/B,SAASgC,UAAUC,aAAaiC,OAAO;QAAEC,OAAOC,OAAOH,CAAAA;MAAG,CAAA;IACnF;EACD;;;;EAKQD,cAAoB;AAC3B,QAAI,CAAC,KAAKlE,YAAa;AAEvB,WAAO,KAAKH,OAAO0E,SAAS,GAAG;AAC9B,WAAKvE,YAAYwE,KAAKC,YAAY,KAAK5E,OAAO6E,OAAO,GAAG,CAAA,EAAG,CAAA,CAAE;IAC9D;EACD;;;;EAKOC,YAAoB;AAC1B,QAAI,CAAC,KAAK1E,QAAQ;AAEjB,WAAKA,SAAS,IAAI2E,OAAO,IAAI;AAE7B,UAAI,KAAKhF,QAAQU,UAAU,WAAW;AACrC,aAAKyC,MAAK;MACX;IACD;AACA,WAAO,KAAK9C;EACb;;;;EAKOiB,KAAKC,UAAwB;AACnC,SAAKwD,UAAS,EAAGzD,KAAKC,QAAAA;EACvB;;;;EAKO0D,SAASC,OAAoB;AACnC,eAAWC,KAAKD,OAAO;AACtBC,QAAEC,YAAY,KAAKpF,QAAQqF;AAC3BF,QAAEG,YAAYH,EAAEI,YAAY,KAAKvF,QAAQqF;IAC1C;AAEA,QAAI,KAAKjF,aAAa;AACrB,WAAKA,YAAYwE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;QACNnE,UAAU2D;MACX,CAAA,CAAA;IAEF,OAAO;AACN,WAAKjF,OAAOY,KACX2E,KAAKC,UAAU;QACdC,MAAM;QACNnE,UAAU2D;MACX,CAAA,CAAA;IAEF;EACD;;;;EAKO1D,cAAoB;AAC1B,QAAI,KAAKpB,aAAa;AACrB,WAAKA,YAAYwE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF,OAAO;AACN,WAAKzF,OAAOY,KACX2E,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF;AAEA,SAAK1D,QAAO;EACb;;;;EAKO2D,WAAW/E,MAA2B;AAC5C,SAAKV,QAAQW,KAAKD,IAAAA;EACnB;;;;EAKOgF,cAAchF,MAA2B;AAC/C,UAAMiF,QAAQ,KAAK3F,QAAQ4F,QAAQlF,IAAAA;AACnC,QAAIiF,SAAS,GAAG;AACf,WAAK3F,QAAQ4E,OAAOe,OAAO,CAAA;IAC5B;EACD;;;;EAKO7D,UAAgB;AACtB,eAAW+D,KAAK,KAAK7F,SAAS;AAC7B,UAAI;AACH6F,UAAEC,KAAI;MACP,SAASC,KAAK;AACb5D,2BAAmB,KAAK/B,SAASgC,UAAUC,aAAa2D,OAAO;UAAEzB,OAAOC,OAAOuB,GAAAA;QAAK,CAAA;MACrF;IACD;AACA,SAAK/F,UAAU,CAAA;EAChB;AACD;;;AIvSO,IAAMiG,QAAN,MAAMA;EAJb,OAIaA;;;EACLC,QAAgB;EAChBC,OAAe;EACfC;EACAC;EACAC,UAAmB;EAClBC;EAER,YAAYA,OAAYH,KAAa;AACpC,SAAKG,QAAQA;AACb,SAAKH,MAAMA;AACX,SAAKC,MAAM,IAAIG,MAAM,KAAKJ,GAAG;AAC7B,SAAKF,QAAQ;EACd;;;;EAKOO,KAAKC,SAAiB,GAAGC,SAAkB,OAAY;AAC7D,SAAKL,UAAU;AACf,SAAKD,IAAIO,OAAO,CAAC,CAACD;AAClB,SAAKN,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGL,MAAAA,CAAAA;AAE1C,QAAI,KAAKH,MAAMS,UAAS,GAAI;AAC3B,WAAKX,IAAII,KAAI;IACd,OAAO;AACN,WAAKF,MAAMU,gBAAgB,IAAI;IAChC;AAEA,SAAKV,MAAMW,WAAW,IAAI;AAE1B,WAAO;MACNT,MAAM,6BAAA;AACL,eAAO,KAAKJ,IAAII,KAAI;MACrB,GAFM;MAGNU,MAAM,6BAAA;AACL,aAAKb,UAAU;AACf,aAAKD,IAAIe,MAAK;AACd,aAAKb,MAAMc,cAAc,IAAI;MAC9B,GAJM;MAKNC,WAAW,wBAACC,MAAAA;AACX,aAAKlB,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGQ,CAAAA,CAAAA;MAC3C,GAFW;MAGXC,aAAa,6BAAA;AACZ,eAAO,KAAKnB,IAAIoB;MACjB,GAFa;MAGbC,aAAa,6BAAA;AACZ,eAAO,KAAKrB,IAAIsB;MACjB,GAFa;MAGbC,aAAa,wBAACC,QAAAA;AACb,aAAKxB,IAAIe,MAAK;AACd,aAAKf,IAAIoB,cAAcZ,KAAKC,IAAI,GAAGD,KAAKE,IAAI,KAAKV,IAAIsB,UAAUE,GAAAA,CAAAA;AAC/D,YAAI,KAAKvB,SAAS;AACjB,eAAKD,IAAII,KAAI;QACd;MACD,GANa;IAOd;EACD;;;;EAKOqB,SAAe;AACrB,QAAI,KAAKxB,SAAS;AACjB,WAAKD,IAAII,KAAI;IACd;EACD;;;;EAKOU,OAAa;AACnB,SAAKb,UAAU;AACf,SAAKD,IAAIe,MAAK;AACd,SAAKb,MAAMc,cAAc,IAAI;EAC9B;AACD;;;AC5EA,SAASU,gBAAAA,eAAcC,sBAAAA,2BAA0B;AAE1C,IAAMC,QAAN,MAAMA,OAAAA;EANb,OAMaA;;;EACLC,QAAgB;EAChBC;EACAC,OAAe;EACfC;EACCC;EAER,YAAYA,OAAYD,KAA2B;AAClD,SAAKC,QAAQA;AAEb,QAAID,eAAeE,aAAa;AAC/B,WAAKJ,SAASE;AACd,WAAKA,MAAM;AACX,WAAKH,QAAQ;IACd,OAAO;AACN,WAAKG,MAAMA;AACX,WAAKG,UAAUH,GAAAA;IAChB;EACD;;;;EAKQG,UAAUH,KAAmB;AACpC,UAAMI,UAAU,IAAIC,eAAAA;AACpBD,YAAQE,KAAK,OAAON,KAAK,IAAA;AACzBI,YAAQG,eAAe;AAEvBH,YAAQI,SAAS,MAAA;AAChB,WAAKP,MAAMQ,QAAQC,gBAClBN,QAAQO,UACR,CAACb,WAAAA;AACA,aAAKA,SAASA;AACd,aAAKD,QAAQ;MACd,GACA,CAACe,QAAAA;AACAC,QAAAA,oBAAmB,KAAKZ,OAAOa,SAASC,UAAUC,cAAaC,OAAO;UACrEC,OAAO,0BAA0BC,OAAOP,GAAAA,CAAAA;QACzC,CAAA;MACD,CAAA;IAEF;AAEAR,YAAQgB,UAAU,MAAA;AACjBP,MAAAA,oBAAmB,KAAKZ,OAAOa,SAASC,UAAUC,cAAaC,OAAO;QACrEC,OAAO,yBAAyBlB,GAAAA;MACjC,CAAA;IACD;AAEAI,YAAQiB,KAAI;EACb;;;;EAKOC,KAAKC,SAAiB,GAAGC,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAY;AACjG,QAAI,CAAC,KAAK5B,OACT,QAAO;MACN6B,MAAM,6BAAA;MAAO,GAAP;MACNC,UAAU;IACX;AAED,UAAMnB,UAAU,KAAKR,MAAMQ;AAG3B,UAAMoB,SAASpB,QAAQqB,mBAAkB;AACzCD,WAAOE,aAAaC,QAAQR;AAC5BK,WAAO/B,SAAS,KAAKA;AACrB,QAAI4B,OAAQG,QAAOI,OAAO;AAG1B,UAAMC,OAAOzB,QAAQ0B,WAAU;AAC/BD,SAAKA,KAAKF,QAAQT;AAGlB,UAAMa,SAAc3B,QAAQ4B,aAAY;AACxCD,WAAOE,eAAe;AACtBF,WAAOG,SAAS,CAACC,MAAAA;AAChBJ,aAAOK,YAAYD,GAAG,GAAG,IAAIE,KAAKC,IAAIH,CAAAA,CAAAA;IACvC;AACAJ,WAAOG,OAAOd,GAAAA;AAGdI,WAAOe,QAAQV,IAAAA;AACfA,SAAKU,QAAQR,MAAAA;AACbA,WAAOQ,QAAQnC,QAAQoC,WAAW;AAGlChB,WAAOiB,MAAK;AAGZ,QAAIC,UAAe;AACnB,QAAIrB,QAAQ;AACXqB,gBAAU;QACTpB,MAAM,6BAAA;AACLE,iBAAOF,KAAI;QACZ,GAFM;MAGP;AACA,WAAK1B,MAAM+C,WAAWD,OAAAA;IACvB;AAGA,UAAME,MAAM;MACXtB,MAAM,6BAAA;AACLE,eAAOF,KAAI;AACX,YAAIoB,QAAS,MAAK9C,MAAMiD,cAAcH,OAAAA;AACtC,eAAO;MACR,GAJM;MAKNI,WAAW,wBAACC,MAAAA;AACXlB,aAAKA,KAAKF,QAAQU,KAAKW,IAAI,GAAGX,KAAKY,IAAI,GAAGF,CAAAA,CAAAA;MAC3C,GAFW;MAGXG,UAAU,wBAACf,MAAAA;AACVX,eAAOE,aAAaC,QAAQU,KAAKW,IAAI,MAAOX,KAAKY,IAAI,KAAMd,CAAAA,CAAAA;MAC5D,GAFU;MAGVD,QAAQ,wBAACC,MAAAA;AACRJ,eAAOG,OAAOG,KAAKW,IAAI,IAAIX,KAAKY,IAAI,GAAGd,CAAAA,CAAAA,CAAAA;MACxC,GAFQ;MAGRgB,aAAa,6BAAA;AACZ,eAAO3B,OAAO/B,SAAS+B,OAAO/B,OAAO2D,WAAW;MACjD,GAFa;MAGb7B,UAAU;IACX;AAEAC,WAAO6B,UAAU,MAAA;AAChBT,UAAIrB,WAAW;IAChB;AAEA,WAAOqB;EACR;;;;EAKA,OAAcU,iBAAiBC,WAAqB;AACnD,WAAO,MAAMC,WAAAA;MA5If,OA4IeA;;;MACZ,OAAcC,YAAY;MACnBC;MACAC;MACAC;MACCC;MACApE;MAER,YAAYiE,UAAkBC,QAAgBC,aAAqB,OAAO;AAEzEF,mBAAWA,aAAa,IAAI,IAAI;AAChC,YAAI,EAAEC,SAAS,KAAKA,SAAS,QAAQ,MAAO;AAC3CA,mBAAS;QACV;AACA,YAAI,EAAEC,cAAc,OAAQA,cAAc,OAAQ;AACjDA,uBAAa;QACd;AAEA,aAAKF,WAAWA;AAChB,aAAKC,SAASA;AACd,aAAKC,aAAaA;AAGlB,aAAKnE,SAAS8D,UAAUnD,QAAQ0D,aAAaJ,UAAUC,QAAQC,UAAAA;AAC/D,aAAKC,QAAQ,IAAItE,OAAMgE,WAAW,KAAK9D,MAAM;MAC9C;;;;MAKOwB,KAAKC,QAAiBC,OAAgBC,KAAcC,QAAuB;AACjF,eAAO,KAAKwC,MAAM5C,KAAKC,QAAQC,OAAOC,KAAKC,MAAAA;MAC5C;;;;MAKO0C,MAAMC,SAAiBC,UAAkBtC,OAAqB;AACpE,YAAIqC,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAKzE,OAAO0E,eAAe,CAAA;AACvCD,cAAID,QAAAA,IAAYtC;QACjB,WAAW,KAAK+B,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK3E,OAAO0E,eAAe,CAAA;AACvCC,cAAIH,QAAAA,IAAYtC;QACjB;MACD;;;;MAKO0C,KAAKL,SAAiBC,UAA0B;AACtD,YAAID,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAKzE,OAAO0E,eAAe,CAAA;AACvC,iBAAOD,IAAID,QAAAA;QACZ,WAAW,KAAKP,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK3E,OAAO0E,eAAe,CAAA;AACvC,iBAAOC,IAAIH,QAAAA;QACZ;AACA,eAAO;MACR;IACD;EACD;AACD;","names":["APIErrorCode","reportRuntimeError","A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","Beeper","audio","notes","plainNotes","currentOctave","currentDuration","currentVolume","currentSpan","currentWaveform","initializeNotes","noteNames","i","oct","Math","floor","n","beep","input","status","sequence","loops","note","parsed","split","t","undefined","push","frequency","A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","volume","span","duration","waveform","includes","length","lop","splice","loopto","start","repeats","tempo","Number","parseFloat","isNaN","step","addBeeps","AUDIO_WORKLET_CODE","AudioCore","context","buffer","playing","wakeupList","workletNode","beeper","runtime","masterVolume","getContext","isStarted","state","addToWakeUpList","item","push","interfaceCache","setVolume","volume","Math","max","min","getVolume","getInterface","beep","sequence","cancelBeeps","playSound","sound","pitch","pan","loopit","playMusic","music","stopAll","soundName","replace","s","sounds","reportRuntimeError","listener","APIErrorCode","E7013","play","musicName","m","E7014","AudioContextClass","window","AudioContext","webkitAudioContext","activate","resume","start","wakeUp","document","body","removeEventListener","addEventListener","once","blob","Blob","AUDIO_WORKLET_CODE","type","url","URL","createObjectURL","audioWorklet","addModule","AudioWorkletNode","connect","destination","flushBuffer","e","E7012","error","String","length","port","postMessage","splice","getBeeper","Beeper","addBeeps","beeps","b","duration","sampleRate","increment","frequency","JSON","stringify","name","addPlaying","removePlaying","index","indexOf","p","stop","err","E7016","Music","ready","name","url","tag","playing","audio","Audio","play","volume","loopit","loop","Math","max","min","isStarted","addToWakeUpList","addPlaying","stop","pause","removePlaying","setVolume","v","getPosition","currentTime","getDuration","duration","setPosition","pos","wakeUp","APIErrorCode","reportRuntimeError","Sound","ready","buffer","name","url","audio","AudioBuffer","loadSound","request","XMLHttpRequest","open","responseType","onload","context","decodeAudioData","response","err","reportRuntimeError","runtime","listener","APIErrorCode","E7016","error","String","onerror","send","play","volume","pitch","pan","loopit","stop","finished","source","createBufferSource","playbackRate","value","loop","gain","createGain","panner","createPanner","panningModel","setPan","p","setPosition","Math","abs","connect","destination","start","playing","addPlaying","res","removePlaying","setVolume","v","max","min","setPitch","getDuration","duration","onended","createSoundClass","audiocore","MicroSound","classname","channels","length","sampleRate","sound","createBuffer","write","channel","position","ch1","getChannelData","ch2","read"]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/devices/beeper.ts","../src/core/audio-worklet.ts","../src/core/audio-core.ts","../src/devices/music.ts","../src/devices/sound.ts"],"sourcesContent":["/** A4 reference frequency in Hz (concert pitch) */\nexport const A4_FREQUENCY = 440;\n\n/** Ratio between adjacent semitones in equal temperament */\nexport const SEMITONE_RATIO = 2 ** (1 / 12);\n\n/** MIDI note number for A4 */\nexport const A4_MIDI_NOTE = 69;\n","/**\n * Beeper - Procedural sound generation from text sequences\n * Converts music notation strings into beep sequences\n * Example: \"square tempo 120 C4 D4 E4 F4\"\n */\nimport { A4_FREQUENCY, A4_MIDI_NOTE, SEMITONE_RATIO } from \"../constants\";\nexport class Beeper {\n\tprivate audio: any;\n\tprivate notes: Record<string | number, number> = {};\n\tprivate plainNotes: Record<string, number> = {};\n\tprivate currentOctave = 5;\n\tprivate currentDuration = 0.5;\n\tprivate currentVolume = 0.5;\n\tprivate currentSpan = 1;\n\tprivate currentWaveform = \"square\";\n\n\tconstructor(audio: any) {\n\t\tthis.audio = audio;\n\t\tthis.initializeNotes();\n\t}\n\n\t/**\n\t * Initialize note mappings\n\t */\n\tprivate initializeNotes(): void {\n\t\tconst noteNames = [\n\t\t\t[\"C\", \"DO\"],\n\t\t\t[\"C#\", \"DO#\", \"Db\", \"REb\"],\n\t\t\t[\"D\", \"RE\"],\n\t\t\t[\"D#\", \"RE#\", \"Eb\", \"MIb\"],\n\t\t\t[\"E\", \"MI\"],\n\t\t\t[\"F\", \"FA\"],\n\t\t\t[\"F#\", \"FA#\", \"Gb\", \"SOLb\"],\n\t\t\t[\"G\", \"SOL\"],\n\t\t\t[\"G#\", \"SOL#\", \"Ab\", \"LAb\"],\n\t\t\t[\"A\", \"LA\"],\n\t\t\t[\"A#\", \"LA#\", \"Bb\", \"SIb\"],\n\t\t\t[\"B\", \"SI\"],\n\t\t];\n\n\t\tfor (let i = 0; i <= 127; i++) {\n\t\t\tthis.notes[i] = i;\n\t\t\tconst oct = Math.floor(i / 12) - 1;\n\n\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\tthis.notes[n + oct] = i;\n\t\t\t}\n\n\t\t\tif (oct === -1) {\n\t\t\t\tfor (const n of noteNames[i % 12]) {\n\t\t\t\t\tthis.plainNotes[n] = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parse and play beep sequence\n\t */\n\tpublic beep(input: string): void {\n\t\tlet status: string = \"normal\";\n\t\tconst sequence: any[] = [];\n\t\tconst loops: any[] = [];\n\t\tlet note: number | undefined;\n\n\t\tconst parsed = input.split(\" \");\n\n\t\tfor (const t of parsed) {\n\t\t\tif (t === \"\") continue;\n\n\t\t\tswitch (status) {\n\t\t\t\tcase \"normal\":\n\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t// Full note with octave (e.g., \"C4\")\n\t\t\t\t\t\tnote = this.notes[t];\n\t\t\t\t\t\tthis.currentOctave = Math.floor(note / 12);\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t// Note without octave (e.g., \"C\")\n\t\t\t\t\t\tnote = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (note - A4_MIDI_NOTE),\n\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if ([\"square\", \"sine\", \"saw\", \"noise\"].includes(t)) {\n\t\t\t\t\t\t// Waveform\n\t\t\t\t\t\tthis.currentWaveform = t;\n\t\t\t\t\t} else if ([\"tempo\", \"duration\", \"volume\", \"span\", \"loop\", \"to\"].includes(t)) {\n\t\t\t\t\t\t// Commands\n\t\t\t\t\t\tstatus = t;\n\t\t\t\t\t} else if (t === \"-\") {\n\t\t\t\t\t\t// Rest/silence\n\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t});\n\t\t\t\t\t} else if (t === \"end\") {\n\t\t\t\t\t\t// End loop\n\t\t\t\t\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\t\t\t\t\tvolume: 0,\n\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\tduration: 0,\n\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\t\t\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\t\t\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase \"tempo\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst tempo = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(tempo) && tempo > 0) {\n\t\t\t\t\t\tthis.currentDuration = 60 / tempo;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"duration\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst duration = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(duration) && duration > 0) {\n\t\t\t\t\t\tthis.currentDuration = duration / 1000;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"volume\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst volume = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(volume)) {\n\t\t\t\t\t\tthis.currentVolume = volume / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"span\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tconst span = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(span)) {\n\t\t\t\t\t\tthis.currentSpan = span / 100;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"loop\": {\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tloops.push({\n\t\t\t\t\t\tstart: sequence.length,\n\t\t\t\t\t});\n\t\t\t\t\tconst repeats = Number.parseFloat(t);\n\t\t\t\t\tif (!Number.isNaN(repeats)) {\n\t\t\t\t\t\tloops[loops.length - 1].repeats = repeats;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"to\":\n\t\t\t\t\tstatus = \"normal\";\n\t\t\t\t\tif (note !== undefined) {\n\t\t\t\t\t\tlet n: number | undefined;\n\n\t\t\t\t\t\tif (this.notes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.notes[t];\n\t\t\t\t\t\t} else if (this.plainNotes[t] !== undefined) {\n\t\t\t\t\t\t\tn = this.plainNotes[t] + this.currentOctave * 12;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (n !== undefined && n !== note) {\n\t\t\t\t\t\t\t// Generate slide from note to n\n\t\t\t\t\t\t\tconst step = n > note ? 1 : -1;\n\t\t\t\t\t\t\tfor (let i = note + step; step > 0 ? i <= n : i >= n; i += step) {\n\t\t\t\t\t\t\t\tsequence.push({\n\t\t\t\t\t\t\t\t\tfrequency: A4_FREQUENCY * SEMITONE_RATIO ** (i - A4_MIDI_NOTE),\n\t\t\t\t\t\t\t\t\tvolume: this.currentVolume,\n\t\t\t\t\t\t\t\t\tspan: this.currentSpan,\n\t\t\t\t\t\t\t\t\tduration: this.currentDuration,\n\t\t\t\t\t\t\t\t\twaveform: this.currentWaveform,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tnote = n;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Close any remaining loops\n\t\tif (loops.length > 0 && sequence.length > 0) {\n\t\t\tconst lop = loops.splice(loops.length - 1, 1)[0];\n\t\t\tsequence.push({\n\t\t\t\tfrequency: A4_FREQUENCY,\n\t\t\t\tvolume: 0,\n\t\t\t\tspan: this.currentSpan,\n\t\t\t\tduration: 0,\n\t\t\t\twaveform: this.currentWaveform,\n\t\t\t});\n\n\t\t\tsequence[sequence.length - 1].loopto = lop.start;\n\t\t\tsequence[sequence.length - 1].repeats = lop.repeats;\n\t\t}\n\n\t\tthis.audio.addBeeps(sequence);\n\t}\n}\n","export const AUDIO_WORKLET_CODE = `\nclass L8bAudioProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.beeps = [];\n this.last = 0;\n this.port.onmessage = (event) => {\n const data = JSON.parse(event.data);\n if (data.name === \"cancel_beeps\") {\n this.beeps = [];\n } else if (data.name === \"beep\") {\n const seq = data.sequence;\n // Link sequence notes together\n for (let i = 0; i < seq.length; i++) {\n const note = seq[i];\n if (i > 0) {\n seq[i - 1].next = note;\n }\n // Resolve loopto index to actual note reference\n if (note.loopto != null) {\n note.loopto = seq[note.loopto];\n }\n // Initialize phase and time\n note.phase = 0;\n note.time = 0;\n }\n // Add first note to beeps queue\n if (seq.length > 0) {\n this.beeps.push(seq[0]);\n }\n }\n };\n }\n\n process(inputs, outputs, parameters) {\n const output = outputs[0];\n \n for (let i = 0; i < output.length; i++) {\n const channel = output[i];\n \n if (i > 0) {\n // Copy first channel to other channels\n for (let j = 0; j < channel.length; j++) {\n channel[j] = output[0][j];\n }\n } else {\n // Generate audio for first channel\n for (let j = 0; j < channel.length; j++) {\n let sig = 0;\n \n for (let k = this.beeps.length - 1; k >= 0; k--) {\n const b = this.beeps[k];\n let volume = b.volume;\n \n if (b.time / b.duration > b.span) {\n volume = 0;\n }\n \n // Generate waveform\n switch (b.waveform) {\n case \"square\":\n sig += b.phase > 0.5 ? volume : -volume;\n break;\n case \"saw\":\n sig += (b.phase * 2 - 1) * volume;\n break;\n case \"noise\":\n sig += (Math.random() * 2 - 1) * volume;\n break;\n default: // sine\n sig += Math.sin(b.phase * Math.PI * 2) * volume;\n }\n \n b.phase = (b.phase + b.increment) % 1;\n b.time += 1;\n \n if (b.time >= b.duration) {\n b.time = 0;\n \n if (b.loopto != null) {\n if (b.repeats != null && b.repeats > 0) {\n if (b.loopcount == null) {\n b.loopcount = 0;\n }\n b.loopcount++;\n \n if (b.loopcount >= b.repeats) {\n b.loopcount = 0;\n if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else {\n b.loopto.phase = b.phase;\n this.beeps[k] = b.loopto;\n }\n } else if (b.next != null) {\n b.next.phase = b.phase;\n this.beeps[k] = b.next;\n } else {\n this.beeps.splice(k, 1);\n }\n }\n }\n \n this.last = this.last * 0.9 + sig * 0.1;\n channel[j] = this.last;\n }\n }\n }\n \n return true;\n }\n}\n\nregisterProcessor(\"l8b-audio-processor\", L8bAudioProcessor);\n`;\n","/**\n * AudioCore - Web Audio API wrapper\n * Manages audio context, beeper, and sound/music playback\n */\n\nimport { Beeper } from \"../devices/beeper\";\nimport { AUDIO_WORKLET_CODE } from \"./audio-worklet\";\n\n/** An actively playing sound/music that can be stopped */\ninterface PlayingHandle {\n\tstop: () => void;\n}\n\n/** Item that can be woken up on audio context activation */\ninterface WakeUpItem {\n\twakeUp: () => void;\n}\n\nexport class AudioCore {\n\tpublic context!: AudioContext;\n\tprivate buffer: string[] = [];\n\tprivate playing: PlayingHandle[] = [];\n\tprivate wakeupList: WakeUpItem[] = [];\n\tprivate workletNode?: AudioWorkletNode;\n\tprivate beeper?: Beeper;\n\tprivate runtime: any;\n\tprivate masterVolume: number = 1;\n\n\tconstructor(runtime: any) {\n\t\tthis.runtime = runtime;\n\t\tthis.getContext();\n\t}\n\n\t/**\n\t * Check if audio context is running\n\t */\n\tpublic isStarted(): boolean {\n\t\treturn this.context.state === \"running\";\n\t}\n\n\t/**\n\t * Add item to wakeup list (for mobile audio activation)\n\t */\n\tpublic addToWakeUpList(item: WakeUpItem): void {\n\t\tthis.wakeupList.push(item);\n\t}\n\n\tprivate interfaceCache: Record<string, any> | null = null;\n\n\t/**\n\t * Set master volume (0-1). Applied as a multiplier to all sound/music playback.\n\t */\n\tpublic setVolume(volume: number): void {\n\t\tthis.masterVolume = Math.max(0, Math.min(1, volume));\n\t}\n\n\t/**\n\t * Get current master volume (0-1)\n\t */\n\tpublic getVolume(): number {\n\t\treturn this.masterVolume;\n\t}\n\n\t/**\n\t * Get interface for game code\n\t */\n\tpublic getInterface() {\n\t\tif (this.interfaceCache) {\n\t\t\treturn this.interfaceCache;\n\t\t}\n\t\tthis.interfaceCache = {\n\t\t\tbeep: (sequence: string) => this.beep(sequence),\n\t\t\tcancelBeeps: () => this.cancelBeeps(),\n\t\t\tplaySound: (sound: any, volume?: number, pitch?: number, pan?: number, loopit?: boolean) =>\n\t\t\t\tthis.playSound(sound, volume, pitch, pan, loopit),\n\t\t\tplayMusic: (music: any, volume?: number, loopit?: boolean) => this.playMusic(music, volume, loopit),\n\t\t\tsetVolume: (volume: number) => this.setVolume(volume),\n\t\t\tgetVolume: () => this.getVolume(),\n\t\t\tstopAll: () => this.stopAll(),\n\t\t};\n\t\treturn this.interfaceCache;\n\t}\n\n\t/**\n\t * Play sound effect\n\t */\n\tpublic playSound(sound: any, volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): number {\n\t\tif (typeof sound === \"string\") {\n\t\t\tconst soundName = sound.replace(/\\//g, \"-\");\n\t\t\tconst s = this.runtime.sounds[soundName];\n\t\t\tif (!s) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7013\", message: \"Sound not found\", data: { soundName } });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn s.play(volume * this.masterVolume, pitch, pan, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Play music\n\t */\n\tpublic playMusic(music: any, volume: number = 1, loopit: boolean = false): number {\n\t\tif (typeof music === \"string\") {\n\t\t\tconst musicName = music.replace(/\\//g, \"-\");\n\t\t\tconst m = this.runtime.music[musicName];\n\t\t\tif (!m) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7014\", message: \"Music not found\", data: { musicName } });\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn m.play(volume * this.masterVolume, loopit);\n\t\t}\n\t\treturn 0;\n\t}\n\n\t/**\n\t * Get or create audio context (lazy initialization - created on first use)\n\t * Note: Browser may suspend context until user interaction, which is handled automatically\n\t */\n\tpublic getContext(): AudioContext {\n\t\tif (!this.context) {\n\t\t\tconst AudioContextClass = (window as any).AudioContext || (window as any).webkitAudioContext;\n\t\t\t// Create context - browser may suspend until user interaction\n\t\t\tthis.context = new AudioContextClass();\n\n\t\t\t// If context is suspended, set up activation listeners\n\t\t\tif (this.context.state !== \"running\") {\n\t\t\t\tconst activate = () => {\n\t\t\t\t\tif (this.context && this.context.state !== \"running\") {\n\t\t\t\t\t\tthis.context.resume();\n\t\t\t\t\t\tif (this.beeper) {\n\t\t\t\t\t\t\tthis.start();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor (const item of this.wakeupList) {\n\t\t\t\t\t\t\titem.wakeUp();\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Clean up listeners\n\t\t\t\t\t\tdocument.body.removeEventListener(\"touchend\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"mouseup\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"click\", activate);\n\t\t\t\t\t\tdocument.body.removeEventListener(\"keydown\", activate);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t// Add multiple event listeners for better compatibility\n\t\t\t\tdocument.body.addEventListener(\"touchend\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"mouseup\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"click\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t\tdocument.body.addEventListener(\"keydown\", activate, {\n\t\t\t\t\tonce: true,\n\t\t\t\t});\n\t\t\t} else if (this.beeper) {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\n\t\treturn this.context;\n\t}\n\n\t/**\n\t * Start audio processor\n\t */\n\tpublic async start(): Promise<void> {\n\t\tif (this.workletNode) return;\n\n\t\ttry {\n\t\t\tconst blob = new Blob([AUDIO_WORKLET_CODE], {\n\t\t\t\ttype: \"application/javascript\",\n\t\t\t});\n\t\t\tconst url = URL.createObjectURL(blob);\n\n\t\t\tawait this.context.audioWorklet.addModule(url);\n\n\t\t\tthis.workletNode = new AudioWorkletNode(this.context, \"l8b-audio-processor\");\n\t\t\tthis.workletNode.connect(this.context.destination);\n\n\t\t\tthis.flushBuffer();\n\t\t} catch (e) {\n\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7012\", message: \"Audio worklet error\", data: { error: String(e) } });\n\t\t}\n\t}\n\n\t/**\n\t * Flush buffered messages\n\t */\n\tprivate flushBuffer(): void {\n\t\tif (!this.workletNode) return;\n\n\t\twhile (this.buffer.length > 0) {\n\t\t\tthis.workletNode.port.postMessage(this.buffer.splice(0, 1)[0]);\n\t\t}\n\t}\n\n\t/**\n\t * Get or create beeper\n\t */\n\tpublic getBeeper(): Beeper {\n\t\tif (!this.beeper) {\n\t\t\t// Create Beeper instance\n\t\t\tthis.beeper = new Beeper(this);\n\n\t\t\tif (this.context.state === \"running\") {\n\t\t\t\tthis.start();\n\t\t\t}\n\t\t}\n\t\treturn this.beeper;\n\t}\n\n\t/**\n\t * Play beep sequence\n\t */\n\tpublic beep(sequence: string): void {\n\t\tthis.getBeeper().beep(sequence);\n\t}\n\n\t/**\n\t * Add beeps to audio processor\n\t */\n\tpublic addBeeps(beeps: any[]): void {\n\t\tfor (const b of beeps) {\n\t\t\tb.duration *= this.context.sampleRate;\n\t\t\tb.increment = b.frequency / this.context.sampleRate;\n\t\t}\n\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"beep\",\n\t\t\t\t\tsequence: beeps,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Cancel all beeps\n\t */\n\tpublic cancelBeeps(): void {\n\t\tif (this.workletNode) {\n\t\t\tthis.workletNode.port.postMessage(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t} else {\n\t\t\tthis.buffer.push(\n\t\t\t\tJSON.stringify({\n\t\t\t\t\tname: \"cancel_beeps\",\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\n\t\tthis.stopAll();\n\t}\n\n\t/**\n\t * Add playing sound/music to list\n\t */\n\tpublic addPlaying(item: PlayingHandle): void {\n\t\tthis.playing.push(item);\n\t}\n\n\t/**\n\t * Remove playing sound/music from list\n\t */\n\tpublic removePlaying(item: PlayingHandle): void {\n\t\tconst index = this.playing.indexOf(item);\n\t\tif (index >= 0) {\n\t\t\tthis.playing.splice(index, 1);\n\t\t}\n\t}\n\n\t/**\n\t * Stop all playing sounds/music\n\t */\n\tpublic stopAll(): void {\n\t\tfor (const p of this.playing) {\n\t\t\ttry {\n\t\t\t\tp.stop();\n\t\t\t} catch (err) {\n\t\t\t\tthis.runtime?.listener?.reportError?.({ code: \"E7016\", message: \"Audio error\", data: { error: String(err) } });\n\t\t\t}\n\t\t}\n\t\tthis.playing = [];\n\t}\n}\n","/**\n * Music - Music streaming and playback using HTML5 Audio\n * L8B Music class for LootiScript\n */\nexport class Music {\n\tpublic ready: number = 1;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tpublic tag: HTMLAudioElement;\n\tpublic playing: boolean = false;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string) {\n\t\tthis.audio = audio;\n\t\tthis.url = url;\n\t\tthis.tag = new Audio(this.url);\n\t\tthis.ready = 1;\n\t}\n\n\t/**\n\t * Play music with volume and loop (HTML5 Audio implementation)\n\t */\n\tpublic play(volume: number = 1, loopit: boolean = false): any {\n\t\tthis.playing = true;\n\t\tthis.tag.loop = !!loopit;\n\t\tthis.tag.volume = Math.max(0, Math.min(1, volume));\n\n\t\tif (this.audio.isStarted()) {\n\t\t\tthis.tag.play();\n\t\t} else {\n\t\t\tthis.audio.addToWakeUpList(this);\n\t\t}\n\n\t\tthis.audio.addPlaying(this);\n\n\t\treturn {\n\t\t\tplay: () => {\n\t\t\t\treturn this.tag.play();\n\t\t\t},\n\t\t\tstop: () => {\n\t\t\t\tthis.playing = false;\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.audio.removePlaying(this);\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tthis.tag.volume = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tgetPosition: () => {\n\t\t\t\treturn this.tag.currentTime;\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn this.tag.duration;\n\t\t\t},\n\t\t\tsetPosition: (pos: number) => {\n\t\t\t\tthis.tag.pause();\n\t\t\t\tthis.tag.currentTime = Math.max(0, Math.min(this.tag.duration, pos));\n\t\t\t\tif (this.playing) {\n\t\t\t\t\tthis.tag.play();\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Wake up audio (for autoplay policy)\n\t */\n\tpublic wakeUp(): void {\n\t\tif (this.playing) {\n\t\t\tthis.tag.play();\n\t\t}\n\t}\n\n\t/**\n\t * Stop music\n\t */\n\tpublic stop(): void {\n\t\tthis.playing = false;\n\t\tthis.tag.pause();\n\t\tthis.audio.removePlaying(this);\n\t}\n}\n","/**\n * Sound - Sound effect playback\n * Handles loading and playing audio buffers\n */\n\nexport class Sound {\n\tpublic ready: number = 0;\n\tpublic buffer?: AudioBuffer;\n\tpublic name: string = \"\";\n\tpublic url: string;\n\tprivate audio: any;\n\n\tconstructor(audio: any, url: string | AudioBuffer) {\n\t\tthis.audio = audio;\n\n\t\tif (url instanceof AudioBuffer) {\n\t\t\tthis.buffer = url;\n\t\t\tthis.url = \"\";\n\t\t\tthis.ready = 1;\n\t\t} else {\n\t\t\tthis.url = url;\n\t\t\tthis.loadSound(url);\n\t\t}\n\t}\n\n\t/**\n\t * Load sound from URL\n\t */\n\tprivate loadSound(url: string): void {\n\t\tconst request = new XMLHttpRequest();\n\t\trequest.open(\"GET\", url, true);\n\t\trequest.responseType = \"arraybuffer\";\n\n\t\trequest.onload = () => {\n\t\t\tthis.audio.context.decodeAudioData(\n\t\t\t\trequest.response,\n\t\t\t\t(buffer: AudioBuffer) => {\n\t\t\t\t\tthis.buffer = buffer;\n\t\t\t\t\tthis.ready = 1;\n\t\t\t\t},\n\t\t\t\t(err: any) => {\n\t\t\t\t\tthis.audio?.runtime?.listener?.reportError?.({\n\t\t\t\t\t\tcode: \"E7016\",\n\t\t\t\t\t\tmessage: \"Audio decoding failed\",\n\t\t\t\t\t\tdata: { error: `Audio decoding failed: ${String(err)}` },\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t};\n\n\t\trequest.onerror = () => {\n\t\t\tthis.audio?.runtime?.listener?.reportError?.({\n\t\t\t\tcode: \"E7016\",\n\t\t\t\tmessage: \"Failed to load sound\",\n\t\t\t\tdata: { error: `Failed to load sound: ${url}` },\n\t\t\t});\n\t\t};\n\n\t\trequest.send();\n\t}\n\n\t/**\n\t * Play sound with volume, pitch, pan, and loop\n\t */\n\tpublic play(volume: number = 1, pitch: number = 1, pan: number = 0, loopit: boolean = false): any {\n\t\tif (!this.buffer)\n\t\t\treturn {\n\t\t\t\tstop: () => {},\n\t\t\t\tfinished: true,\n\t\t\t};\n\n\t\tconst context = this.audio.context;\n\n\t\t// Create source\n\t\tconst source = context.createBufferSource();\n\t\tsource.playbackRate.value = pitch;\n\t\tsource.buffer = this.buffer;\n\t\tif (loopit) source.loop = true;\n\n\t\t// Create gain node\n\t\tconst gain = context.createGain();\n\t\tgain.gain.value = volume;\n\n\t\t// Create panner\n\t\tconst panner: any = context.createPanner();\n\t\tpanner.panningModel = \"equalpower\";\n\t\tpanner.setPan = (p: number) => {\n\t\t\tpanner.setPosition(p, 0, 1 - Math.abs(p));\n\t\t};\n\t\tpanner.setPan(pan);\n\n\t\t// Connect nodes\n\t\tsource.connect(gain);\n\t\tgain.connect(panner);\n\t\tpanner.connect(context.destination);\n\n\t\t// Start playback\n\t\tsource.start();\n\n\t\t// Track playing sounds for looping\n\t\tlet playing: any = null;\n\t\tif (loopit) {\n\t\t\tplaying = {\n\t\t\t\tstop: () => {\n\t\t\t\t\tsource.stop();\n\t\t\t\t},\n\t\t\t};\n\t\t\tthis.audio.addPlaying(playing);\n\t\t}\n\n\t\t// Return control interface\n\t\tconst res = {\n\t\t\tstop: () => {\n\t\t\t\tsource.stop();\n\t\t\t\tif (playing) this.audio.removePlaying(playing);\n\t\t\t\treturn 1;\n\t\t\t},\n\t\t\tsetVolume: (v: number) => {\n\t\t\t\tgain.gain.value = Math.max(0, Math.min(1, v));\n\t\t\t},\n\t\t\tsetPitch: (p: number) => {\n\t\t\t\tsource.playbackRate.value = Math.max(0.001, Math.min(1000, p));\n\t\t\t},\n\t\t\tsetPan: (p: number) => {\n\t\t\t\tpanner.setPan(Math.max(-1, Math.min(1, p)));\n\t\t\t},\n\t\t\tgetDuration: () => {\n\t\t\t\treturn source.buffer ? source.buffer.duration : 0;\n\t\t\t},\n\t\t\tfinished: false,\n\t\t};\n\n\t\tsource.onended = () => {\n\t\t\tres.finished = true;\n\t\t};\n\n\t\treturn res;\n\t}\n\n\t/**\n\t * Create MicroSound class for procedural sound generation\n\t */\n\tpublic static createSoundClass(audiocore: any): any {\n\t\treturn class MicroSound {\n\t\t\tpublic static classname = \"Sound\";\n\t\t\tpublic channels: number;\n\t\t\tpublic length: number;\n\t\t\tpublic sampleRate: number;\n\t\t\tprivate sound: Sound;\n\t\t\tprivate buffer: AudioBuffer;\n\n\t\t\tconstructor(channels: number, length: number, sampleRate: number = 44100) {\n\t\t\t\t// Validate parameters\n\t\t\t\tchannels = channels === 1 ? 1 : 2;\n\t\t\t\tif (!(length > 1 && length < 44100 * 1000)) {\n\t\t\t\t\tlength = 44100;\n\t\t\t\t}\n\t\t\t\tif (!(sampleRate >= 8000 && sampleRate <= 96000)) {\n\t\t\t\t\tsampleRate = 44100;\n\t\t\t\t}\n\n\t\t\t\tthis.channels = channels;\n\t\t\t\tthis.length = length;\n\t\t\t\tthis.sampleRate = sampleRate;\n\n\t\t\t\t// Create audio buffer\n\t\t\t\tthis.buffer = audiocore.context.createBuffer(channels, length, sampleRate);\n\t\t\t\tthis.sound = new Sound(audiocore, this.buffer);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Play the sound\n\t\t\t */\n\t\t\tpublic play(volume?: number, pitch?: number, pan?: number, loopit?: boolean): any {\n\t\t\t\treturn this.sound.play(volume, pitch, pan, loopit);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Write sample value to buffer\n\t\t\t */\n\t\t\tpublic write(channel: number, position: number, value: number): void {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\tch1[position] = value;\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\tch2[position] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Read sample value from buffer\n\t\t\t */\n\t\t\tpublic read(channel: number, position: number): number {\n\t\t\t\tif (channel === 0) {\n\t\t\t\t\tconst ch1 = this.buffer.getChannelData(0);\n\t\t\t\t\treturn ch1[position];\n\t\t\t\t} else if (this.channels === 2) {\n\t\t\t\t\tconst ch2 = this.buffer.getChannelData(1);\n\t\t\t\t\treturn ch2[position];\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t};\n\t}\n}\n"],"mappings":";;;;AACO,IAAMA,eAAe;AAGrB,IAAMC,iBAAiB,MAAM,IAAI;AAGjC,IAAMC,eAAe;;;ACDrB,IAAMC,SAAN,MAAMA;EANb,OAMaA;;;EACJC;EACAC,QAAyC,CAAC;EAC1CC,aAAqC,CAAC;EACtCC,gBAAgB;EAChBC,kBAAkB;EAClBC,gBAAgB;EAChBC,cAAc;EACdC,kBAAkB;EAE1B,YAAYP,OAAY;AACvB,SAAKA,QAAQA;AACb,SAAKQ,gBAAe;EACrB;;;;EAKQA,kBAAwB;AAC/B,UAAMC,YAAY;MACjB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAQ;QAAM;;MACrB;QAAC;QAAK;;MACN;QAAC;QAAM;QAAO;QAAM;;MACpB;QAAC;QAAK;;;AAGP,aAASC,IAAI,GAAGA,KAAK,KAAKA,KAAK;AAC9B,WAAKT,MAAMS,CAAAA,IAAKA;AAChB,YAAMC,MAAMC,KAAKC,MAAMH,IAAI,EAAA,IAAM;AAEjC,iBAAWI,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,aAAKT,MAAMa,IAAIH,GAAAA,IAAOD;MACvB;AAEA,UAAIC,QAAQ,IAAI;AACf,mBAAWG,KAAKL,UAAUC,IAAI,EAAA,GAAK;AAClC,eAAKR,WAAWY,CAAAA,IAAKJ;QACtB;MACD;IACD;EACD;;;;EAKOK,KAAKC,OAAqB;AAChC,QAAIC,SAAiB;AACrB,UAAMC,WAAkB,CAAA;AACxB,UAAMC,QAAe,CAAA;AACrB,QAAIC;AAEJ,UAAMC,SAASL,MAAMM,MAAM,GAAA;AAE3B,eAAWC,KAAKF,QAAQ;AACvB,UAAIE,MAAM,GAAI;AAEd,cAAQN,QAAAA;QACP,KAAK;AACJ,cAAI,KAAKhB,MAAMsB,CAAAA,MAAOC,QAAW;AAEhCJ,mBAAO,KAAKnB,MAAMsB,CAAAA;AAClB,iBAAKpB,gBAAgBS,KAAKC,MAAMO,OAAO,EAAA;AACvCF,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW,KAAKL,WAAWqB,CAAAA,MAAOC,QAAW;AAE5CJ,mBAAO,KAAKlB,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;AACjDe,qBAASO,KAAK;cACbC,WAAWC,eAAeC,mBAAmBR,OAAOS;cACpDC,QAAQ,KAAKzB;cACb0B,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAW;YAAC;YAAU;YAAQ;YAAO;YAAS2B,SAASX,CAAAA,GAAI;AAE1D,iBAAKhB,kBAAkBgB;UACxB,WAAW;YAAC;YAAS;YAAY;YAAU;YAAQ;YAAQ;YAAMW,SAASX,CAAAA,GAAI;AAE7EN,qBAASM;UACV,WAAWA,MAAM,KAAK;AAErBL,qBAASO,KAAK;cACbC,WAAWC;cACXG,QAAQ;cACRC,MAAM,KAAKzB;cACX0B,UAAU,KAAK5B;cACf6B,UAAU,KAAK1B;YAChB,CAAA;UACD,WAAWgB,MAAM,OAAO;AAEvB,gBAAIJ,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5CjB,uBAASO,KAAK;gBACbC,WAAWC;gBACXG,QAAQ;gBACRC,MAAM,KAAKzB;gBACX0B,UAAU;gBACVC,UAAU,KAAK1B;cAChB,CAAA;AAEA,oBAAM6B,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,uBAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,uBAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;YAC7C;UACD;AACA;QAED,KAAK,SAAS;AACbvB,mBAAS;AACT,gBAAMwB,QAAQC,OAAOC,WAAWpB,CAAAA;AAChC,cAAI,CAACmB,OAAOE,MAAMH,KAAAA,KAAUA,QAAQ,GAAG;AACtC,iBAAKrC,kBAAkB,KAAKqC;UAC7B;AACA;QACD;QAEA,KAAK,YAAY;AAChBxB,mBAAS;AACT,gBAAMe,WAAWU,OAAOC,WAAWpB,CAAAA;AACnC,cAAI,CAACmB,OAAOE,MAAMZ,QAAAA,KAAaA,WAAW,GAAG;AAC5C,iBAAK5B,kBAAkB4B,WAAW;UACnC;AACA;QACD;QAEA,KAAK,UAAU;AACdf,mBAAS;AACT,gBAAMa,SAASY,OAAOC,WAAWpB,CAAAA;AACjC,cAAI,CAACmB,OAAOE,MAAMd,MAAAA,GAAS;AAC1B,iBAAKzB,gBAAgByB,SAAS;UAC/B;AACA;QACD;QAEA,KAAK,QAAQ;AACZb,mBAAS;AACT,gBAAMc,OAAOW,OAAOC,WAAWpB,CAAAA;AAC/B,cAAI,CAACmB,OAAOE,MAAMb,IAAAA,GAAO;AACxB,iBAAKzB,cAAcyB,OAAO;UAC3B;AACA;QACD;QAEA,KAAK,QAAQ;AACZd,mBAAS;AACTE,gBAAMM,KAAK;YACVc,OAAOrB,SAASiB;UACjB,CAAA;AACA,gBAAMK,UAAUE,OAAOC,WAAWpB,CAAAA;AAClC,cAAI,CAACmB,OAAOE,MAAMJ,OAAAA,GAAU;AAC3BrB,kBAAMA,MAAMgB,SAAS,CAAA,EAAGK,UAAUA;UACnC;AACA;QACD;QAEA,KAAK;AACJvB,mBAAS;AACT,cAAIG,SAASI,QAAW;AACvB,gBAAIV;AAEJ,gBAAI,KAAKb,MAAMsB,CAAAA,MAAOC,QAAW;AAChCV,kBAAI,KAAKb,MAAMsB,CAAAA;YAChB,WAAW,KAAKrB,WAAWqB,CAAAA,MAAOC,QAAW;AAC5CV,kBAAI,KAAKZ,WAAWqB,CAAAA,IAAK,KAAKpB,gBAAgB;YAC/C;AAEA,gBAAIW,MAAMU,UAAaV,MAAMM,MAAM;AAElC,oBAAMyB,OAAO/B,IAAIM,OAAO,IAAI;AAC5B,uBAASV,IAAIU,OAAOyB,MAAMA,OAAO,IAAInC,KAAKI,IAAIJ,KAAKI,GAAGJ,KAAKmC,MAAM;AAChE3B,yBAASO,KAAK;kBACbC,WAAWC,eAAeC,mBAAmBlB,IAAImB;kBACjDC,QAAQ,KAAKzB;kBACb0B,MAAM,KAAKzB;kBACX0B,UAAU,KAAK5B;kBACf6B,UAAU,KAAK1B;gBAChB,CAAA;cACD;AACAa,qBAAON;YACR;UACD;AACA;MACF;IACD;AAGA,QAAIK,MAAMgB,SAAS,KAAKjB,SAASiB,SAAS,GAAG;AAC5C,YAAMC,MAAMjB,MAAMkB,OAAOlB,MAAMgB,SAAS,GAAG,CAAA,EAAG,CAAA;AAC9CjB,eAASO,KAAK;QACbC,WAAWC;QACXG,QAAQ;QACRC,MAAM,KAAKzB;QACX0B,UAAU;QACVC,UAAU,KAAK1B;MAChB,CAAA;AAEAW,eAASA,SAASiB,SAAS,CAAA,EAAGG,SAASF,IAAIG;AAC3CrB,eAASA,SAASiB,SAAS,CAAA,EAAGK,UAAUJ,IAAII;IAC7C;AAEA,SAAKxC,MAAM8C,SAAS5B,QAAAA;EACrB;AACD;;;AC7NO,IAAM6B,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACkB3B,IAAMC,YAAN,MAAMA;EAlBb,OAkBaA;;;EACLC;EACCC,SAAmB,CAAA;EACnBC,UAA2B,CAAA;EAC3BC,aAA2B,CAAA;EAC3BC;EACAC;EACAC;EACAC,eAAuB;EAE/B,YAAYD,SAAc;AACzB,SAAKA,UAAUA;AACf,SAAKE,WAAU;EAChB;;;;EAKOC,YAAqB;AAC3B,WAAO,KAAKT,QAAQU,UAAU;EAC/B;;;;EAKOC,gBAAgBC,MAAwB;AAC9C,SAAKT,WAAWU,KAAKD,IAAAA;EACtB;EAEQE,iBAA6C;;;;EAK9CC,UAAUC,QAAsB;AACtC,SAAKT,eAAeU,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGH,MAAAA,CAAAA;EAC7C;;;;EAKOI,YAAoB;AAC1B,WAAO,KAAKb;EACb;;;;EAKOc,eAAe;AACrB,QAAI,KAAKP,gBAAgB;AACxB,aAAO,KAAKA;IACb;AACA,SAAKA,iBAAiB;MACrBQ,MAAM,wBAACC,aAAqB,KAAKD,KAAKC,QAAAA,GAAhC;MACNC,aAAa,6BAAM,KAAKA,YAAW,GAAtB;MACbC,WAAW,wBAACC,OAAYV,QAAiBW,OAAgBC,KAAcC,WACtE,KAAKJ,UAAUC,OAAOV,QAAQW,OAAOC,KAAKC,MAAAA,GADhC;MAEXC,WAAW,wBAACC,OAAYf,QAAiBa,WAAqB,KAAKC,UAAUC,OAAOf,QAAQa,MAAAA,GAAjF;MACXd,WAAW,wBAACC,WAAmB,KAAKD,UAAUC,MAAAA,GAAnC;MACXI,WAAW,6BAAM,KAAKA,UAAS,GAApB;MACXY,SAAS,6BAAM,KAAKA,QAAO,GAAlB;IACV;AACA,WAAO,KAAKlB;EACb;;;;EAKOW,UAAUC,OAAYV,SAAiB,GAAGW,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAe;AACrH,QAAI,OAAOH,UAAU,UAAU;AAC9B,YAAMO,YAAYP,MAAMQ,QAAQ,OAAO,GAAA;AACvC,YAAMC,IAAI,KAAK7B,QAAQ8B,OAAOH,SAAAA;AAC9B,UAAI,CAACE,GAAG;AACP,aAAK7B,SAAS+B,UAAUC,cAAc;UAAEC,MAAM;UAASC,SAAS;UAAmBC,MAAM;YAAER;UAAU;QAAE,CAAA;AACvG,eAAO;MACR;AACA,aAAOE,EAAEO,KAAK1B,SAAS,KAAKT,cAAcoB,OAAOC,KAAKC,MAAAA;IACvD;AACA,WAAO;EACR;;;;EAKOC,UAAUC,OAAYf,SAAiB,GAAGa,SAAkB,OAAe;AACjF,QAAI,OAAOE,UAAU,UAAU;AAC9B,YAAMY,YAAYZ,MAAMG,QAAQ,OAAO,GAAA;AACvC,YAAMU,IAAI,KAAKtC,QAAQyB,MAAMY,SAAAA;AAC7B,UAAI,CAACC,GAAG;AACP,aAAKtC,SAAS+B,UAAUC,cAAc;UAAEC,MAAM;UAASC,SAAS;UAAmBC,MAAM;YAAEE;UAAU;QAAE,CAAA;AACvG,eAAO;MACR;AACA,aAAOC,EAAEF,KAAK1B,SAAS,KAAKT,cAAcsB,MAAAA;IAC3C;AACA,WAAO;EACR;;;;;EAMOrB,aAA2B;AACjC,QAAI,CAAC,KAAKR,SAAS;AAClB,YAAM6C,oBAAqBC,OAAeC,gBAAiBD,OAAeE;AAE1E,WAAKhD,UAAU,IAAI6C,kBAAAA;AAGnB,UAAI,KAAK7C,QAAQU,UAAU,WAAW;AACrC,cAAMuC,WAAW,6BAAA;AAChB,cAAI,KAAKjD,WAAW,KAAKA,QAAQU,UAAU,WAAW;AACrD,iBAAKV,QAAQkD,OAAM;AACnB,gBAAI,KAAK7C,QAAQ;AAChB,mBAAK8C,MAAK;YACX;AACA,uBAAWvC,QAAQ,KAAKT,YAAY;AACnCS,mBAAKwC,OAAM;YACZ;AAEAC,qBAASC,KAAKC,oBAAoB,YAAYN,QAAAA;AAC9CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;AAC7CI,qBAASC,KAAKC,oBAAoB,SAASN,QAAAA;AAC3CI,qBAASC,KAAKC,oBAAoB,WAAWN,QAAAA;UAC9C;QACD,GAfiB;AAkBjBI,iBAASC,KAAKE,iBAAiB,YAAYP,UAAU;UACpDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,SAASP,UAAU;UACjDQ,MAAM;QACP,CAAA;AACAJ,iBAASC,KAAKE,iBAAiB,WAAWP,UAAU;UACnDQ,MAAM;QACP,CAAA;MACD,WAAW,KAAKpD,QAAQ;AACvB,aAAK8C,MAAK;MACX;IACD;AAEA,WAAO,KAAKnD;EACb;;;;EAKA,MAAamD,QAAuB;AACnC,QAAI,KAAK/C,YAAa;AAEtB,QAAI;AACH,YAAMsD,OAAO,IAAIC,KAAK;QAACC;SAAqB;QAC3CC,MAAM;MACP,CAAA;AACA,YAAMC,MAAMC,IAAIC,gBAAgBN,IAAAA;AAEhC,YAAM,KAAK1D,QAAQiE,aAAaC,UAAUJ,GAAAA;AAE1C,WAAK1D,cAAc,IAAI+D,iBAAiB,KAAKnE,SAAS,qBAAA;AACtD,WAAKI,YAAYgE,QAAQ,KAAKpE,QAAQqE,WAAW;AAEjD,WAAKC,YAAW;IACjB,SAASC,GAAG;AACX,WAAKjE,SAAS+B,UAAUC,cAAc;QAAEC,MAAM;QAASC,SAAS;QAAuBC,MAAM;UAAE+B,OAAOC,OAAOF,CAAAA;QAAG;MAAE,CAAA;IACnH;EACD;;;;EAKQD,cAAoB;AAC3B,QAAI,CAAC,KAAKlE,YAAa;AAEvB,WAAO,KAAKH,OAAOyE,SAAS,GAAG;AAC9B,WAAKtE,YAAYuE,KAAKC,YAAY,KAAK3E,OAAO4E,OAAO,GAAG,CAAA,EAAG,CAAA,CAAE;IAC9D;EACD;;;;EAKOC,YAAoB;AAC1B,QAAI,CAAC,KAAKzE,QAAQ;AAEjB,WAAKA,SAAS,IAAI0E,OAAO,IAAI;AAE7B,UAAI,KAAK/E,QAAQU,UAAU,WAAW;AACrC,aAAKyC,MAAK;MACX;IACD;AACA,WAAO,KAAK9C;EACb;;;;EAKOiB,KAAKC,UAAwB;AACnC,SAAKuD,UAAS,EAAGxD,KAAKC,QAAAA;EACvB;;;;EAKOyD,SAASC,OAAoB;AACnC,eAAWC,KAAKD,OAAO;AACtBC,QAAEC,YAAY,KAAKnF,QAAQoF;AAC3BF,QAAEG,YAAYH,EAAEI,YAAY,KAAKtF,QAAQoF;IAC1C;AAEA,QAAI,KAAKhF,aAAa;AACrB,WAAKA,YAAYuE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;QACNlE,UAAU0D;MACX,CAAA,CAAA;IAEF,OAAO;AACN,WAAKhF,OAAOY,KACX0E,KAAKC,UAAU;QACdC,MAAM;QACNlE,UAAU0D;MACX,CAAA,CAAA;IAEF;EACD;;;;EAKOzD,cAAoB;AAC1B,QAAI,KAAKpB,aAAa;AACrB,WAAKA,YAAYuE,KAAKC,YACrBW,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF,OAAO;AACN,WAAKxF,OAAOY,KACX0E,KAAKC,UAAU;QACdC,MAAM;MACP,CAAA,CAAA;IAEF;AAEA,SAAKzD,QAAO;EACb;;;;EAKO0D,WAAW9E,MAA2B;AAC5C,SAAKV,QAAQW,KAAKD,IAAAA;EACnB;;;;EAKO+E,cAAc/E,MAA2B;AAC/C,UAAMgF,QAAQ,KAAK1F,QAAQ2F,QAAQjF,IAAAA;AACnC,QAAIgF,SAAS,GAAG;AACf,WAAK1F,QAAQ2E,OAAOe,OAAO,CAAA;IAC5B;EACD;;;;EAKO5D,UAAgB;AACtB,eAAW8D,KAAK,KAAK5F,SAAS;AAC7B,UAAI;AACH4F,UAAEC,KAAI;MACP,SAASC,KAAK;AACb,aAAK1F,SAAS+B,UAAUC,cAAc;UAAEC,MAAM;UAASC,SAAS;UAAeC,MAAM;YAAE+B,OAAOC,OAAOuB,GAAAA;UAAK;QAAE,CAAA;MAC7G;IACD;AACA,SAAK9F,UAAU,CAAA;EAChB;AACD;;;ACtSO,IAAM+F,QAAN,MAAMA;EAJb,OAIaA;;;EACLC,QAAgB;EAChBC,OAAe;EACfC;EACAC;EACAC,UAAmB;EAClBC;EAER,YAAYA,OAAYH,KAAa;AACpC,SAAKG,QAAQA;AACb,SAAKH,MAAMA;AACX,SAAKC,MAAM,IAAIG,MAAM,KAAKJ,GAAG;AAC7B,SAAKF,QAAQ;EACd;;;;EAKOO,KAAKC,SAAiB,GAAGC,SAAkB,OAAY;AAC7D,SAAKL,UAAU;AACf,SAAKD,IAAIO,OAAO,CAAC,CAACD;AAClB,SAAKN,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGL,MAAAA,CAAAA;AAE1C,QAAI,KAAKH,MAAMS,UAAS,GAAI;AAC3B,WAAKX,IAAII,KAAI;IACd,OAAO;AACN,WAAKF,MAAMU,gBAAgB,IAAI;IAChC;AAEA,SAAKV,MAAMW,WAAW,IAAI;AAE1B,WAAO;MACNT,MAAM,6BAAA;AACL,eAAO,KAAKJ,IAAII,KAAI;MACrB,GAFM;MAGNU,MAAM,6BAAA;AACL,aAAKb,UAAU;AACf,aAAKD,IAAIe,MAAK;AACd,aAAKb,MAAMc,cAAc,IAAI;MAC9B,GAJM;MAKNC,WAAW,wBAACC,MAAAA;AACX,aAAKlB,IAAIK,SAASG,KAAKC,IAAI,GAAGD,KAAKE,IAAI,GAAGQ,CAAAA,CAAAA;MAC3C,GAFW;MAGXC,aAAa,6BAAA;AACZ,eAAO,KAAKnB,IAAIoB;MACjB,GAFa;MAGbC,aAAa,6BAAA;AACZ,eAAO,KAAKrB,IAAIsB;MACjB,GAFa;MAGbC,aAAa,wBAACC,QAAAA;AACb,aAAKxB,IAAIe,MAAK;AACd,aAAKf,IAAIoB,cAAcZ,KAAKC,IAAI,GAAGD,KAAKE,IAAI,KAAKV,IAAIsB,UAAUE,GAAAA,CAAAA;AAC/D,YAAI,KAAKvB,SAAS;AACjB,eAAKD,IAAII,KAAI;QACd;MACD,GANa;IAOd;EACD;;;;EAKOqB,SAAe;AACrB,QAAI,KAAKxB,SAAS;AACjB,WAAKD,IAAII,KAAI;IACd;EACD;;;;EAKOU,OAAa;AACnB,SAAKb,UAAU;AACf,SAAKD,IAAIe,MAAK;AACd,SAAKb,MAAMc,cAAc,IAAI;EAC9B;AACD;;;AC3EO,IAAMU,QAAN,MAAMA,OAAAA;EALb,OAKaA;;;EACLC,QAAgB;EAChBC;EACAC,OAAe;EACfC;EACCC;EAER,YAAYA,OAAYD,KAA2B;AAClD,SAAKC,QAAQA;AAEb,QAAID,eAAeE,aAAa;AAC/B,WAAKJ,SAASE;AACd,WAAKA,MAAM;AACX,WAAKH,QAAQ;IACd,OAAO;AACN,WAAKG,MAAMA;AACX,WAAKG,UAAUH,GAAAA;IAChB;EACD;;;;EAKQG,UAAUH,KAAmB;AACpC,UAAMI,UAAU,IAAIC,eAAAA;AACpBD,YAAQE,KAAK,OAAON,KAAK,IAAA;AACzBI,YAAQG,eAAe;AAEvBH,YAAQI,SAAS,MAAA;AAChB,WAAKP,MAAMQ,QAAQC,gBAClBN,QAAQO,UACR,CAACb,WAAAA;AACA,aAAKA,SAASA;AACd,aAAKD,QAAQ;MACd,GACA,CAACe,QAAAA;AACA,aAAKX,OAAOY,SAASC,UAAUC,cAAc;UAC5CC,MAAM;UACNC,SAAS;UACTC,MAAM;YAAEC,OAAO,0BAA0BC,OAAOR,GAAAA,CAAAA;UAAO;QACxD,CAAA;MACD,CAAA;IAEF;AAEAR,YAAQiB,UAAU,MAAA;AACjB,WAAKpB,OAAOY,SAASC,UAAUC,cAAc;QAC5CC,MAAM;QACNC,SAAS;QACTC,MAAM;UAAEC,OAAO,yBAAyBnB,GAAAA;QAAM;MAC/C,CAAA;IACD;AAEAI,YAAQkB,KAAI;EACb;;;;EAKOC,KAAKC,SAAiB,GAAGC,QAAgB,GAAGC,MAAc,GAAGC,SAAkB,OAAY;AACjG,QAAI,CAAC,KAAK7B,OACT,QAAO;MACN8B,MAAM,6BAAA;MAAO,GAAP;MACNC,UAAU;IACX;AAED,UAAMpB,UAAU,KAAKR,MAAMQ;AAG3B,UAAMqB,SAASrB,QAAQsB,mBAAkB;AACzCD,WAAOE,aAAaC,QAAQR;AAC5BK,WAAOhC,SAAS,KAAKA;AACrB,QAAI6B,OAAQG,QAAOI,OAAO;AAG1B,UAAMC,OAAO1B,QAAQ2B,WAAU;AAC/BD,SAAKA,KAAKF,QAAQT;AAGlB,UAAMa,SAAc5B,QAAQ6B,aAAY;AACxCD,WAAOE,eAAe;AACtBF,WAAOG,SAAS,CAACC,MAAAA;AAChBJ,aAAOK,YAAYD,GAAG,GAAG,IAAIE,KAAKC,IAAIH,CAAAA,CAAAA;IACvC;AACAJ,WAAOG,OAAOd,GAAAA;AAGdI,WAAOe,QAAQV,IAAAA;AACfA,SAAKU,QAAQR,MAAAA;AACbA,WAAOQ,QAAQpC,QAAQqC,WAAW;AAGlChB,WAAOiB,MAAK;AAGZ,QAAIC,UAAe;AACnB,QAAIrB,QAAQ;AACXqB,gBAAU;QACTpB,MAAM,6BAAA;AACLE,iBAAOF,KAAI;QACZ,GAFM;MAGP;AACA,WAAK3B,MAAMgD,WAAWD,OAAAA;IACvB;AAGA,UAAME,MAAM;MACXtB,MAAM,6BAAA;AACLE,eAAOF,KAAI;AACX,YAAIoB,QAAS,MAAK/C,MAAMkD,cAAcH,OAAAA;AACtC,eAAO;MACR,GAJM;MAKNI,WAAW,wBAACC,MAAAA;AACXlB,aAAKA,KAAKF,QAAQU,KAAKW,IAAI,GAAGX,KAAKY,IAAI,GAAGF,CAAAA,CAAAA;MAC3C,GAFW;MAGXG,UAAU,wBAACf,MAAAA;AACVX,eAAOE,aAAaC,QAAQU,KAAKW,IAAI,MAAOX,KAAKY,IAAI,KAAMd,CAAAA,CAAAA;MAC5D,GAFU;MAGVD,QAAQ,wBAACC,MAAAA;AACRJ,eAAOG,OAAOG,KAAKW,IAAI,IAAIX,KAAKY,IAAI,GAAGd,CAAAA,CAAAA,CAAAA;MACxC,GAFQ;MAGRgB,aAAa,6BAAA;AACZ,eAAO3B,OAAOhC,SAASgC,OAAOhC,OAAO4D,WAAW;MACjD,GAFa;MAGb7B,UAAU;IACX;AAEAC,WAAO6B,UAAU,MAAA;AAChBT,UAAIrB,WAAW;IAChB;AAEA,WAAOqB;EACR;;;;EAKA,OAAcU,iBAAiBC,WAAqB;AACnD,WAAO,MAAMC,WAAAA;MA/If,OA+IeA;;;MACZ,OAAcC,YAAY;MACnBC;MACAC;MACAC;MACCC;MACArE;MAER,YAAYkE,UAAkBC,QAAgBC,aAAqB,OAAO;AAEzEF,mBAAWA,aAAa,IAAI,IAAI;AAChC,YAAI,EAAEC,SAAS,KAAKA,SAAS,QAAQ,MAAO;AAC3CA,mBAAS;QACV;AACA,YAAI,EAAEC,cAAc,OAAQA,cAAc,OAAQ;AACjDA,uBAAa;QACd;AAEA,aAAKF,WAAWA;AAChB,aAAKC,SAASA;AACd,aAAKC,aAAaA;AAGlB,aAAKpE,SAAS+D,UAAUpD,QAAQ2D,aAAaJ,UAAUC,QAAQC,UAAAA;AAC/D,aAAKC,QAAQ,IAAIvE,OAAMiE,WAAW,KAAK/D,MAAM;MAC9C;;;;MAKOyB,KAAKC,QAAiBC,OAAgBC,KAAcC,QAAuB;AACjF,eAAO,KAAKwC,MAAM5C,KAAKC,QAAQC,OAAOC,KAAKC,MAAAA;MAC5C;;;;MAKO0C,MAAMC,SAAiBC,UAAkBtC,OAAqB;AACpE,YAAIqC,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAK1E,OAAO2E,eAAe,CAAA;AACvCD,cAAID,QAAAA,IAAYtC;QACjB,WAAW,KAAK+B,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK5E,OAAO2E,eAAe,CAAA;AACvCC,cAAIH,QAAAA,IAAYtC;QACjB;MACD;;;;MAKO0C,KAAKL,SAAiBC,UAA0B;AACtD,YAAID,YAAY,GAAG;AAClB,gBAAME,MAAM,KAAK1E,OAAO2E,eAAe,CAAA;AACvC,iBAAOD,IAAID,QAAAA;QACZ,WAAW,KAAKP,aAAa,GAAG;AAC/B,gBAAMU,MAAM,KAAK5E,OAAO2E,eAAe,CAAA;AACvC,iBAAOC,IAAIH,QAAAA;QACZ;AACA,eAAO;MACR;IACD;EACD;AACD;","names":["A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","Beeper","audio","notes","plainNotes","currentOctave","currentDuration","currentVolume","currentSpan","currentWaveform","initializeNotes","noteNames","i","oct","Math","floor","n","beep","input","status","sequence","loops","note","parsed","split","t","undefined","push","frequency","A4_FREQUENCY","SEMITONE_RATIO","A4_MIDI_NOTE","volume","span","duration","waveform","includes","length","lop","splice","loopto","start","repeats","tempo","Number","parseFloat","isNaN","step","addBeeps","AUDIO_WORKLET_CODE","AudioCore","context","buffer","playing","wakeupList","workletNode","beeper","runtime","masterVolume","getContext","isStarted","state","addToWakeUpList","item","push","interfaceCache","setVolume","volume","Math","max","min","getVolume","getInterface","beep","sequence","cancelBeeps","playSound","sound","pitch","pan","loopit","playMusic","music","stopAll","soundName","replace","s","sounds","listener","reportError","code","message","data","play","musicName","m","AudioContextClass","window","AudioContext","webkitAudioContext","activate","resume","start","wakeUp","document","body","removeEventListener","addEventListener","once","blob","Blob","AUDIO_WORKLET_CODE","type","url","URL","createObjectURL","audioWorklet","addModule","AudioWorkletNode","connect","destination","flushBuffer","e","error","String","length","port","postMessage","splice","getBeeper","Beeper","addBeeps","beeps","b","duration","sampleRate","increment","frequency","JSON","stringify","name","addPlaying","removePlaying","index","indexOf","p","stop","err","Music","ready","name","url","tag","playing","audio","Audio","play","volume","loopit","loop","Math","max","min","isStarted","addToWakeUpList","addPlaying","stop","pause","removePlaying","setVolume","v","getPosition","currentTime","getDuration","duration","setPosition","pos","wakeUp","Sound","ready","buffer","name","url","audio","AudioBuffer","loadSound","request","XMLHttpRequest","open","responseType","onload","context","decodeAudioData","response","err","runtime","listener","reportError","code","message","data","error","String","onerror","send","play","volume","pitch","pan","loopit","stop","finished","source","createBufferSource","playbackRate","value","loop","gain","createGain","panner","createPanner","panningModel","setPan","p","setPosition","Math","abs","connect","destination","start","playing","addPlaying","res","removePlaying","setVolume","v","max","min","setPitch","getDuration","duration","onended","createSoundClass","audiocore","MicroSound","classname","channels","length","sampleRate","sound","createBuffer","write","channel","position","ch1","getChannelData","ch2","read"]}
|