spessasynth_lib 4.2.1 → 4.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <img src='https://raw.githubusercontent.com/spessasus/SpessaSynth/refs/heads/master/src/website/spessasynth_logo_rounded.png' width='300' alt='SpessaSynth logo'>
4
4
  </p>
5
5
 
6
- _A powerful SF2/DLS/MIDI TypeScript/JavaScript library for the browsers, based on spessasynth_core.
6
+ _A powerful multipurpose SF2/DLS/MIDI TypeScript/JavaScript library for the browsers, based on spessasynth_core.
7
7
  This is a WebAudioAPI wrapper for the [spessasynth_core](https://github.com/spessasus/spessasynth_core) library._
8
8
 
9
9
  It allows you to:
@@ -91,9 +91,15 @@ document.getElementById("button").onclick = async () => {
91
91
  };
92
92
  ```
93
93
 
94
- # License
94
+ ## License
95
95
 
96
96
  Copyright © 2026 Spessasus
97
97
  Licensed under the Apache-2.0 License.
98
98
 
99
+ #### Legal
100
+
101
+ This project is in no way endorsed or otherwise affiliated with the MIDI Manufacturers Association,
102
+ Roland Corporation, Yamaha Corporation, Creative Technology Ltd. or E-mu Systems, Inc.,
103
+ or any other organization mentioned.
99
104
  SoundFont® is a registered trademark of Creative Technology Ltd.
105
+ All other trademarks are the property of their respective owners.
package/dist/index.js CHANGED
@@ -1223,8 +1223,6 @@ function renderAudioWorker(sampleRate, options) {
1223
1223
  const rendererSynth = new SpessaSynthProcessor(sampleRate, {
1224
1224
  enableEventSystem: false
1225
1225
  });
1226
- const rendererSeq = new SpessaSynthSequencer(rendererSynth);
1227
- rendererSynth.setMasterParameter("autoAllocateVoices", true);
1228
1226
  for (const entry of this.synthesizer.soundBankManager.soundBankList)
1229
1227
  rendererSynth.soundBankManager.addSoundBank(
1230
1228
  entry.soundBank,
@@ -1244,12 +1242,14 @@ function renderAudioWorker(sampleRate, options) {
1244
1242
  const loopDuration = loopEndAbsolute - loopStartAbsolute;
1245
1243
  const duration = parsedMid.duration / playbackRate + options.extraTime + loopDuration * options.loopCount;
1246
1244
  const sampleDuration = sampleRate * duration;
1245
+ const rendererSeq = new SpessaSynthSequencer(rendererSynth);
1247
1246
  rendererSeq.loopCount = options.loopCount;
1248
1247
  if (options.preserveSynthParams) {
1249
1248
  rendererSeq.playbackRate = seq.playbackRate;
1250
1249
  const snapshot = this.synthesizer.getSnapshot();
1251
1250
  rendererSynth.applySynthesizerSnapshot(snapshot);
1252
1251
  }
1252
+ rendererSynth.setMasterParameter("autoAllocateVoices", true);
1253
1253
  rendererSeq.loadNewSongList([parsedMid]);
1254
1254
  rendererSeq.play();
1255
1255
  const wetL = new Float32Array(sampleDuration);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/synthesizer/basic/key_modifier_manager.ts","../src/utils/fill_with_defaults.ts","../src/synthesizer/basic/sound_bank_manager.ts","../src/synthesizer/basic/synth_event_handler.ts","../src/synthesizer/basic/basic_synthesizer.ts","../src/utils/other.ts","../src/synthesizer/basic/snapshot.ts","../src/synthesizer/basic/synth_config.ts","../src/synthesizer/worklet/worklet_processor_name.ts","../src/synthesizer/worklet/worklet_synthesizer.ts","../src/synthesizer/worker/playback_worklet.ts","../src/synthesizer/worker/render_audio_worker.ts","../src/synthesizer/worker/worker_synthesizer.ts","../src/synthesizer/worker/worker_synthesizer_core.ts","../src/synthesizer/basic/basic_synthesizer_core.ts","../src/sequencer/midi_data.ts","../src/sequencer/enums.ts","../src/synthesizer/worker/write_sf_worker.ts","../src/synthesizer/worker/write_rmi_worker.ts","../src/sequencer/sequencer.ts","../src/sequencer/default_sequencer_options.ts","../src/sequencer/seq_event_handler.ts","../src/utils/buffer_to_wav.ts","../src/external_midi/midi_handler.ts","../src/external_midi/web_midi_link.ts"],"sourcesContent":["import { KeyModifier, type MIDIPatch } from \"spessasynth_core\";\nimport type { WorkletKMManagerData } from \"../types.ts\";\nimport type { BasicSynthesizer } from \"./basic_synthesizer.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\n\nexport class WorkletKeyModifierManagerWrapper {\n // The velocity override mappings for MIDI keys\n private keyModifiers: (KeyModifier | undefined)[][] = [];\n\n private synth: BasicSynthesizer;\n\n public constructor(synth: BasicSynthesizer) {\n this.synth = synth;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Modifies a single key.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n * @param options The key's modifiers.\n */\n public addModifier(\n channel: number,\n midiNote: number,\n options: Partial<{\n velocity: number;\n patch: MIDIPatch;\n gain: number;\n }>\n ) {\n const mod = new KeyModifier();\n mod.gain = options?.gain ?? 1;\n mod.velocity = options?.velocity ?? -1;\n mod.patch = fillWithDefaults(\n options.patch ?? ({} as Partial<MIDIPatch>),\n {\n isGMGSDrum: false,\n bankLSB: -1,\n bankMSB: -1,\n program: -1\n }\n );\n this.keyModifiers[channel] ??= [];\n this.keyModifiers[channel][midiNote] = mod;\n this.sendToWorklet(\"addMapping\", {\n channel,\n midiNote,\n mapping: mod\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a key modifier.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n * @returns The key modifier if it exists.\n */\n public getModifier(\n channel: number,\n midiNote: number\n ): KeyModifier | undefined {\n return this.keyModifiers?.[channel]?.[midiNote];\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Deletes a key modifier.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n */\n public deleteModifier(channel: number, midiNote: number) {\n this.sendToWorklet(\"deleteMapping\", {\n channel,\n midiNote\n });\n if (this.keyModifiers[channel]?.[midiNote] === undefined) {\n return;\n }\n this.keyModifiers[channel][midiNote] = undefined;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Clears ALL Modifiers\n */\n public clearModifiers() {\n this.sendToWorklet(\"clearMappings\", null);\n this.keyModifiers = [];\n }\n\n private sendToWorklet<T extends keyof WorkletKMManagerData>(\n type: T,\n data: WorkletKMManagerData[T]\n ) {\n const msg = {\n type,\n data\n } as {\n [K in keyof WorkletKMManagerData]: {\n type: K;\n data: WorkletKMManagerData[K];\n };\n }[keyof WorkletKMManagerData];\n this.synth.post({\n type: \"keyModifierManager\",\n channelNumber: -1,\n data: msg\n });\n }\n}\n","/**\n * Fills the object with default values.\n * @param obj object to fill.\n * @param defObj object to fill with.\n */\nexport function fillWithDefaults<T>(obj: Partial<T> | undefined, defObj: T): T {\n return {\n ...defObj,\n ...obj\n };\n}\n","import {\n type SoundBankManagerListEntry,\n SpessaSynthCoreUtils\n} from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n WorkletSBKManagerData\n} from \"../types.ts\";\nimport type { BasicSynthesizer } from \"./basic_synthesizer.ts\";\n\ntype LibSBKManagerEntry = Omit<SoundBankManagerListEntry, \"soundBank\">;\n\nexport class SoundBankManager {\n /**\n * All the sound banks, ordered from the most important to the least.\n */\n public soundBankList: LibSBKManagerEntry[];\n\n private synth: BasicSynthesizer;\n\n /**\n * Creates a new instance of the sound bank manager.\n */\n public constructor(synth: BasicSynthesizer) {\n this.soundBankList = [];\n this.synth = synth;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * The current sound bank priority order.\n * @returns The IDs of the sound banks in the current order.\n */\n public get priorityOrder() {\n return this.soundBankList.map((s) => s.id);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Rearranges the sound banks in a given order.\n * @param newList The order of sound banks, a list of identifiers, first overwrites second.\n */\n public set priorityOrder(newList: string[]) {\n this.sendToWorklet(\"rearrangeSoundBanks\", newList);\n this.soundBankList.sort(\n (a, b) => newList.indexOf(a.id) - newList.indexOf(b.id)\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new sound bank buffer with a given ID.\n * @param soundBankBuffer The sound bank's buffer\n * @param id The sound bank's unique identifier.\n * @param bankOffset The sound bank's bank offset. Default is 0.\n */\n public async addSoundBank(\n soundBankBuffer: ArrayBuffer,\n id: string,\n bankOffset = 0\n ) {\n this.sendToWorklet(\n \"addSoundBank\",\n {\n soundBankBuffer,\n bankOffset,\n id\n },\n [soundBankBuffer]\n );\n await this.awaitResponse();\n const found = this.soundBankList.find((s) => s.id === id);\n if (found === undefined) {\n this.soundBankList.push({\n id: id,\n bankOffset: bankOffset\n });\n } else {\n found.bankOffset = bankOffset;\n }\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Deletes a sound bank with the given ID.\n * @param id The sound bank to delete.\n */\n public async deleteSoundBank(id: string) {\n if (this.soundBankList.length < 2) {\n SpessaSynthCoreUtils.SpessaSynthWarn(\n \"1 sound bank left. Aborting!\"\n );\n return;\n }\n if (!this.soundBankList.some((s) => s.id === id)) {\n SpessaSynthCoreUtils.SpessaSynthWarn(\n `No sound banks with id of \"${id}\" found. Aborting!`\n );\n return;\n }\n this.sendToWorklet(\"deleteSoundBank\", id);\n this.soundBankList = this.soundBankList.filter((s) => s.id !== id);\n await this.awaitResponse();\n }\n\n private async awaitResponse() {\n return new Promise((r) =>\n this.synth.awaitWorkerResponse(\"soundBankManager\", r)\n );\n }\n\n private sendToWorklet<T extends keyof WorkletSBKManagerData>(\n type: T,\n data: WorkletSBKManagerData[T],\n transferable: Transferable[] = []\n ) {\n const msg: BasicSynthesizerMessage = {\n type: \"soundBankManager\",\n channelNumber: -1,\n data: {\n type,\n data\n } as {\n [K in keyof WorkletSBKManagerData]: {\n type: K;\n data: WorkletSBKManagerData[K];\n };\n }[keyof WorkletSBKManagerData]\n };\n this.synth.post(msg, transferable);\n }\n}\n","import type { SynthProcessorEventData } from \"spessasynth_core\";\n\ntype ProcessorEventCallback<T extends keyof SynthProcessorEventData> = (\n callbackData: SynthProcessorEventData[T]\n) => unknown;\n\ntype EventsMap = {\n [K in keyof SynthProcessorEventData]: Map<\n string,\n ProcessorEventCallback<K>\n >;\n};\n\nexport class SynthEventHandler {\n /**\n * The time delay before an event is called.\n * Set to 0 to disable it.\n */\n public timeDelay = 0;\n\n /**\n * The main list of events.\n * @private\n */\n private readonly events: EventsMap = {\n noteOff: new Map<string, ProcessorEventCallback<\"noteOff\">>(), // Called on a note off message\n noteOn: new Map<string, ProcessorEventCallback<\"noteOn\">>(), // Called on a note on message\n pitchWheel: new Map<string, ProcessorEventCallback<\"pitchWheel\">>(), // Called on a pitch-wheel change\n controllerChange: new Map<\n string,\n ProcessorEventCallback<\"controllerChange\">\n >(), // Called on a controller change\n programChange: new Map<\n string,\n ProcessorEventCallback<\"programChange\">\n >(), // Called on a program change\n channelPressure: new Map<\n string,\n ProcessorEventCallback<\"channelPressure\">\n >(), // Called on a channel pressure message\n polyPressure: new Map<string, ProcessorEventCallback<\"polyPressure\">>(), // Called on a poly pressure message\n drumChange: new Map<string, ProcessorEventCallback<\"drumChange\">>(), // Called when a channel type changes\n stopAll: new Map<string, ProcessorEventCallback<\"stopAll\">>(), // Called when the synth receives stop all command\n newChannel: new Map<string, ProcessorEventCallback<\"newChannel\">>(), // Called when a new channel is created\n muteChannel: new Map<string, ProcessorEventCallback<\"muteChannel\">>(), // Called when a channel is muted/unmuted\n presetListChange: new Map<\n string,\n ProcessorEventCallback<\"presetListChange\">\n >(), // Called when the preset list changes (soundfont gets reloaded)\n allControllerReset: new Map<\n string,\n ProcessorEventCallback<\"allControllerReset\">\n >(), // Called when all controllers are reset\n soundBankError: new Map<\n string,\n ProcessorEventCallback<\"soundBankError\">\n >(), // Called when a sound bank parsing error occurs\n synthDisplay: new Map<string, ProcessorEventCallback<\"synthDisplay\">>(), // Called when there's a SysEx message to display some text\n masterParameterChange: new Map<\n string,\n ProcessorEventCallback<\"masterParameterChange\">\n >(), // Called when a master parameter changes\n channelPropertyChange: new Map<\n string,\n ProcessorEventCallback<\"channelPropertyChange\">\n >(), // Called when a channel property changes\n effectChange: new Map<string, ProcessorEventCallback<\"effectChange\">>() // Called when an effect processor parameter is changed\n };\n\n /**\n * Adds a new event listener.\n * @param event The event to listen to.\n * @param id The unique identifier for the event. It can be used to overwrite existing callback with the same ID.\n * @param callback The callback for the event.\n */\n public addEvent<T extends keyof SynthProcessorEventData>(\n event: T,\n id: string,\n callback: ProcessorEventCallback<T>\n ) {\n this.events[event].set(id, callback);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Removes an event listener\n * @param name The event to remove a listener from.\n * @param id The unique identifier for the event to remove.\n */\n public removeEvent<T extends keyof SynthProcessorEventData>(\n name: T,\n id: string\n ) {\n this.events[name].delete(id);\n }\n\n /**\n * Calls the given event.\n * INTERNAL USE ONLY!\n * @internal\n */\n public callEventInternal<T extends keyof SynthProcessorEventData>(\n name: T,\n eventData: SynthProcessorEventData[T]\n ) {\n const eventList = this.events[name];\n const callback = () => {\n for (const callback of eventList.values()) {\n try {\n callback(eventData);\n } catch (error) {\n console.error(\n `Error while executing an event callback for ${name}:`,\n error\n );\n }\n }\n };\n if (this.timeDelay > 0) {\n setTimeout(callback.bind(this), this.timeDelay * 1000);\n } else {\n callback();\n }\n }\n}\n","import { WorkletKeyModifierManagerWrapper } from \"./key_modifier_manager.ts\";\nimport { SoundBankManager } from \"./sound_bank_manager.ts\";\nimport { SynthEventHandler } from \"./synth_event_handler.ts\";\nimport {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type ChannelProperty,\n DEFAULT_MASTER_PARAMETERS,\n DEFAULT_PERCUSSION,\n type MasterParameterType,\n type MIDIController,\n midiControllers,\n midiMessageTypes,\n type PresetList,\n SpessaSynthCoreUtils as util,\n type SynthMethodOptions\n} from \"spessasynth_core\";\nimport type { SequencerReturnMessage } from \"../../sequencer/types.ts\";\nimport type { SynthConfig } from \"./types.ts\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn\n} from \"../types.ts\";\nimport { consoleColors } from \"../../utils/other.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\nimport { LibSynthesizerSnapshot } from \"./snapshot.ts\";\n\nconst DEFAULT_SYNTH_METHOD_OPTIONS: SynthMethodOptions = {\n time: 0\n};\n\n// The \"remote controller\" of a given processor and abstraction for both synth engines.\nexport abstract class BasicSynthesizer {\n /**\n * Allows managing the sound bank list.\n */\n public readonly soundBankManager = new SoundBankManager(this);\n /**\n * Allows managing key modifications.\n */\n public readonly keyModifierManager = new WorkletKeyModifierManagerWrapper(\n this\n );\n /**\n * Allows setting up custom event listeners for the synthesizer.\n */\n public readonly eventHandler: SynthEventHandler = new SynthEventHandler();\n /**\n * Synthesizer's parent AudioContext instance.\n */\n public readonly context: BaseAudioContext;\n /**\n * Synth's current channel properties.\n */\n public readonly channelProperties: ChannelProperty[] = [];\n /**\n * The current preset list.\n */\n public presetList: PresetList = [];\n\n /**\n * INTERNAL USE ONLY!\n * @internal\n * All sequencer callbacks\n */\n public sequencers = new Array<(m: SequencerReturnMessage) => unknown>();\n /**\n * Resolves when the synthesizer is ready.\n */\n public readonly isReady: Promise<unknown>;\n // noinspection JSUnusedGlobalSymbols\n /**\n * Legacy parameter.\n * @deprecated\n */\n public readonly reverbProcessor = undefined;\n // noinspection JSUnusedGlobalSymbols\n /**\n * Legacy parameter.\n * @deprecated\n */\n public readonly chorusProcessor = undefined;\n /**\n * INTERNAL USE ONLY!\n * @internal\n */\n public readonly post: (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown;\n protected readonly worklet: AudioWorkletNode;\n /**\n * The new channels will have their audio sent to the modulated output by this constant.\n * what does that mean?\n * e.g., if outputsAmount is 16, then channel's 16 audio data will be sent to channel 0\n */\n protected readonly _outputsAmount = 16;\n /**\n * The current amount of MIDI channels the synthesizer has.\n */\n public channelsAmount = this._outputsAmount;\n protected readonly masterParameters: MasterParameterType = {\n ...DEFAULT_MASTER_PARAMETERS\n };\n\n // Resolve map, waiting for the worklet to confirm the operation\n protected resolveMap = new Map<\n keyof SynthesizerReturn,\n (data: SynthesizerReturn[keyof SynthesizerReturn]) => unknown\n >();\n\n protected renderingProgressTracker = new Map<\n keyof SynthesizerProgress,\n {\n [K in keyof SynthesizerProgress]: (\n args: SynthesizerProgress[K]\n ) => unknown;\n }[keyof SynthesizerProgress]\n >();\n\n /**\n * Creates a new instance of a synthesizer.\n * @param worklet The AudioWorkletNode to use.\n * @param postFunction The internal post function.\n * @param config Optional configuration for the synthesizer.\n */\n protected constructor(\n worklet: AudioWorkletNode,\n postFunction: (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown,\n config: SynthConfig\n ) {\n util.SpessaSynthInfo(\n \"%cInitializing SpessaSynth synthesizer...\",\n consoleColors.info\n );\n this.context = worklet.context;\n this.worklet = worklet;\n this.post = postFunction;\n\n // Used in child classes\n void config;\n\n this.isReady = new Promise((resolve) =>\n this.awaitWorkerResponse(\"sf3Decoder\", resolve)\n );\n\n // Set up message handling and managers\n this.worklet.port.onmessage = (\n e: MessageEvent<BasicSynthesizerReturnMessage>\n ) => this.handleMessage(e.data);\n\n // Create initial channels\n for (let i = 0; i < this.channelsAmount; i++) {\n this.addNewChannelInternal(false);\n }\n this.channelProperties[DEFAULT_PERCUSSION].isDrum = true;\n\n // Attach event handlers\n this.eventHandler.addEvent(\n \"newChannel\",\n `synth-new-channel-${Math.random()}`,\n () => {\n this.channelsAmount++;\n }\n );\n this.eventHandler.addEvent(\n \"presetListChange\",\n `synth-preset-list-change-${Math.random()}`,\n (e) => {\n this.presetList = [...e];\n }\n );\n this.eventHandler.addEvent(\n \"masterParameterChange\",\n `synth-master-parameter-change-${Math.random()}`,\n <P extends keyof MasterParameterType>(e: {\n parameter: P;\n value: MasterParameterType[P];\n }) => {\n this.masterParameters[e.parameter] = e.value;\n }\n );\n this.eventHandler.addEvent(\n \"channelPropertyChange\",\n `synth-channel-property-change-${Math.random()}`,\n (e) => {\n this.channelProperties[e.channel] = e.property;\n\n this._voicesAmount = this.channelProperties.reduce(\n (sum, voices) => sum + voices.voicesAmount,\n 0\n );\n }\n );\n }\n\n /**\n * Current voice amount\n */\n protected _voicesAmount = 0;\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * The current number of voices playing.\n */\n public get voicesAmount() {\n return this._voicesAmount;\n }\n\n /**\n * The audioContext's current time.\n */\n public get currentTime() {\n return this.context.currentTime;\n }\n\n /**\n * Connects from a given node.\n * @param destinationNode The node to connect to.\n */\n public connect(destinationNode: AudioNode) {\n // Connect all other worklet outputs (effects + 16 channels)\n for (let i = 0; i < 17; i++) {\n this.worklet.connect(destinationNode, i);\n }\n return destinationNode;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects from a given node.\n * @param destinationNode The node to disconnect from.\n */\n public disconnect(destinationNode?: AudioNode) {\n if (!destinationNode) {\n this.worklet.disconnect();\n return undefined;\n }\n // Disconnect all other worklet outputs\n for (let i = 0; i < 17; i++) {\n this.worklet.disconnect(destinationNode, i);\n }\n return destinationNode;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets the SpessaSynth's log level in the processor.\n * @param enableInfo Enable info (verbose)\n * @param enableWarning Enable warnings (unrecognized messages)\n * @param enableGroup Enable groups (to group a lot of logs)\n */\n public setLogLevel(\n enableInfo: boolean,\n enableWarning: boolean,\n enableGroup: boolean\n ) {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"setLogLevel\",\n data: {\n enableInfo,\n enableWarning,\n enableGroup\n }\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a master parameter from the synthesizer.\n * @param type The parameter to get.\n * @returns The parameter value.\n */\n public getMasterParameter<K extends keyof MasterParameterType>(\n type: K\n ): MasterParameterType[K] {\n return this.masterParameters[type];\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets a master parameter to a given value.\n * @param type The parameter to set.\n * @param value The value to set.\n */\n public setMasterParameter<K extends keyof MasterParameterType>(\n type: K,\n value: MasterParameterType[K]\n ) {\n this.masterParameters[type] = value;\n this.post({\n type: \"setMasterParameter\",\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n data: {\n type,\n data: value\n } as {\n [K in keyof MasterParameterType]: {\n type: K;\n data: MasterParameterType[K];\n };\n }[keyof MasterParameterType]\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a complete snapshot of the synthesizer, effects.\n */\n public async getSnapshot(): Promise<LibSynthesizerSnapshot> {\n return new Promise((resolve) => {\n this.awaitWorkerResponse(\"synthesizerSnapshot\", (s) => {\n const snapshot = LibSynthesizerSnapshot.copyFrom(s);\n resolve(snapshot);\n });\n this.post({\n type: \"requestSynthesizerSnapshot\",\n data: null,\n channelNumber: -1\n });\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new channel to the synthesizer.\n */\n public addNewChannel() {\n this.addNewChannelInternal(true);\n }\n\n /**\n * DEPRECATED, please don't use it!\n * @deprecated\n */\n public setVibrato(\n channel: number,\n value: { delay: number; depth: number; rate: number }\n ) {\n void channel;\n void value;\n }\n\n /**\n * Connects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.\n * @param audioNodes Exactly 16 outputs.\n */\n public connectIndividualOutputs(audioNodes: AudioNode[]) {\n if (audioNodes.length !== this._outputsAmount) {\n throw new Error(`input nodes amount differs from the system's outputs amount!\n Expected ${this._outputsAmount} got ${audioNodes.length}`);\n }\n for (\n let outputNumber = 0;\n outputNumber < this._outputsAmount;\n outputNumber++\n ) {\n // + 1 because effects come first!\n this.worklet.connect(audioNodes[outputNumber], outputNumber + 1);\n }\n }\n\n /**\n * Disconnects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.\n * @param audioNodes Exactly 16 outputs.\n */\n public disconnectIndividualOutputs(audioNodes: AudioNode[]) {\n if (audioNodes.length !== this._outputsAmount) {\n throw new Error(`input nodes amount differs from the system's outputs amount!\n Expected ${this._outputsAmount} got ${audioNodes.length}`);\n }\n for (\n let outputNumber = 0;\n outputNumber < this._outputsAmount;\n outputNumber++\n ) {\n // + 2 because chorus and reverb come first!\n this.worklet.disconnect(audioNodes[outputNumber], outputNumber + 2);\n }\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disables the GS NRPN parameters like vibrato or drum key tuning.\n * @deprecated Deprecated! Please use master parameters\n */\n public disableGSNPRNParams() {\n this.setMasterParameter(\"nprnParamLock\", true);\n }\n\n /**\n * Sends a raw MIDI message to the synthesizer.\n * @param message the midi message, each number is a byte.\n * @param channelOffset the channel offset of the message.\n * @param eventOptions additional options for this command.\n */\n public sendMessage(\n message: Iterable<number>,\n channelOffset = 0,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n this._sendInternal(message, channelOffset, false, eventOptions);\n }\n\n /**\n * Starts playing a note\n * @param channel Usually 0-15: the channel to play the note.\n * @param midiNote 0-127 the key number of the note.\n * @param velocity 0-127 the velocity of the note (generally controls loudness).\n * @param eventOptions Additional options for this command.\n */\n public noteOn(\n channel: number,\n midiNote: number,\n velocity: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n midiNote %= 128;\n velocity %= 128;\n this.sendMessage(\n [midiMessageTypes.noteOn | ch, midiNote, velocity],\n offset,\n eventOptions\n );\n }\n\n /**\n * Stops playing a note.\n * @param channel Usually 0-15: the channel of the note.\n * @param midiNote {number} 0-127 the key number of the note.\n * @param force Instantly kills the note if true.\n * @param eventOptions Additional options for this command.\n */\n public noteOff(\n channel: number,\n midiNote: number,\n force = false,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n midiNote %= 128;\n\n const ch = channel % 16;\n const offset = channel - ch;\n this._sendInternal(\n [midiMessageTypes.noteOff | ch, midiNote],\n offset,\n force,\n eventOptions\n );\n }\n\n /**\n * Stops all notes.\n * @param force If the notes should immediately be stopped, defaults to false.\n */\n public stopAll(force = false) {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"stopAll\",\n data: force ? 1 : 0\n });\n }\n\n /**\n * Changes the given controller\n * @param channel Usually 0-15: the channel to change the controller.\n * @param controllerNumber 0-127 the MIDI CC number.\n * @param controllerValue 0-127 the controller value.\n * @param force Forces the controller-change message, even if it's locked or gm system is set and the cc is bank select.\n * @param eventOptions Additional options for this command.\n */\n public controllerChange(\n channel: number,\n controllerNumber: MIDIController,\n controllerValue: number,\n force = false,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n if (controllerNumber > 127 || controllerNumber < 0) {\n throw new Error(`Invalid controller number: ${controllerNumber}`);\n }\n controllerValue = Math.floor(controllerValue) % 128;\n controllerNumber = Math.floor(controllerNumber) % 128;\n // Controller change has its own message for the force property\n const ch = channel % 16;\n const offset = channel - ch;\n this._sendInternal(\n [\n midiMessageTypes.controllerChange | ch,\n controllerNumber,\n controllerValue\n ],\n offset,\n force,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Resets all controllers (for every channel)\n */\n public resetControllers() {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"ccReset\",\n data: null\n });\n }\n\n /**\n * Causes the given midi channel to ignore controller messages for the given controller number.\n * @param channel Usually 0-15: the channel to lock.\n * @param controllerNumber 0-127 MIDI CC number.\n * @param isLocked True if locked, false if unlocked.\n * @remarks\n * Controller number -1 locks the preset.\n */\n public lockController(\n channel: number,\n controllerNumber: MIDIController | -1,\n isLocked: boolean\n ) {\n this.post({\n channelNumber: channel,\n type: \"lockController\",\n data: {\n controllerNumber,\n isLocked\n }\n });\n }\n\n /**\n * Applies pressure to a given channel.\n * @param channel Usually 0-15: the channel to change the controller.\n * @param pressure 0-127: the pressure to apply.\n * @param eventOptions Additional options for this command.\n */\n public channelPressure(\n channel: number,\n pressure: number,\n eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n pressure %= 128;\n this.sendMessage(\n [midiMessageTypes.channelPressure | ch, pressure],\n offset,\n eventOptions\n );\n }\n\n /**\n * Applies pressure to a given note.\n * @param channel Usually 0-15: the channel to change the controller.\n * @param midiNote 0-127: the MIDI note.\n * @param pressure 0-127: the pressure to apply.\n * @param eventOptions Additional options for this command.\n */\n public polyPressure(\n channel: number,\n midiNote: number,\n pressure: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n midiNote %= 128;\n pressure %= 128;\n this.sendMessage(\n [midiMessageTypes.polyPressure | ch, midiNote, pressure],\n offset,\n eventOptions\n );\n }\n\n /**\n * Sets the pitch of the given channel.\n * @param channel Usually 0-15: the channel to change pitch.\n * @param value The bend of the MIDI pitch wheel message. 0 - 16384\n * @param eventOptions Additional options for this command.\n */\n public pitchWheel(\n channel: number,\n value: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n this.sendMessage(\n [midiMessageTypes.pitchWheel | ch, value & 0x7f, value >> 7],\n offset,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets the channel's pitch wheel range, in semitones.\n * @param channel Usually 0-15: the channel to change.\n * @param range The bend range in semitones.\n */\n public pitchWheelRange(channel: number, range: number) {\n // Set range\n this.controllerChange(\n channel,\n midiControllers.registeredParameterMSB,\n 0\n );\n this.controllerChange(\n channel,\n midiControllers.registeredParameterLSB,\n 0\n );\n this.controllerChange(channel, midiControllers.dataEntryMSB, range);\n\n // Reset rpn\n this.controllerChange(\n channel,\n midiControllers.registeredParameterMSB,\n 127\n );\n this.controllerChange(\n channel,\n midiControllers.registeredParameterLSB,\n 127\n );\n this.controllerChange(channel, midiControllers.dataEntryMSB, 0);\n }\n\n /**\n * Changes the program for a given channel\n * @param channel Usually 0-15: the channel to change.\n * @param programNumber 0-127 the MIDI patch number.\n * defaults to false\n */\n public programChange(channel: number, programNumber: number) {\n const ch = channel % 16;\n const offset = channel - ch;\n programNumber %= 128;\n this.sendMessage(\n [midiMessageTypes.programChange | ch, programNumber],\n offset\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Transposes the channel by given number of semitones.\n * @param channel The channel number.\n * @param semitones The transposition of the channel, it can be a float.\n * @param force Defaults to false, if true transposes the channel even if it's a drum channel.\n */\n public transposeChannel(channel: number, semitones: number, force = false) {\n this.post({\n channelNumber: channel,\n type: \"transposeChannel\",\n data: {\n semitones,\n force\n }\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Mutes or unmutes the given channel.\n * @param channel Usually 0-15: the channel to mute.\n * @param isMuted Indicates if the channel is muted.\n */\n public muteChannel(channel: number, isMuted: boolean) {\n this.post({\n channelNumber: channel,\n type: \"muteChannel\",\n data: isMuted\n });\n }\n\n /**\n * Sends a MIDI Sysex message to the synthesizer.\n * @param messageData The message's data, excluding the F0 byte, but including the F7 at the end.\n * @param channelOffset Channel offset for the system exclusive message, defaults to zero.\n * @param eventOptions Additional options for this command.\n */\n public systemExclusive(\n messageData: number[] | Iterable<number> | Uint8Array,\n channelOffset = 0,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n this._sendInternal(\n [midiMessageTypes.systemExclusive, ...Array.from(messageData)],\n channelOffset,\n false,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Tune MIDI keys of a given program using the MIDI Tuning Standard.\n * @param program 0 - 127 the MIDI program number to use.\n * @param tunings The keys and their tunings.\n * TargetPitch of -1 sets the tuning for this key to be tuned regularly.\n */\n public tuneKeys(\n program: number,\n tunings: { sourceKey: number; targetPitch: number }[]\n ) {\n if (tunings.length > 127) {\n throw new Error(\"Too many tunings. Maximum allowed is 127.\");\n }\n const systemExclusive = [\n 0x7f, // Real-time\n 0x10, // Device id\n 0x08, // MIDI Tuning\n 0x02, // Note change\n program, // Tuning program number\n tunings.length // Number of changes\n ];\n for (const tuning of tunings) {\n systemExclusive.push(tuning.sourceKey); // [kk] MIDI Key number\n if (tuning.targetPitch === -1) {\n // No change\n systemExclusive.push(0x7f, 0x7f, 0x7f);\n } else {\n const midiNote = Math.floor(tuning.targetPitch);\n const fraction = Math.floor(\n (tuning.targetPitch - midiNote) / 0.000_061\n );\n systemExclusive.push(\n midiNote, // Frequency data byte 1\n (fraction >> 7) & 0x7f, // Frequency data byte 2\n fraction & 0x7f // Frequency data byte 3\n );\n }\n }\n systemExclusive.push(0xf7);\n this.systemExclusive(systemExclusive);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Toggles drums on a given channel.\n * @param channel The channel number.\n * @param isDrum If the channel should be drums.\n */\n public setDrums(channel: number, isDrum: boolean) {\n this.post({\n channelNumber: channel,\n type: \"setDrums\",\n data: isDrum\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Yes please!\n */\n public reverbateEverythingBecauseWhyNot(): \"That's the spirit!\" {\n for (let i = 0; i < this.channelsAmount; i++) {\n this.controllerChange(i, midiControllers.reverbDepth, 127);\n this.lockController(i, midiControllers.reverbDepth, true);\n }\n return \"That's the spirit!\";\n }\n\n /**\n * INTERNAL USE ONLY!\n * @param type INTERNAL USE ONLY!\n * @param resolve INTERNAL USE ONLY!\n * @internal\n */\n public awaitWorkerResponse<K extends keyof SynthesizerReturn>(\n type: K,\n resolve: (data: SynthesizerReturn[K]) => unknown\n ) {\n // @ts-expect-error I can't use generics with map\n this.resolveMap.set(type, resolve);\n }\n\n /**\n * INTERNAL USE ONLY!\n * @param callback the sequencer callback\n * @internal\n */\n public assignNewSequencer(\n callback: (m: SequencerReturnMessage) => unknown\n ) {\n this.post({\n channelNumber: -1,\n type: \"requestNewSequencer\",\n data: null\n });\n this.sequencers.push(callback);\n return this.sequencers.length - 1;\n }\n\n protected assignProgressTracker<K extends keyof SynthesizerProgress>(\n type: K,\n progressFunction: (args: SynthesizerProgress[K]) => unknown\n ) {\n if (this.renderingProgressTracker.get(type)) {\n throw new Error(\"Something is already being rendered!\");\n }\n // @ts-expect-error I can't use generics with map\n this.renderingProgressTracker.set(type, progressFunction);\n }\n\n protected revokeProgressTracker<K extends keyof SynthesizerProgress>(\n type: K\n ) {\n this.renderingProgressTracker.delete(type);\n }\n\n protected _sendInternal(\n message: Iterable<number>,\n channelOffset: number,\n force = false,\n eventOptions: Partial<SynthMethodOptions>\n ) {\n const options = fillWithDefaults(\n eventOptions,\n DEFAULT_SYNTH_METHOD_OPTIONS\n );\n this.post({\n type: \"midiMessage\",\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n data: {\n messageData: new Uint8Array(message),\n channelOffset,\n force,\n options\n }\n //[new Uint8Array(message), offset, force, opts]\n });\n }\n\n /**\n * Handles the messages received from the worklet.\n */\n protected handleMessage(m: BasicSynthesizerReturnMessage) {\n switch (m.type) {\n case \"eventCall\": {\n this.eventHandler.callEventInternal(m.data.type, m.data.data);\n break;\n }\n\n case \"sequencerReturn\": {\n this.sequencers[m.data.id](m.data);\n break;\n }\n\n case \"isFullyInitialized\": {\n this.workletResponds(m.data.type, m.data.data);\n break;\n }\n\n case \"soundBankError\": {\n util.SpessaSynthWarn(m.data as unknown as string);\n this.eventHandler.callEventInternal(\"soundBankError\", m.data);\n break;\n }\n\n case \"renderingProgress\": {\n this.renderingProgressTracker.get(m.data.type)?.(\n // @ts-expect-error I can't use generics with map\n m.data.data\n );\n }\n }\n }\n\n protected addNewChannelInternal(post: boolean) {\n this.channelProperties.push({\n voicesAmount: 0,\n pitchWheel: 0,\n pitchWheelRange: 0,\n isMuted: false,\n isDrum: this.channelsAmount % 16 === DEFAULT_PERCUSSION,\n isEFX: false,\n transposition: 0\n });\n if (!post) {\n return;\n }\n this.post({\n channelNumber: 0,\n type: \"addNewChannel\",\n data: null\n });\n }\n\n protected workletResponds<K extends keyof SynthesizerReturn>(\n type: K,\n data: SynthesizerReturn[K]\n ) {\n this.resolveMap.get(type)?.(data);\n this.resolveMap.delete(type);\n }\n}\n","/**\n * Other.js\n * purpose: contains some useful functions that don't belong in any specific category\n */\n\nimport { SpessaSynthCoreUtils } from \"spessasynth_core\";\n\nconst consoleColors = SpessaSynthCoreUtils.consoleColors;\n\nexport { consoleColors };\n","/**\n * Old synthesizer snapshot, used to contain audio effects.\n * @deprecated\n */\nexport { SynthesizerSnapshot as LibSynthesizerSnapshot } from \"spessasynth_core\";\n","import type { SynthConfig } from \"./types\";\n\nexport const DEFAULT_SYNTH_CONFIG: SynthConfig = {\n enableEventSystem: true,\n oneOutput: false,\n audioNodeCreators: undefined\n};\n","export const WORKLET_PROCESSOR_NAME = \"spessasynth-worklet-processor\";\n","import { DEFAULT_SYNTH_CONFIG } from \"../basic/synth_config.ts\";\nimport { WORKLET_PROCESSOR_NAME } from \"./worklet_processor_name.js\";\nimport type { SynthConfig } from \"../basic/types.ts\";\nimport { BasicSynthesizer } from \"../basic/basic_synthesizer.ts\";\nimport type { OfflineRenderWorkletData } from \"../types.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\n\n/**\n * This synthesizer uses an audio worklet node containing the processor.\n */\nexport class WorkletSynthesizer extends BasicSynthesizer {\n /**\n * Creates a new instance of an AudioWorklet-based synthesizer.\n * @param context The audio context.\n * @param config Optional configuration for the synthesizer.\n */\n public constructor(\n context: BaseAudioContext,\n config: Partial<SynthConfig> = DEFAULT_SYNTH_CONFIG\n ) {\n // Ensure default values for options\n const synthConfig = fillWithDefaults(config, DEFAULT_SYNTH_CONFIG);\n\n let outputChannelCount = new Array<number>(17).fill(2);\n let numberOfOutputs = 17;\n\n if (synthConfig.oneOutput) {\n // One output with 34 channels\n outputChannelCount = [34];\n numberOfOutputs = 1;\n }\n\n let worklet: AudioWorkletNode;\n // Create the audio worklet node\n try {\n const workletConstructor =\n synthConfig?.audioNodeCreators?.worklet ??\n ((context, name, options) => {\n return new AudioWorkletNode(context, name, options);\n });\n worklet = workletConstructor(context, WORKLET_PROCESSOR_NAME, {\n outputChannelCount,\n numberOfOutputs,\n processorOptions: {\n oneOutput: synthConfig.oneOutput,\n enableEventSystem: synthConfig.enableEventSystem\n }\n });\n } catch (error) {\n console.error(error);\n throw new Error(\n \"Could not create the AudioWorkletNode. Did you forget to addModule()?\"\n );\n }\n super(\n worklet,\n (data, transfer = []) => {\n worklet.port.postMessage(data, transfer);\n },\n synthConfig\n );\n }\n\n /**\n * Starts an offline audio render.\n * @param config The configuration to use.\n * @remarks\n * Call this method immediately after you've set up the synthesizer.\n * Do NOT call any other methods after initializing before this one.\n * Chromium seems to ignore worklet messages for OfflineAudioContext.\n */\n public async startOfflineRender(config: OfflineRenderWorkletData) {\n this.post(\n {\n type: \"startOfflineRender\",\n data: config,\n channelNumber: -1\n },\n config.soundBankList.map((b) => b.soundBankBuffer)\n );\n await new Promise((r) =>\n this.awaitWorkerResponse(\"startOfflineRender\", r)\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Destroys the synthesizer instance.\n */\n public destroy() {\n // noinspection JSCheckFunctionSignatures\n this.post({\n channelNumber: 0,\n type: \"destroyWorklet\",\n data: null\n });\n this.worklet.disconnect();\n // @ts-expect-error destruction!\n // noinspection JSConstantReassignment\n delete this.worklet;\n }\n}\n","export const PLAYBACK_WORKLET_PROCESSOR_NAME = `spessasynth-playback-worklet-processor`;\n\nexport function getPlaybackWorkletURL(maxQueuedChunks: number) {\n // Thanks to the wonderful Audio Worklet API, we have this: code in strings!\n const PLAYBACK_WORKLET_CODE = `\nconst BLOCK_SIZE = 128;\n\nconst MAX_QUEUED = ${maxQueuedChunks};\n\n/**\n * An AudioWorkletProcessor that plays back 18 separate streams of stereo audio: reverb, and chorus and 16 dry channels.\n */\nclass PlaybackProcessor extends AudioWorkletProcessor\n{\n \n \n /** @type {Float32Array[]} */\n data = [];\n \n updateRequested = false;\n \n alive = true;\n \n /**\n *\n * @type {MessagePort}\n */\n sentPort;\n \n constructor()\n {\n super();\n \n /**\n * @param e {MessageEvent}\n */\n this.port.onmessage = (e) =>\n {\n if (e.ports.length)\n {\n const sentPort = e.ports[0];\n this.sentPort = sentPort;\n sentPort.onmessage = (e) =>\n {\n if(e.data === null)\n {\n // the worklet is dead\n this.alive = false;\n }\n this.data.push(e.data);\n this.updateRequested = false;\n // if we need more, request immediately\n if (this.data.length < MAX_QUEUED)\n {\n this.sentPort.postMessage(null);\n }\n };\n \n }\n };\n }\n \n // noinspection JSUnusedGlobalSymbols\n /**\n * @param _inputs {[Float32Array, Float32Array][]}\n * @param outputs {[Float32Array, Float32Array][]}\n * @returns {boolean}\n */\n process(_inputs, outputs)\n {\n const data = this.data.shift();\n if (!data)\n {\n return this.alive;\n }\n let offset = 0;\n // decode the data nicely\n for (let i = 0; i < 17; i++)\n {\n outputs[i][0].set(data.subarray(offset, offset + BLOCK_SIZE));\n offset += BLOCK_SIZE;\n outputs[i][1].set(data.subarray(offset, offset + BLOCK_SIZE));\n offset += BLOCK_SIZE;\n }\n \n // if it has already been requested, we need to wait\n if (!this.updateRequested)\n {\n this.sentPort.postMessage(null);\n this.updateRequested = true;\n }\n \n // keep it online\n return this.alive;\n }\n}\nregisterProcessor(\"${PLAYBACK_WORKLET_PROCESSOR_NAME}\", PlaybackProcessor);\n `;\n const blob = new Blob([PLAYBACK_WORKLET_CODE], {\n type: \"application/javascript\"\n });\n return URL.createObjectURL(blob);\n}\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport { SpessaSynthProcessor, SpessaSynthSequencer } from \"spessasynth_core\";\n\nexport interface WorkerRenderAudioOptions {\n /**\n * Extra fadeout time after the song finishes, in seconds.\n */\n extraTime: number;\n /**\n * If channels should be rendered separately.\n */\n separateChannels: boolean;\n\n /**\n * The amount of times to loop the song.\n */\n loopCount: number;\n\n /**\n * The function that tracks the rendering progress.\n * @param progress mapped 0 to 1.\n * @param stage 0 is a dry pass, 1 is adding effects.\n */\n progressCallback?: (progress: number, stage: number) => unknown;\n\n /**\n * If the current parameters of the synthesizer should be preserved.\n */\n preserveSynthParams: boolean;\n\n /**\n * If the effects should be enabled.\n */\n enableEffects: boolean;\n\n /**\n * Which sequencer to render. Defaults to the first one (0).\n */\n sequencerID: number;\n}\n\nexport const DEFAULT_WORKER_RENDER_AUDIO_OPTIONS: WorkerRenderAudioOptions = {\n extraTime: 2,\n separateChannels: false,\n loopCount: 0,\n progressCallback: undefined,\n preserveSynthParams: true,\n enableEffects: true,\n sequencerID: 0\n};\n\nconst RENDER_BLOCKS_PER_PROGRESS = 64;\nconst BLOCK_SIZE = 128;\n\ntype StereoAudioChunk = [Float32Array, Float32Array];\n\ninterface ReturnedChunks {\n effects: StereoAudioChunk;\n dry: StereoAudioChunk[];\n}\n\nexport function renderAudioWorker(\n this: WorkerSynthesizerCore,\n sampleRate: number,\n options: WorkerRenderAudioOptions\n): ReturnedChunks {\n const rendererSynth = new SpessaSynthProcessor(sampleRate, {\n enableEventSystem: false\n });\n const rendererSeq = new SpessaSynthSequencer(rendererSynth);\n\n // No cap\n rendererSynth.setMasterParameter(\"autoAllocateVoices\", true);\n\n // Copy sound banks\n for (const entry of this.synthesizer.soundBankManager.soundBankList)\n rendererSynth.soundBankManager.addSoundBank(\n entry.soundBank,\n entry.id,\n entry.bankOffset\n );\n rendererSynth.soundBankManager.priorityOrder =\n this.synthesizer.soundBankManager.priorityOrder;\n this.stopAudioLoop();\n\n const seq = this.sequencers[options.sequencerID];\n const parsedMid = seq.midiData;\n if (!parsedMid) {\n throw new Error(\"No MIDI is loaded!\");\n }\n const playbackRate = seq.playbackRate;\n // Calculate times\n const loopStartAbsolute =\n parsedMid.midiTicksToSeconds(parsedMid.loop.start) / playbackRate;\n const loopEndAbsolute =\n parsedMid.midiTicksToSeconds(parsedMid.loop.end) / playbackRate;\n const loopDuration = loopEndAbsolute - loopStartAbsolute;\n const duration =\n parsedMid.duration / playbackRate +\n options.extraTime +\n loopDuration * options.loopCount;\n // Total duration in samples\n const sampleDuration = sampleRate * duration;\n\n // Initialize\n rendererSeq.loopCount = options.loopCount;\n if (options.preserveSynthParams) {\n rendererSeq.playbackRate = seq.playbackRate;\n const snapshot = this.synthesizer.getSnapshot();\n rendererSynth.applySynthesizerSnapshot(snapshot);\n }\n rendererSeq.loadNewSongList([parsedMid]);\n rendererSeq.play();\n\n // Allocate memory\n // Effects\n const wetL = new Float32Array(sampleDuration);\n const wetR = new Float32Array(sampleDuration);\n const effects: StereoAudioChunk = [wetL, wetR];\n // Final output\n const returnedChunks: ReturnedChunks = {\n effects,\n dry: []\n };\n const sampleDurationNoLastQuantum = sampleDuration - BLOCK_SIZE;\n if (options.separateChannels) {\n const dry: StereoAudioChunk[] = [];\n for (let i = 0; i < 16; i++) {\n const d: StereoAudioChunk = [\n new Float32Array(sampleDuration),\n new Float32Array(sampleDuration)\n ];\n dry.push(d);\n returnedChunks.dry.push(d);\n }\n let index = 0;\n while (true) {\n for (let i = 0; i < RENDER_BLOCKS_PER_PROGRESS; i++) {\n if (index >= sampleDurationNoLastQuantum) {\n rendererSeq.processTick();\n rendererSynth.processSplit(\n dry,\n wetL,\n wetR,\n index,\n sampleDuration - index\n );\n this.startAudioLoop();\n return returnedChunks;\n }\n rendererSeq.processTick();\n rendererSynth.processSplit(dry, wetL, wetR, index, BLOCK_SIZE);\n index += BLOCK_SIZE;\n }\n this.postProgress(\"renderAudio\", index / sampleDuration);\n }\n } else {\n const dryL = new Float32Array(sampleDuration);\n const dryR = new Float32Array(sampleDuration);\n const dry: StereoAudioChunk = [dryL, dryR];\n returnedChunks.dry.push(dry);\n let index = 0;\n while (true) {\n for (let i = 0; i < RENDER_BLOCKS_PER_PROGRESS; i++) {\n if (index >= sampleDurationNoLastQuantum) {\n rendererSeq.processTick();\n rendererSynth.process(\n dryL,\n dryR,\n index,\n sampleDuration - index\n );\n this.startAudioLoop();\n return returnedChunks;\n }\n rendererSeq.processTick();\n\n rendererSynth.process(dryL, dryR, index, BLOCK_SIZE);\n index += BLOCK_SIZE;\n }\n this.postProgress(\"renderAudio\", index / sampleDuration);\n }\n }\n}\n","import { BasicSynthesizer } from \"../basic/basic_synthesizer.ts\";\nimport type { SynthConfig } from \"../basic/types.ts\";\nimport { DEFAULT_SYNTH_CONFIG } from \"../basic/synth_config.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\nimport {\n getPlaybackWorkletURL,\n PLAYBACK_WORKLET_PROCESSOR_NAME\n} from \"./playback_worklet.ts\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn,\n WorkerBankWriteOptions,\n WorkerDLSWriteOptions,\n WorkerRMIDIWriteOptions,\n WorkerSoundFont2WriteOptions\n} from \"../types.ts\";\nimport {\n DEFAULT_WORKER_RENDER_AUDIO_OPTIONS,\n type WorkerRenderAudioOptions\n} from \"./render_audio_worker.ts\";\n\nconst DEFAULT_BANK_WRITE_OPTIONS: WorkerBankWriteOptions = {\n trim: true,\n bankID: \"\",\n writeEmbeddedSoundBank: true,\n sequencerID: 0\n};\n\nconst DEFAULT_SF2_WRITE_OPTIONS: WorkerSoundFont2WriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS,\n writeDefaultModulators: true,\n writeExtendedLimits: true,\n compress: false,\n compressionQuality: 1,\n decompress: false\n};\n\nconst DEFAULT_RMIDI_WRITE_OPTIONS: WorkerRMIDIWriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS,\n bankOffset: 0,\n correctBankOffset: true,\n metadata: {},\n format: \"sf2\",\n ...DEFAULT_SF2_WRITE_OPTIONS\n};\n\nconst DEFAULT_DLS_WRITE_OPTIONS: WorkerDLSWriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS\n};\n\ntype WorkerSynthWriteOptions<K> = K & {\n progressFunction?: (\n args: SynthesizerProgress[\"workerSynthWriteFile\"]\n ) => unknown;\n};\n\n/**\n * This synthesizer uses a Worker containing the processor and an audio worklet node for playback.\n */\nexport class WorkerSynthesizer extends BasicSynthesizer {\n /**\n * Time offset for syncing with the synth\n * @private\n */\n private timeOffset = 0;\n\n /**\n * Creates a new instance of a Worker-based synthesizer.\n * @param context The audio context.\n * @param workerPostMessage The postMessage for the worker containing the synthesizer core.\n * @param config Optional configuration for the synthesizer.\n */\n public constructor(\n context: BaseAudioContext,\n workerPostMessage: typeof Worker.prototype.postMessage,\n config: Partial<SynthConfig> = DEFAULT_SYNTH_CONFIG\n ) {\n // Ensure default values for options\n const synthConfig = fillWithDefaults(config, DEFAULT_SYNTH_CONFIG);\n if (synthConfig.oneOutput) {\n throw new Error(\n \"One output mode is not supported in the WorkerSynthesizer.\"\n );\n }\n\n let worklet: AudioWorkletNode;\n // Create the audio worklet node\n try {\n const workletConstructor =\n synthConfig?.audioNodeCreators?.worklet ??\n ((context, name, options) => {\n return new AudioWorkletNode(context, name, options);\n });\n worklet = workletConstructor(\n context,\n PLAYBACK_WORKLET_PROCESSOR_NAME,\n {\n outputChannelCount: new Array<number>(18).fill(2),\n numberOfOutputs: 18,\n processorOptions: {\n oneOutput: synthConfig.oneOutput,\n enableEventSystem: synthConfig.enableEventSystem\n }\n }\n );\n } catch (error) {\n console.error(error);\n throw new Error(\n \"Could not create the AudioWorkletNode. Did you forget to registerPlaybackWorklet()?\"\n );\n }\n super(\n worklet,\n workerPostMessage as (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown,\n synthConfig\n );\n\n // Create a message channel for communication between the worker and the worklet\n const messageChannel = new MessageChannel();\n const workerPort = messageChannel.port1;\n const workletPort = messageChannel.port2;\n // Post the channel to worklet\n this.worklet.port.postMessage(null, [workletPort]);\n // Post the channel and init worker\n workerPostMessage(\n {\n initialTime: this.context.currentTime,\n sampleRate: this.context.sampleRate\n },\n [workerPort]\n );\n }\n\n public get currentTime() {\n return this.context.currentTime + this.timeOffset;\n }\n\n /**\n * Registers an audio worklet for the WorkerSynthesizer.\n * @param context The context to register the worklet for.\n * @param maxQueueSize The maximum amount of 128-sample chunks to store in the worklet. Higher values result in less breakups but higher latency.\n */\n public static async registerPlaybackWorklet(\n context: BaseAudioContext,\n maxQueueSize = 20\n ) {\n if (!context?.audioWorklet.addModule) {\n throw new Error(\"Audio worklet is not supported.\");\n }\n return context.audioWorklet.addModule(\n getPlaybackWorkletURL(maxQueueSize)\n );\n }\n\n /**\n * Handles a return message from the Worker.\n * @param e The event received from the Worker.\n */\n public handleWorkerMessage(e: BasicSynthesizerReturnMessage) {\n this.timeOffset = e.currentTime - this.context.currentTime;\n this.handleMessage(e);\n }\n\n /**\n * Writes a DLS file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer and its corresponding name.\n */\n public async writeDLS(\n options: Partial<\n WorkerSynthWriteOptions<WorkerDLSWriteOptions>\n > = DEFAULT_DLS_WRITE_OPTIONS\n ): Promise<SynthesizerReturn[\"workerSynthWriteFile\"]> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_DLS_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data)\n );\n this.post({\n type: \"writeDLS\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Writes an SF2/SF3 file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer and its corresponding name.\n */\n public async writeSF2(\n options: Partial<\n WorkerSynthWriteOptions<WorkerSoundFont2WriteOptions>\n > = DEFAULT_SF2_WRITE_OPTIONS\n ): Promise<SynthesizerReturn[\"workerSynthWriteFile\"]> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_SF2_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data)\n );\n this.post({\n type: \"writeSF2\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Writes an embedded MIDI (RMIDI) file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer.\n */\n public async writeRMIDI(\n options: Partial<\n WorkerSynthWriteOptions<WorkerRMIDIWriteOptions>\n > = DEFAULT_RMIDI_WRITE_OPTIONS\n ): Promise<ArrayBuffer> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_RMIDI_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data.binary)\n );\n this.post({\n type: \"writeRMIDI\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Renders the current song in the connected sequencer to Float32 buffers.\n * @param sampleRate The sample rate to use, in Hertz.\n * @param renderOptions Extra options for the render.\n * @returns A single audioBuffer if separate channels were not enabled, otherwise 16.\n * @remarks\n * This stops the synthesizer.\n */\n public async renderAudio(\n sampleRate: number,\n renderOptions: Partial<WorkerRenderAudioOptions> = DEFAULT_WORKER_RENDER_AUDIO_OPTIONS\n ): Promise<AudioBuffer[]> {\n const options = fillWithDefaults(\n renderOptions,\n DEFAULT_WORKER_RENDER_AUDIO_OPTIONS\n );\n if (options.enableEffects && options.separateChannels) {\n throw new Error(\"Effects cannot be applied to separate channels.\");\n }\n return new Promise((resolve) => {\n // First pass: Worker renders the dry audio\n this.awaitWorkerResponse(\"renderAudio\", (data) => {\n this.revokeProgressTracker(\"renderAudio\");\n const bufferLength = data.dry[0][0].length;\n // Convert to audio buffers\n const dryChannels = data.dry.map((dryPair) => {\n const buffer = new AudioBuffer({\n sampleRate,\n numberOfChannels: 2,\n length: bufferLength\n });\n buffer.copyToChannel(\n dryPair[0] as Float32Array<ArrayBuffer>,\n 0\n );\n buffer.copyToChannel(\n dryPair[1] as Float32Array<ArrayBuffer>,\n 1\n );\n return buffer;\n });\n if (options.enableEffects) {\n // Append effects\n const buffer = new AudioBuffer({\n sampleRate,\n numberOfChannels: 2,\n length: bufferLength\n });\n buffer.copyToChannel(\n data.effects[0] as Float32Array<ArrayBuffer>,\n 0\n );\n buffer.copyToChannel(\n data.effects[1] as Float32Array<ArrayBuffer>,\n 1\n );\n dryChannels.push(buffer);\n }\n resolve(dryChannels);\n return;\n });\n // Assign progress tracker and render\n this.assignProgressTracker(\"renderAudio\", (p) => {\n options.progressCallback?.(p, 0);\n });\n\n // Functions cannot be cloned\n const strippedOptions: WorkerRenderAudioOptions = {\n ...options,\n progressCallback: undefined\n };\n this.post({\n type: \"renderAudio\",\n data: {\n sampleRate,\n options: strippedOptions\n },\n channelNumber: -1\n });\n });\n }\n}\n","import { type BasicSoundBank, SoundBankLoader } from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n WorkerBankWriteOptions,\n WorkerSampleEncodingFunction\n} from \"../types.ts\";\nimport { renderAudioWorker } from \"./render_audio_worker.ts\";\nimport {\n BasicSynthesizerCore,\n type PostMessageSynthCore,\n SEQUENCER_SYNC_INTERVAL\n} from \"../basic/basic_synthesizer_core.ts\";\nimport { writeDLSWorker, writeSF2Worker } from \"./write_sf_worker.ts\";\nimport { writeRMIDIWorker } from \"./write_rmi_worker.ts\";\n\nconst BLOCK_SIZE = 128;\n\ntype AudioChunk = [Float32Array, Float32Array];\ntype AudioChunks = AudioChunk[];\n\n// The core audio engine for the worker synthesizer.\nexport class WorkerSynthesizerCore extends BasicSynthesizerCore {\n /**\n * The message port to the playback audio worklet.\n */\n public readonly workletMessagePort: MessagePort;\n\n protected readonly compressionFunction?: WorkerSampleEncodingFunction;\n\n /**\n * Creates a new worker synthesizer core: the synthesizer that runs in the worker.\n * Most parameters here are provided with the first message that is posted to the worker by the WorkerSynthesizer.\n * @param synthesizerConfiguration The data from the first message sent from WorkerSynthesizer.\n * Listen for the first event and use its data to initialize this class.\n * @param workletMessagePort The first port from the first message sent from WorkerSynthesizer.\n * @param mainThreadCallback postMessage function or similar.\n * @param compressionFunction Optional function for compressing SF3 banks.\n */\n public constructor(\n synthesizerConfiguration: {\n sampleRate: number;\n initialTime: number;\n },\n workletMessagePort: MessagePort,\n mainThreadCallback: typeof Worker.prototype.postMessage,\n compressionFunction?: WorkerSampleEncodingFunction\n ) {\n super(\n synthesizerConfiguration.sampleRate,\n {\n enableEventSystem: true,\n enableEffects: true,\n initialTime: synthesizerConfiguration.initialTime\n },\n mainThreadCallback as PostMessageSynthCore\n );\n\n this.workletMessagePort = workletMessagePort;\n this.workletMessagePort.onmessage = this.process.bind(this);\n this.compressionFunction = compressionFunction;\n void this.synthesizer.processorInitialized.then(() => {\n this.postReady(\"sf3Decoder\", null);\n this.startAudioLoop();\n });\n }\n\n /**\n * Handles a message received from the main thread.\n * @param m The message received.\n */\n public handleMessage(m: BasicSynthesizerMessage) {\n switch (m.type) {\n case \"renderAudio\": {\n const rendered = renderAudioWorker.call(\n this,\n m.data.sampleRate,\n m.data.options\n );\n const transferable: Transferable[] = [];\n for (const r of rendered.effects) transferable.push(r.buffer);\n for (const d of rendered.dry)\n transferable.push(...d.map((c) => c.buffer));\n this.postReady(\"renderAudio\", rendered, transferable);\n break;\n }\n\n case \"writeRMIDI\": {\n this.stopAudioLoop();\n void writeRMIDIWorker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data,\n fileName: \"\"\n },\n [data]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n case \"writeSF2\": {\n this.stopAudioLoop();\n void writeSF2Worker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data.binary,\n fileName:\n data.bank.soundBankInfo.name +\n (data.bank.soundBankInfo.version.major === 3\n ? \".sf3\"\n : \".sf2\")\n },\n [data.binary]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n case \"writeDLS\": {\n this.stopAudioLoop();\n void writeDLSWorker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data.binary,\n fileName: data.bank.soundBankInfo.name + \".dls\"\n },\n [data.binary]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n default: {\n super.handleMessage(m);\n }\n }\n }\n\n protected getBank(opts: WorkerBankWriteOptions): BasicSoundBank {\n const sq = this.sequencers[opts.sequencerID];\n const sf =\n opts.writeEmbeddedSoundBank && sq.midiData?.embeddedSoundBank\n ? SoundBankLoader.fromArrayBuffer(sq.midiData.embeddedSoundBank)\n : this.synthesizer.soundBankManager.soundBankList.find(\n (b) => b.id === opts.bankID\n )?.soundBank;\n if (!sf) {\n const e = new Error(\n `${opts.bankID} does not exist in the sound bank list!`\n );\n this.post({\n type: \"soundBankError\",\n data: e,\n currentTime: this.synthesizer.currentSynthTime\n });\n throw e;\n }\n return sf;\n }\n\n protected stopAudioLoop() {\n this.synthesizer.stopAllChannels(true);\n for (const seq of this.sequencers) {\n seq.pause();\n }\n this.alive = false;\n }\n\n protected startAudioLoop() {\n this.alive = true;\n this.process();\n }\n\n protected destroy() {\n // Null indicates end of life\n this.workletMessagePort.postMessage(null);\n this.stopAudioLoop();\n super.destroy();\n }\n\n protected process() {\n if (!this.alive) {\n return;\n }\n // Data is encoded into a single f32 array as follows\n // WetL, WetR,\n // Dry1L, dry1R\n // DryNL, dryNR\n // Dry16L, dry16R\n // To improve performance\n const byteStep = BLOCK_SIZE * Float32Array.BYTES_PER_ELEMENT;\n const data = new Float32Array(BLOCK_SIZE * 34);\n let byteOffset = 0;\n const wetR = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n const wetL = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n const dry: AudioChunks = [];\n for (let i = 0; i < 16; i++) {\n const dryL = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n\n const dryR = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n\n dry.push([dryL, dryR]);\n }\n for (const seq of this.sequencers) {\n seq.processTick();\n }\n this.synthesizer.processSplit(dry, wetL, wetR);\n this.workletMessagePort.postMessage(data, [data.buffer]);\n\n const t = this.synthesizer.currentSynthTime;\n if (t - this.lastSequencerSync > SEQUENCER_SYNC_INTERVAL) {\n for (let id = 0; id < this.sequencers.length; id++) {\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"sync\",\n data: this.sequencers[id].currentTime,\n id\n },\n currentTime: t\n });\n }\n this.lastSequencerSync = t;\n }\n }\n}\n","import {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n BasicMIDI,\n SoundBankLoader,\n SpessaSynthCoreUtils as util,\n SpessaSynthLogging,\n SpessaSynthProcessor,\n SpessaSynthSequencer,\n SynthesizerSnapshot,\n type SynthProcessorOptions\n} from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn\n} from \"../types.ts\";\nimport { MIDIData } from \"../../sequencer/midi_data.ts\";\nimport { songChangeType } from \"../../sequencer/enums.ts\";\n\nexport type PostMessageSynthCore = (\n data: BasicSynthesizerReturnMessage,\n transfer?: Transferable[]\n) => unknown;\n\n// Seconds\nexport const SEQUENCER_SYNC_INTERVAL = 1;\n\n/**\n * The interface for the audio processing code that uses spessasynth_core and runs on a separate thread.\n */\nexport abstract class BasicSynthesizerCore {\n public readonly synthesizer: SpessaSynthProcessor;\n public readonly sequencers = new Array<SpessaSynthSequencer>();\n protected readonly post: PostMessageSynthCore;\n protected lastSequencerSync = 0;\n /**\n * Indicates if the processor is alive.\n * @protected\n */\n protected alive = false;\n\n protected constructor(\n sampleRate: number,\n options: Omit<\n SynthProcessorOptions,\n \"reverbProcessor\" | \"chorusProcessor\" | \"delayProcessor\"\n >,\n postMessage: PostMessageSynthCore\n ) {\n this.synthesizer = new SpessaSynthProcessor(sampleRate, options);\n this.post = postMessage;\n\n // Prepare synthesizer connections\n this.synthesizer.onEventCall = (event) => {\n this.post({\n type: \"eventCall\",\n data: event,\n currentTime: this.synthesizer.currentSynthTime\n });\n };\n }\n\n protected createNewSequencer() {\n const sequencer = new SpessaSynthSequencer(this.synthesizer);\n const sequencerID = this.sequencers.length;\n this.sequencers.push(sequencer);\n\n // Prepare sequencer connections\n sequencer.onEventCall = (e) => {\n if (e.type === \"songListChange\") {\n const songs = e.data.newSongList;\n const midiDatas = songs.map((s) => {\n return new MIDIData(s);\n });\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: e.type,\n data: {\n newSongList: midiDatas,\n shuffledSongIndexes: sequencer.shuffledSongIndexes\n },\n id: sequencerID\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n return;\n }\n this.post({\n type: \"sequencerReturn\",\n data: { ...e, id: sequencerID },\n currentTime: this.synthesizer.currentSynthTime\n });\n };\n }\n\n protected postReady<K extends keyof SynthesizerReturn>(\n type: K,\n data: SynthesizerReturn[K],\n transferable: Transferable[] = []\n ) {\n this.post(\n {\n type: \"isFullyInitialized\",\n data: {\n type,\n data\n } as {\n [K in keyof SynthesizerReturn]: {\n type: K;\n data: SynthesizerReturn[K];\n };\n }[keyof SynthesizerReturn],\n currentTime: this.synthesizer.currentSynthTime\n },\n transferable\n );\n }\n\n protected postProgress<K extends keyof SynthesizerProgress>(\n type: K,\n data: SynthesizerProgress[K]\n ) {\n this.post({\n type: \"renderingProgress\",\n data: {\n type,\n data\n } as {\n [K in keyof SynthesizerProgress]: {\n type: K;\n data: SynthesizerProgress[K];\n };\n }[keyof SynthesizerProgress],\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n\n protected destroy() {\n this.synthesizer.destroySynthProcessor();\n // @ts-expect-error JS Deletion\n // noinspection JSConstantReassignment\n delete this.synthesizer;\n // @ts-expect-error JS Deletion\n // noinspection JSConstantReassignment\n delete this.sequencers;\n }\n\n protected handleMessage(m: BasicSynthesizerMessage) {\n const channel = m.channelNumber;\n\n let channelObject:\n | (typeof this.synthesizer.midiChannels)[number]\n | undefined = undefined;\n if (channel >= 0) {\n channelObject = this.synthesizer.midiChannels[channel];\n if (channelObject === undefined) {\n util.SpessaSynthWarn(\n `Trying to access channel ${channel} which does not exist... ignoring!`\n );\n return;\n }\n }\n switch (m.type) {\n case \"midiMessage\": {\n this.synthesizer.processMessage(\n m.data.messageData,\n m.data.channelOffset,\n m.data.force,\n m.data.options\n );\n break;\n }\n\n case \"customCcChange\": {\n // Custom controller change\n channelObject?.setCustomController(\n m.data.ccNumber,\n m.data.ccValue\n );\n break;\n }\n\n case \"ccReset\": {\n if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION) {\n this.synthesizer.resetAllControllers();\n } else {\n channelObject?.resetControllers();\n }\n break;\n }\n\n case \"stopAll\": {\n if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION) {\n this.synthesizer.stopAllChannels(m.data === 1);\n } else {\n channelObject?.stopAllNotes(m.data === 1);\n }\n break;\n }\n\n case \"muteChannel\": {\n channelObject?.muteChannel(m.data);\n break;\n }\n\n case \"addNewChannel\": {\n this.synthesizer.createMIDIChannel();\n break;\n }\n\n case \"setMasterParameter\": {\n this.synthesizer.setMasterParameter(m.data.type, m.data.data);\n break;\n }\n\n case \"setDrums\": {\n channelObject?.setDrums(m.data);\n break;\n }\n\n case \"transposeChannel\": {\n channelObject?.transposeChannel(m.data.semitones, m.data.force);\n break;\n }\n\n case \"lockController\": {\n if (\n m.data.controllerNumber === ALL_CHANNELS_OR_DIFFERENT_ACTION\n ) {\n channelObject?.setPresetLock(m.data.isLocked);\n } else {\n if (!channelObject) {\n return;\n }\n channelObject.lockedControllers[m.data.controllerNumber] =\n m.data.isLocked;\n }\n break;\n }\n\n case \"sequencerSpecific\": {\n const seq = this.sequencers[m.data.id];\n if (!seq) {\n return;\n }\n const seqMsg = m.data;\n switch (seqMsg.type) {\n default: {\n break;\n }\n\n case \"loadNewSongList\": {\n try {\n const sList = seqMsg.data;\n const songMap = sList.map((s) => {\n if (\"duration\" in s) {\n // Cloned objects don't have methods\n return BasicMIDI.copyFrom(s);\n }\n return BasicMIDI.fromArrayBuffer(\n s.binary,\n s.fileName\n );\n });\n seq.loadNewSongList(songMap);\n } catch (error) {\n console.error(error);\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"midiError\",\n data: error as Error,\n id: m.data.id\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n break;\n }\n\n case \"pause\": {\n seq.pause();\n break;\n }\n\n case \"play\": {\n seq.play();\n break;\n }\n\n case \"setTime\": {\n seq.currentTime = seqMsg.data;\n break;\n }\n\n case \"changeMIDIMessageSending\": {\n seq.externalMIDIPlayback = seqMsg.data;\n break;\n }\n\n case \"setPlaybackRate\": {\n seq.playbackRate = seqMsg.data;\n break;\n }\n\n case \"setLoopCount\": {\n seq.loopCount = seqMsg.data;\n break;\n }\n\n case \"changeSong\": {\n switch (seqMsg.data.changeType) {\n case songChangeType.shuffleOff: {\n seq.shuffleMode = false;\n break;\n }\n\n case songChangeType.shuffleOn: {\n seq.shuffleMode = true;\n break;\n }\n\n case songChangeType.index: {\n if (seqMsg.data.data !== undefined) {\n seq.songIndex = seqMsg.data.data;\n }\n break;\n }\n }\n break;\n }\n\n case \"getMIDI\": {\n if (!seq.midiData) {\n throw new Error(\"No MIDI is loaded!\");\n }\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"getMIDI\",\n data: seq.midiData,\n id: m.data.id\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n break;\n }\n\n case \"setSkipToFirstNote\": {\n seq.skipToFirstNoteOn = seqMsg.data;\n break;\n }\n }\n break;\n }\n\n case \"soundBankManager\": {\n try {\n const sfManager = this.synthesizer.soundBankManager;\n const sfManMsg = m.data;\n let font;\n switch (sfManMsg.type) {\n case \"addSoundBank\": {\n font = SoundBankLoader.fromArrayBuffer(\n sfManMsg.data.soundBankBuffer\n );\n sfManager.addSoundBank(\n font,\n sfManMsg.data.id,\n sfManMsg.data.bankOffset\n );\n this.postReady(\"soundBankManager\", null);\n break;\n }\n\n case \"deleteSoundBank\": {\n sfManager.deleteSoundBank(sfManMsg.data);\n this.postReady(\"soundBankManager\", null);\n break;\n }\n\n case \"rearrangeSoundBanks\": {\n sfManager.priorityOrder = sfManMsg.data;\n this.postReady(\"soundBankManager\", null);\n }\n }\n } catch (error) {\n this.post({\n type: \"soundBankError\",\n data: error as Error,\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n break;\n }\n\n case \"keyModifierManager\": {\n const kmMsg = m.data;\n const man = this.synthesizer.keyModifierManager;\n switch (kmMsg.type) {\n default: {\n return;\n }\n\n case \"addMapping\": {\n man.addMapping(\n kmMsg.data.channel,\n kmMsg.data.midiNote,\n kmMsg.data.mapping\n );\n break;\n }\n\n case \"clearMappings\": {\n man.clearMappings();\n break;\n }\n\n case \"deleteMapping\": {\n man.deleteMapping(\n kmMsg.data.channel,\n kmMsg.data.midiNote\n );\n }\n }\n break;\n }\n\n case \"requestSynthesizerSnapshot\": {\n const snapshot = SynthesizerSnapshot.create(this.synthesizer);\n this.postReady(\"synthesizerSnapshot\", snapshot);\n break;\n }\n\n case \"requestNewSequencer\": {\n this.createNewSequencer();\n break;\n }\n\n case \"setLogLevel\": {\n SpessaSynthLogging(\n m.data.enableInfo,\n m.data.enableWarning,\n m.data.enableGroup\n );\n break;\n }\n\n case \"destroyWorklet\": {\n this.alive = false;\n this.synthesizer.destroySynthProcessor();\n this.destroy();\n break;\n }\n\n default: {\n util.SpessaSynthWarn(\"Unrecognized event!\", m);\n break;\n }\n }\n }\n}\n","import { BasicMIDI, MIDITrack } from \"spessasynth_core\";\n\nexport class MIDIDataTrack extends MIDITrack {\n /**\n * THIS DATA WILL BE EMPTY! USE sequencer.getMIDI() TO GET THE ACTUAL DATA!\n */\n public events: never[] = [];\n\n public constructor(track: MIDITrack) {\n super();\n super.copyFrom(track);\n this.events = [];\n }\n}\n\n/**\n * A simplified version of the MIDI, accessible at all times from the Sequencer.\n * Use getMIDI() to get the actual sequence.\n * This class contains all properties that MIDI does, except for tracks and the embedded sound bank.\n */\nexport class MIDIData extends BasicMIDI {\n public override tracks: MIDIDataTrack[];\n\n /**\n * THIS DATA WILL BE EMPTY! USE sequencer.getMIDI() TO GET THE ACTUAL DATA!\n */\n public override embeddedSoundBank = undefined;\n\n /**\n * The byte length of the sound bank if it exists.\n */\n public readonly embeddedSoundBankSize?: number;\n\n public constructor(mid: BasicMIDI) {\n super();\n super.copyMetadataFrom(mid);\n this.tracks = mid.tracks.map((t) => new MIDIDataTrack(t));\n this.embeddedSoundBankSize =\n mid instanceof MIDIData\n ? mid.embeddedSoundBankSize\n : mid?.embeddedSoundBank?.byteLength;\n }\n}\n","export const songChangeType = {\n shuffleOn: 1, // No additional data\n shuffleOff: 2, // No additional data\n index: 3 // SongIndex<number>\n} as const;\nexport type SongChangeType =\n (typeof songChangeType)[keyof typeof songChangeType];\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport type {\n WorkerDLSWriteOptions,\n WorkerSoundFont2WriteOptions\n} from \"../types.ts\";\nimport { BasicSoundBank, type SampleEncodingFunction } from \"spessasynth_core\";\n\nexport async function writeSF2Worker(\n this: WorkerSynthesizerCore,\n opts: WorkerSoundFont2WriteOptions\n): Promise<{\n binary: ArrayBuffer;\n bank: BasicSoundBank;\n}> {\n let sf = this.getBank(opts);\n\n if (opts.compress && !this.compressionFunction) {\n const e = new Error(\n `Compression enabled but no compression has been provided to WorkerSynthesizerCore.`\n );\n this.post({\n type: \"soundBankError\",\n data: e,\n currentTime: this.synthesizer.currentSynthTime\n });\n throw e;\n }\n\n const sq = this.sequencers[opts.sequencerID];\n\n // Trim\n if (opts.trim) {\n if (!sq.midiData) {\n throw new Error(\n \"Sound bank MIDI trimming is enabled but no MIDI is loaded!\"\n );\n }\n // Copy\n const sfCopy = BasicSoundBank.copyFrom(sf);\n sfCopy.trimSoundBank(sq.midiData);\n sf = sfCopy;\n }\n\n let compressionFunction: SampleEncodingFunction | undefined;\n\n if (this.compressionFunction !== undefined) {\n compressionFunction = (audioData, sampleRate) =>\n this.compressionFunction!(\n audioData,\n sampleRate,\n opts.compressionQuality\n );\n }\n\n const b = await sf.writeSF2({\n ...opts,\n progressFunction: (sampleName, sampleIndex, sampleCount) => {\n this.postProgress(\"workerSynthWriteFile\", {\n sampleCount,\n sampleIndex,\n sampleName\n });\n return new Promise<void>((r) => r());\n },\n compressionFunction\n });\n return {\n binary: b,\n bank: sf\n };\n}\n\nexport async function writeDLSWorker(\n this: WorkerSynthesizerCore,\n opts: WorkerDLSWriteOptions\n): Promise<{\n binary: ArrayBuffer;\n bank: BasicSoundBank;\n}> {\n let sf = this.getBank(opts);\n const sq = this.sequencers[opts.sequencerID];\n\n // Trim\n if (opts.trim) {\n if (!sq.midiData) {\n throw new Error(\n \"Sound bank MIDI trimming is enabled but no MIDI is loaded!\"\n );\n }\n const sfCopy = BasicSoundBank.copyFrom(sf);\n sfCopy.trimSoundBank(sq.midiData);\n sf = sfCopy;\n }\n\n const b = await sf.writeDLS({\n ...opts,\n progressFunction: (sampleName, sampleIndex, sampleCount) => {\n this.postProgress(\"workerSynthWriteFile\", {\n sampleCount,\n sampleIndex,\n sampleName\n });\n return new Promise<void>((r) => r());\n }\n });\n return {\n binary: b,\n bank: sf\n };\n}\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport type { WorkerRMIDIWriteOptions } from \"../types.ts\";\nimport { BasicMIDI, BasicSoundBank } from \"spessasynth_core\";\nimport { writeDLSWorker, writeSF2Worker } from \"./write_sf_worker.ts\";\n\nexport async function writeRMIDIWorker(\n this: WorkerSynthesizerCore,\n opts: WorkerRMIDIWriteOptions\n) {\n const sq = this.sequencers[opts.sequencerID];\n if (!sq.midiData) {\n throw new Error(\"No MIDI is loaded!\");\n }\n let sf: BasicSoundBank;\n let sfBin: ArrayBuffer;\n if (opts.format === \"sf2\") {\n const bin = await writeSF2Worker.call(this, opts);\n sfBin = bin.binary;\n sf = bin.bank;\n } else {\n const bin = await writeDLSWorker.call(this, opts);\n sfBin = bin.binary;\n sf = bin.bank;\n }\n\n const mid = BasicMIDI.copyFrom(sq.midiData);\n return mid.writeRMIDI(sfBin, {\n soundBank: sf,\n ...opts\n });\n}\n","import {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n BasicMIDI,\n midiMessageTypes,\n SpessaSynthCoreUtils\n} from \"spessasynth_core\";\nimport { songChangeType } from \"./enums.js\";\nimport { MIDIData } from \"./midi_data.js\";\nimport { DEFAULT_SEQUENCER_OPTIONS } from \"./default_sequencer_options.js\";\nimport type {\n SequencerMessage,\n SequencerMessageData,\n SequencerOptions,\n SequencerReturnMessage,\n SuppliedMIDIData,\n WorkletSequencerEventType\n} from \"./types\";\nimport { SeqEventHandler } from \"./seq_event_handler\";\nimport { type BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\"; // noinspection JSUnusedGlobalSymbols\n\n// noinspection JSUnusedGlobalSymbols\nexport class Sequencer {\n /**\n * The current MIDI data for all songs, like the midiData property.\n */\n public songListData: MIDIData[] = [];\n /**\n * Allows setting up custom event listeners for the sequencer.\n */\n public eventHandler = new SeqEventHandler();\n /**\n * Indicates whether the sequencer has finished playing a sequence.\n */\n public isFinished = false;\n /**\n * The synthesizer attached to this sequencer.\n */\n public readonly synth: BasicSynthesizer;\n /**\n * The current MIDI data, with the exclusion of the embedded sound bank and event data.\n */\n public midiData?: MIDIData;\n /**\n * The MIDI port to play to.\n */\n private midiOut?: { send: (data: number[]) => unknown };\n private isLoading = false;\n /**\n * Indicates if the sequencer is paused.\n * Paused if a number, undefined if playing.\n */\n private pausedTime?: number = 0;\n private getMIDICallback?: (receivedMIDI: BasicMIDI) => unknown = undefined;\n private highResTimeOffset = 0;\n /**\n * Absolute playback startTime, bases on the synth's time.\n */\n private absoluteStartTime: number;\n /**\n * For sending the messages to the correct SpessaSynthSequencer in core\n */\n private readonly sequencerID: number;\n\n /**\n * Creates a new MIDI sequencer for playing back MIDI files.\n * @param synth synth to send events to.\n * @param options the sequencer's options.\n */\n public constructor(\n synth: BasicSynthesizer,\n options: Partial<SequencerOptions> = DEFAULT_SEQUENCER_OPTIONS\n ) {\n this.synth = synth;\n this.absoluteStartTime = this.synth.currentTime;\n\n this.sequencerID = this.synth.assignNewSequencer(\n this.handleMessage.bind(this)\n );\n this._skipToFirstNoteOn = options?.skipToFirstNoteOn ?? true;\n\n if (options?.initialPlaybackRate !== 1) {\n this.playbackRate = options?.initialPlaybackRate ?? 1;\n }\n\n if (!this._skipToFirstNoteOn) {\n // Setter sends message\n this.sendMessage(\"setSkipToFirstNote\", false);\n }\n\n window.addEventListener(\n \"beforeunload\",\n this.resetMIDIOutput.bind(this)\n );\n }\n\n private _shuffledSongIndexes: number[] = [];\n\n /**\n * The shuffled song indexes.\n * This is used when shuffleMode is enabled.\n */\n public get shuffledSongIndexes() {\n return this._shuffledSongIndexes;\n }\n\n private _songIndex = 0;\n\n /**\n * The current song number in the playlist.\n * If shuffle Mode is enabled, this is the index of the shuffled song list.\n */\n public get songIndex() {\n return this._songIndex;\n }\n\n /**\n * The current song number in the playlist.\n * If shuffle Mode is enabled, this is the index of the shuffled song list.\n */\n public set songIndex(value: number) {\n /**\n * Sets the song index in the playlist.\n */\n const clamped = Math.max(0, value % this._songsAmount);\n if (clamped === this._songIndex) {\n return;\n }\n this.isLoading = true;\n this.midiData = undefined;\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.index,\n data: clamped\n });\n }\n\n private _currentTempo = 120;\n\n /**\n * Current song's tempo in BPM.\n */\n public get currentTempo() {\n return this._currentTempo;\n }\n\n /**\n * The current sequence's length, in seconds.\n */\n public get duration() {\n return this.midiData?.duration ?? 0;\n }\n\n private _songsAmount = 0;\n\n // The amount of songs in the list.\n public get songsAmount() {\n return this._songsAmount;\n }\n\n private _skipToFirstNoteOn: boolean;\n\n /**\n * Indicates if the sequencer should skip to first note on.\n */\n public get skipToFirstNoteOn(): boolean {\n return this._skipToFirstNoteOn;\n }\n\n /**\n * Indicates if the sequencer should skip to first note on.\n */\n public set skipToFirstNoteOn(val: boolean) {\n this._skipToFirstNoteOn = val;\n this.sendMessage(\"setSkipToFirstNote\", this._skipToFirstNoteOn);\n }\n\n /**\n * Internal loop count marker (-1 is infinite).\n */\n private _loopCount = -1;\n\n /**\n * The current remaining number of loops. -1 means infinite looping.\n */\n public get loopCount() {\n return this._loopCount;\n }\n\n /**\n * The current remaining number of loops. -1 means infinite looping.\n */\n public set loopCount(val) {\n this._loopCount = val;\n this.sendMessage(\"setLoopCount\", val);\n }\n\n /**\n * Controls the playback's rate.\n */\n private _playbackRate = 1;\n\n /**\n * Controls the playback's rate.\n */\n public get playbackRate() {\n return this._playbackRate;\n }\n\n /**\n * Controls the playback's rate.\n */\n public set playbackRate(value: number) {\n const t = this.currentTime;\n this.sendMessage(\"setPlaybackRate\", value);\n this.highResTimeOffset *= value / this._playbackRate;\n this._playbackRate = value;\n this.recalculateStartTime(t);\n }\n\n private _shuffleSongs = false;\n\n /**\n * Controls if the sequencer should shuffle the songs in the song list.\n * If true, the sequencer will play the songs in a random order.\n *\n * Songs are shuffled on a `loadNewSongList` call.\n */\n public get shuffleSongs() {\n return this._shuffleSongs;\n }\n\n /**\n * Controls if the sequencer should shuffle the songs in the song list.\n * If true, the sequencer will play the songs in a random order.\n *\n * Songs are shuffled on a `loadNewSongList` call.\n */\n public set shuffleSongs(value: boolean) {\n this._shuffleSongs = value;\n if (value) {\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.shuffleOn\n });\n } else {\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.shuffleOff\n });\n }\n }\n\n /**\n * Current playback time, in seconds.\n */\n public get currentTime() {\n if (this.isLoading) {\n return 0;\n }\n // Return the paused time if it's set to something other than undefined\n if (this.pausedTime !== undefined) {\n return this.pausedTime;\n }\n\n return (\n (this.synth.currentTime - this.absoluteStartTime) *\n this._playbackRate\n );\n }\n\n /**\n * Current playback time, in seconds.\n */\n public set currentTime(time) {\n this.sendMessage(\"setTime\", time);\n }\n\n /**\n * A smoothed version of currentTime.\n * Use for visualization as it's not affected by the audioContext stutter.\n */\n public get currentHighResolutionTime() {\n if (this.pausedTime !== undefined) {\n return this.pausedTime;\n }\n const highResTimeOffset = this.highResTimeOffset;\n const absoluteStartTime = this.absoluteStartTime;\n\n // Sync performance.now to current time\n const performanceElapsedTime =\n (performance.now() / 1000 - absoluteStartTime) * this._playbackRate;\n\n let currentPerformanceTime = highResTimeOffset + performanceElapsedTime;\n const currentAudioTime = this.currentTime;\n\n const smoothingFactor = 0.01 * this._playbackRate;\n\n // Diff times smoothing factor\n const timeDifference = currentAudioTime - currentPerformanceTime;\n this.highResTimeOffset += timeDifference * smoothingFactor;\n\n // Return a smoothed performance time\n currentPerformanceTime =\n this.highResTimeOffset + performanceElapsedTime;\n return currentPerformanceTime;\n }\n\n /**\n * True if paused, false if playing or stopped.\n */\n public get paused() {\n return this.pausedTime !== undefined;\n }\n\n /**\n * Gets the current MIDI File.\n */\n public async getMIDI(): Promise<BasicMIDI> {\n return new Promise((resolve) => {\n this.getMIDICallback = resolve;\n this.sendMessage(\"getMIDI\", null);\n });\n }\n\n /**\n * Loads a new song list.\n * @param midiBuffers The MIDI files to play.\n */\n public loadNewSongList(midiBuffers: SuppliedMIDIData[]) {\n this.isLoading = true;\n this.midiData = undefined;\n this.sendMessage(\"loadNewSongList\", midiBuffers);\n this._songIndex = 0;\n this._songsAmount = midiBuffers.length;\n }\n\n /**\n * Connects a given output to the sequencer.\n * @param output The output to connect. Pass undefined to use the connected synthesizer.\n */\n public connectMIDIOutput(output?: { send: (data: number[]) => unknown }) {\n this.resetMIDIOutput();\n this.midiOut = output;\n this.sendMessage(\"changeMIDIMessageSending\", output !== undefined);\n this.currentTime -= 0.1;\n }\n\n /**\n * Pauses the playback.\n */\n public pause() {\n if (this.paused) {\n return;\n }\n this.pausedTime = this.currentTime;\n this.sendMessage(\"pause\", null);\n }\n\n /**\n * Starts or resumes the playback.\n */\n public play() {\n this.recalculateStartTime(this.pausedTime ?? 0);\n this.pausedTime = undefined;\n this.isFinished = false;\n this.sendMessage(\"play\", null);\n }\n\n private handleMessage(m: SequencerReturnMessage) {\n switch (m.type) {\n case \"midiMessage\": {\n const midiEventData = m.data.message as number[];\n if (this.midiOut && midiEventData[0] >= 0x80) {\n this.midiOut.send(midiEventData);\n return;\n }\n break;\n }\n\n case \"songChange\": {\n this._songIndex = m.data.songIndex;\n const idx = this._shuffleSongs\n ? this._shuffledSongIndexes[this._songIndex]\n : this._songIndex;\n const songChangeData = this.songListData[idx];\n this.midiData = songChangeData;\n this.isLoading = false;\n this.absoluteStartTime = 0;\n this.callEventInternal(\"songChange\", songChangeData);\n break;\n }\n\n case \"sync\": {\n if (Math.abs(m.data - this.currentTime) > 0.05)\n this.recalculateStartTime(m.data);\n break;\n }\n\n case \"timeChange\": {\n // Message data is absolute time\n const time = m.data.newTime;\n this.recalculateStartTime(time);\n this.callEventInternal(\"timeChange\", time);\n break;\n }\n\n case \"pause\": {\n this.pausedTime = this.currentTime;\n this.isFinished = m.data.isFinished;\n if (this.isFinished) {\n this.callEventInternal(\"songEnded\", null);\n }\n break;\n }\n\n case \"midiError\": {\n this.callEventInternal(\"midiError\", m.data);\n break;\n }\n\n case \"getMIDI\": {\n if (this.getMIDICallback) {\n this.getMIDICallback(BasicMIDI.copyFrom(m.data));\n }\n break;\n }\n\n case \"metaEvent\": {\n const event = m.data.event;\n switch (event.statusByte) {\n case midiMessageTypes.setTempo: {\n this._currentTempo =\n 60_000_000 /\n SpessaSynthCoreUtils.readBytesAsUintBigEndian(\n event.data,\n 3\n );\n break;\n }\n\n case midiMessageTypes.text:\n case midiMessageTypes.lyric:\n case midiMessageTypes.copyright:\n case midiMessageTypes.trackName:\n case midiMessageTypes.marker:\n case midiMessageTypes.cuePoint:\n case midiMessageTypes.instrumentName:\n case midiMessageTypes.programName: {\n if (!this.midiData) {\n break;\n }\n let lyricsIndex = -1;\n if (event.statusByte === midiMessageTypes.lyric) {\n lyricsIndex = Math.min(\n this.midiData.lyrics.findIndex(\n (l) => l.ticks === event.ticks\n ),\n this.midiData.lyrics.length - 1\n );\n }\n // If MIDI is a karaoke file, it uses the \"text\" event type or \"lyrics\" for lyrics (duh)\n // Why?\n // Because the MIDI standard is a messy pile of garbage,\n // And it's not my fault that it's like this :(\n // I'm just trying to make the best out of a bad situation.\n // I'm sorry\n // Okay I should get back to work\n // Anyway,\n // Check for a karaoke file and change the status byte to \"lyric\"\n // If it's a karaoke file\n if (\n this.midiData.isKaraokeFile &&\n (event.statusByte === midiMessageTypes.text ||\n event.statusByte === midiMessageTypes.lyric)\n ) {\n lyricsIndex = Math.min(\n this.midiData.lyrics.findIndex(\n (l) => l.ticks === event.ticks\n ),\n this.midiData.lyrics.length\n );\n }\n this.callEventInternal(\"textEvent\", {\n event,\n lyricsIndex\n });\n break;\n }\n }\n this.callEventInternal(\"metaEvent\", {\n event: m.data.event,\n trackNumber: m.data.trackIndex\n });\n break;\n }\n\n case \"loopCountChange\": {\n this._loopCount = m.data.newCount;\n if (this._loopCount === 0) {\n }\n break;\n }\n\n case \"songListChange\": {\n // Remap to MIDI data again as cloned objects don't get methods.\n this.songListData = m.data.newSongList.map(\n (m) => new MIDIData(m)\n );\n this._shuffledSongIndexes = m.data.shuffledSongIndexes;\n break;\n }\n\n default: {\n break;\n }\n }\n }\n\n private callEventInternal<\n EventType extends keyof WorkletSequencerEventType\n >(type: EventType, data: WorkletSequencerEventType[EventType]) {\n this.eventHandler.callEventInternal(type, data);\n }\n\n private resetMIDIOutput() {\n if (!this.midiOut) {\n return;\n }\n for (let i = 0; i < 16; i++) {\n this.midiOut.send([midiMessageTypes.controllerChange | i, 120, 0]); // All notes off\n this.midiOut.send([midiMessageTypes.controllerChange | i, 123, 0]); // All sound off\n }\n this.midiOut.send([midiMessageTypes.reset]); // Reset\n }\n\n private recalculateStartTime(time: number) {\n this.absoluteStartTime =\n this.synth.currentTime - time / this._playbackRate;\n this.highResTimeOffset =\n (this.synth.currentTime - performance.now() / 1000) *\n this._playbackRate;\n if (this.paused) {\n this.pausedTime = time;\n }\n }\n\n private sendMessage<T extends keyof SequencerMessageData>(\n messageType: T,\n messageData: SequencerMessageData[T]\n ) {\n this.synth.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"sequencerSpecific\",\n data: {\n type: messageType,\n data: messageData,\n id: this.sequencerID\n } as SequencerMessage\n });\n }\n}\n","import type { SequencerOptions } from \"./types\";\n\nexport const DEFAULT_SEQUENCER_OPTIONS: SequencerOptions = {\n skipToFirstNoteOn: true,\n initialPlaybackRate: 1\n};\n","import type { WorkletSequencerEventType } from \"./types\";\n\ntype SequencerEventCallback<T extends keyof WorkletSequencerEventType> = (\n callbackData: WorkletSequencerEventType[T]\n) => unknown;\n\ntype EventsMap = {\n [K in keyof WorkletSequencerEventType]: Map<\n string,\n SequencerEventCallback<K>\n >;\n};\n\nexport class SeqEventHandler {\n /**\n * The time delay before an event is called.\n * Set to 0 to disable it.\n */\n public timeDelay = 0;\n\n private readonly events: EventsMap = {\n songChange: new Map<string, SequencerEventCallback<\"songChange\">>(),\n songEnded: new Map<string, SequencerEventCallback<\"songEnded\">>(),\n metaEvent: new Map<string, SequencerEventCallback<\"metaEvent\">>(),\n timeChange: new Map<string, SequencerEventCallback<\"timeChange\">>(),\n midiError: new Map<string, SequencerEventCallback<\"midiError\">>(),\n textEvent: new Map<string, SequencerEventCallback<\"textEvent\">>()\n };\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new event listener.\n * @param event The event to listen to.\n * @param id The unique identifier for the event. It can be used to overwrite existing callback with the same ID.\n * @param callback The callback for the event.\n */\n public addEvent<T extends keyof WorkletSequencerEventType>(\n event: T,\n id: string,\n callback: SequencerEventCallback<T>\n ) {\n this.events[event].set(id, callback);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Removes an event listener\n * @param name The event to remove a listener from.\n * @param id The unique identifier for the event to remove.\n */\n public removeEvent<T extends keyof WorkletSequencerEventType>(\n name: T,\n id: string\n ) {\n this.events[name].delete(id);\n }\n\n /**\n * Calls the given event.\n * Internal use only.\n * @internal\n */\n public callEventInternal<T extends keyof WorkletSequencerEventType>(\n name: T,\n eventData: WorkletSequencerEventType[T]\n ) {\n const eventList = this.events[name];\n const callback = () => {\n for (const callback of eventList.values()) {\n try {\n callback(eventData);\n } catch (error) {\n console.error(\n `Error while executing a sequencer event callback for ${name}:`,\n error\n );\n }\n }\n };\n if (this.timeDelay > 0) {\n setTimeout(callback.bind(this), this.timeDelay * 1000);\n } else {\n callback();\n }\n }\n}\n","import { audioToWav, type WaveWriteOptions } from \"spessasynth_core\";\n\ninterface ExtraWaveOptions extends WaveWriteOptions {\n /**\n * The channel offset in the AudioBuffer. Defaults to 0.\n */\n channelOffset: number;\n\n /**\n * The amount of channels from the AudioBuffer to write. Defaults to all.\n */\n channelCount: number;\n}\n\n/**\n * Converts an audio buffer into a wave file.\n * @param audioBuffer The audio data channels.\n * @param options Additional options for writing the file.\n * @returns The binary file.\n */\nexport function audioBufferToWav(\n audioBuffer: AudioBuffer,\n options?: Partial<ExtraWaveOptions>\n): Blob {\n const channels: Float32Array[] = [];\n const channelOffset = options?.channelOffset ?? 0;\n const channelCount = options?.channelCount ?? audioBuffer.numberOfChannels;\n for (let i = channelOffset; i < audioBuffer.numberOfChannels; i++) {\n channels.push(audioBuffer.getChannelData(i));\n if (channels.length >= channelCount) {\n break;\n }\n }\n return new Blob([audioToWav(channels, audioBuffer.sampleRate, options)], {\n type: \"audio/wav\"\n });\n}\n","import { SpessaSynthCoreUtils as util } from \"spessasynth_core\";\nimport { consoleColors } from \"../utils/other.js\";\nimport type { Sequencer } from \"../sequencer/sequencer\";\nimport type { BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\";\n\n/**\n * Midi_handler.js\n * purpose: handles the connection between MIDI devices and synthesizer/sequencer via Web MIDI API\n */\n\nclass LibMIDIPort {\n public readonly port: MIDIPort;\n\n protected constructor(port: MIDIPort) {\n this.port = port;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get id() {\n return this.port.id;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get name() {\n return this.port.name;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get manufacturer() {\n return this.port.manufacturer;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get version() {\n return this.port.version;\n }\n}\n\nclass LibMIDIInput extends LibMIDIPort {\n private readonly connectedSynths = new Set<BasicSynthesizer>();\n\n public constructor(input: MIDIInput) {\n super(input);\n input.onmidimessage = (e) => {\n for (const s of this.connectedSynths) {\n if (e.data) s.sendMessage(e.data);\n }\n };\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Connects the input to a given synth, listening for all incoming events.\n * @param synth The synth to connect to.\n */\n public connect(synth: BasicSynthesizer) {\n this.connectedSynths.add(synth);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects the input from a given synth.\n * @param synth The synth to disconnect from.\n */\n public disconnect(synth: BasicSynthesizer) {\n this.connectedSynths.delete(synth);\n }\n}\n\nclass LibMIDIOutput extends LibMIDIPort {\n public readonly port: MIDIOutput;\n\n public constructor(output: MIDIOutput) {\n super(output);\n this.port = output;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Connects a given sequencer to the output, playing back the MIDI file to it.\n * @param seq The sequencer to connect.\n */\n public connect(seq: Sequencer) {\n seq.connectMIDIOutput(this.port);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects sequencer from the output, making it play to the attached Synthesizer instead.\n * @param seq The sequencer to disconnect.\n */\n public disconnect(seq: Sequencer) {\n seq.connectMIDIOutput(undefined);\n }\n}\n\n// noinspection JSUnusedGlobalSymbols\n/**\n * A class for handling physical MIDI devices.\n */\nexport class MIDIDeviceHandler {\n /**\n * The available MIDI inputs. ID maps to the input.\n */\n public readonly inputs = new Map<string, LibMIDIInput>();\n /**\n * The available MIDI outputs. ID maps to the output.\n */\n public readonly outputs = new Map<string, LibMIDIOutput>();\n\n private constructor(access: MIDIAccess) {\n for (const [key, value] of access.inputs.entries()) {\n this.inputs.set(key, new LibMIDIInput(value));\n }\n for (const [key, value] of access.outputs.entries()) {\n this.outputs.set(key, new LibMIDIOutput(value));\n }\n }\n\n /**\n * Attempts to initialize the MIDI Device Handler.\n * @returns The handler.\n * @throws An error if the MIDI Devices fail to initialize.\n */\n public static async createMIDIDeviceHandler(): Promise<MIDIDeviceHandler> {\n if (navigator.requestMIDIAccess) {\n // Prepare the midi access\n try {\n const response = await navigator.requestMIDIAccess({\n sysex: true,\n software: true\n });\n util.SpessaSynthInfo(\n \"%cMIDI handler created!\",\n consoleColors.recognized\n );\n return new MIDIDeviceHandler(response);\n } catch (error) {\n util.SpessaSynthWarn(`Could not get MIDI Devices:`, error);\n throw error;\n }\n } else {\n util.SpessaSynthWarn(\n \"Web MIDI API is not supported.\",\n consoleColors.unrecognized\n );\n throw new Error(\"Web MIDI API is not supported.\");\n }\n }\n}\n","import { consoleColors } from \"../utils/other.js\";\nimport { SpessaSynthCoreUtils } from \"spessasynth_core\";\nimport type { BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\";\n\n/**\n * Web_midi_link.js\n * purpose: handles the web midi link connection to the synthesizer\n * https://www.g200kg.com/en/docs/webmidilink/\n */\n\nexport class WebMIDILinkHandler {\n /**\n * Initializes support for Web MIDI Link (https://www.g200kg.com/en/docs/webmidilink/)\n * @param synth The synthesizer to enable support with.\n */\n public constructor(synth: BasicSynthesizer) {\n window.addEventListener(\"message\", (msg) => {\n if (typeof msg.data !== \"string\") {\n return;\n }\n const data: string[] = msg.data.split(\",\");\n if (data[0] !== \"midi\") {\n return;\n }\n\n data.shift(); // Remove MIDI\n\n const midiData = data.map((byte) => Number.parseInt(byte, 16));\n\n synth.sendMessage(midiData);\n });\n\n SpessaSynthCoreUtils.SpessaSynthInfo(\n \"%cWeb MIDI Link handler created!\",\n consoleColors.recognized\n );\n }\n}\n"],"mappings":"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","names":["callback","SpessaSynthCoreUtils","context","context","SoundBankLoader","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","util","SpessaSynthProcessor","SpessaSynthSequencer","SynthesizerSnapshot","SpessaSynthProcessor","SpessaSynthSequencer","util","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","SynthesizerSnapshot","BasicMIDI","BasicMIDI","BLOCK_SIZE","SoundBankLoader","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","midiMessageTypes","SpessaSynthCoreUtils","callback","BasicMIDI","midiMessageTypes","SpessaSynthCoreUtils","m","ALL_CHANNELS_OR_DIFFERENT_ACTION","util","util","SpessaSynthCoreUtils"]}
1
+ {"version":3,"sources":["../src/synthesizer/basic/key_modifier_manager.ts","../src/utils/fill_with_defaults.ts","../src/synthesizer/basic/sound_bank_manager.ts","../src/synthesizer/basic/synth_event_handler.ts","../src/synthesizer/basic/basic_synthesizer.ts","../src/utils/other.ts","../src/synthesizer/basic/snapshot.ts","../src/synthesizer/basic/synth_config.ts","../src/synthesizer/worklet/worklet_processor_name.ts","../src/synthesizer/worklet/worklet_synthesizer.ts","../src/synthesizer/worker/playback_worklet.ts","../src/synthesizer/worker/render_audio_worker.ts","../src/synthesizer/worker/worker_synthesizer.ts","../src/synthesizer/worker/worker_synthesizer_core.ts","../src/synthesizer/basic/basic_synthesizer_core.ts","../src/sequencer/midi_data.ts","../src/sequencer/enums.ts","../src/synthesizer/worker/write_sf_worker.ts","../src/synthesizer/worker/write_rmi_worker.ts","../src/sequencer/sequencer.ts","../src/sequencer/default_sequencer_options.ts","../src/sequencer/seq_event_handler.ts","../src/utils/buffer_to_wav.ts","../src/external_midi/midi_handler.ts","../src/external_midi/web_midi_link.ts"],"sourcesContent":["import { KeyModifier, type MIDIPatch } from \"spessasynth_core\";\nimport type { WorkletKMManagerData } from \"../types.ts\";\nimport type { BasicSynthesizer } from \"./basic_synthesizer.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\n\nexport class WorkletKeyModifierManagerWrapper {\n // The velocity override mappings for MIDI keys\n private keyModifiers: (KeyModifier | undefined)[][] = [];\n\n private synth: BasicSynthesizer;\n\n public constructor(synth: BasicSynthesizer) {\n this.synth = synth;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Modifies a single key.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n * @param options The key's modifiers.\n */\n public addModifier(\n channel: number,\n midiNote: number,\n options: Partial<{\n velocity: number;\n patch: MIDIPatch;\n gain: number;\n }>\n ) {\n const mod = new KeyModifier();\n mod.gain = options?.gain ?? 1;\n mod.velocity = options?.velocity ?? -1;\n mod.patch = fillWithDefaults(\n options.patch ?? ({} as Partial<MIDIPatch>),\n {\n isGMGSDrum: false,\n bankLSB: -1,\n bankMSB: -1,\n program: -1\n }\n );\n this.keyModifiers[channel] ??= [];\n this.keyModifiers[channel][midiNote] = mod;\n this.sendToWorklet(\"addMapping\", {\n channel,\n midiNote,\n mapping: mod\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a key modifier.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n * @returns The key modifier if it exists.\n */\n public getModifier(\n channel: number,\n midiNote: number\n ): KeyModifier | undefined {\n return this.keyModifiers?.[channel]?.[midiNote];\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Deletes a key modifier.\n * @param channel The channel affected. Usually 0-15.\n * @param midiNote The MIDI note to change. 0-127.\n */\n public deleteModifier(channel: number, midiNote: number) {\n this.sendToWorklet(\"deleteMapping\", {\n channel,\n midiNote\n });\n if (this.keyModifiers[channel]?.[midiNote] === undefined) {\n return;\n }\n this.keyModifiers[channel][midiNote] = undefined;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Clears ALL Modifiers\n */\n public clearModifiers() {\n this.sendToWorklet(\"clearMappings\", null);\n this.keyModifiers = [];\n }\n\n private sendToWorklet<T extends keyof WorkletKMManagerData>(\n type: T,\n data: WorkletKMManagerData[T]\n ) {\n const msg = {\n type,\n data\n } as {\n [K in keyof WorkletKMManagerData]: {\n type: K;\n data: WorkletKMManagerData[K];\n };\n }[keyof WorkletKMManagerData];\n this.synth.post({\n type: \"keyModifierManager\",\n channelNumber: -1,\n data: msg\n });\n }\n}\n","/**\n * Fills the object with default values.\n * @param obj object to fill.\n * @param defObj object to fill with.\n */\nexport function fillWithDefaults<T>(obj: Partial<T> | undefined, defObj: T): T {\n return {\n ...defObj,\n ...obj\n };\n}\n","import {\n type SoundBankManagerListEntry,\n SpessaSynthCoreUtils\n} from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n WorkletSBKManagerData\n} from \"../types.ts\";\nimport type { BasicSynthesizer } from \"./basic_synthesizer.ts\";\n\ntype LibSBKManagerEntry = Omit<SoundBankManagerListEntry, \"soundBank\">;\n\nexport class SoundBankManager {\n /**\n * All the sound banks, ordered from the most important to the least.\n */\n public soundBankList: LibSBKManagerEntry[];\n\n private synth: BasicSynthesizer;\n\n /**\n * Creates a new instance of the sound bank manager.\n */\n public constructor(synth: BasicSynthesizer) {\n this.soundBankList = [];\n this.synth = synth;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * The current sound bank priority order.\n * @returns The IDs of the sound banks in the current order.\n */\n public get priorityOrder() {\n return this.soundBankList.map((s) => s.id);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Rearranges the sound banks in a given order.\n * @param newList The order of sound banks, a list of identifiers, first overwrites second.\n */\n public set priorityOrder(newList: string[]) {\n this.sendToWorklet(\"rearrangeSoundBanks\", newList);\n this.soundBankList.sort(\n (a, b) => newList.indexOf(a.id) - newList.indexOf(b.id)\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new sound bank buffer with a given ID.\n * @param soundBankBuffer The sound bank's buffer\n * @param id The sound bank's unique identifier.\n * @param bankOffset The sound bank's bank offset. Default is 0.\n */\n public async addSoundBank(\n soundBankBuffer: ArrayBuffer,\n id: string,\n bankOffset = 0\n ) {\n this.sendToWorklet(\n \"addSoundBank\",\n {\n soundBankBuffer,\n bankOffset,\n id\n },\n [soundBankBuffer]\n );\n await this.awaitResponse();\n const found = this.soundBankList.find((s) => s.id === id);\n if (found === undefined) {\n this.soundBankList.push({\n id: id,\n bankOffset: bankOffset\n });\n } else {\n found.bankOffset = bankOffset;\n }\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Deletes a sound bank with the given ID.\n * @param id The sound bank to delete.\n */\n public async deleteSoundBank(id: string) {\n if (this.soundBankList.length < 2) {\n SpessaSynthCoreUtils.SpessaSynthWarn(\n \"1 sound bank left. Aborting!\"\n );\n return;\n }\n if (!this.soundBankList.some((s) => s.id === id)) {\n SpessaSynthCoreUtils.SpessaSynthWarn(\n `No sound banks with id of \"${id}\" found. Aborting!`\n );\n return;\n }\n this.sendToWorklet(\"deleteSoundBank\", id);\n this.soundBankList = this.soundBankList.filter((s) => s.id !== id);\n await this.awaitResponse();\n }\n\n private async awaitResponse() {\n return new Promise((r) =>\n this.synth.awaitWorkerResponse(\"soundBankManager\", r)\n );\n }\n\n private sendToWorklet<T extends keyof WorkletSBKManagerData>(\n type: T,\n data: WorkletSBKManagerData[T],\n transferable: Transferable[] = []\n ) {\n const msg: BasicSynthesizerMessage = {\n type: \"soundBankManager\",\n channelNumber: -1,\n data: {\n type,\n data\n } as {\n [K in keyof WorkletSBKManagerData]: {\n type: K;\n data: WorkletSBKManagerData[K];\n };\n }[keyof WorkletSBKManagerData]\n };\n this.synth.post(msg, transferable);\n }\n}\n","import type { SynthProcessorEventData } from \"spessasynth_core\";\n\ntype ProcessorEventCallback<T extends keyof SynthProcessorEventData> = (\n callbackData: SynthProcessorEventData[T]\n) => unknown;\n\ntype EventsMap = {\n [K in keyof SynthProcessorEventData]: Map<\n string,\n ProcessorEventCallback<K>\n >;\n};\n\nexport class SynthEventHandler {\n /**\n * The time delay before an event is called.\n * Set to 0 to disable it.\n */\n public timeDelay = 0;\n\n /**\n * The main list of events.\n * @private\n */\n private readonly events: EventsMap = {\n noteOff: new Map<string, ProcessorEventCallback<\"noteOff\">>(), // Called on a note off message\n noteOn: new Map<string, ProcessorEventCallback<\"noteOn\">>(), // Called on a note on message\n pitchWheel: new Map<string, ProcessorEventCallback<\"pitchWheel\">>(), // Called on a pitch-wheel change\n controllerChange: new Map<\n string,\n ProcessorEventCallback<\"controllerChange\">\n >(), // Called on a controller change\n programChange: new Map<\n string,\n ProcessorEventCallback<\"programChange\">\n >(), // Called on a program change\n channelPressure: new Map<\n string,\n ProcessorEventCallback<\"channelPressure\">\n >(), // Called on a channel pressure message\n polyPressure: new Map<string, ProcessorEventCallback<\"polyPressure\">>(), // Called on a poly pressure message\n drumChange: new Map<string, ProcessorEventCallback<\"drumChange\">>(), // Called when a channel type changes\n stopAll: new Map<string, ProcessorEventCallback<\"stopAll\">>(), // Called when the synth receives stop all command\n newChannel: new Map<string, ProcessorEventCallback<\"newChannel\">>(), // Called when a new channel is created\n muteChannel: new Map<string, ProcessorEventCallback<\"muteChannel\">>(), // Called when a channel is muted/unmuted\n presetListChange: new Map<\n string,\n ProcessorEventCallback<\"presetListChange\">\n >(), // Called when the preset list changes (soundfont gets reloaded)\n allControllerReset: new Map<\n string,\n ProcessorEventCallback<\"allControllerReset\">\n >(), // Called when all controllers are reset\n soundBankError: new Map<\n string,\n ProcessorEventCallback<\"soundBankError\">\n >(), // Called when a sound bank parsing error occurs\n synthDisplay: new Map<string, ProcessorEventCallback<\"synthDisplay\">>(), // Called when there's a SysEx message to display some text\n masterParameterChange: new Map<\n string,\n ProcessorEventCallback<\"masterParameterChange\">\n >(), // Called when a master parameter changes\n channelPropertyChange: new Map<\n string,\n ProcessorEventCallback<\"channelPropertyChange\">\n >(), // Called when a channel property changes\n effectChange: new Map<string, ProcessorEventCallback<\"effectChange\">>() // Called when an effect processor parameter is changed\n };\n\n /**\n * Adds a new event listener.\n * @param event The event to listen to.\n * @param id The unique identifier for the event. It can be used to overwrite existing callback with the same ID.\n * @param callback The callback for the event.\n */\n public addEvent<T extends keyof SynthProcessorEventData>(\n event: T,\n id: string,\n callback: ProcessorEventCallback<T>\n ) {\n this.events[event].set(id, callback);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Removes an event listener\n * @param name The event to remove a listener from.\n * @param id The unique identifier for the event to remove.\n */\n public removeEvent<T extends keyof SynthProcessorEventData>(\n name: T,\n id: string\n ) {\n this.events[name].delete(id);\n }\n\n /**\n * Calls the given event.\n * INTERNAL USE ONLY!\n * @internal\n */\n public callEventInternal<T extends keyof SynthProcessorEventData>(\n name: T,\n eventData: SynthProcessorEventData[T]\n ) {\n const eventList = this.events[name];\n const callback = () => {\n for (const callback of eventList.values()) {\n try {\n callback(eventData);\n } catch (error) {\n console.error(\n `Error while executing an event callback for ${name}:`,\n error\n );\n }\n }\n };\n if (this.timeDelay > 0) {\n setTimeout(callback.bind(this), this.timeDelay * 1000);\n } else {\n callback();\n }\n }\n}\n","import { WorkletKeyModifierManagerWrapper } from \"./key_modifier_manager.ts\";\nimport { SoundBankManager } from \"./sound_bank_manager.ts\";\nimport { SynthEventHandler } from \"./synth_event_handler.ts\";\nimport {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type ChannelProperty,\n DEFAULT_MASTER_PARAMETERS,\n DEFAULT_PERCUSSION,\n type MasterParameterType,\n type MIDIController,\n midiControllers,\n midiMessageTypes,\n type PresetList,\n SpessaSynthCoreUtils as util,\n type SynthMethodOptions\n} from \"spessasynth_core\";\nimport type { SequencerReturnMessage } from \"../../sequencer/types.ts\";\nimport type { SynthConfig } from \"./types.ts\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn\n} from \"../types.ts\";\nimport { consoleColors } from \"../../utils/other.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\nimport { LibSynthesizerSnapshot } from \"./snapshot.ts\";\n\nconst DEFAULT_SYNTH_METHOD_OPTIONS: SynthMethodOptions = {\n time: 0\n};\n\n// The \"remote controller\" of a given processor and abstraction for both synth engines.\nexport abstract class BasicSynthesizer {\n /**\n * Allows managing the sound bank list.\n */\n public readonly soundBankManager = new SoundBankManager(this);\n /**\n * Allows managing key modifications.\n */\n public readonly keyModifierManager = new WorkletKeyModifierManagerWrapper(\n this\n );\n /**\n * Allows setting up custom event listeners for the synthesizer.\n */\n public readonly eventHandler: SynthEventHandler = new SynthEventHandler();\n /**\n * Synthesizer's parent AudioContext instance.\n */\n public readonly context: BaseAudioContext;\n /**\n * Synth's current channel properties.\n */\n public readonly channelProperties: ChannelProperty[] = [];\n /**\n * The current preset list.\n */\n public presetList: PresetList = [];\n\n /**\n * INTERNAL USE ONLY!\n * @internal\n * All sequencer callbacks\n */\n public sequencers = new Array<(m: SequencerReturnMessage) => unknown>();\n /**\n * Resolves when the synthesizer is ready.\n */\n public readonly isReady: Promise<unknown>;\n // noinspection JSUnusedGlobalSymbols\n /**\n * Legacy parameter.\n * @deprecated\n */\n public readonly reverbProcessor = undefined;\n // noinspection JSUnusedGlobalSymbols\n /**\n * Legacy parameter.\n * @deprecated\n */\n public readonly chorusProcessor = undefined;\n /**\n * INTERNAL USE ONLY!\n * @internal\n */\n public readonly post: (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown;\n protected readonly worklet: AudioWorkletNode;\n /**\n * The new channels will have their audio sent to the modulated output by this constant.\n * what does that mean?\n * e.g., if outputsAmount is 16, then channel's 16 audio data will be sent to channel 0\n */\n protected readonly _outputsAmount = 16;\n /**\n * The current amount of MIDI channels the synthesizer has.\n */\n public channelsAmount = this._outputsAmount;\n protected readonly masterParameters: MasterParameterType = {\n ...DEFAULT_MASTER_PARAMETERS\n };\n\n // Resolve map, waiting for the worklet to confirm the operation\n protected resolveMap = new Map<\n keyof SynthesizerReturn,\n (data: SynthesizerReturn[keyof SynthesizerReturn]) => unknown\n >();\n\n protected renderingProgressTracker = new Map<\n keyof SynthesizerProgress,\n {\n [K in keyof SynthesizerProgress]: (\n args: SynthesizerProgress[K]\n ) => unknown;\n }[keyof SynthesizerProgress]\n >();\n\n /**\n * Creates a new instance of a synthesizer.\n * @param worklet The AudioWorkletNode to use.\n * @param postFunction The internal post function.\n * @param config Optional configuration for the synthesizer.\n */\n protected constructor(\n worklet: AudioWorkletNode,\n postFunction: (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown,\n config: SynthConfig\n ) {\n util.SpessaSynthInfo(\n \"%cInitializing SpessaSynth synthesizer...\",\n consoleColors.info\n );\n this.context = worklet.context;\n this.worklet = worklet;\n this.post = postFunction;\n\n // Used in child classes\n void config;\n\n this.isReady = new Promise((resolve) =>\n this.awaitWorkerResponse(\"sf3Decoder\", resolve)\n );\n\n // Set up message handling and managers\n this.worklet.port.onmessage = (\n e: MessageEvent<BasicSynthesizerReturnMessage>\n ) => this.handleMessage(e.data);\n\n // Create initial channels\n for (let i = 0; i < this.channelsAmount; i++) {\n this.addNewChannelInternal(false);\n }\n this.channelProperties[DEFAULT_PERCUSSION].isDrum = true;\n\n // Attach event handlers\n this.eventHandler.addEvent(\n \"newChannel\",\n `synth-new-channel-${Math.random()}`,\n () => {\n this.channelsAmount++;\n }\n );\n this.eventHandler.addEvent(\n \"presetListChange\",\n `synth-preset-list-change-${Math.random()}`,\n (e) => {\n this.presetList = [...e];\n }\n );\n this.eventHandler.addEvent(\n \"masterParameterChange\",\n `synth-master-parameter-change-${Math.random()}`,\n <P extends keyof MasterParameterType>(e: {\n parameter: P;\n value: MasterParameterType[P];\n }) => {\n this.masterParameters[e.parameter] = e.value;\n }\n );\n this.eventHandler.addEvent(\n \"channelPropertyChange\",\n `synth-channel-property-change-${Math.random()}`,\n (e) => {\n this.channelProperties[e.channel] = e.property;\n\n this._voicesAmount = this.channelProperties.reduce(\n (sum, voices) => sum + voices.voicesAmount,\n 0\n );\n }\n );\n }\n\n /**\n * Current voice amount\n */\n protected _voicesAmount = 0;\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * The current number of voices playing.\n */\n public get voicesAmount() {\n return this._voicesAmount;\n }\n\n /**\n * The audioContext's current time.\n */\n public get currentTime() {\n return this.context.currentTime;\n }\n\n /**\n * Connects from a given node.\n * @param destinationNode The node to connect to.\n */\n public connect(destinationNode: AudioNode) {\n // Connect all other worklet outputs (effects + 16 channels)\n for (let i = 0; i < 17; i++) {\n this.worklet.connect(destinationNode, i);\n }\n return destinationNode;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects from a given node.\n * @param destinationNode The node to disconnect from.\n */\n public disconnect(destinationNode?: AudioNode) {\n if (!destinationNode) {\n this.worklet.disconnect();\n return undefined;\n }\n // Disconnect all other worklet outputs\n for (let i = 0; i < 17; i++) {\n this.worklet.disconnect(destinationNode, i);\n }\n return destinationNode;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets the SpessaSynth's log level in the processor.\n * @param enableInfo Enable info (verbose)\n * @param enableWarning Enable warnings (unrecognized messages)\n * @param enableGroup Enable groups (to group a lot of logs)\n */\n public setLogLevel(\n enableInfo: boolean,\n enableWarning: boolean,\n enableGroup: boolean\n ) {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"setLogLevel\",\n data: {\n enableInfo,\n enableWarning,\n enableGroup\n }\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a master parameter from the synthesizer.\n * @param type The parameter to get.\n * @returns The parameter value.\n */\n public getMasterParameter<K extends keyof MasterParameterType>(\n type: K\n ): MasterParameterType[K] {\n return this.masterParameters[type];\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets a master parameter to a given value.\n * @param type The parameter to set.\n * @param value The value to set.\n */\n public setMasterParameter<K extends keyof MasterParameterType>(\n type: K,\n value: MasterParameterType[K]\n ) {\n this.masterParameters[type] = value;\n this.post({\n type: \"setMasterParameter\",\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n data: {\n type,\n data: value\n } as {\n [K in keyof MasterParameterType]: {\n type: K;\n data: MasterParameterType[K];\n };\n }[keyof MasterParameterType]\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Gets a complete snapshot of the synthesizer, effects.\n */\n public async getSnapshot(): Promise<LibSynthesizerSnapshot> {\n return new Promise((resolve) => {\n this.awaitWorkerResponse(\"synthesizerSnapshot\", (s) => {\n const snapshot = LibSynthesizerSnapshot.copyFrom(s);\n resolve(snapshot);\n });\n this.post({\n type: \"requestSynthesizerSnapshot\",\n data: null,\n channelNumber: -1\n });\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new channel to the synthesizer.\n */\n public addNewChannel() {\n this.addNewChannelInternal(true);\n }\n\n /**\n * DEPRECATED, please don't use it!\n * @deprecated\n */\n public setVibrato(\n channel: number,\n value: { delay: number; depth: number; rate: number }\n ) {\n void channel;\n void value;\n }\n\n /**\n * Connects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.\n * @param audioNodes Exactly 16 outputs.\n */\n public connectIndividualOutputs(audioNodes: AudioNode[]) {\n if (audioNodes.length !== this._outputsAmount) {\n throw new Error(`input nodes amount differs from the system's outputs amount!\n Expected ${this._outputsAmount} got ${audioNodes.length}`);\n }\n for (\n let outputNumber = 0;\n outputNumber < this._outputsAmount;\n outputNumber++\n ) {\n // + 1 because effects come first!\n this.worklet.connect(audioNodes[outputNumber], outputNumber + 1);\n }\n }\n\n /**\n * Disconnects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.\n * @param audioNodes Exactly 16 outputs.\n */\n public disconnectIndividualOutputs(audioNodes: AudioNode[]) {\n if (audioNodes.length !== this._outputsAmount) {\n throw new Error(`input nodes amount differs from the system's outputs amount!\n Expected ${this._outputsAmount} got ${audioNodes.length}`);\n }\n for (\n let outputNumber = 0;\n outputNumber < this._outputsAmount;\n outputNumber++\n ) {\n // + 2 because chorus and reverb come first!\n this.worklet.disconnect(audioNodes[outputNumber], outputNumber + 2);\n }\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disables the GS NRPN parameters like vibrato or drum key tuning.\n * @deprecated Deprecated! Please use master parameters\n */\n public disableGSNPRNParams() {\n this.setMasterParameter(\"nprnParamLock\", true);\n }\n\n /**\n * Sends a raw MIDI message to the synthesizer.\n * @param message the midi message, each number is a byte.\n * @param channelOffset the channel offset of the message.\n * @param eventOptions additional options for this command.\n */\n public sendMessage(\n message: Iterable<number>,\n channelOffset = 0,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n this._sendInternal(message, channelOffset, false, eventOptions);\n }\n\n /**\n * Starts playing a note\n * @param channel Usually 0-15: the channel to play the note.\n * @param midiNote 0-127 the key number of the note.\n * @param velocity 0-127 the velocity of the note (generally controls loudness).\n * @param eventOptions Additional options for this command.\n */\n public noteOn(\n channel: number,\n midiNote: number,\n velocity: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n midiNote %= 128;\n velocity %= 128;\n this.sendMessage(\n [midiMessageTypes.noteOn | ch, midiNote, velocity],\n offset,\n eventOptions\n );\n }\n\n /**\n * Stops playing a note.\n * @param channel Usually 0-15: the channel of the note.\n * @param midiNote {number} 0-127 the key number of the note.\n * @param force Instantly kills the note if true.\n * @param eventOptions Additional options for this command.\n */\n public noteOff(\n channel: number,\n midiNote: number,\n force = false,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n midiNote %= 128;\n\n const ch = channel % 16;\n const offset = channel - ch;\n this._sendInternal(\n [midiMessageTypes.noteOff | ch, midiNote],\n offset,\n force,\n eventOptions\n );\n }\n\n /**\n * Stops all notes.\n * @param force If the notes should immediately be stopped, defaults to false.\n */\n public stopAll(force = false) {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"stopAll\",\n data: force ? 1 : 0\n });\n }\n\n /**\n * Changes the given controller\n * @param channel Usually 0-15: the channel to change the controller.\n * @param controllerNumber 0-127 the MIDI CC number.\n * @param controllerValue 0-127 the controller value.\n * @param force Forces the controller-change message, even if it's locked or gm system is set and the cc is bank select.\n * @param eventOptions Additional options for this command.\n */\n public controllerChange(\n channel: number,\n controllerNumber: MIDIController,\n controllerValue: number,\n force = false,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n if (controllerNumber > 127 || controllerNumber < 0) {\n throw new Error(`Invalid controller number: ${controllerNumber}`);\n }\n controllerValue = Math.floor(controllerValue) % 128;\n controllerNumber = Math.floor(controllerNumber) % 128;\n // Controller change has its own message for the force property\n const ch = channel % 16;\n const offset = channel - ch;\n this._sendInternal(\n [\n midiMessageTypes.controllerChange | ch,\n controllerNumber,\n controllerValue\n ],\n offset,\n force,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Resets all controllers (for every channel)\n */\n public resetControllers() {\n this.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"ccReset\",\n data: null\n });\n }\n\n /**\n * Causes the given midi channel to ignore controller messages for the given controller number.\n * @param channel Usually 0-15: the channel to lock.\n * @param controllerNumber 0-127 MIDI CC number.\n * @param isLocked True if locked, false if unlocked.\n * @remarks\n * Controller number -1 locks the preset.\n */\n public lockController(\n channel: number,\n controllerNumber: MIDIController | -1,\n isLocked: boolean\n ) {\n this.post({\n channelNumber: channel,\n type: \"lockController\",\n data: {\n controllerNumber,\n isLocked\n }\n });\n }\n\n /**\n * Applies pressure to a given channel.\n * @param channel Usually 0-15: the channel to change the controller.\n * @param pressure 0-127: the pressure to apply.\n * @param eventOptions Additional options for this command.\n */\n public channelPressure(\n channel: number,\n pressure: number,\n eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n pressure %= 128;\n this.sendMessage(\n [midiMessageTypes.channelPressure | ch, pressure],\n offset,\n eventOptions\n );\n }\n\n /**\n * Applies pressure to a given note.\n * @param channel Usually 0-15: the channel to change the controller.\n * @param midiNote 0-127: the MIDI note.\n * @param pressure 0-127: the pressure to apply.\n * @param eventOptions Additional options for this command.\n */\n public polyPressure(\n channel: number,\n midiNote: number,\n pressure: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n midiNote %= 128;\n pressure %= 128;\n this.sendMessage(\n [midiMessageTypes.polyPressure | ch, midiNote, pressure],\n offset,\n eventOptions\n );\n }\n\n /**\n * Sets the pitch of the given channel.\n * @param channel Usually 0-15: the channel to change pitch.\n * @param value The bend of the MIDI pitch wheel message. 0 - 16384\n * @param eventOptions Additional options for this command.\n */\n public pitchWheel(\n channel: number,\n value: number,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n const ch = channel % 16;\n const offset = channel - ch;\n this.sendMessage(\n [midiMessageTypes.pitchWheel | ch, value & 0x7f, value >> 7],\n offset,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Sets the channel's pitch wheel range, in semitones.\n * @param channel Usually 0-15: the channel to change.\n * @param range The bend range in semitones.\n */\n public pitchWheelRange(channel: number, range: number) {\n // Set range\n this.controllerChange(\n channel,\n midiControllers.registeredParameterMSB,\n 0\n );\n this.controllerChange(\n channel,\n midiControllers.registeredParameterLSB,\n 0\n );\n this.controllerChange(channel, midiControllers.dataEntryMSB, range);\n\n // Reset rpn\n this.controllerChange(\n channel,\n midiControllers.registeredParameterMSB,\n 127\n );\n this.controllerChange(\n channel,\n midiControllers.registeredParameterLSB,\n 127\n );\n this.controllerChange(channel, midiControllers.dataEntryMSB, 0);\n }\n\n /**\n * Changes the program for a given channel\n * @param channel Usually 0-15: the channel to change.\n * @param programNumber 0-127 the MIDI patch number.\n * defaults to false\n */\n public programChange(channel: number, programNumber: number) {\n const ch = channel % 16;\n const offset = channel - ch;\n programNumber %= 128;\n this.sendMessage(\n [midiMessageTypes.programChange | ch, programNumber],\n offset\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Transposes the channel by given number of semitones.\n * @param channel The channel number.\n * @param semitones The transposition of the channel, it can be a float.\n * @param force Defaults to false, if true transposes the channel even if it's a drum channel.\n */\n public transposeChannel(channel: number, semitones: number, force = false) {\n this.post({\n channelNumber: channel,\n type: \"transposeChannel\",\n data: {\n semitones,\n force\n }\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Mutes or unmutes the given channel.\n * @param channel Usually 0-15: the channel to mute.\n * @param isMuted Indicates if the channel is muted.\n */\n public muteChannel(channel: number, isMuted: boolean) {\n this.post({\n channelNumber: channel,\n type: \"muteChannel\",\n data: isMuted\n });\n }\n\n /**\n * Sends a MIDI Sysex message to the synthesizer.\n * @param messageData The message's data, excluding the F0 byte, but including the F7 at the end.\n * @param channelOffset Channel offset for the system exclusive message, defaults to zero.\n * @param eventOptions Additional options for this command.\n */\n public systemExclusive(\n messageData: number[] | Iterable<number> | Uint8Array,\n channelOffset = 0,\n eventOptions: SynthMethodOptions = DEFAULT_SYNTH_METHOD_OPTIONS\n ) {\n this._sendInternal(\n [midiMessageTypes.systemExclusive, ...Array.from(messageData)],\n channelOffset,\n false,\n eventOptions\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Tune MIDI keys of a given program using the MIDI Tuning Standard.\n * @param program 0 - 127 the MIDI program number to use.\n * @param tunings The keys and their tunings.\n * TargetPitch of -1 sets the tuning for this key to be tuned regularly.\n */\n public tuneKeys(\n program: number,\n tunings: { sourceKey: number; targetPitch: number }[]\n ) {\n if (tunings.length > 127) {\n throw new Error(\"Too many tunings. Maximum allowed is 127.\");\n }\n const systemExclusive = [\n 0x7f, // Real-time\n 0x10, // Device id\n 0x08, // MIDI Tuning\n 0x02, // Note change\n program, // Tuning program number\n tunings.length // Number of changes\n ];\n for (const tuning of tunings) {\n systemExclusive.push(tuning.sourceKey); // [kk] MIDI Key number\n if (tuning.targetPitch === -1) {\n // No change\n systemExclusive.push(0x7f, 0x7f, 0x7f);\n } else {\n const midiNote = Math.floor(tuning.targetPitch);\n const fraction = Math.floor(\n (tuning.targetPitch - midiNote) / 0.000_061\n );\n systemExclusive.push(\n midiNote, // Frequency data byte 1\n (fraction >> 7) & 0x7f, // Frequency data byte 2\n fraction & 0x7f // Frequency data byte 3\n );\n }\n }\n systemExclusive.push(0xf7);\n this.systemExclusive(systemExclusive);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Toggles drums on a given channel.\n * @param channel The channel number.\n * @param isDrum If the channel should be drums.\n */\n public setDrums(channel: number, isDrum: boolean) {\n this.post({\n channelNumber: channel,\n type: \"setDrums\",\n data: isDrum\n });\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Yes please!\n */\n public reverbateEverythingBecauseWhyNot(): \"That's the spirit!\" {\n for (let i = 0; i < this.channelsAmount; i++) {\n this.controllerChange(i, midiControllers.reverbDepth, 127);\n this.lockController(i, midiControllers.reverbDepth, true);\n }\n return \"That's the spirit!\";\n }\n\n /**\n * INTERNAL USE ONLY!\n * @param type INTERNAL USE ONLY!\n * @param resolve INTERNAL USE ONLY!\n * @internal\n */\n public awaitWorkerResponse<K extends keyof SynthesizerReturn>(\n type: K,\n resolve: (data: SynthesizerReturn[K]) => unknown\n ) {\n // @ts-expect-error I can't use generics with map\n this.resolveMap.set(type, resolve);\n }\n\n /**\n * INTERNAL USE ONLY!\n * @param callback the sequencer callback\n * @internal\n */\n public assignNewSequencer(\n callback: (m: SequencerReturnMessage) => unknown\n ) {\n this.post({\n channelNumber: -1,\n type: \"requestNewSequencer\",\n data: null\n });\n this.sequencers.push(callback);\n return this.sequencers.length - 1;\n }\n\n protected assignProgressTracker<K extends keyof SynthesizerProgress>(\n type: K,\n progressFunction: (args: SynthesizerProgress[K]) => unknown\n ) {\n if (this.renderingProgressTracker.get(type)) {\n throw new Error(\"Something is already being rendered!\");\n }\n // @ts-expect-error I can't use generics with map\n this.renderingProgressTracker.set(type, progressFunction);\n }\n\n protected revokeProgressTracker<K extends keyof SynthesizerProgress>(\n type: K\n ) {\n this.renderingProgressTracker.delete(type);\n }\n\n protected _sendInternal(\n message: Iterable<number>,\n channelOffset: number,\n force = false,\n eventOptions: Partial<SynthMethodOptions>\n ) {\n const options = fillWithDefaults(\n eventOptions,\n DEFAULT_SYNTH_METHOD_OPTIONS\n );\n this.post({\n type: \"midiMessage\",\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n data: {\n messageData: new Uint8Array(message),\n channelOffset,\n force,\n options\n }\n //[new Uint8Array(message), offset, force, opts]\n });\n }\n\n /**\n * Handles the messages received from the worklet.\n */\n protected handleMessage(m: BasicSynthesizerReturnMessage) {\n switch (m.type) {\n case \"eventCall\": {\n this.eventHandler.callEventInternal(m.data.type, m.data.data);\n break;\n }\n\n case \"sequencerReturn\": {\n this.sequencers[m.data.id](m.data);\n break;\n }\n\n case \"isFullyInitialized\": {\n this.workletResponds(m.data.type, m.data.data);\n break;\n }\n\n case \"soundBankError\": {\n util.SpessaSynthWarn(m.data as unknown as string);\n this.eventHandler.callEventInternal(\"soundBankError\", m.data);\n break;\n }\n\n case \"renderingProgress\": {\n this.renderingProgressTracker.get(m.data.type)?.(\n // @ts-expect-error I can't use generics with map\n m.data.data\n );\n }\n }\n }\n\n protected addNewChannelInternal(post: boolean) {\n this.channelProperties.push({\n voicesAmount: 0,\n pitchWheel: 0,\n pitchWheelRange: 0,\n isMuted: false,\n isDrum: this.channelsAmount % 16 === DEFAULT_PERCUSSION,\n isEFX: false,\n transposition: 0\n });\n if (!post) {\n return;\n }\n this.post({\n channelNumber: 0,\n type: \"addNewChannel\",\n data: null\n });\n }\n\n protected workletResponds<K extends keyof SynthesizerReturn>(\n type: K,\n data: SynthesizerReturn[K]\n ) {\n this.resolveMap.get(type)?.(data);\n this.resolveMap.delete(type);\n }\n}\n","/**\n * Other.js\n * purpose: contains some useful functions that don't belong in any specific category\n */\n\nimport { SpessaSynthCoreUtils } from \"spessasynth_core\";\n\nconst consoleColors = SpessaSynthCoreUtils.consoleColors;\n\nexport { consoleColors };\n","/**\n * Old synthesizer snapshot, used to contain audio effects.\n * @deprecated\n */\nexport { SynthesizerSnapshot as LibSynthesizerSnapshot } from \"spessasynth_core\";\n","import type { SynthConfig } from \"./types\";\n\nexport const DEFAULT_SYNTH_CONFIG: SynthConfig = {\n enableEventSystem: true,\n oneOutput: false,\n audioNodeCreators: undefined\n};\n","export const WORKLET_PROCESSOR_NAME = \"spessasynth-worklet-processor\";\n","import { DEFAULT_SYNTH_CONFIG } from \"../basic/synth_config.ts\";\nimport { WORKLET_PROCESSOR_NAME } from \"./worklet_processor_name.js\";\nimport type { SynthConfig } from \"../basic/types.ts\";\nimport { BasicSynthesizer } from \"../basic/basic_synthesizer.ts\";\nimport type { OfflineRenderWorkletData } from \"../types.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\n\n/**\n * This synthesizer uses an audio worklet node containing the processor.\n */\nexport class WorkletSynthesizer extends BasicSynthesizer {\n /**\n * Creates a new instance of an AudioWorklet-based synthesizer.\n * @param context The audio context.\n * @param config Optional configuration for the synthesizer.\n */\n public constructor(\n context: BaseAudioContext,\n config: Partial<SynthConfig> = DEFAULT_SYNTH_CONFIG\n ) {\n // Ensure default values for options\n const synthConfig = fillWithDefaults(config, DEFAULT_SYNTH_CONFIG);\n\n let outputChannelCount = new Array<number>(17).fill(2);\n let numberOfOutputs = 17;\n\n if (synthConfig.oneOutput) {\n // One output with 34 channels\n outputChannelCount = [34];\n numberOfOutputs = 1;\n }\n\n let worklet: AudioWorkletNode;\n // Create the audio worklet node\n try {\n const workletConstructor =\n synthConfig?.audioNodeCreators?.worklet ??\n ((context, name, options) => {\n return new AudioWorkletNode(context, name, options);\n });\n worklet = workletConstructor(context, WORKLET_PROCESSOR_NAME, {\n outputChannelCount,\n numberOfOutputs,\n processorOptions: {\n oneOutput: synthConfig.oneOutput,\n enableEventSystem: synthConfig.enableEventSystem\n }\n });\n } catch (error) {\n console.error(error);\n throw new Error(\n \"Could not create the AudioWorkletNode. Did you forget to addModule()?\"\n );\n }\n super(\n worklet,\n (data, transfer = []) => {\n worklet.port.postMessage(data, transfer);\n },\n synthConfig\n );\n }\n\n /**\n * Starts an offline audio render.\n * @param config The configuration to use.\n * @remarks\n * Call this method immediately after you've set up the synthesizer.\n * Do NOT call any other methods after initializing before this one.\n * Chromium seems to ignore worklet messages for OfflineAudioContext.\n */\n public async startOfflineRender(config: OfflineRenderWorkletData) {\n this.post(\n {\n type: \"startOfflineRender\",\n data: config,\n channelNumber: -1\n },\n config.soundBankList.map((b) => b.soundBankBuffer)\n );\n await new Promise((r) =>\n this.awaitWorkerResponse(\"startOfflineRender\", r)\n );\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Destroys the synthesizer instance.\n */\n public destroy() {\n // noinspection JSCheckFunctionSignatures\n this.post({\n channelNumber: 0,\n type: \"destroyWorklet\",\n data: null\n });\n this.worklet.disconnect();\n // @ts-expect-error destruction!\n // noinspection JSConstantReassignment\n delete this.worklet;\n }\n}\n","export const PLAYBACK_WORKLET_PROCESSOR_NAME = `spessasynth-playback-worklet-processor`;\n\nexport function getPlaybackWorkletURL(maxQueuedChunks: number) {\n // Thanks to the wonderful Audio Worklet API, we have this: code in strings!\n const PLAYBACK_WORKLET_CODE = `\nconst BLOCK_SIZE = 128;\n\nconst MAX_QUEUED = ${maxQueuedChunks};\n\n/**\n * An AudioWorkletProcessor that plays back 18 separate streams of stereo audio: reverb, and chorus and 16 dry channels.\n */\nclass PlaybackProcessor extends AudioWorkletProcessor\n{\n \n \n /** @type {Float32Array[]} */\n data = [];\n \n updateRequested = false;\n \n alive = true;\n \n /**\n *\n * @type {MessagePort}\n */\n sentPort;\n \n constructor()\n {\n super();\n \n /**\n * @param e {MessageEvent}\n */\n this.port.onmessage = (e) =>\n {\n if (e.ports.length)\n {\n const sentPort = e.ports[0];\n this.sentPort = sentPort;\n sentPort.onmessage = (e) =>\n {\n if(e.data === null)\n {\n // the worklet is dead\n this.alive = false;\n }\n this.data.push(e.data);\n this.updateRequested = false;\n // if we need more, request immediately\n if (this.data.length < MAX_QUEUED)\n {\n this.sentPort.postMessage(null);\n }\n };\n \n }\n };\n }\n \n // noinspection JSUnusedGlobalSymbols\n /**\n * @param _inputs {[Float32Array, Float32Array][]}\n * @param outputs {[Float32Array, Float32Array][]}\n * @returns {boolean}\n */\n process(_inputs, outputs)\n {\n const data = this.data.shift();\n if (!data)\n {\n return this.alive;\n }\n let offset = 0;\n // decode the data nicely\n for (let i = 0; i < 17; i++)\n {\n outputs[i][0].set(data.subarray(offset, offset + BLOCK_SIZE));\n offset += BLOCK_SIZE;\n outputs[i][1].set(data.subarray(offset, offset + BLOCK_SIZE));\n offset += BLOCK_SIZE;\n }\n \n // if it has already been requested, we need to wait\n if (!this.updateRequested)\n {\n this.sentPort.postMessage(null);\n this.updateRequested = true;\n }\n \n // keep it online\n return this.alive;\n }\n}\nregisterProcessor(\"${PLAYBACK_WORKLET_PROCESSOR_NAME}\", PlaybackProcessor);\n `;\n const blob = new Blob([PLAYBACK_WORKLET_CODE], {\n type: \"application/javascript\"\n });\n return URL.createObjectURL(blob);\n}\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport { SpessaSynthProcessor, SpessaSynthSequencer } from \"spessasynth_core\";\n\nexport interface WorkerRenderAudioOptions {\n /**\n * Extra fadeout time after the song finishes, in seconds.\n */\n extraTime: number;\n /**\n * If channels should be rendered separately.\n */\n separateChannels: boolean;\n\n /**\n * The amount of times to loop the song.\n */\n loopCount: number;\n\n /**\n * The function that tracks the rendering progress.\n * @param progress mapped 0 to 1.\n * @param stage 0 is a dry pass, 1 is adding effects.\n */\n progressCallback?: (progress: number, stage: number) => unknown;\n\n /**\n * If the current parameters of the synthesizer should be preserved.\n */\n preserveSynthParams: boolean;\n\n /**\n * If the effects should be enabled.\n */\n enableEffects: boolean;\n\n /**\n * Which sequencer to render. Defaults to the first one (0).\n */\n sequencerID: number;\n}\n\nexport const DEFAULT_WORKER_RENDER_AUDIO_OPTIONS: WorkerRenderAudioOptions = {\n extraTime: 2,\n separateChannels: false,\n loopCount: 0,\n progressCallback: undefined,\n preserveSynthParams: true,\n enableEffects: true,\n sequencerID: 0\n};\n\nconst RENDER_BLOCKS_PER_PROGRESS = 64;\nconst BLOCK_SIZE = 128;\n\ntype StereoAudioChunk = [Float32Array, Float32Array];\n\ninterface ReturnedChunks {\n effects: StereoAudioChunk;\n dry: StereoAudioChunk[];\n}\n\nexport function renderAudioWorker(\n this: WorkerSynthesizerCore,\n sampleRate: number,\n options: WorkerRenderAudioOptions\n): ReturnedChunks {\n // Initialize synthesizer\n const rendererSynth = new SpessaSynthProcessor(sampleRate, {\n enableEventSystem: false\n });\n // Copy sound banks\n for (const entry of this.synthesizer.soundBankManager.soundBankList)\n rendererSynth.soundBankManager.addSoundBank(\n entry.soundBank,\n entry.id,\n entry.bankOffset\n );\n rendererSynth.soundBankManager.priorityOrder =\n this.synthesizer.soundBankManager.priorityOrder;\n this.stopAudioLoop();\n\n const seq = this.sequencers[options.sequencerID];\n const parsedMid = seq.midiData;\n if (!parsedMid) {\n throw new Error(\"No MIDI is loaded!\");\n }\n const playbackRate = seq.playbackRate;\n // Calculate times\n const loopStartAbsolute =\n parsedMid.midiTicksToSeconds(parsedMid.loop.start) / playbackRate;\n const loopEndAbsolute =\n parsedMid.midiTicksToSeconds(parsedMid.loop.end) / playbackRate;\n const loopDuration = loopEndAbsolute - loopStartAbsolute;\n const duration =\n parsedMid.duration / playbackRate +\n options.extraTime +\n loopDuration * options.loopCount;\n // Total duration in samples\n const sampleDuration = sampleRate * duration;\n\n // Initialize sequencer\n const rendererSeq = new SpessaSynthSequencer(rendererSynth);\n rendererSeq.loopCount = options.loopCount;\n if (options.preserveSynthParams) {\n // Apply snapshot if needed\n rendererSeq.playbackRate = seq.playbackRate;\n const snapshot = this.synthesizer.getSnapshot();\n rendererSynth.applySynthesizerSnapshot(snapshot);\n }\n\n // Apply no voice cap (applying snapshot resets master parameters)\n rendererSynth.setMasterParameter(\"autoAllocateVoices\", true);\n\n // Begin playing\n rendererSeq.loadNewSongList([parsedMid]);\n rendererSeq.play();\n\n // Allocate memory\n // Effects\n const wetL = new Float32Array(sampleDuration);\n const wetR = new Float32Array(sampleDuration);\n const effects: StereoAudioChunk = [wetL, wetR];\n // Final output\n const returnedChunks: ReturnedChunks = {\n effects,\n dry: []\n };\n const sampleDurationNoLastQuantum = sampleDuration - BLOCK_SIZE;\n if (options.separateChannels) {\n const dry: StereoAudioChunk[] = [];\n for (let i = 0; i < 16; i++) {\n const d: StereoAudioChunk = [\n new Float32Array(sampleDuration),\n new Float32Array(sampleDuration)\n ];\n dry.push(d);\n returnedChunks.dry.push(d);\n }\n let index = 0;\n while (true) {\n for (let i = 0; i < RENDER_BLOCKS_PER_PROGRESS; i++) {\n if (index >= sampleDurationNoLastQuantum) {\n rendererSeq.processTick();\n rendererSynth.processSplit(\n dry,\n wetL,\n wetR,\n index,\n sampleDuration - index\n );\n this.startAudioLoop();\n return returnedChunks;\n }\n rendererSeq.processTick();\n rendererSynth.processSplit(dry, wetL, wetR, index, BLOCK_SIZE);\n index += BLOCK_SIZE;\n }\n this.postProgress(\"renderAudio\", index / sampleDuration);\n }\n } else {\n const dryL = new Float32Array(sampleDuration);\n const dryR = new Float32Array(sampleDuration);\n const dry: StereoAudioChunk = [dryL, dryR];\n returnedChunks.dry.push(dry);\n let index = 0;\n while (true) {\n for (let i = 0; i < RENDER_BLOCKS_PER_PROGRESS; i++) {\n if (index >= sampleDurationNoLastQuantum) {\n rendererSeq.processTick();\n rendererSynth.process(\n dryL,\n dryR,\n index,\n sampleDuration - index\n );\n this.startAudioLoop();\n return returnedChunks;\n }\n rendererSeq.processTick();\n\n rendererSynth.process(dryL, dryR, index, BLOCK_SIZE);\n index += BLOCK_SIZE;\n }\n this.postProgress(\"renderAudio\", index / sampleDuration);\n }\n }\n}\n","import { BasicSynthesizer } from \"../basic/basic_synthesizer.ts\";\nimport type { SynthConfig } from \"../basic/types.ts\";\nimport { DEFAULT_SYNTH_CONFIG } from \"../basic/synth_config.ts\";\nimport { fillWithDefaults } from \"../../utils/fill_with_defaults.ts\";\nimport {\n getPlaybackWorkletURL,\n PLAYBACK_WORKLET_PROCESSOR_NAME\n} from \"./playback_worklet.ts\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn,\n WorkerBankWriteOptions,\n WorkerDLSWriteOptions,\n WorkerRMIDIWriteOptions,\n WorkerSoundFont2WriteOptions\n} from \"../types.ts\";\nimport {\n DEFAULT_WORKER_RENDER_AUDIO_OPTIONS,\n type WorkerRenderAudioOptions\n} from \"./render_audio_worker.ts\";\n\nconst DEFAULT_BANK_WRITE_OPTIONS: WorkerBankWriteOptions = {\n trim: true,\n bankID: \"\",\n writeEmbeddedSoundBank: true,\n sequencerID: 0\n};\n\nconst DEFAULT_SF2_WRITE_OPTIONS: WorkerSoundFont2WriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS,\n writeDefaultModulators: true,\n writeExtendedLimits: true,\n compress: false,\n compressionQuality: 1,\n decompress: false\n};\n\nconst DEFAULT_RMIDI_WRITE_OPTIONS: WorkerRMIDIWriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS,\n bankOffset: 0,\n correctBankOffset: true,\n metadata: {},\n format: \"sf2\",\n ...DEFAULT_SF2_WRITE_OPTIONS\n};\n\nconst DEFAULT_DLS_WRITE_OPTIONS: WorkerDLSWriteOptions = {\n ...DEFAULT_BANK_WRITE_OPTIONS\n};\n\ntype WorkerSynthWriteOptions<K> = K & {\n progressFunction?: (\n args: SynthesizerProgress[\"workerSynthWriteFile\"]\n ) => unknown;\n};\n\n/**\n * This synthesizer uses a Worker containing the processor and an audio worklet node for playback.\n */\nexport class WorkerSynthesizer extends BasicSynthesizer {\n /**\n * Time offset for syncing with the synth\n * @private\n */\n private timeOffset = 0;\n\n /**\n * Creates a new instance of a Worker-based synthesizer.\n * @param context The audio context.\n * @param workerPostMessage The postMessage for the worker containing the synthesizer core.\n * @param config Optional configuration for the synthesizer.\n */\n public constructor(\n context: BaseAudioContext,\n workerPostMessage: typeof Worker.prototype.postMessage,\n config: Partial<SynthConfig> = DEFAULT_SYNTH_CONFIG\n ) {\n // Ensure default values for options\n const synthConfig = fillWithDefaults(config, DEFAULT_SYNTH_CONFIG);\n if (synthConfig.oneOutput) {\n throw new Error(\n \"One output mode is not supported in the WorkerSynthesizer.\"\n );\n }\n\n let worklet: AudioWorkletNode;\n // Create the audio worklet node\n try {\n const workletConstructor =\n synthConfig?.audioNodeCreators?.worklet ??\n ((context, name, options) => {\n return new AudioWorkletNode(context, name, options);\n });\n worklet = workletConstructor(\n context,\n PLAYBACK_WORKLET_PROCESSOR_NAME,\n {\n outputChannelCount: new Array<number>(18).fill(2),\n numberOfOutputs: 18,\n processorOptions: {\n oneOutput: synthConfig.oneOutput,\n enableEventSystem: synthConfig.enableEventSystem\n }\n }\n );\n } catch (error) {\n console.error(error);\n throw new Error(\n \"Could not create the AudioWorkletNode. Did you forget to registerPlaybackWorklet()?\"\n );\n }\n super(\n worklet,\n workerPostMessage as (\n data: BasicSynthesizerMessage,\n transfer?: Transferable[]\n ) => unknown,\n synthConfig\n );\n\n // Create a message channel for communication between the worker and the worklet\n const messageChannel = new MessageChannel();\n const workerPort = messageChannel.port1;\n const workletPort = messageChannel.port2;\n // Post the channel to worklet\n this.worklet.port.postMessage(null, [workletPort]);\n // Post the channel and init worker\n workerPostMessage(\n {\n initialTime: this.context.currentTime,\n sampleRate: this.context.sampleRate\n },\n [workerPort]\n );\n }\n\n public get currentTime() {\n return this.context.currentTime + this.timeOffset;\n }\n\n /**\n * Registers an audio worklet for the WorkerSynthesizer.\n * @param context The context to register the worklet for.\n * @param maxQueueSize The maximum amount of 128-sample chunks to store in the worklet. Higher values result in less breakups but higher latency.\n */\n public static async registerPlaybackWorklet(\n context: BaseAudioContext,\n maxQueueSize = 20\n ) {\n if (!context?.audioWorklet.addModule) {\n throw new Error(\"Audio worklet is not supported.\");\n }\n return context.audioWorklet.addModule(\n getPlaybackWorkletURL(maxQueueSize)\n );\n }\n\n /**\n * Handles a return message from the Worker.\n * @param e The event received from the Worker.\n */\n public handleWorkerMessage(e: BasicSynthesizerReturnMessage) {\n this.timeOffset = e.currentTime - this.context.currentTime;\n this.handleMessage(e);\n }\n\n /**\n * Writes a DLS file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer and its corresponding name.\n */\n public async writeDLS(\n options: Partial<\n WorkerSynthWriteOptions<WorkerDLSWriteOptions>\n > = DEFAULT_DLS_WRITE_OPTIONS\n ): Promise<SynthesizerReturn[\"workerSynthWriteFile\"]> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_DLS_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data)\n );\n this.post({\n type: \"writeDLS\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Writes an SF2/SF3 file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer and its corresponding name.\n */\n public async writeSF2(\n options: Partial<\n WorkerSynthWriteOptions<WorkerSoundFont2WriteOptions>\n > = DEFAULT_SF2_WRITE_OPTIONS\n ): Promise<SynthesizerReturn[\"workerSynthWriteFile\"]> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_SF2_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data)\n );\n this.post({\n type: \"writeSF2\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Writes an embedded MIDI (RMIDI) file directly in the worker.\n * @param options Options for writing the file.\n * @returns The file array buffer.\n */\n public async writeRMIDI(\n options: Partial<\n WorkerSynthWriteOptions<WorkerRMIDIWriteOptions>\n > = DEFAULT_RMIDI_WRITE_OPTIONS\n ): Promise<ArrayBuffer> {\n const writeOptions = fillWithDefaults(\n options,\n DEFAULT_RMIDI_WRITE_OPTIONS\n );\n return new Promise((resolve) => {\n this.assignProgressTracker(\"workerSynthWriteFile\", (p) => {\n void options.progressFunction?.(p);\n });\n const postOptions = {\n ...writeOptions,\n progressFunction: null\n };\n this.awaitWorkerResponse(\"workerSynthWriteFile\", (data) =>\n resolve(data.binary)\n );\n this.post({\n type: \"writeRMIDI\",\n data: postOptions,\n channelNumber: -1\n });\n });\n }\n\n /**\n * Renders the current song in the connected sequencer to Float32 buffers.\n * @param sampleRate The sample rate to use, in Hertz.\n * @param renderOptions Extra options for the render.\n * @returns A single audioBuffer if separate channels were not enabled, otherwise 16.\n * @remarks\n * This stops the synthesizer.\n */\n public async renderAudio(\n sampleRate: number,\n renderOptions: Partial<WorkerRenderAudioOptions> = DEFAULT_WORKER_RENDER_AUDIO_OPTIONS\n ): Promise<AudioBuffer[]> {\n const options = fillWithDefaults(\n renderOptions,\n DEFAULT_WORKER_RENDER_AUDIO_OPTIONS\n );\n if (options.enableEffects && options.separateChannels) {\n throw new Error(\"Effects cannot be applied to separate channels.\");\n }\n return new Promise((resolve) => {\n // First pass: Worker renders the dry audio\n this.awaitWorkerResponse(\"renderAudio\", (data) => {\n this.revokeProgressTracker(\"renderAudio\");\n const bufferLength = data.dry[0][0].length;\n // Convert to audio buffers\n const dryChannels = data.dry.map((dryPair) => {\n const buffer = new AudioBuffer({\n sampleRate,\n numberOfChannels: 2,\n length: bufferLength\n });\n buffer.copyToChannel(\n dryPair[0] as Float32Array<ArrayBuffer>,\n 0\n );\n buffer.copyToChannel(\n dryPair[1] as Float32Array<ArrayBuffer>,\n 1\n );\n return buffer;\n });\n if (options.enableEffects) {\n // Append effects\n const buffer = new AudioBuffer({\n sampleRate,\n numberOfChannels: 2,\n length: bufferLength\n });\n buffer.copyToChannel(\n data.effects[0] as Float32Array<ArrayBuffer>,\n 0\n );\n buffer.copyToChannel(\n data.effects[1] as Float32Array<ArrayBuffer>,\n 1\n );\n dryChannels.push(buffer);\n }\n resolve(dryChannels);\n return;\n });\n // Assign progress tracker and render\n this.assignProgressTracker(\"renderAudio\", (p) => {\n options.progressCallback?.(p, 0);\n });\n\n // Functions cannot be cloned\n const strippedOptions: WorkerRenderAudioOptions = {\n ...options,\n progressCallback: undefined\n };\n this.post({\n type: \"renderAudio\",\n data: {\n sampleRate,\n options: strippedOptions\n },\n channelNumber: -1\n });\n });\n }\n}\n","import { type BasicSoundBank, SoundBankLoader } from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n WorkerBankWriteOptions,\n WorkerSampleEncodingFunction\n} from \"../types.ts\";\nimport { renderAudioWorker } from \"./render_audio_worker.ts\";\nimport {\n BasicSynthesizerCore,\n type PostMessageSynthCore,\n SEQUENCER_SYNC_INTERVAL\n} from \"../basic/basic_synthesizer_core.ts\";\nimport { writeDLSWorker, writeSF2Worker } from \"./write_sf_worker.ts\";\nimport { writeRMIDIWorker } from \"./write_rmi_worker.ts\";\n\nconst BLOCK_SIZE = 128;\n\ntype AudioChunk = [Float32Array, Float32Array];\ntype AudioChunks = AudioChunk[];\n\n// The core audio engine for the worker synthesizer.\nexport class WorkerSynthesizerCore extends BasicSynthesizerCore {\n /**\n * The message port to the playback audio worklet.\n */\n public readonly workletMessagePort: MessagePort;\n\n protected readonly compressionFunction?: WorkerSampleEncodingFunction;\n\n /**\n * Creates a new worker synthesizer core: the synthesizer that runs in the worker.\n * Most parameters here are provided with the first message that is posted to the worker by the WorkerSynthesizer.\n * @param synthesizerConfiguration The data from the first message sent from WorkerSynthesizer.\n * Listen for the first event and use its data to initialize this class.\n * @param workletMessagePort The first port from the first message sent from WorkerSynthesizer.\n * @param mainThreadCallback postMessage function or similar.\n * @param compressionFunction Optional function for compressing SF3 banks.\n */\n public constructor(\n synthesizerConfiguration: {\n sampleRate: number;\n initialTime: number;\n },\n workletMessagePort: MessagePort,\n mainThreadCallback: typeof Worker.prototype.postMessage,\n compressionFunction?: WorkerSampleEncodingFunction\n ) {\n super(\n synthesizerConfiguration.sampleRate,\n {\n enableEventSystem: true,\n enableEffects: true,\n initialTime: synthesizerConfiguration.initialTime\n },\n mainThreadCallback as PostMessageSynthCore\n );\n\n this.workletMessagePort = workletMessagePort;\n this.workletMessagePort.onmessage = this.process.bind(this);\n this.compressionFunction = compressionFunction;\n void this.synthesizer.processorInitialized.then(() => {\n this.postReady(\"sf3Decoder\", null);\n this.startAudioLoop();\n });\n }\n\n /**\n * Handles a message received from the main thread.\n * @param m The message received.\n */\n public handleMessage(m: BasicSynthesizerMessage) {\n switch (m.type) {\n case \"renderAudio\": {\n const rendered = renderAudioWorker.call(\n this,\n m.data.sampleRate,\n m.data.options\n );\n const transferable: Transferable[] = [];\n for (const r of rendered.effects) transferable.push(r.buffer);\n for (const d of rendered.dry)\n transferable.push(...d.map((c) => c.buffer));\n this.postReady(\"renderAudio\", rendered, transferable);\n break;\n }\n\n case \"writeRMIDI\": {\n this.stopAudioLoop();\n void writeRMIDIWorker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data,\n fileName: \"\"\n },\n [data]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n case \"writeSF2\": {\n this.stopAudioLoop();\n void writeSF2Worker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data.binary,\n fileName:\n data.bank.soundBankInfo.name +\n (data.bank.soundBankInfo.version.major === 3\n ? \".sf3\"\n : \".sf2\")\n },\n [data.binary]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n case \"writeDLS\": {\n this.stopAudioLoop();\n void writeDLSWorker.call(this, m.data).then((data) => {\n this.postReady(\n \"workerSynthWriteFile\",\n {\n binary: data.binary,\n fileName: data.bank.soundBankInfo.name + \".dls\"\n },\n [data.binary]\n );\n this.startAudioLoop();\n });\n break;\n }\n\n default: {\n super.handleMessage(m);\n }\n }\n }\n\n protected getBank(opts: WorkerBankWriteOptions): BasicSoundBank {\n const sq = this.sequencers[opts.sequencerID];\n const sf =\n opts.writeEmbeddedSoundBank && sq.midiData?.embeddedSoundBank\n ? SoundBankLoader.fromArrayBuffer(sq.midiData.embeddedSoundBank)\n : this.synthesizer.soundBankManager.soundBankList.find(\n (b) => b.id === opts.bankID\n )?.soundBank;\n if (!sf) {\n const e = new Error(\n `${opts.bankID} does not exist in the sound bank list!`\n );\n this.post({\n type: \"soundBankError\",\n data: e,\n currentTime: this.synthesizer.currentSynthTime\n });\n throw e;\n }\n return sf;\n }\n\n protected stopAudioLoop() {\n this.synthesizer.stopAllChannels(true);\n for (const seq of this.sequencers) {\n seq.pause();\n }\n this.alive = false;\n }\n\n protected startAudioLoop() {\n this.alive = true;\n this.process();\n }\n\n protected destroy() {\n // Null indicates end of life\n this.workletMessagePort.postMessage(null);\n this.stopAudioLoop();\n super.destroy();\n }\n\n protected process() {\n if (!this.alive) {\n return;\n }\n // Data is encoded into a single f32 array as follows\n // WetL, WetR,\n // Dry1L, dry1R\n // DryNL, dryNR\n // Dry16L, dry16R\n // To improve performance\n const byteStep = BLOCK_SIZE * Float32Array.BYTES_PER_ELEMENT;\n const data = new Float32Array(BLOCK_SIZE * 34);\n let byteOffset = 0;\n const wetR = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n const wetL = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n const dry: AudioChunks = [];\n for (let i = 0; i < 16; i++) {\n const dryL = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n\n const dryR = new Float32Array(data.buffer, byteOffset, BLOCK_SIZE);\n byteOffset += byteStep;\n\n dry.push([dryL, dryR]);\n }\n for (const seq of this.sequencers) {\n seq.processTick();\n }\n this.synthesizer.processSplit(dry, wetL, wetR);\n this.workletMessagePort.postMessage(data, [data.buffer]);\n\n const t = this.synthesizer.currentSynthTime;\n if (t - this.lastSequencerSync > SEQUENCER_SYNC_INTERVAL) {\n for (let id = 0; id < this.sequencers.length; id++) {\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"sync\",\n data: this.sequencers[id].currentTime,\n id\n },\n currentTime: t\n });\n }\n this.lastSequencerSync = t;\n }\n }\n}\n","import {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n BasicMIDI,\n SoundBankLoader,\n SpessaSynthCoreUtils as util,\n SpessaSynthLogging,\n SpessaSynthProcessor,\n SpessaSynthSequencer,\n SynthesizerSnapshot,\n type SynthProcessorOptions\n} from \"spessasynth_core\";\nimport type {\n BasicSynthesizerMessage,\n BasicSynthesizerReturnMessage,\n SynthesizerProgress,\n SynthesizerReturn\n} from \"../types.ts\";\nimport { MIDIData } from \"../../sequencer/midi_data.ts\";\nimport { songChangeType } from \"../../sequencer/enums.ts\";\n\nexport type PostMessageSynthCore = (\n data: BasicSynthesizerReturnMessage,\n transfer?: Transferable[]\n) => unknown;\n\n// Seconds\nexport const SEQUENCER_SYNC_INTERVAL = 1;\n\n/**\n * The interface for the audio processing code that uses spessasynth_core and runs on a separate thread.\n */\nexport abstract class BasicSynthesizerCore {\n public readonly synthesizer: SpessaSynthProcessor;\n public readonly sequencers = new Array<SpessaSynthSequencer>();\n protected readonly post: PostMessageSynthCore;\n protected lastSequencerSync = 0;\n /**\n * Indicates if the processor is alive.\n * @protected\n */\n protected alive = false;\n\n protected constructor(\n sampleRate: number,\n options: Omit<\n SynthProcessorOptions,\n \"reverbProcessor\" | \"chorusProcessor\" | \"delayProcessor\"\n >,\n postMessage: PostMessageSynthCore\n ) {\n this.synthesizer = new SpessaSynthProcessor(sampleRate, options);\n this.post = postMessage;\n\n // Prepare synthesizer connections\n this.synthesizer.onEventCall = (event) => {\n this.post({\n type: \"eventCall\",\n data: event,\n currentTime: this.synthesizer.currentSynthTime\n });\n };\n }\n\n protected createNewSequencer() {\n const sequencer = new SpessaSynthSequencer(this.synthesizer);\n const sequencerID = this.sequencers.length;\n this.sequencers.push(sequencer);\n\n // Prepare sequencer connections\n sequencer.onEventCall = (e) => {\n if (e.type === \"songListChange\") {\n const songs = e.data.newSongList;\n const midiDatas = songs.map((s) => {\n return new MIDIData(s);\n });\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: e.type,\n data: {\n newSongList: midiDatas,\n shuffledSongIndexes: sequencer.shuffledSongIndexes\n },\n id: sequencerID\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n return;\n }\n this.post({\n type: \"sequencerReturn\",\n data: { ...e, id: sequencerID },\n currentTime: this.synthesizer.currentSynthTime\n });\n };\n }\n\n protected postReady<K extends keyof SynthesizerReturn>(\n type: K,\n data: SynthesizerReturn[K],\n transferable: Transferable[] = []\n ) {\n this.post(\n {\n type: \"isFullyInitialized\",\n data: {\n type,\n data\n } as {\n [K in keyof SynthesizerReturn]: {\n type: K;\n data: SynthesizerReturn[K];\n };\n }[keyof SynthesizerReturn],\n currentTime: this.synthesizer.currentSynthTime\n },\n transferable\n );\n }\n\n protected postProgress<K extends keyof SynthesizerProgress>(\n type: K,\n data: SynthesizerProgress[K]\n ) {\n this.post({\n type: \"renderingProgress\",\n data: {\n type,\n data\n } as {\n [K in keyof SynthesizerProgress]: {\n type: K;\n data: SynthesizerProgress[K];\n };\n }[keyof SynthesizerProgress],\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n\n protected destroy() {\n this.synthesizer.destroySynthProcessor();\n // @ts-expect-error JS Deletion\n // noinspection JSConstantReassignment\n delete this.synthesizer;\n // @ts-expect-error JS Deletion\n // noinspection JSConstantReassignment\n delete this.sequencers;\n }\n\n protected handleMessage(m: BasicSynthesizerMessage) {\n const channel = m.channelNumber;\n\n let channelObject:\n | (typeof this.synthesizer.midiChannels)[number]\n | undefined = undefined;\n if (channel >= 0) {\n channelObject = this.synthesizer.midiChannels[channel];\n if (channelObject === undefined) {\n util.SpessaSynthWarn(\n `Trying to access channel ${channel} which does not exist... ignoring!`\n );\n return;\n }\n }\n switch (m.type) {\n case \"midiMessage\": {\n this.synthesizer.processMessage(\n m.data.messageData,\n m.data.channelOffset,\n m.data.force,\n m.data.options\n );\n break;\n }\n\n case \"customCcChange\": {\n // Custom controller change\n channelObject?.setCustomController(\n m.data.ccNumber,\n m.data.ccValue\n );\n break;\n }\n\n case \"ccReset\": {\n if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION) {\n this.synthesizer.resetAllControllers();\n } else {\n channelObject?.resetControllers();\n }\n break;\n }\n\n case \"stopAll\": {\n if (channel === ALL_CHANNELS_OR_DIFFERENT_ACTION) {\n this.synthesizer.stopAllChannels(m.data === 1);\n } else {\n channelObject?.stopAllNotes(m.data === 1);\n }\n break;\n }\n\n case \"muteChannel\": {\n channelObject?.muteChannel(m.data);\n break;\n }\n\n case \"addNewChannel\": {\n this.synthesizer.createMIDIChannel();\n break;\n }\n\n case \"setMasterParameter\": {\n this.synthesizer.setMasterParameter(m.data.type, m.data.data);\n break;\n }\n\n case \"setDrums\": {\n channelObject?.setDrums(m.data);\n break;\n }\n\n case \"transposeChannel\": {\n channelObject?.transposeChannel(m.data.semitones, m.data.force);\n break;\n }\n\n case \"lockController\": {\n if (\n m.data.controllerNumber === ALL_CHANNELS_OR_DIFFERENT_ACTION\n ) {\n channelObject?.setPresetLock(m.data.isLocked);\n } else {\n if (!channelObject) {\n return;\n }\n channelObject.lockedControllers[m.data.controllerNumber] =\n m.data.isLocked;\n }\n break;\n }\n\n case \"sequencerSpecific\": {\n const seq = this.sequencers[m.data.id];\n if (!seq) {\n return;\n }\n const seqMsg = m.data;\n switch (seqMsg.type) {\n default: {\n break;\n }\n\n case \"loadNewSongList\": {\n try {\n const sList = seqMsg.data;\n const songMap = sList.map((s) => {\n if (\"duration\" in s) {\n // Cloned objects don't have methods\n return BasicMIDI.copyFrom(s);\n }\n return BasicMIDI.fromArrayBuffer(\n s.binary,\n s.fileName\n );\n });\n seq.loadNewSongList(songMap);\n } catch (error) {\n console.error(error);\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"midiError\",\n data: error as Error,\n id: m.data.id\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n break;\n }\n\n case \"pause\": {\n seq.pause();\n break;\n }\n\n case \"play\": {\n seq.play();\n break;\n }\n\n case \"setTime\": {\n seq.currentTime = seqMsg.data;\n break;\n }\n\n case \"changeMIDIMessageSending\": {\n seq.externalMIDIPlayback = seqMsg.data;\n break;\n }\n\n case \"setPlaybackRate\": {\n seq.playbackRate = seqMsg.data;\n break;\n }\n\n case \"setLoopCount\": {\n seq.loopCount = seqMsg.data;\n break;\n }\n\n case \"changeSong\": {\n switch (seqMsg.data.changeType) {\n case songChangeType.shuffleOff: {\n seq.shuffleMode = false;\n break;\n }\n\n case songChangeType.shuffleOn: {\n seq.shuffleMode = true;\n break;\n }\n\n case songChangeType.index: {\n if (seqMsg.data.data !== undefined) {\n seq.songIndex = seqMsg.data.data;\n }\n break;\n }\n }\n break;\n }\n\n case \"getMIDI\": {\n if (!seq.midiData) {\n throw new Error(\"No MIDI is loaded!\");\n }\n this.post({\n type: \"sequencerReturn\",\n data: {\n type: \"getMIDI\",\n data: seq.midiData,\n id: m.data.id\n },\n currentTime: this.synthesizer.currentSynthTime\n });\n break;\n }\n\n case \"setSkipToFirstNote\": {\n seq.skipToFirstNoteOn = seqMsg.data;\n break;\n }\n }\n break;\n }\n\n case \"soundBankManager\": {\n try {\n const sfManager = this.synthesizer.soundBankManager;\n const sfManMsg = m.data;\n let font;\n switch (sfManMsg.type) {\n case \"addSoundBank\": {\n font = SoundBankLoader.fromArrayBuffer(\n sfManMsg.data.soundBankBuffer\n );\n sfManager.addSoundBank(\n font,\n sfManMsg.data.id,\n sfManMsg.data.bankOffset\n );\n this.postReady(\"soundBankManager\", null);\n break;\n }\n\n case \"deleteSoundBank\": {\n sfManager.deleteSoundBank(sfManMsg.data);\n this.postReady(\"soundBankManager\", null);\n break;\n }\n\n case \"rearrangeSoundBanks\": {\n sfManager.priorityOrder = sfManMsg.data;\n this.postReady(\"soundBankManager\", null);\n }\n }\n } catch (error) {\n this.post({\n type: \"soundBankError\",\n data: error as Error,\n currentTime: this.synthesizer.currentSynthTime\n });\n }\n break;\n }\n\n case \"keyModifierManager\": {\n const kmMsg = m.data;\n const man = this.synthesizer.keyModifierManager;\n switch (kmMsg.type) {\n default: {\n return;\n }\n\n case \"addMapping\": {\n man.addMapping(\n kmMsg.data.channel,\n kmMsg.data.midiNote,\n kmMsg.data.mapping\n );\n break;\n }\n\n case \"clearMappings\": {\n man.clearMappings();\n break;\n }\n\n case \"deleteMapping\": {\n man.deleteMapping(\n kmMsg.data.channel,\n kmMsg.data.midiNote\n );\n }\n }\n break;\n }\n\n case \"requestSynthesizerSnapshot\": {\n const snapshot = SynthesizerSnapshot.create(this.synthesizer);\n this.postReady(\"synthesizerSnapshot\", snapshot);\n break;\n }\n\n case \"requestNewSequencer\": {\n this.createNewSequencer();\n break;\n }\n\n case \"setLogLevel\": {\n SpessaSynthLogging(\n m.data.enableInfo,\n m.data.enableWarning,\n m.data.enableGroup\n );\n break;\n }\n\n case \"destroyWorklet\": {\n this.alive = false;\n this.synthesizer.destroySynthProcessor();\n this.destroy();\n break;\n }\n\n default: {\n util.SpessaSynthWarn(\"Unrecognized event!\", m);\n break;\n }\n }\n }\n}\n","import { BasicMIDI, MIDITrack } from \"spessasynth_core\";\n\nexport class MIDIDataTrack extends MIDITrack {\n /**\n * THIS DATA WILL BE EMPTY! USE sequencer.getMIDI() TO GET THE ACTUAL DATA!\n */\n public events: never[] = [];\n\n public constructor(track: MIDITrack) {\n super();\n super.copyFrom(track);\n this.events = [];\n }\n}\n\n/**\n * A simplified version of the MIDI, accessible at all times from the Sequencer.\n * Use getMIDI() to get the actual sequence.\n * This class contains all properties that MIDI does, except for tracks and the embedded sound bank.\n */\nexport class MIDIData extends BasicMIDI {\n public override tracks: MIDIDataTrack[];\n\n /**\n * THIS DATA WILL BE EMPTY! USE sequencer.getMIDI() TO GET THE ACTUAL DATA!\n */\n public override embeddedSoundBank = undefined;\n\n /**\n * The byte length of the sound bank if it exists.\n */\n public readonly embeddedSoundBankSize?: number;\n\n public constructor(mid: BasicMIDI) {\n super();\n super.copyMetadataFrom(mid);\n this.tracks = mid.tracks.map((t) => new MIDIDataTrack(t));\n this.embeddedSoundBankSize =\n mid instanceof MIDIData\n ? mid.embeddedSoundBankSize\n : mid?.embeddedSoundBank?.byteLength;\n }\n}\n","export const songChangeType = {\n shuffleOn: 1, // No additional data\n shuffleOff: 2, // No additional data\n index: 3 // SongIndex<number>\n} as const;\nexport type SongChangeType =\n (typeof songChangeType)[keyof typeof songChangeType];\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport type {\n WorkerDLSWriteOptions,\n WorkerSoundFont2WriteOptions\n} from \"../types.ts\";\nimport { BasicSoundBank, type SampleEncodingFunction } from \"spessasynth_core\";\n\nexport async function writeSF2Worker(\n this: WorkerSynthesizerCore,\n opts: WorkerSoundFont2WriteOptions\n): Promise<{\n binary: ArrayBuffer;\n bank: BasicSoundBank;\n}> {\n let sf = this.getBank(opts);\n\n if (opts.compress && !this.compressionFunction) {\n const e = new Error(\n `Compression enabled but no compression has been provided to WorkerSynthesizerCore.`\n );\n this.post({\n type: \"soundBankError\",\n data: e,\n currentTime: this.synthesizer.currentSynthTime\n });\n throw e;\n }\n\n const sq = this.sequencers[opts.sequencerID];\n\n // Trim\n if (opts.trim) {\n if (!sq.midiData) {\n throw new Error(\n \"Sound bank MIDI trimming is enabled but no MIDI is loaded!\"\n );\n }\n // Copy\n const sfCopy = BasicSoundBank.copyFrom(sf);\n sfCopy.trimSoundBank(sq.midiData);\n sf = sfCopy;\n }\n\n let compressionFunction: SampleEncodingFunction | undefined;\n\n if (this.compressionFunction !== undefined) {\n compressionFunction = (audioData, sampleRate) =>\n this.compressionFunction!(\n audioData,\n sampleRate,\n opts.compressionQuality\n );\n }\n\n const b = await sf.writeSF2({\n ...opts,\n progressFunction: (sampleName, sampleIndex, sampleCount) => {\n this.postProgress(\"workerSynthWriteFile\", {\n sampleCount,\n sampleIndex,\n sampleName\n });\n return new Promise<void>((r) => r());\n },\n compressionFunction\n });\n return {\n binary: b,\n bank: sf\n };\n}\n\nexport async function writeDLSWorker(\n this: WorkerSynthesizerCore,\n opts: WorkerDLSWriteOptions\n): Promise<{\n binary: ArrayBuffer;\n bank: BasicSoundBank;\n}> {\n let sf = this.getBank(opts);\n const sq = this.sequencers[opts.sequencerID];\n\n // Trim\n if (opts.trim) {\n if (!sq.midiData) {\n throw new Error(\n \"Sound bank MIDI trimming is enabled but no MIDI is loaded!\"\n );\n }\n const sfCopy = BasicSoundBank.copyFrom(sf);\n sfCopy.trimSoundBank(sq.midiData);\n sf = sfCopy;\n }\n\n const b = await sf.writeDLS({\n ...opts,\n progressFunction: (sampleName, sampleIndex, sampleCount) => {\n this.postProgress(\"workerSynthWriteFile\", {\n sampleCount,\n sampleIndex,\n sampleName\n });\n return new Promise<void>((r) => r());\n }\n });\n return {\n binary: b,\n bank: sf\n };\n}\n","import type { WorkerSynthesizerCore } from \"./worker_synthesizer_core.ts\";\nimport type { WorkerRMIDIWriteOptions } from \"../types.ts\";\nimport { BasicMIDI, BasicSoundBank } from \"spessasynth_core\";\nimport { writeDLSWorker, writeSF2Worker } from \"./write_sf_worker.ts\";\n\nexport async function writeRMIDIWorker(\n this: WorkerSynthesizerCore,\n opts: WorkerRMIDIWriteOptions\n) {\n const sq = this.sequencers[opts.sequencerID];\n if (!sq.midiData) {\n throw new Error(\"No MIDI is loaded!\");\n }\n let sf: BasicSoundBank;\n let sfBin: ArrayBuffer;\n if (opts.format === \"sf2\") {\n const bin = await writeSF2Worker.call(this, opts);\n sfBin = bin.binary;\n sf = bin.bank;\n } else {\n const bin = await writeDLSWorker.call(this, opts);\n sfBin = bin.binary;\n sf = bin.bank;\n }\n\n const mid = BasicMIDI.copyFrom(sq.midiData);\n return mid.writeRMIDI(sfBin, {\n soundBank: sf,\n ...opts\n });\n}\n","import {\n ALL_CHANNELS_OR_DIFFERENT_ACTION,\n BasicMIDI,\n midiMessageTypes,\n SpessaSynthCoreUtils\n} from \"spessasynth_core\";\nimport { songChangeType } from \"./enums.js\";\nimport { MIDIData } from \"./midi_data.js\";\nimport { DEFAULT_SEQUENCER_OPTIONS } from \"./default_sequencer_options.js\";\nimport type {\n SequencerMessage,\n SequencerMessageData,\n SequencerOptions,\n SequencerReturnMessage,\n SuppliedMIDIData,\n WorkletSequencerEventType\n} from \"./types\";\nimport { SeqEventHandler } from \"./seq_event_handler\";\nimport { type BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\"; // noinspection JSUnusedGlobalSymbols\n\n// noinspection JSUnusedGlobalSymbols\nexport class Sequencer {\n /**\n * The current MIDI data for all songs, like the midiData property.\n */\n public songListData: MIDIData[] = [];\n /**\n * Allows setting up custom event listeners for the sequencer.\n */\n public eventHandler = new SeqEventHandler();\n /**\n * Indicates whether the sequencer has finished playing a sequence.\n */\n public isFinished = false;\n /**\n * The synthesizer attached to this sequencer.\n */\n public readonly synth: BasicSynthesizer;\n /**\n * The current MIDI data, with the exclusion of the embedded sound bank and event data.\n */\n public midiData?: MIDIData;\n /**\n * The MIDI port to play to.\n */\n private midiOut?: { send: (data: number[]) => unknown };\n private isLoading = false;\n /**\n * Indicates if the sequencer is paused.\n * Paused if a number, undefined if playing.\n */\n private pausedTime?: number = 0;\n private getMIDICallback?: (receivedMIDI: BasicMIDI) => unknown = undefined;\n private highResTimeOffset = 0;\n /**\n * Absolute playback startTime, bases on the synth's time.\n */\n private absoluteStartTime: number;\n /**\n * For sending the messages to the correct SpessaSynthSequencer in core\n */\n private readonly sequencerID: number;\n\n /**\n * Creates a new MIDI sequencer for playing back MIDI files.\n * @param synth synth to send events to.\n * @param options the sequencer's options.\n */\n public constructor(\n synth: BasicSynthesizer,\n options: Partial<SequencerOptions> = DEFAULT_SEQUENCER_OPTIONS\n ) {\n this.synth = synth;\n this.absoluteStartTime = this.synth.currentTime;\n\n this.sequencerID = this.synth.assignNewSequencer(\n this.handleMessage.bind(this)\n );\n this._skipToFirstNoteOn = options?.skipToFirstNoteOn ?? true;\n\n if (options?.initialPlaybackRate !== 1) {\n this.playbackRate = options?.initialPlaybackRate ?? 1;\n }\n\n if (!this._skipToFirstNoteOn) {\n // Setter sends message\n this.sendMessage(\"setSkipToFirstNote\", false);\n }\n\n window.addEventListener(\n \"beforeunload\",\n this.resetMIDIOutput.bind(this)\n );\n }\n\n private _shuffledSongIndexes: number[] = [];\n\n /**\n * The shuffled song indexes.\n * This is used when shuffleMode is enabled.\n */\n public get shuffledSongIndexes() {\n return this._shuffledSongIndexes;\n }\n\n private _songIndex = 0;\n\n /**\n * The current song number in the playlist.\n * If shuffle Mode is enabled, this is the index of the shuffled song list.\n */\n public get songIndex() {\n return this._songIndex;\n }\n\n /**\n * The current song number in the playlist.\n * If shuffle Mode is enabled, this is the index of the shuffled song list.\n */\n public set songIndex(value: number) {\n /**\n * Sets the song index in the playlist.\n */\n const clamped = Math.max(0, value % this._songsAmount);\n if (clamped === this._songIndex) {\n return;\n }\n this.isLoading = true;\n this.midiData = undefined;\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.index,\n data: clamped\n });\n }\n\n private _currentTempo = 120;\n\n /**\n * Current song's tempo in BPM.\n */\n public get currentTempo() {\n return this._currentTempo;\n }\n\n /**\n * The current sequence's length, in seconds.\n */\n public get duration() {\n return this.midiData?.duration ?? 0;\n }\n\n private _songsAmount = 0;\n\n // The amount of songs in the list.\n public get songsAmount() {\n return this._songsAmount;\n }\n\n private _skipToFirstNoteOn: boolean;\n\n /**\n * Indicates if the sequencer should skip to first note on.\n */\n public get skipToFirstNoteOn(): boolean {\n return this._skipToFirstNoteOn;\n }\n\n /**\n * Indicates if the sequencer should skip to first note on.\n */\n public set skipToFirstNoteOn(val: boolean) {\n this._skipToFirstNoteOn = val;\n this.sendMessage(\"setSkipToFirstNote\", this._skipToFirstNoteOn);\n }\n\n /**\n * Internal loop count marker (-1 is infinite).\n */\n private _loopCount = -1;\n\n /**\n * The current remaining number of loops. -1 means infinite looping.\n */\n public get loopCount() {\n return this._loopCount;\n }\n\n /**\n * The current remaining number of loops. -1 means infinite looping.\n */\n public set loopCount(val) {\n this._loopCount = val;\n this.sendMessage(\"setLoopCount\", val);\n }\n\n /**\n * Controls the playback's rate.\n */\n private _playbackRate = 1;\n\n /**\n * Controls the playback's rate.\n */\n public get playbackRate() {\n return this._playbackRate;\n }\n\n /**\n * Controls the playback's rate.\n */\n public set playbackRate(value: number) {\n const t = this.currentTime;\n this.sendMessage(\"setPlaybackRate\", value);\n this.highResTimeOffset *= value / this._playbackRate;\n this._playbackRate = value;\n this.recalculateStartTime(t);\n }\n\n private _shuffleSongs = false;\n\n /**\n * Controls if the sequencer should shuffle the songs in the song list.\n * If true, the sequencer will play the songs in a random order.\n *\n * Songs are shuffled on a `loadNewSongList` call.\n */\n public get shuffleSongs() {\n return this._shuffleSongs;\n }\n\n /**\n * Controls if the sequencer should shuffle the songs in the song list.\n * If true, the sequencer will play the songs in a random order.\n *\n * Songs are shuffled on a `loadNewSongList` call.\n */\n public set shuffleSongs(value: boolean) {\n this._shuffleSongs = value;\n if (value) {\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.shuffleOn\n });\n } else {\n this.sendMessage(\"changeSong\", {\n changeType: songChangeType.shuffleOff\n });\n }\n }\n\n /**\n * Current playback time, in seconds.\n */\n public get currentTime() {\n if (this.isLoading) {\n return 0;\n }\n // Return the paused time if it's set to something other than undefined\n if (this.pausedTime !== undefined) {\n return this.pausedTime;\n }\n\n return (\n (this.synth.currentTime - this.absoluteStartTime) *\n this._playbackRate\n );\n }\n\n /**\n * Current playback time, in seconds.\n */\n public set currentTime(time) {\n this.sendMessage(\"setTime\", time);\n }\n\n /**\n * A smoothed version of currentTime.\n * Use for visualization as it's not affected by the audioContext stutter.\n */\n public get currentHighResolutionTime() {\n if (this.pausedTime !== undefined) {\n return this.pausedTime;\n }\n const highResTimeOffset = this.highResTimeOffset;\n const absoluteStartTime = this.absoluteStartTime;\n\n // Sync performance.now to current time\n const performanceElapsedTime =\n (performance.now() / 1000 - absoluteStartTime) * this._playbackRate;\n\n let currentPerformanceTime = highResTimeOffset + performanceElapsedTime;\n const currentAudioTime = this.currentTime;\n\n const smoothingFactor = 0.01 * this._playbackRate;\n\n // Diff times smoothing factor\n const timeDifference = currentAudioTime - currentPerformanceTime;\n this.highResTimeOffset += timeDifference * smoothingFactor;\n\n // Return a smoothed performance time\n currentPerformanceTime =\n this.highResTimeOffset + performanceElapsedTime;\n return currentPerformanceTime;\n }\n\n /**\n * True if paused, false if playing or stopped.\n */\n public get paused() {\n return this.pausedTime !== undefined;\n }\n\n /**\n * Gets the current MIDI File.\n */\n public async getMIDI(): Promise<BasicMIDI> {\n return new Promise((resolve) => {\n this.getMIDICallback = resolve;\n this.sendMessage(\"getMIDI\", null);\n });\n }\n\n /**\n * Loads a new song list.\n * @param midiBuffers The MIDI files to play.\n */\n public loadNewSongList(midiBuffers: SuppliedMIDIData[]) {\n this.isLoading = true;\n this.midiData = undefined;\n this.sendMessage(\"loadNewSongList\", midiBuffers);\n this._songIndex = 0;\n this._songsAmount = midiBuffers.length;\n }\n\n /**\n * Connects a given output to the sequencer.\n * @param output The output to connect. Pass undefined to use the connected synthesizer.\n */\n public connectMIDIOutput(output?: { send: (data: number[]) => unknown }) {\n this.resetMIDIOutput();\n this.midiOut = output;\n this.sendMessage(\"changeMIDIMessageSending\", output !== undefined);\n this.currentTime -= 0.1;\n }\n\n /**\n * Pauses the playback.\n */\n public pause() {\n if (this.paused) {\n return;\n }\n this.pausedTime = this.currentTime;\n this.sendMessage(\"pause\", null);\n }\n\n /**\n * Starts or resumes the playback.\n */\n public play() {\n this.recalculateStartTime(this.pausedTime ?? 0);\n this.pausedTime = undefined;\n this.isFinished = false;\n this.sendMessage(\"play\", null);\n }\n\n private handleMessage(m: SequencerReturnMessage) {\n switch (m.type) {\n case \"midiMessage\": {\n const midiEventData = m.data.message as number[];\n if (this.midiOut && midiEventData[0] >= 0x80) {\n this.midiOut.send(midiEventData);\n return;\n }\n break;\n }\n\n case \"songChange\": {\n this._songIndex = m.data.songIndex;\n const idx = this._shuffleSongs\n ? this._shuffledSongIndexes[this._songIndex]\n : this._songIndex;\n const songChangeData = this.songListData[idx];\n this.midiData = songChangeData;\n this.isLoading = false;\n this.absoluteStartTime = 0;\n this.callEventInternal(\"songChange\", songChangeData);\n break;\n }\n\n case \"sync\": {\n if (Math.abs(m.data - this.currentTime) > 0.05)\n this.recalculateStartTime(m.data);\n break;\n }\n\n case \"timeChange\": {\n // Message data is absolute time\n const time = m.data.newTime;\n this.recalculateStartTime(time);\n this.callEventInternal(\"timeChange\", time);\n break;\n }\n\n case \"pause\": {\n this.pausedTime = this.currentTime;\n this.isFinished = m.data.isFinished;\n if (this.isFinished) {\n this.callEventInternal(\"songEnded\", null);\n }\n break;\n }\n\n case \"midiError\": {\n this.callEventInternal(\"midiError\", m.data);\n break;\n }\n\n case \"getMIDI\": {\n if (this.getMIDICallback) {\n this.getMIDICallback(BasicMIDI.copyFrom(m.data));\n }\n break;\n }\n\n case \"metaEvent\": {\n const event = m.data.event;\n switch (event.statusByte) {\n case midiMessageTypes.setTempo: {\n this._currentTempo =\n 60_000_000 /\n SpessaSynthCoreUtils.readBytesAsUintBigEndian(\n event.data,\n 3\n );\n break;\n }\n\n case midiMessageTypes.text:\n case midiMessageTypes.lyric:\n case midiMessageTypes.copyright:\n case midiMessageTypes.trackName:\n case midiMessageTypes.marker:\n case midiMessageTypes.cuePoint:\n case midiMessageTypes.instrumentName:\n case midiMessageTypes.programName: {\n if (!this.midiData) {\n break;\n }\n let lyricsIndex = -1;\n if (event.statusByte === midiMessageTypes.lyric) {\n lyricsIndex = Math.min(\n this.midiData.lyrics.findIndex(\n (l) => l.ticks === event.ticks\n ),\n this.midiData.lyrics.length - 1\n );\n }\n // If MIDI is a karaoke file, it uses the \"text\" event type or \"lyrics\" for lyrics (duh)\n // Why?\n // Because the MIDI standard is a messy pile of garbage,\n // And it's not my fault that it's like this :(\n // I'm just trying to make the best out of a bad situation.\n // I'm sorry\n // Okay I should get back to work\n // Anyway,\n // Check for a karaoke file and change the status byte to \"lyric\"\n // If it's a karaoke file\n if (\n this.midiData.isKaraokeFile &&\n (event.statusByte === midiMessageTypes.text ||\n event.statusByte === midiMessageTypes.lyric)\n ) {\n lyricsIndex = Math.min(\n this.midiData.lyrics.findIndex(\n (l) => l.ticks === event.ticks\n ),\n this.midiData.lyrics.length\n );\n }\n this.callEventInternal(\"textEvent\", {\n event,\n lyricsIndex\n });\n break;\n }\n }\n this.callEventInternal(\"metaEvent\", {\n event: m.data.event,\n trackNumber: m.data.trackIndex\n });\n break;\n }\n\n case \"loopCountChange\": {\n this._loopCount = m.data.newCount;\n if (this._loopCount === 0) {\n }\n break;\n }\n\n case \"songListChange\": {\n // Remap to MIDI data again as cloned objects don't get methods.\n this.songListData = m.data.newSongList.map(\n (m) => new MIDIData(m)\n );\n this._shuffledSongIndexes = m.data.shuffledSongIndexes;\n break;\n }\n\n default: {\n break;\n }\n }\n }\n\n private callEventInternal<\n EventType extends keyof WorkletSequencerEventType\n >(type: EventType, data: WorkletSequencerEventType[EventType]) {\n this.eventHandler.callEventInternal(type, data);\n }\n\n private resetMIDIOutput() {\n if (!this.midiOut) {\n return;\n }\n for (let i = 0; i < 16; i++) {\n this.midiOut.send([midiMessageTypes.controllerChange | i, 120, 0]); // All notes off\n this.midiOut.send([midiMessageTypes.controllerChange | i, 123, 0]); // All sound off\n }\n this.midiOut.send([midiMessageTypes.reset]); // Reset\n }\n\n private recalculateStartTime(time: number) {\n this.absoluteStartTime =\n this.synth.currentTime - time / this._playbackRate;\n this.highResTimeOffset =\n (this.synth.currentTime - performance.now() / 1000) *\n this._playbackRate;\n if (this.paused) {\n this.pausedTime = time;\n }\n }\n\n private sendMessage<T extends keyof SequencerMessageData>(\n messageType: T,\n messageData: SequencerMessageData[T]\n ) {\n this.synth.post({\n channelNumber: ALL_CHANNELS_OR_DIFFERENT_ACTION,\n type: \"sequencerSpecific\",\n data: {\n type: messageType,\n data: messageData,\n id: this.sequencerID\n } as SequencerMessage\n });\n }\n}\n","import type { SequencerOptions } from \"./types\";\n\nexport const DEFAULT_SEQUENCER_OPTIONS: SequencerOptions = {\n skipToFirstNoteOn: true,\n initialPlaybackRate: 1\n};\n","import type { WorkletSequencerEventType } from \"./types\";\n\ntype SequencerEventCallback<T extends keyof WorkletSequencerEventType> = (\n callbackData: WorkletSequencerEventType[T]\n) => unknown;\n\ntype EventsMap = {\n [K in keyof WorkletSequencerEventType]: Map<\n string,\n SequencerEventCallback<K>\n >;\n};\n\nexport class SeqEventHandler {\n /**\n * The time delay before an event is called.\n * Set to 0 to disable it.\n */\n public timeDelay = 0;\n\n private readonly events: EventsMap = {\n songChange: new Map<string, SequencerEventCallback<\"songChange\">>(),\n songEnded: new Map<string, SequencerEventCallback<\"songEnded\">>(),\n metaEvent: new Map<string, SequencerEventCallback<\"metaEvent\">>(),\n timeChange: new Map<string, SequencerEventCallback<\"timeChange\">>(),\n midiError: new Map<string, SequencerEventCallback<\"midiError\">>(),\n textEvent: new Map<string, SequencerEventCallback<\"textEvent\">>()\n };\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Adds a new event listener.\n * @param event The event to listen to.\n * @param id The unique identifier for the event. It can be used to overwrite existing callback with the same ID.\n * @param callback The callback for the event.\n */\n public addEvent<T extends keyof WorkletSequencerEventType>(\n event: T,\n id: string,\n callback: SequencerEventCallback<T>\n ) {\n this.events[event].set(id, callback);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Removes an event listener\n * @param name The event to remove a listener from.\n * @param id The unique identifier for the event to remove.\n */\n public removeEvent<T extends keyof WorkletSequencerEventType>(\n name: T,\n id: string\n ) {\n this.events[name].delete(id);\n }\n\n /**\n * Calls the given event.\n * Internal use only.\n * @internal\n */\n public callEventInternal<T extends keyof WorkletSequencerEventType>(\n name: T,\n eventData: WorkletSequencerEventType[T]\n ) {\n const eventList = this.events[name];\n const callback = () => {\n for (const callback of eventList.values()) {\n try {\n callback(eventData);\n } catch (error) {\n console.error(\n `Error while executing a sequencer event callback for ${name}:`,\n error\n );\n }\n }\n };\n if (this.timeDelay > 0) {\n setTimeout(callback.bind(this), this.timeDelay * 1000);\n } else {\n callback();\n }\n }\n}\n","import { audioToWav, type WaveWriteOptions } from \"spessasynth_core\";\n\ninterface ExtraWaveOptions extends WaveWriteOptions {\n /**\n * The channel offset in the AudioBuffer. Defaults to 0.\n */\n channelOffset: number;\n\n /**\n * The amount of channels from the AudioBuffer to write. Defaults to all.\n */\n channelCount: number;\n}\n\n/**\n * Converts an audio buffer into a wave file.\n * @param audioBuffer The audio data channels.\n * @param options Additional options for writing the file.\n * @returns The binary file.\n */\nexport function audioBufferToWav(\n audioBuffer: AudioBuffer,\n options?: Partial<ExtraWaveOptions>\n): Blob {\n const channels: Float32Array[] = [];\n const channelOffset = options?.channelOffset ?? 0;\n const channelCount = options?.channelCount ?? audioBuffer.numberOfChannels;\n for (let i = channelOffset; i < audioBuffer.numberOfChannels; i++) {\n channels.push(audioBuffer.getChannelData(i));\n if (channels.length >= channelCount) {\n break;\n }\n }\n return new Blob([audioToWav(channels, audioBuffer.sampleRate, options)], {\n type: \"audio/wav\"\n });\n}\n","import { SpessaSynthCoreUtils as util } from \"spessasynth_core\";\nimport { consoleColors } from \"../utils/other.js\";\nimport type { Sequencer } from \"../sequencer/sequencer\";\nimport type { BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\";\n\n/**\n * Midi_handler.js\n * purpose: handles the connection between MIDI devices and synthesizer/sequencer via Web MIDI API\n */\n\nclass LibMIDIPort {\n public readonly port: MIDIPort;\n\n protected constructor(port: MIDIPort) {\n this.port = port;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get id() {\n return this.port.id;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get name() {\n return this.port.name;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get manufacturer() {\n return this.port.manufacturer;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n *\n */\n public get version() {\n return this.port.version;\n }\n}\n\nclass LibMIDIInput extends LibMIDIPort {\n private readonly connectedSynths = new Set<BasicSynthesizer>();\n\n public constructor(input: MIDIInput) {\n super(input);\n input.onmidimessage = (e) => {\n for (const s of this.connectedSynths) {\n if (e.data) s.sendMessage(e.data);\n }\n };\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Connects the input to a given synth, listening for all incoming events.\n * @param synth The synth to connect to.\n */\n public connect(synth: BasicSynthesizer) {\n this.connectedSynths.add(synth);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects the input from a given synth.\n * @param synth The synth to disconnect from.\n */\n public disconnect(synth: BasicSynthesizer) {\n this.connectedSynths.delete(synth);\n }\n}\n\nclass LibMIDIOutput extends LibMIDIPort {\n public readonly port: MIDIOutput;\n\n public constructor(output: MIDIOutput) {\n super(output);\n this.port = output;\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Connects a given sequencer to the output, playing back the MIDI file to it.\n * @param seq The sequencer to connect.\n */\n public connect(seq: Sequencer) {\n seq.connectMIDIOutput(this.port);\n }\n\n // noinspection JSUnusedGlobalSymbols\n /**\n * Disconnects sequencer from the output, making it play to the attached Synthesizer instead.\n * @param seq The sequencer to disconnect.\n */\n public disconnect(seq: Sequencer) {\n seq.connectMIDIOutput(undefined);\n }\n}\n\n// noinspection JSUnusedGlobalSymbols\n/**\n * A class for handling physical MIDI devices.\n */\nexport class MIDIDeviceHandler {\n /**\n * The available MIDI inputs. ID maps to the input.\n */\n public readonly inputs = new Map<string, LibMIDIInput>();\n /**\n * The available MIDI outputs. ID maps to the output.\n */\n public readonly outputs = new Map<string, LibMIDIOutput>();\n\n private constructor(access: MIDIAccess) {\n for (const [key, value] of access.inputs.entries()) {\n this.inputs.set(key, new LibMIDIInput(value));\n }\n for (const [key, value] of access.outputs.entries()) {\n this.outputs.set(key, new LibMIDIOutput(value));\n }\n }\n\n /**\n * Attempts to initialize the MIDI Device Handler.\n * @returns The handler.\n * @throws An error if the MIDI Devices fail to initialize.\n */\n public static async createMIDIDeviceHandler(): Promise<MIDIDeviceHandler> {\n if (navigator.requestMIDIAccess) {\n // Prepare the midi access\n try {\n const response = await navigator.requestMIDIAccess({\n sysex: true,\n software: true\n });\n util.SpessaSynthInfo(\n \"%cMIDI handler created!\",\n consoleColors.recognized\n );\n return new MIDIDeviceHandler(response);\n } catch (error) {\n util.SpessaSynthWarn(`Could not get MIDI Devices:`, error);\n throw error;\n }\n } else {\n util.SpessaSynthWarn(\n \"Web MIDI API is not supported.\",\n consoleColors.unrecognized\n );\n throw new Error(\"Web MIDI API is not supported.\");\n }\n }\n}\n","import { consoleColors } from \"../utils/other.js\";\nimport { SpessaSynthCoreUtils } from \"spessasynth_core\";\nimport type { BasicSynthesizer } from \"../synthesizer/basic/basic_synthesizer.ts\";\n\n/**\n * Web_midi_link.js\n * purpose: handles the web midi link connection to the synthesizer\n * https://www.g200kg.com/en/docs/webmidilink/\n */\n\nexport class WebMIDILinkHandler {\n /**\n * Initializes support for Web MIDI Link (https://www.g200kg.com/en/docs/webmidilink/)\n * @param synth The synthesizer to enable support with.\n */\n public constructor(synth: BasicSynthesizer) {\n window.addEventListener(\"message\", (msg) => {\n if (typeof msg.data !== \"string\") {\n return;\n }\n const data: string[] = msg.data.split(\",\");\n if (data[0] !== \"midi\") {\n return;\n }\n\n data.shift(); // Remove MIDI\n\n const midiData = data.map((byte) => Number.parseInt(byte, 16));\n\n synth.sendMessage(midiData);\n });\n\n SpessaSynthCoreUtils.SpessaSynthInfo(\n \"%cWeb MIDI Link handler created!\",\n consoleColors.recognized\n );\n }\n}\n"],"mappings":"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","names":["callback","SpessaSynthCoreUtils","context","context","SoundBankLoader","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","util","SpessaSynthProcessor","SpessaSynthSequencer","SynthesizerSnapshot","SpessaSynthProcessor","SpessaSynthSequencer","util","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","SynthesizerSnapshot","BasicMIDI","BasicMIDI","BLOCK_SIZE","SoundBankLoader","ALL_CHANNELS_OR_DIFFERENT_ACTION","BasicMIDI","midiMessageTypes","SpessaSynthCoreUtils","callback","BasicMIDI","midiMessageTypes","SpessaSynthCoreUtils","m","ALL_CHANNELS_OR_DIFFERENT_ACTION","util","util","SpessaSynthCoreUtils"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "description": "MIDI and SoundFont2/DLS library for the browsers with no compromises",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "debug": "tsx build_scripts/debug_enable.ts",
16
16
  "release": "tsx build_scripts/debug_disable.ts",
17
17
  "prepack": "npm run build:npm",
18
- "prepublishOnly": "npm run release && npm run build",
18
+ "prepublishOnly": "npm run release",
19
19
  "prepare": "husky install"
20
20
  },
21
21
  "repository": {