@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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/index.ts","../../src/core/audio-core.ts","../../src/constants.ts","../../src/devices/beeper.ts","../../src/core/audio-worklet.ts"],"sourcesContent":["export { AudioCore } from \"./audio-core\";\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"],"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","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"]}
1
+ {"version":3,"sources":["../../src/core/index.ts","../../src/constants.ts","../../src/devices/beeper.ts","../../src/core/audio-worklet.ts","../../src/core/audio-core.ts"],"sourcesContent":["export { AudioCore } from \"./audio-core\";\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;ACCO,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;","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"]}
@@ -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
- reportRuntimeError(this.runtime?.listener, APIErrorCode.E7013, {
456
- soundName
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
- reportRuntimeError(this.runtime?.listener, APIErrorCode.E7014, {
473
- musicName
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
- reportRuntimeError(this.runtime?.listener, APIErrorCode.E7012, {
541
- error: String(e)
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
- reportRuntimeError(this.runtime?.listener, APIErrorCode.E7016, {
631
- error: String(err)
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
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/audio-core.ts","../../src/constants.ts","../../src/devices/beeper.ts","../../src/core/audio-worklet.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"],"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;","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"]}
1
+ {"version":3,"sources":["../../src/constants.ts","../../src/devices/beeper.ts","../../src/core/audio-worklet.ts","../../src/core/audio-core.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"],"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"]}
@@ -358,7 +358,6 @@ var Music = class {
358
358
  };
359
359
 
360
360
  // src/devices/sound.ts
361
- var import_diagnostics = require("@al8b/diagnostics");
362
361
  var Sound = class _Sound {
363
362
  static {
364
363
  __name(this, "Sound");
@@ -391,14 +390,22 @@ var Sound = class _Sound {
391
390
  this.buffer = buffer;
392
391
  this.ready = 1;
393
392
  }, (err) => {
394
- (0, import_diagnostics.reportRuntimeError)(this.audio?.runtime?.listener, import_diagnostics.APIErrorCode.E7016, {
395
- error: `Audio decoding failed: ${String(err)}`
393
+ this.audio?.runtime?.listener?.reportError?.({
394
+ code: "E7016",
395
+ message: "Audio decoding failed",
396
+ data: {
397
+ error: `Audio decoding failed: ${String(err)}`
398
+ }
396
399
  });
397
400
  });
398
401
  };
399
402
  request.onerror = () => {
400
- (0, import_diagnostics.reportRuntimeError)(this.audio?.runtime?.listener, import_diagnostics.APIErrorCode.E7016, {
401
- error: `Failed to load sound: ${url}`
403
+ this.audio?.runtime?.listener?.reportError?.({
404
+ code: "E7016",
405
+ message: "Failed to load sound",
406
+ data: {
407
+ error: `Failed to load sound: ${url}`
408
+ }
402
409
  });
403
410
  };
404
411
  request.send();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/devices/index.ts","../../src/constants.ts","../../src/devices/beeper.ts","../../src/devices/music.ts","../../src/devices/sound.ts"],"sourcesContent":["export { Beeper } from \"./beeper\";\nexport { Music } from \"./music\";\nexport { Sound } from \"./sound\";\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","/**\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":"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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","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","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/devices/index.ts","../../src/constants.ts","../../src/devices/beeper.ts","../../src/devices/music.ts","../../src/devices/sound.ts"],"sourcesContent":["export { Beeper } from \"./beeper\";\nexport { Music } from \"./music\";\nexport { Sound } from \"./sound\";\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","/**\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","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"]}
@@ -332,7 +332,6 @@ var Music = class {
332
332
  };
333
333
 
334
334
  // src/devices/sound.ts
335
- import { APIErrorCode, reportRuntimeError } from "@al8b/diagnostics";
336
335
  var Sound = class _Sound {
337
336
  static {
338
337
  __name(this, "Sound");
@@ -365,14 +364,22 @@ var Sound = class _Sound {
365
364
  this.buffer = buffer;
366
365
  this.ready = 1;
367
366
  }, (err) => {
368
- reportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {
369
- error: `Audio decoding failed: ${String(err)}`
367
+ this.audio?.runtime?.listener?.reportError?.({
368
+ code: "E7016",
369
+ message: "Audio decoding failed",
370
+ data: {
371
+ error: `Audio decoding failed: ${String(err)}`
372
+ }
370
373
  });
371
374
  });
372
375
  };
373
376
  request.onerror = () => {
374
- reportRuntimeError(this.audio?.runtime?.listener, APIErrorCode.E7016, {
375
- error: `Failed to load sound: ${url}`
377
+ this.audio?.runtime?.listener?.reportError?.({
378
+ code: "E7016",
379
+ message: "Failed to load sound",
380
+ data: {
381
+ error: `Failed to load sound: ${url}`
382
+ }
376
383
  });
377
384
  };
378
385
  request.send();