-
Notifications
You must be signed in to change notification settings - Fork 3
Synthetizer Class
This is the main module that generates the sound.
Tip
If you encounter any errors in this documentation, please open an issue!
import { Synthetizer } from "./spessasynth_lib/synthetizer/synthetizer.js";
/**
* @type {Synthetizer}
*/
const synth = new Synthetizer(tagetNode, soundFontBuffer, enableEventSystem(optional), startRenderingData(optional), effectsConfig(optional));
- targetNode - the AudioNode the synth should play to. Usually AudioContext.destination.
- soundFontBuffer - the
ArrayBuffer
to your soundFont. - enableEventSystem -
boolean
, disables the event system. Useful when rendering audio to file - startRenderingData -
object
, used for rendering to file. It's formatted as follows: -
- parsedMIDI: a
MIDI
class instance. The synthesizer will immediately start rendering it if specified
- parsedMIDI: a
-
- snapshot: a
SynthesizerSnapshot
object, a copy of controllers from another synthesizer instance. If specified, synth will copy this configuration.
- snapshot: a
- effectsConfig - optional, the configuration for audio effects. Defined as follows:
/**
* @typedef {Object} EffectsConfig
* @property {boolean} chorusEnabled - indicates if the chorus effect is enabled.
* @property {ChorusConfig} chorusConfig - the configuration for chorus. Pass undefined to use defaults
* @property {boolean} reverbEnabled - indicates if the reverb effect is enabled.
* @property {AudioBuffer} reverbImpulseResponse - the impulse response for the reverb. Pass undefined to use defaults
*/
/**
* @typedef {Object} ChorusConfig
* @property {number} nodesAmount - the amount of delay nodes (for each channel) and the corresponding oscillators
* @property {number} defaultDelay - the initial delay, in seconds
* @property {number} delayVariation - the difference between delays in the delay nodes
* @property {number} stereoDifference - the difference of delays between two channels (added to the left channel and subtracted from the right)
*
* @property {number} oscillatorFrequency - the initial delay oscillator frequency, in Hz.
* @property {number} oscillatorFrequencyVariation - the difference between frequencies of oscillators, in Hz
* @property {number} oscillatorGain - how much will oscillator alter the delay in delay nodes, in seconds
*/
Tip
Pass undefined
to chorusConfig
or reverbImpulseResponse
to use the defaults.
Important
If you're rendering the audio to a file, it is highly recommended to supply the synthesizer with the reverb buffer
(even the stock one) through effects config, because it internally fetch
es the file which will result in reverb enabling after a second or so.
Warning
Note that you need to add the worklet processor for the synthesizer to work!
context.audioWorklet.addModule("./spessasynth_lib/synthetizer/worklet_system/worklet_processor.js")
A promise that gets resolved when the worklet synthesizer gets fully initialized (including sf3 support)
await synth.isReady;
Tip
It is recommended (but not always required) to wait for this promise.
Important
The synthesizer internally sends commands to the AudioWorklet
where all the processing happens.
Keep that in mind as not all methods will immediately report values! (E.g. noteOn
won't instantly increase the voice count in channelProperties
)
Sends a raw MIDI message to the synthesizer. Calls noteOn, noteOff, etc. internally.
synth.sendMessage(message);
- message - an array of numbers. Each number represents a byte of the MIDI message.
Note
This only allows sending messages to the first 16 channels.
Plays the given note.
synth.noteOn(channel, midiNote, velocity, enableDebugging);
- channel - the MIDI channel to use. Usually ranges from 0 to 15, but it depends on the channel count.
- midiNote - the note to play. Ranges from 0 to 127.
- velocity - controls how loud the note is. 127 is normal loudness and 1 is the quietest. Note that velocity of 0 has the same effect as using
noteOff
. Ranges from 0 to 127. - enableDebugging - boolean, used only for debugging. When
true
, the console will print out tables of the soundfont generator data used to play the note.
Stops the given note.
synth.noteOff(channel, midiNote);
- channel - the MIDI channel to use. Usually ranges from 0 to 15, but it depends on the channel count.
- midiNote - the note to play. Ranges from 0 to 127.
Note that when highPerformanceMode
is set to true, the note will always have a release time of 50ms.
Stops all notes. Equivalent of MIDI "panic".
synth.stopAll();
Changes the preset for the given channel.
synth.programChange(channel, programNumber);
- channel - the MIDI channel to change. Usually ranges from 0 to 15, but it depends on the channel count.
- programNumber - the MIDI program number to use. Ranges from 0 to 127. To use other banks, go to controllerChange.
Changes the channel's pitch, including the currently playing notes.
synth.pitchWheel(channel, MSB, LSB);
- channel - the MIDI channel to use. Usually ranges from 0 to 15, but it depends on the channel count.
- MSB and LSB. 7-bit numbers that form a 14-bit pitch bend value.
Changes the channel's pitch bend range, in semitones. Uses Registered Parameter Number internally.
synth.setPitchBendRange(channel, pitchBendRangeSemitones);
- channel - the MIDI channel to use. Usually ranges from 0 to 15, but it depends on the channel count.
- pitchBendRangeSemitones - the pitch bend range, in full semitones.
Handles a MIDI System Exclusive message.
synth.systemExclusive(messageData);
- message data - Uint8Array, the message byte data Excluding the 0xF0 byte!
Tip
Refer to this table for the list of supported System Exclusives.
Sets a given MIDI controller to a given value.
synth.controllerChange(channel, controllerNumber, controllerValue);
- channel - the MIDI channel to use. Usually ranges from 0 to 15, but it depends on the channel count.
- controllerNumber - the MIDI CC number of the controller to change. Refer to this table for the list of controllers supported by default.
- controllerValue - the value to set the given controller to. Ranges from 0 to 127.
Note
Note that theoreticallly all controllers are supported as it depends on the SoundFont's modulators.
Resets all controllers to their default values. (for every channel)
synth.resetControllers();
Causes the given midi channel to ignore controller messages for the given controller number.
synth.lockController(channel, controllerNumber, isLocked);
- channel - the channel to lock. Usually ranges from 0 to 15, but it depends on the channel count.
- controllerNumber - the MIDI CC to lock. Ranges from 0 to 127.
- isLocked - boolean, if true then locked, if false then unlocked.
Mutes or unmutes a given channel
synth.muteChannel(channel, isMuted);
- channel - the channel to mute/unmute. Usually Usually ranges from 0 to 15, but it depends on the channel count.
- isMuted - if the channel should be muted. boolean.
Transposes the synth up or down in semitones. Floating point values can be used for more precise tuning.
synth.transpose(semitones);
- semitones - the amount of semitones to transpose the synth by. Can be positive or negative or zero. Zero resets the pitch.
Sets the synth's main volume.
synth.setMainVolume(volume);
- volume - the synth's volume. Ranges from 0 to 1.
Adds a new channel. Invokes a newchannel
event.
synth.addNewChannel();
Changes the soundfont of a Synthesizer's instance.
await synth.reloadSoundFont(soundFontBuffer);
Important
This function is asynchronous.
- soundFont - the soundfont to change to, an
ArrayBuffer
instance of the file.
gets a current snapshot of the Worklet synthesizer.
Important
This function is asynchronous.
const snapshot = await synth.getSynthesizerSnapshot();
the returned value is formatted as follows:
/**
* @typedef {Object} ChannelSnapshot - a snapshot of the channe;
*
* @property {number} program - the channel's program
* @property {number} bank - the channel's bank
* @property {boolean} lockPreset - indicates whether the channel's program change is disabled
*
* @property {Int16Array} midiControllers - the array of all midi controllers (in 14-bit values), including pitch bend
* @property {boolean[]} lockedControllers - an array of booleans, indicating if the controller with a current index is locked
* @property {Float32Array} customControllers - array of custom (not sf2) control values such as RPN pitch tuning, transpose, modulation depth, etc.
*
* // note: this is a custom vibrato object, set by NRPN messages
* @property {boolean} lockVibrato - indicates whether the channel vibrato is locked
* @property {Object} channelVibrato - the channel's vibrato
* @property {number} channelVibrato.depth - vibrato depth, in gain
* @property {number} channelVibrato.delay - vibrato delay from note on in seconds
* @property {number} channelVibrato.rate - vibrato rate in Hz
*
* @property {boolean} isMuted - indicates whether the channel is muted
* @property {boolean} drumChannel - indicates whether the channel is a drum channel
*/
/**
* @typedef {Object} SynthesizerSnapshot
* @property {ChannelSnapshot[]} channelSnapshots - the individual channel snapshots
* @property {number} mainVolume - main synth volume, from 0 to 1
* @property {number} pan - master stereo panning, from -1 to 1
* @property {SynthSystem} system - the synths system. Values can be "gs", "gm", "gm2" or "xg"
* @property {number} transposition - the current synth transpositon in semitones. can be a float
*/
Prints out the synth class instance, both from the main thread and the AudioWorklet thread.
synth.debugMessage();
The synthesizer's event handler. Refer to Event handling for more.
The current amount of voices (notes) playing or during their release phase.
console.log(`This synthetizer is currently playing ${synth.voicesAmount} notes!`);
The maximum allowed voices at once. If new voices are added, the voices considered unimportand are killed. Defaults to 450.
synth.voiceCap = 100; // max 100 voices at once
The connected AudioContext
's time.
console.log(`The current AudioContext's time is ${synth.currentTime}!`); // example usage
Indicates the current system the synth is in. Currently, there are: GM, GM2, GS, XG. Defaults to GS
console.log(synth.system); // "gm"
Boolean, if the high performance mode is enabled. High performance mode currently overrides release time to be almost instant. Intended for "Black MIDIs".
synth.highPerformanceMode = true; // we can now play black MIDIs! >:)
The current channel properties. An array
of objects formatted like this:
/**
* @typedef {Object} ChannelProperty
* @property {number} voicesAmount - the channel's current voice amount
* @property {number} pitchBend - the channel's current pitch bend from -8192 do 8192
* @property {number} pitchBendRangeSemitones - the pitch bend's range, in semitones
* @property {boolean} isMuted - indicates whether the channel is muted
* @property {boolean} isDrum - indicates whether the channel is a drum channel
*/
console.log(synth.channelProperties[0]); // {voicesAmount: 0, pitchBend: 0, pitchBendRangeSemitones: 2, isMuted: false, isDrum: false }
Below is the list of controllers supported by default.
CC | Controller name | Value | Explanation | Default value |
---|---|---|---|---|
0 | Bank Select | The bank number (0 - 127) | Changes the bank number that is used in programChange. Note that it doesn't change the preset on its own. | 0 |
7 | Main Volume | The volume (0 - 127) 0 is silent, 127 is normal volume | Changes the channel's volume. | 127 |
64 | Sustain Pedal | 0 - 63 is off 64 - 127 is on | Holds the noteOff messages until the pedal is off, then stops them all at once. | 0 |
10 | Pan | 0 is left, 64 is middle, 127 is right | Controls the channel's stereo balance | 64 |
123 or 120 | All Notes Off or All Sound Off | Not Applicable | Stops all the notes. Equivalent to MIDI "panic". | N.A. |
11 | Expression controller | The expression (0 - 127) 0 is silent, 127 is normal volume | Works exactly like Main Volume, but it's independent. | 127 |
1 | Modulation Wheel | The modulation depth (0 - 127) mapped to max 50 cents of detune | Controls the vibrato for the given patch. | 0 |
91 | Effects 1 Depth (reverb) | The reverb depth (0 - 127) | Controls the reverb effect send for the given channel. | 0 |
92 | Effects 2 Depth (tremolo) | The tremolo depth (0 - 127) mapped to 25dB of loudness variation | Controls the tremolo (trembling) effect for the given patch. | 0 |
93 | Effects 3 Depth (chorus) | The chorus depth (0 - 127) | Controls the chorus effect for the given channel. | 0 |
72 | Release Time | The release time (0- 127) 64 is normal, 0 is the fastest, 127 is the slowest | Controls the release time for the given patch. | 64 |
74 | Brightness | The brightness (0 - 127) 0 is muffled, 64 is no additional filter, 127 is most clear | Controls the brightness (lowpass frequency) of the given patch. | 64 |
121 | Reset All Controllers | Not Applicable | Resets all controllers to their default values. | N.A. |
101 | Registered Parameter Number MSB | Parameter number (0 - 127) | Selects a Registered Parameter's Coarse to the given value. Here are the currently supported values.. | none |
100 | Registered Parameter Number LSB | Parameter number (0 - 127) | Selects a Registered Parameter's Fine to the given value. Here are the currently supported values.. | none |
99 | Non-Registered Parameter Number MSB | Parameter number (0 - 127) | Selects a Non-Registered Parameter's Coarse to the given value. Here are the currently supported values.. | none |
98 | Non-Registered Parameter Number LSB | Parameter number (0 - 127) | Selects a Non-Registered Parameter's Fine to the given value. Here are the currently supported values.. | none |
6 | Data Entry MSB | Data entry value (0 - 127) | This is sets the selected RP or NRP to the given value. Note that the RPN and NRPN controlles only select the parameter, while this controller actually sets the values. | none |
38 | Data Entry LSB | Data entry value (0 - 127) | This is sets the selected RP or NRP to the given value. Note that the RPN and NRPN controlles only select the parameter, while this controller actually sets the values. | none |
Below is the list of currently implemented Registered-Parameters.
RPN MSB | RPN LSB | Name | Explanation | Default |
---|---|---|---|---|
0 | 0 | Pitch Wheel range | The range in semitones of the synth.pitchWheel() method. |
2 semitones |
0 | 2 | Channel Coarse Tuning | The channel's tuning in semitones | No tuning (0 semitones) |
0 | 3 | Channel Fine Tuning | The channel's tuning, like a pitch bend message (precise tuning in 2 semitones) | No tuning (0 cents) |
0 | 5 | Channel Modulation Depth | The channel's modulation (vibrato) depth. Note that this doesn't set the cents directly, but rather scales the soundfont modulator value (for example if set to twice the MIDI default value, the modulator controlling vibrato depth will be multiplied by 2) | default sf2 depth (50 cents) |
127 | 127 | Reset parameters | Resets all parameters | N.A. |
Below is the list of currently implemented Non-Registered-Parameters.
NRPN MSB | NRPN LSB | Name | Explanation | Default |
---|---|---|---|---|
1 | 8 | Vibrato rate | Controls the vibrato rate. The calculation to hertz is as follows: hz = (value / 64) * 8
|
0 (disabled) |
1 | 9 | Vibrato depth | Controls the vibrato depth. Depth ratio is as calculated as follows: depth = value / 2
|
0 (disabled) |
1 | 10 | Vibrato delay | Controls the vibrato delay. Calculation to seconds is as follows: (64 / value) / 2
|
0 (disabled) |
1 | A | TVF Filter Cutoff | Controls the filter cutoff using the CC 74 (brightness) | 64 (no change) |
1D | N/A | Drum Reverb | Adjusts the reverb controller if the channel is drum chanel | 40 (default reverb) |
1E | N/A | Chorus Reverb | Adjusts the chorus controller if the channel is drum chanel | 0 (default chorus) |
Below is the list of currently implemented System Exclusive messages.
Name | Description |
---|---|
GM on | Turns the GM mode on. Ignores all the Bank Select controllers. |
GM2 on | Turns the GM2 mode on. |
GS reset | Turns on the Roland GS mode. |
XG reset | Turns on the Yamaha XG mode. Changes the bank selection system to XG. |
Roland GS Use for drums part | Can turn the desired channel into a drum channel. |
Roland Master Volume | Controls the overall synth's volume. |
MIDI Master Volume | Controls the overall synth's volume. |
Roland GS Master Pan | Controls the synth's stereo output. |
Roland GS Master Volume | Controls the overall synth's volume. |
The synthesizer supports event handling. For example the MidiKeyboard
uses handling to visualize keypresses.
Use the property .eventHandler
to access the system.
eventHandler.addEvent(name, id, callback);
- name - the type of the event. refer to the table below.
- id - unique id for the event listener. Can be anything, as long as it's unique.
- callback. a fuction that gets called on the event. Callback takes an
object
argument. The properties depend on the event type. Refer to the table below.
eventHandler.removeEvent(name, id);
- name - the type of the event.
- id - the unique id of the event you wish to remove.
Name | Description | Callback Properties |
---|---|---|
noteoff |
Note off message | midiNote: number - the note that was released, channel: number - the channel number which got the note released |
noteon |
Note on message | midiNote: number - the note that was pressed, channel: number - the channel that the note was played on, velocty: the velocity of the note |
pitchwheel |
Pitch wheel message | channel: number - the the channel that was pitch bent, MSB: number - Most Significant byte of the message, LSB: number - least significant byte of the message |
controllerchange |
Controller change message | channel: number - the channel that CC was changed on, controllerNumber: number - the number of the MIDI controller list. controllerValue: number - the new value of the controller |
programchange |
Program change message | channel: number - the channel that had its program changed preset: Preset - The preset that was set |
drumchange |
Channel's drum mode was changed | channel: number - the channel, isDrumChannel: boolean - if the channel is now a drum channel or not |
stopall |
All voices were stopped | None |
newchannel |
A new channel was added to the synth | None |
mutechannel |
A channel has been muted/unmuted | channel: number - the channel that was altered isMuted: boolean - if the channel is muted or unmuted |
presetlistchange |
The preset list has been changed/initialized | The soundfont preset list. As follows: an array of objects: {presetName: the name of the preset, program: the preset's program number, bank: the preset's bank number}
|
allcontrollerreset |
All controllers have been reset | None. Note: if there were any locked controllers, they will be restored via controllerchange event. |
soundfonterror |
The loaded soundfont was invalid | The error message from the SoundFont2 class |