spessasynth_core
Version:
MIDI and SoundFont2/DLS library with no compromises
1,645 lines (1,610 loc) • 133 kB
TypeScript
/**
* Indexed_array.ts
* purpose: extends Uint8Array with a currentIndex property.
*/
declare class IndexedByteArray extends Uint8Array {
/**
* The current index of the array.
*/
currentIndex: number;
/**
* Returns a section of an array.
* @param start The beginning of the specified portion of the array.
* @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.
*/
slice(start?: number, end?: number): IndexedByteArray;
}
/**
* Writes an audio into a valid WAV file.
* @param audioData the audio data channels.
* @param sampleRate the sample rate, in Hertz.
* @param options Additional options for writing the file.
* @returns the binary file.
*/
declare function audioToWav(audioData: Float32Array[], sampleRate: number, options?: Partial<WaveWriteOptions>): ArrayBuffer;
/**
* Reads number as Big endian.
* @param dataArray the array to read from.
* @param bytesAmount the number of bytes to read.
* @param offset the offset to start reading from.
* @returns the number.
*/
declare function readBigEndian(dataArray: number[] | ArrayLike<number>, bytesAmount: number, offset?: number): number;
/**
* Reads the number as little endian from an IndexedByteArray.
* @param dataArray the array to read from.
* @param bytesAmount the number of bytes to read.
* @returns the number.
*/
declare function readLittleEndianIndexed(dataArray: IndexedByteArray, bytesAmount: number): number;
/**
* Reads bytes as an ASCII string from an IndexedByteArray.
* @param dataArray the IndexedByteArray to read from.
* @param bytes the amount of bytes to read.
* @returns the string.
*/
declare function readBinaryStringIndexed(dataArray: IndexedByteArray, bytes: number): string;
/**
* Reads VLQ from a MIDI byte array.
* @param MIDIbyteArray the array to read from.
* @returns the number.
*/
declare function readVariableLengthQuantity(MIDIbyteArray: IndexedByteArray): number;
/**
* Enables or disables logging.
* @param enableInfo enables info.
* @param enableWarn enables warning.
* @param enableGroup enables groups.
*/
declare function SpessaSynthLogging(enableInfo: boolean, enableWarn: boolean, enableGroup: boolean): void;
declare function SpessaSynthInfo(...message: unknown[]): void;
declare function SpessaSynthWarn(...message: unknown[]): void;
declare function SpessaSynthGroup(...message: unknown[]): void;
declare function SpessaSynthGroupCollapsed(...message: unknown[]): void;
declare function SpessaSynthGroupEnd(): void;
/**
* All SoundFont2 Generator enumerations.
*/
declare const generatorTypes: {
readonly INVALID: -1;
readonly startAddrsOffset: 0;
readonly endAddrOffset: 1;
readonly startloopAddrsOffset: 2;
readonly endloopAddrsOffset: 3;
readonly startAddrsCoarseOffset: 4;
readonly modLfoToPitch: 5;
readonly vibLfoToPitch: 6;
readonly modEnvToPitch: 7;
readonly initialFilterFc: 8;
readonly initialFilterQ: 9;
readonly modLfoToFilterFc: 10;
readonly modEnvToFilterFc: 11;
readonly endAddrsCoarseOffset: 12;
readonly modLfoToVolume: 13;
readonly unused1: 14;
readonly chorusEffectsSend: 15;
readonly reverbEffectsSend: 16;
readonly pan: 17;
readonly unused2: 18;
readonly unused3: 19;
readonly unused4: 20;
readonly delayModLFO: 21;
readonly freqModLFO: 22;
readonly delayVibLFO: 23;
readonly freqVibLFO: 24;
readonly delayModEnv: 25;
readonly attackModEnv: 26;
readonly holdModEnv: 27;
readonly decayModEnv: 28;
readonly sustainModEnv: 29;
readonly releaseModEnv: 30;
readonly keyNumToModEnvHold: 31;
readonly keyNumToModEnvDecay: 32;
readonly delayVolEnv: 33;
readonly attackVolEnv: 34;
readonly holdVolEnv: 35;
readonly decayVolEnv: 36;
readonly sustainVolEnv: 37;
readonly releaseVolEnv: 38;
readonly keyNumToVolEnvHold: 39;
readonly keyNumToVolEnvDecay: 40;
readonly instrument: 41;
readonly reserved1: 42;
readonly keyRange: 43;
readonly velRange: 44;
readonly startloopAddrsCoarseOffset: 45;
readonly keyNum: 46;
readonly velocity: 47;
readonly initialAttenuation: 48;
readonly reserved2: 49;
readonly endloopAddrsCoarseOffset: 50;
readonly coarseTune: 51;
readonly fineTune: 52;
readonly sampleID: 53;
readonly sampleModes: 54;
readonly reserved3: 55;
readonly scaleTuning: 56;
readonly exclusiveClass: 57;
readonly overridingRootKey: 58;
readonly unused5: 59;
readonly endOper: 60;
readonly vibLfoToVolume: 61;
readonly vibLfoToFilterFc: 62;
};
type GeneratorType = (typeof generatorTypes)[keyof typeof generatorTypes];
declare const GENERATORS_AMOUNT: number;
declare const MAX_GENERATOR: number;
/**
* Min: minimum value, max: maximum value, def: default value, nrpn: nrpn scale...
*/
declare const generatorLimits: {
min: number;
max: number;
def: number;
nrpn: number;
}[];
declare class Generator {
/**
* The generator's SF2 type.
*/
generatorType: GeneratorType;
/**
* The generator's 16-bit value.
*/
generatorValue: number;
/**
* Constructs a new generator
* @param type generator type
* @param value generator value
* @param validate if the limits should be validated
*/
constructor(type: GeneratorType, value: number, validate?: boolean);
write(genData: IndexedByteArray): void;
toString(): string;
}
declare const sampleTypes: {
readonly monoSample: 1;
readonly rightSample: 2;
readonly leftSample: 4;
readonly linkedSample: 8;
readonly romMonoSample: 32769;
readonly romRightSample: 32770;
readonly romLeftSample: 32772;
readonly romLinkedSample: 32776;
};
type SampleType = (typeof sampleTypes)[keyof typeof sampleTypes];
declare const modulatorSources: {
readonly noController: 0;
readonly noteOnVelocity: 2;
readonly noteOnKeyNum: 3;
readonly polyPressure: 10;
readonly channelPressure: 13;
readonly pitchWheel: 14;
readonly pitchWheelRange: 16;
readonly link: 127;
};
type ModulatorSourceEnum = (typeof modulatorSources)[keyof typeof modulatorSources];
declare const modulatorCurveTypes: {
readonly linear: 0;
readonly concave: 1;
readonly convex: 2;
readonly switch: 3;
};
type ModulatorCurveType = (typeof modulatorCurveTypes)[keyof typeof modulatorCurveTypes];
declare const modulatorTransformTypes: {
readonly linear: 0;
readonly absolute: 2;
};
type ModulatorTransformType = (typeof modulatorTransformTypes)[keyof typeof modulatorTransformTypes];
type DLSTransform = ModulatorCurveType;
declare const dlsSources: {
readonly none: 0;
readonly modLfo: 1;
readonly velocity: 2;
readonly keyNum: 3;
readonly volEnv: 4;
readonly modEnv: 5;
readonly pitchWheel: 6;
readonly polyPressure: 7;
readonly channelPressure: 8;
readonly vibratoLfo: 9;
readonly modulationWheel: 129;
readonly volume: 135;
readonly pan: 138;
readonly expression: 139;
readonly chorus: 221;
readonly reverb: 219;
readonly pitchWheelRange: 256;
readonly fineTune: 257;
readonly coarseTune: 258;
};
type DLSSource = (typeof dlsSources)[keyof typeof dlsSources];
declare const dlsDestinations: {
readonly none: 0;
readonly gain: 1;
readonly reserved: 2;
readonly pitch: 3;
readonly pan: 4;
readonly keyNum: 5;
readonly chorusSend: 128;
readonly reverbSend: 129;
readonly modLfoFreq: 260;
readonly modLfoDelay: 261;
readonly vibLfoFreq: 276;
readonly vibLfoDelay: 277;
readonly volEnvAttack: 518;
readonly volEnvDecay: 519;
readonly reservedEG1: 520;
readonly volEnvRelease: 521;
readonly volEnvSustain: 522;
readonly volEnvDelay: 523;
readonly volEnvHold: 524;
readonly modEnvAttack: 778;
readonly modEnvDecay: 779;
readonly reservedEG2: 780;
readonly modEnvRelease: 781;
readonly modEnvSustain: 782;
readonly modEnvDelay: 783;
readonly modEnvHold: 784;
readonly filterCutoff: 1280;
readonly filterQ: 1281;
};
type DLSDestination = (typeof dlsDestinations)[keyof typeof dlsDestinations];
declare const DLSLoopTypes: {
readonly forward: 0;
readonly loopAndRelease: 1;
};
type DLSLoopType = (typeof DLSLoopTypes)[keyof typeof DLSLoopTypes];
declare class BasicZone {
/**
* The zone's velocity range.
* min -1 means that it is a default value
*/
velRange: GenericRange;
/**
* The zone's key range.
* min -1 means that it is a default value.
*/
keyRange: GenericRange;
/**
* The zone's generators.
*/
generators: Generator[];
/**
* The zone's modulators.
*/
modulators: Modulator[];
get hasKeyRange(): boolean;
get hasVelRange(): boolean;
/**
* The current tuning in cents, taking in both coarse and fine generators.
*/
get fineTuning(): number;
/**
* The current tuning in cents, taking in both coarse and fine generators.
*/
set fineTuning(tuningCents: number);
/**
* Adds to a given generator, or its default value.
*/
addToGenerator(type: GeneratorType, value: number, validate?: boolean): void;
/**
* Sets a generator to a given value if preset, otherwise adds a new one.
*/
setGenerator(type: GeneratorType, value: number | null, validate?: boolean): void;
/**
* Adds generators to the zone.
* @param generators
*/
addGenerators(...generators: Generator[]): void;
addModulators(...modulators: Modulator[]): void;
getGenerator<K>(generatorType: GeneratorType, notFoundValue: number | K): number | K;
copyFrom(zone: BasicZone): void;
/**
* Filters the generators and prepends the range generators.
*/
getWriteGenerators(bank: BasicSoundBank): Generator[];
}
declare class BasicGlobalZone extends BasicZone {
}
declare class BasicInstrumentZone extends BasicZone {
/**
* The instrument this zone belongs to.
*/
readonly parentInstrument: BasicInstrument;
/**
* For tracking on the individual zone level, since multiple presets can refer to the same instrument.
*/
useCount: number;
/**
* Creates a new instrument zone.
* @param instrument The parent instrument.
* @param sample The sample to use in this zone.
*/
constructor(instrument: BasicInstrument, sample: BasicSample);
/**
* Zone's sample.
*/
private _sample;
/**
* Zone's sample.
*/
get sample(): BasicSample;
/**
* Sets a sample for this zone.
* @param sample the sample to set.
*/
set sample(sample: BasicSample);
getWriteGenerators(bank: BasicSoundBank): Generator[];
}
declare class BasicPresetZone extends BasicZone {
/**
* The preset this zone belongs to.
*/
readonly parentPreset: BasicPreset;
/**
* Creates a new preset zone.
* @param preset the preset this zone belongs to.
* @param instrument the instrument to use in this zone.
*/
constructor(preset: BasicPreset, instrument: BasicInstrument);
/**
* Zone's instrument.
*/
private _instrument;
/**
* Zone's instrument.
*/
get instrument(): BasicInstrument;
/**
* Zone's instrument.
*/
set instrument(instrument: BasicInstrument);
getWriteGenerators(bank: BasicSoundBank): Generator[];
}
interface MIDIPatch {
/**
* The MIDI program number.
*/
program: number;
/**
* The MIDI bank MSB number.
*/
bankMSB: number;
/**
* The MIDI bank LSB number.
*/
bankLSB: number;
/**
* If the preset is marked as GM/GS drum preset. Note that XG drums do not have this flag.
*/
isGMGSDrum: boolean;
}
interface MIDIPatchNamed extends MIDIPatch {
/**
* The name of the patch.
*/
name: string;
}
declare class MIDIPatchTools {
/**
* Converts a MIDI patch to a string.
*/
static toMIDIString(patch: MIDIPatch): string;
/**
* Gets a MIDI patch from a string.
* @param string
*/
static fromMIDIString(string: string): MIDIPatch;
/**
* Converts a named MIDI patch to string.
* @param patch
*/
static toNamedMIDIString(patch: MIDIPatchNamed): string;
/**
* Checks if two MIDI patches match.
* @param patch1
* @param patch2
*/
static matches(patch1: MIDIPatch, patch2: MIDIPatch): boolean;
/**
* Gets a named MIDI patch from a string.
* @param string
*/
static fromNamedMIDIString(string: string): MIDIPatchNamed;
static sorter(a: MIDIPatch, b: MIDIPatch): number;
}
/**
* Returned structure containing extended SF2 chunks.
*/
interface ExtendedSF2Chunks {
/**
* The PDTA part of the chunk.
*/
pdta: IndexedByteArray;
/**
* The XDTA (https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md) part of the chunk.
*/
xdta: IndexedByteArray;
}
/**
* Write indexes for tracking writing a SoundFont file.
*/
interface SoundFontWriteIndexes {
/**
* Generator start index.
*/
gen: number;
/**
* Modulator start index.
*/
mod: number;
/**
* Zone start index.
*/
bag: number;
/**
* Preset/instrument start index.
*/
hdr: number;
}
declare class BasicPreset implements MIDIPatchNamed {
/**
* The parent soundbank instance
* Currently used for determining default modulators and XG status
*/
readonly parentSoundBank: BasicSoundBank;
/**
* The preset's name
*/
name: string;
program: number;
bankMSB: number;
bankLSB: number;
isGMGSDrum: boolean;
/**
* The preset's zones
*/
zones: BasicPresetZone[];
/**
* Preset's global zone
*/
readonly globalZone: BasicGlobalZone;
/**
* Unused metadata
*/
library: number;
/**
* Unused metadata
*/
genre: number;
/**
* Unused metadata
*/
morphology: number;
/**
* Creates a new preset representation.
* @param parentSoundBank the sound bank this preset belongs to.
* @param globalZone optional, a global zone to use.
*/
constructor(parentSoundBank: BasicSoundBank, globalZone?: BasicGlobalZone);
get isXGDrums(): boolean;
/**
* Checks if this preset is a drum preset
*/
get isAnyDrums(): boolean;
/**
* Unlinks everything from this preset.
*/
delete(): void;
/**
* Deletes an instrument zone from this preset.
* @param index the zone's index to delete.
*/
deleteZone(index: number): void;
/**
* Creates a new preset zone and returns it.
* @param instrument the instrument to use in the zone.
*/
createZone(instrument: BasicInstrument): BasicPresetZone;
/**
* Preloads (loads and caches synthesis data) for a given key range.
*/
preload(keyMin: number, keyMax: number): void;
/**
* Checks if the bank and program numbers are the same for the given preset as this one.
* @param preset The preset to check.
*/
matches(preset: MIDIPatch): boolean;
/**
* Returns the synthesis data from this preset
* @param midiNote the MIDI note number
* @param velocity the MIDI velocity
* @returns the returned sound data
*/
getSynthesisData(midiNote: number, velocity: number): VoiceSynthesisData[];
/**
* BankMSB:bankLSB:program:isGMGSDrum
*/
toMIDIString(): string;
toString(): string;
/**
* Combines preset into an instrument, flattening the preset zones into instrument zones.
* This is a really complex function that attempts to work around the DLS limitations of only having the instrument layer.
* @returns The instrument containing the flattened zones. In theory, it should exactly the same as this preset.
*/
toFlattenedInstrument(): BasicInstrument;
/**
* Writes the SF2 header
* @param phdrData
* @param index
*/
write(phdrData: ExtendedSF2Chunks, index: number): void;
}
/**
* Represents a single instrument
*/
declare class BasicInstrument {
/**
* The instrument's name
*/
name: string;
/**
* The instrument's zones
*/
zones: BasicInstrumentZone[];
/**
* Instrument's global zone
*/
readonly globalZone: BasicGlobalZone;
/**
* Instrument's linked presets (the presets that use it)
* note that duplicates are allowed since one preset can use the same instrument multiple times.
*/
readonly linkedTo: BasicPreset[];
/**
* How many presets is this instrument used by
*/
get useCount(): number;
/**
* Creates a new instrument zone and returns it.
* @param sample The sample to use in the zone.
*/
createZone(sample: BasicSample): BasicInstrumentZone;
/**
* Links the instrument ta a given preset
* @param preset the preset to link to
*/
linkTo(preset: BasicPreset): void;
/**
* Unlinks the instrument from a given preset
* @param preset the preset to unlink from
*/
unlinkFrom(preset: BasicPreset): void;
deleteUnusedZones(): void;
delete(): void;
/**
* Deletes a given instrument zone if it has no uses
* @param index the index of the zone to delete
* @param force ignores the use count and deletes forcibly
* @returns if the zone has been deleted
*/
deleteZone(index: number, force?: boolean): boolean;
/**
* Globalizes the instrument *in-place.*
* This means trying to move as many generators and modulators
* to the global zone as possible to reduce clutter and the count of parameters.
*/
globalize(): void;
write(instData: ExtendedSF2Chunks, index: number): void;
}
declare class BasicSample {
/**
* The sample's name.
*/
name: string;
/**
* Sample rate in Hz.
*/
sampleRate: number;
/**
* Original pitch of the sample as a MIDI note number.
*/
originalKey: number;
/**
* Pitch correction, in cents. Can be negative.
*/
pitchCorrection: number;
/**
* Linked sample, unused if mono.
*/
linkedSample?: BasicSample;
/**
* The type of the sample.
*/
sampleType: SampleType;
/**
* Relative to the start of the sample in sample points.
*/
loopStart: number;
/**
* Relative to the start of the sample in sample points.
*/
loopEnd: number;
/**
* Sample's linked instruments (the instruments that use it)
* note that duplicates are allowed since one instrument can use the same sample multiple times.
*/
linkedTo: BasicInstrument[];
/**
* Indicates if the data was overridden, so it cannot be copied back unchanged.
*/
protected dataOverridden: boolean;
/**
* The compressed sample data if the sample has been compressed.
*/
protected compressedData?: Uint8Array;
/**
* The sample's audio data.
*/
protected audioData?: Float32Array;
/**
* The basic representation of a sample
* @param sampleName The sample's name
* @param sampleRate The sample's rate in Hz
* @param originalKey The sample's pitch as a MIDI note number
* @param pitchCorrection The sample's pitch correction in cents
* @param sampleType The sample's type, an enum that can indicate SF3
* @param loopStart The sample's loop start relative to the sample start in sample points
* @param loopEnd The sample's loop end relative to the sample start in sample points
*/
constructor(sampleName: string, sampleRate: number, originalKey: number, pitchCorrection: number, sampleType: SampleType, loopStart: number, loopEnd: number);
/**
* Indicates if the sample is compressed using vorbis SF3.
*/
get isCompressed(): boolean;
/**
* If the sample is linked to another sample.
*/
get isLinked(): boolean;
/**
* The sample's use count
*/
get useCount(): number;
/**
* Get raw data for writing the file, either a compressed bit stream or signed 16-bit little endian PCM data.
* @param allowVorbis if vorbis file data is allowed.
* @return either s16le or vorbis data.
*/
getRawData(allowVorbis: boolean): Uint8Array;
/**
* Resamples the audio data to a given sample rate.
*/
resampleData(newSampleRate: number): void;
/**
* Compresses the audio data
* @param encodeVorbis the compression function to use when compressing
*/
compressSample(encodeVorbis: SampleEncodingFunction): Promise<void>;
/**
* Sets the sample type and unlinks if needed.
* @param type The type to set it to.
*/
setSampleType(type: SampleType): void;
/**
* Unlinks the sample from its stereo link if it has any.
*/
unlinkSample(): void;
/**
* Links a stereo sample.
* @param sample the sample to link to.
* @param type either left, right or linked.
*/
setLinkedSample(sample: BasicSample, type: SampleType): void;
/**
* Links the sample to a given instrument
* @param instrument the instrument to link to
*/
linkTo(instrument: BasicInstrument): void;
/**
* Unlinks the sample from a given instrument
* @param instrument the instrument to unlink from
*/
unlinkFrom(instrument: BasicInstrument): void;
/**
* Get the float32 audio data.
* Note that this either decodes the compressed data or passes the ready sampleData.
* If neither are set then it will throw an error!
* @returns the audio data
*/
getAudioData(): Float32Array;
/**
* Replaces the audio data *in-place*.
* @param audioData The new audio data as Float32.
* @param sampleRate The new sample rate, in Hertz.
*/
setAudioData(audioData: Float32Array, sampleRate: number): void;
/**
* Replaces the audio with a compressed data sample and flags the sample as compressed
* @param data the new compressed data
*/
setCompressedData(data: Uint8Array): void;
/**
* Encodes s16le sample
* @return the encoded data
*/
protected encodeS16LE(): IndexedByteArray;
/**
* Decode binary vorbis into a float32 pcm
*/
protected decodeVorbis(): Float32Array;
}
declare class EmptySample extends BasicSample {
/**
* A simplified class for creating samples.
*/
constructor();
}
declare const midiMessageTypes: {
readonly noteOff: 128;
readonly noteOn: 144;
readonly polyPressure: 160;
readonly controllerChange: 176;
readonly programChange: 192;
readonly channelPressure: 208;
readonly pitchWheel: 224;
readonly systemExclusive: 240;
readonly timecode: 241;
readonly songPosition: 242;
readonly songSelect: 243;
readonly tuneRequest: 246;
readonly clock: 248;
readonly start: 250;
readonly continue: 251;
readonly stop: 252;
readonly activeSensing: 254;
readonly reset: 255;
readonly sequenceNumber: 0;
readonly text: 1;
readonly copyright: 2;
readonly trackName: 3;
readonly instrumentName: 4;
readonly lyric: 5;
readonly marker: 6;
readonly cuePoint: 7;
readonly programName: 8;
readonly midiChannelPrefix: 32;
readonly midiPort: 33;
readonly endOfTrack: 47;
readonly setTempo: 81;
readonly smpteOffset: 84;
readonly timeSignature: 88;
readonly keySignature: 89;
readonly sequenceSpecific: 127;
};
type MIDIMessageType = (typeof midiMessageTypes)[keyof typeof midiMessageTypes];
declare const midiControllers: {
readonly bankSelect: 0;
readonly modulationWheel: 1;
readonly breathController: 2;
readonly undefinedCC3: 3;
readonly footController: 4;
readonly portamentoTime: 5;
readonly dataEntryMSB: 6;
readonly mainVolume: 7;
readonly balance: 8;
readonly undefinedCC9: 9;
readonly pan: 10;
readonly expressionController: 11;
readonly effectControl1: 12;
readonly effectControl2: 13;
readonly undefinedCC14: 14;
readonly undefinedCC15: 15;
readonly generalPurposeController1: 16;
readonly generalPurposeController2: 17;
readonly generalPurposeController3: 18;
readonly generalPurposeController4: 19;
readonly undefinedCC20: 20;
readonly undefinedCC21: 21;
readonly undefinedCC22: 22;
readonly undefinedCC23: 23;
readonly undefinedCC24: 24;
readonly undefinedCC25: 25;
readonly undefinedCC26: 26;
readonly undefinedCC27: 27;
readonly undefinedCC28: 28;
readonly undefinedCC29: 29;
readonly undefinedCC30: 30;
readonly undefinedCC31: 31;
readonly bankSelectLSB: 32;
readonly modulationWheelLSB: 33;
readonly breathControllerLSB: 34;
readonly undefinedCC3LSB: 35;
readonly footControllerLSB: 36;
readonly portamentoTimeLSB: 37;
readonly dataEntryLSB: 38;
readonly mainVolumeLSB: 39;
readonly balanceLSB: 40;
readonly undefinedCC9LSB: 41;
readonly panLSB: 42;
readonly expressionControllerLSB: 43;
readonly effectControl1LSB: 44;
readonly effectControl2LSB: 45;
readonly undefinedCC14LSB: 46;
readonly undefinedCC15LSB: 47;
readonly undefinedCC16LSB: 48;
readonly undefinedCC17LSB: 49;
readonly undefinedCC18LSB: 50;
readonly undefinedCC19LSB: 51;
readonly undefinedCC20LSB: 52;
readonly undefinedCC21LSB: 53;
readonly undefinedCC22LSB: 54;
readonly undefinedCC23LSB: 55;
readonly undefinedCC24LSB: 56;
readonly undefinedCC25LSB: 57;
readonly undefinedCC26LSB: 58;
readonly undefinedCC27LSB: 59;
readonly undefinedCC28LSB: 60;
readonly undefinedCC29LSB: 61;
readonly undefinedCC30LSB: 62;
readonly undefinedCC31LSB: 63;
readonly sustainPedal: 64;
readonly portamentoOnOff: 65;
readonly sostenutoPedal: 66;
readonly softPedal: 67;
readonly legatoFootswitch: 68;
readonly hold2Pedal: 69;
readonly soundVariation: 70;
readonly filterResonance: 71;
readonly releaseTime: 72;
readonly attackTime: 73;
readonly brightness: 74;
readonly decayTime: 75;
readonly vibratoRate: 76;
readonly vibratoDepth: 77;
readonly vibratoDelay: 78;
readonly soundController10: 79;
readonly generalPurposeController5: 80;
readonly generalPurposeController6: 81;
readonly generalPurposeController7: 82;
readonly generalPurposeController8: 83;
readonly portamentoControl: 84;
readonly undefinedCC85: 85;
readonly undefinedCC86: 86;
readonly undefinedCC87: 87;
readonly undefinedCC88: 88;
readonly undefinedCC89: 89;
readonly undefinedCC90: 90;
readonly reverbDepth: 91;
readonly tremoloDepth: 92;
readonly chorusDepth: 93;
readonly detuneDepth: 94;
readonly phaserDepth: 95;
readonly dataIncrement: 96;
readonly dataDecrement: 97;
readonly nonRegisteredParameterLSB: 98;
readonly nonRegisteredParameterMSB: 99;
readonly registeredParameterLSB: 100;
readonly registeredParameterMSB: 101;
readonly undefinedCC102LSB: 102;
readonly undefinedCC103LSB: 103;
readonly undefinedCC104LSB: 104;
readonly undefinedCC105LSB: 105;
readonly undefinedCC106LSB: 106;
readonly undefinedCC107LSB: 107;
readonly undefinedCC108LSB: 108;
readonly undefinedCC109LSB: 109;
readonly undefinedCC110LSB: 110;
readonly undefinedCC111LSB: 111;
readonly undefinedCC112LSB: 112;
readonly undefinedCC113LSB: 113;
readonly undefinedCC114LSB: 114;
readonly undefinedCC115LSB: 115;
readonly undefinedCC116LSB: 116;
readonly undefinedCC117LSB: 117;
readonly undefinedCC118LSB: 118;
readonly undefinedCC119LSB: 119;
readonly allSoundOff: 120;
readonly resetAllControllers: 121;
readonly localControlOnOff: 122;
readonly allNotesOff: 123;
readonly omniModeOff: 124;
readonly omniModeOn: 125;
readonly monoModeOn: 126;
readonly polyModeOn: 127;
};
type MIDIController = (typeof midiControllers)[keyof typeof midiControllers];
type GenericRIFFFourCC = "RIFF" | "LIST" | "INFO";
type WAVFourCC = "wave" | "cue " | "fmt ";
type FourCC = GenericRIFFFourCC | SoundBankInfoFourCC | SF2InfoFourCC | SF2ChunkFourCC | DLSInfoFourCC | DLSChunkFourCC | RMIDInfoFourCC | WAVFourCC;
interface SoundBankManagerListEntry {
/**
* The unique string identifier of the sound bank.
*/
id: string;
/**
* The sound bank itself.
*/
soundBank: BasicSoundBank;
/**
* The bank MSB offset for this sound bank.
*/
bankOffset: number;
}
interface SF2VersionTag {
/**
* The major revision number of the sound bank.
*/
major: number;
/**
* The minor revision number of this sound bank.
*/
minor: number;
}
type GenericBankInfoFourCC = "INAM" | "ICRD" | "IENG" | "IPRD" | "ICOP" | "ICMT" | "ISFT";
type SF2InfoFourCC = GenericBankInfoFourCC | "ifil" | "isng" | "irom" | "iver" | "DMOD" | "LIST";
type SF2ChunkFourCC = "pdta" | "xdta" | "sdta" | "smpl" | "sm24" | "phdr" | "pbag" | "pmod" | "pgen" | "inst" | "ibag" | "imod" | "igen" | "shdr";
type DLSInfoFourCC = GenericBankInfoFourCC | "ISBJ";
type DLSChunkFourCC = WAVFourCC | "dls " | "dlid" | "cdl " | "ptbl" | "vers" | "colh" | "wvpl" | "wsmp" | "data" | "lart" | "lar2" | "art2" | "art1" | "lrgn" | "rgnh" | "wlnk" | "lins" | "ins " | "insh" | "rgn " | "rgn2" | "pgal";
interface SoundBankInfoData {
/**
* Name.
*/
name: string;
/**
* The sound bank's version.
*/
version: SF2VersionTag;
/**
* Creation date.
*/
creationDate: Date;
/**
* Sound engine.
*/
soundEngine: string;
/**
* Author.
*/
engineer?: string;
/**
* Product.
*/
product?: string;
/**
* Copyright.
*/
copyright?: string;
/**
* Comment.
*/
comment?: string;
/**
* Subject.
*/
subject?: string;
/**
* ROM information.
*/
romInfo?: string;
/**
* Software used to edit the file.
*/
software?: string;
/**
* A tag that only applies to SF2 and will usually be undefined.
*/
romVersion?: SF2VersionTag;
}
type SoundBankInfoFourCC = keyof SoundBankInfoData;
interface VoiceSynthesisData {
instrumentGenerators: Generator[];
presetGenerators: Generator[];
modulators: Modulator[];
sample: BasicSample;
}
type SampleEncodingFunction = (audioData: Float32Array, sampleRate: number) => Promise<Uint8Array>;
type ModulatorSourceIndex = ModulatorSourceEnum | MIDIController;
/**
* A function to track progress during writing.
*/
type ProgressFunction = (
/**
* The written sample name.
*/
sampleName: string,
/**
* The sample's index.
*/
sampleIndex: number,
/**
* The total sample count for progress displaying.
*/
sampleCount: number) => Promise<unknown>;
/**
* Options for writing a SoundFont2 file.
*/
interface SoundFont2WriteOptions {
/**
* If the soundfont should be compressed with a given function.
*/
compress: boolean;
/**
* The function for compressing samples. It can be undefined if not compressed.
*/
compressionFunction?: SampleEncodingFunction;
/**
* A function to show progress for writing large banks. It can be undefined.
*/
progressFunction?: ProgressFunction;
/**
* If the DMOD chunk should be written. Recommended.
* Note that it will only be written if the modulators are unchanged.
*/
writeDefaultModulators: boolean;
/**
* If the XDTA chunk should be written to allow virtually infinite parameters. Recommended.
* Note that it will only be written needed.
*/
writeExtendedLimits: boolean;
/**
* If an SF3 bank should be decompressed back to SF2. Not recommended.
*/
decompress: boolean;
}
/**
* Options for writing a DLS file.
*/
interface DLSWriteOptions {
/**
* A function to show progress for writing large banks. It can be undefined.
*/
progressFunction?: ProgressFunction;
}
interface GenericRange {
min: number;
max: number;
}
interface DLSLoop {
loopType: DLSLoopType;
loopStart: number;
loopLength: number;
}
declare const interpolationTypes: {
readonly linear: 0;
readonly nearestNeighbor: 1;
readonly hermite: 2;
};
type InterpolationType = (typeof interpolationTypes)[keyof typeof interpolationTypes];
declare const dataEntryStates: {
readonly Idle: 0;
readonly RPCoarse: 1;
readonly RPFine: 2;
readonly NRPCoarse: 3;
readonly NRPFine: 4;
readonly DataCoarse: 5;
readonly DataFine: 6;
};
type DataEntryState = (typeof dataEntryStates)[keyof typeof dataEntryStates];
declare const customControllers: {
readonly channelTuning: 0;
readonly channelTransposeFine: 1;
readonly modulationMultiplier: 2;
readonly masterTuning: 3;
readonly channelTuningSemitones: 4;
readonly channelKeyShift: 5;
readonly sf2NPRNGeneratorLSB: 6;
};
type CustomController = (typeof customControllers)[keyof typeof customControllers];
type SynthSystem = "gm" | "gm2" | "gs" | "xg";
interface NoteOnCallback {
/** The MIDI note number. */
midiNote: number;
/** The MIDI channel number. */
channel: number;
/** The velocity of the note. */
velocity: number;
}
interface NoteOffCallback {
/** The MIDI note number. */
midiNote: number;
/** The MIDI channel number. */
channel: number;
}
interface DrumChangeCallback {
/** The MIDI channel number. */
channel: number;
/** Indicates if the channel is a drum channel. */
isDrumChannel: boolean;
}
interface ProgramChangeCallback extends MIDIPatch {
/** The MIDI channel number. */
channel: number;
}
interface ControllerChangeCallback {
/** The MIDI channel number. */
channel: number;
/** The controller number. */
controllerNumber: number;
/** The value of the controller. */
controllerValue: number;
}
interface MuteChannelCallback {
/** The MIDI channel number. */
channel: number;
/** Indicates if the channel is muted. */
isMuted: boolean;
}
interface PresetListEntry extends MIDIPatchNamed {
/**
* Indicates if this preset is any kind of drum preset.
*/
isAnyDrums: boolean;
}
/**
* A list of preset changes, each with a name, bank, and program number.
*/
type PresetList = PresetListEntry[];
/**
* The synthesizer display system exclusive data, EXCLUDING THE F0 BYTE!
*/
type SynthDisplayCallback = number[];
interface PitchWheelCallback {
/** The MIDI channel number. */
channel: number;
/**
* The unsigned 14-bit value of the pitch: 0 - 16383.
*/
pitch: number;
}
interface ChannelPressureCallback {
/** The MIDI channel number. */
channel: number;
/** The pressure value. */
pressure: number;
}
interface PolyPressureCallback {
/** The MIDI channel number. */
channel: number;
/** The MIDI note number. */
midiNote: number;
/** The pressure value. */
pressure: number;
}
/**
* The error message for sound bank errors.
*/
type SoundBankErrorCallback = Error;
interface StopAllCallback {
/**
* The MIDI channel number.
*/
channel: number;
/**
* If the channel was force stopped. (no release time)
*/
force: boolean;
}
type MasterParameterChangeCallback = {
[P in keyof MasterParameterType]: {
/**
* The parameter that was changed.
*/
parameter: P;
/**
* The new value of this parameter.
*/
value: MasterParameterType[P];
};
}[keyof MasterParameterType];
interface ChannelPropertyChangeCallback {
/**
* The channel number of the new property.
*/
channel: number;
/**
* The updated property.
*/
property: ChannelProperty;
}
interface SynthProcessorEventData {
/**
* This event fires when a note is played.
*/
noteOn: NoteOnCallback;
/**
* This event fires when a note is released.
*/
noteOff: NoteOffCallback;
/**
* This event fires when a pitch wheel is changed.
*/
pitchWheel: PitchWheelCallback;
/**
* This event fires when a controller is changed.
*/
controllerChange: ControllerChangeCallback;
/**
* This event fires when a program is changed.
*/
programChange: ProgramChangeCallback;
/**
* This event fires when a channel pressure is changed.
*/
channelPressure: ChannelPressureCallback;
/**
* This event fires when a polyphonic pressure is changed.
*/
polyPressure: PolyPressureCallback;
/**
* This event fires when a drum channel is changed.
*/
drumChange: DrumChangeCallback;
/**
* This event fires when all notes on a channel are stopped.
*/
stopAll: StopAllCallback;
/**
* This event fires when a new channel is created. There is no data for this event.
*/
newChannel: void;
/**
* This event fires when a channel is muted or unmuted.
*/
muteChannel: MuteChannelCallback;
/**
* This event fires when the preset list is changed.
*/
presetListChange: PresetList;
/**
* This event fires when all controllers on all channels are reset. There is no data for this event.
*/
allControllerReset: void;
/**
* This event fires when a sound bank parsing error occurs.
*/
soundBankError: SoundBankErrorCallback;
/**
* This event fires when the synthesizer receives a display message.
*/
synthDisplay: SynthDisplayCallback;
/**
* This event fires when a master parameter changes.
*/
masterParameterChange: MasterParameterChangeCallback;
/**
* This event fires when a channel property changes.
*/
channelPropertyChange: ChannelPropertyChangeCallback;
}
type SynthProcessorEvent = {
[K in keyof SynthProcessorEventData]: {
type: K;
data: SynthProcessorEventData[K];
};
}[keyof SynthProcessorEventData];
interface SynthMethodOptions {
/**
* The audio context time when the event should execute, in seconds.
*/
time: number;
}
/**
* KeyNum: tuning.
*/
type MTSProgramTuning = MTSNoteTuning[];
interface MTSNoteTuning {
/**
* The base MIDI note to use, -1 means no change.
*/
midiNote: number;
/**
* Additional tuning.
*/
centTuning: number | null;
}
/**
* Looping mode of the sample.
* 0 - no loop.
* 1 - loop.
* 2 - UNOFFICIAL: polyphone 2.4 added start on release.
* 3 - loop then play when released.
*/
type SampleLoopingMode = 0 | 1 | 2 | 3;
/**
* A list of voices for a given key:velocity.
*/
type VoiceList = Voice[];
interface ChannelProperty {
/**
* The channel's current voice amount.
*/
voicesAmount: number;
/**
* The channel's current pitch wheel 0 - 16384.
*/
pitchWheel: number;
/**
* The pitch wheel's range, in semitones.
*/
pitchWheelRange: number;
/**
* Indicates whether the channel is muted.
*/
isMuted: boolean;
/**
* Indicates whether the channel is a drum channel.
*/
isDrum: boolean;
/**
* The channel's transposition, in semitones.
*/
transposition: number;
}
interface SynthProcessorOptions {
/**
* Indicates if the event system is enabled. This can be changed later.
*/
enableEventSystem: boolean;
/**
* The initial time of the synth, in seconds.
*/
initialTime: number;
/**
* Indicates if the effects are enabled. This can be changed later.
*/
enableEffects: boolean;
}
/**
* The master parameters of the synthesizer.
*/
interface MasterParameterType {
/**
* The master gain, from 0 to any number. 1 is 100% volume.
*/
masterGain: number;
/**
* The master pan, from -1 (left) to 1 (right). 0 is center.
*/
masterPan: number;
/**
* The maximum number of voices that can be played at once.
*/
voiceCap: number;
/**
* The interpolation type used for sample playback.
*/
interpolationType: InterpolationType;
/**
* The MIDI system used by the synthesizer for bank selects and system exclusives. (GM, GM2, GS, XG)
*/
midiSystem: SynthSystem;
/**
* Indicates whether the synthesizer is in monophonic retrigger mode.
* This emulates the behavior of Microsoft GS Wavetable Synth,
* Where a new note will kill the previous one if it is still playing.
*/
monophonicRetriggerMode: boolean;
/**
* The reverb gain, from 0 to any number. 1 is 100% reverb.
*/
reverbGain: number;
/**
* The chorus gain, from 0 to any number. 1 is 100% chorus.
*/
chorusGain: number;
/**
* Forces note killing instead of releasing. Improves performance in black MIDIs.
*/
blackMIDIMode: boolean;
/**
* The global transposition in semitones. It can be decimal to provide microtonal tuning.
*/
transposition: number;
/**
* Synthesizer's device ID for system exclusive messages. Set to -1 to accept all.
*/
deviceID: number;
}
/**
* Sets a master parameter of the synthesizer.
* @param parameter The type of the master parameter to set.
* @param value The value to set for the master parameter.
*/
declare function setMasterParameterInternal<P extends keyof MasterParameterType>(this: SpessaSynthProcessor, parameter: P, value: MasterParameterType[P]): void;
/**
* Gets a master parameter of the synthesizer.
* @param type The type of the master parameter to get.
* @returns The value of the master parameter.
*/
declare function getMasterParameterInternal<P extends keyof MasterParameterType>(this: SpessaSynthProcessor, type: P): MasterParameterType[P];
/**
* Gets all master parameters of the synthesizer.
* @returns All the master parameters.
*/
declare function getAllMasterParametersInternal(this: SpessaSynthProcessor): MasterParameterType;
declare class SoundBankManager {
/**
* All the sound banks, ordered from the most important to the least.
*/
soundBankList: SoundBankManagerListEntry[];
private readonly presetListChangeCallback;
private selectablePresetList;
/**
* @param presetListChangeCallback Supplied by the parent synthesizer class,
* this is called whenever the preset list changes.
*/
constructor(presetListChangeCallback: () => unknown);
private _presetList;
/**
* The list of all presets in the sound bank stack.
*/
get presetList(): PresetListEntry[];
/**
* The current sound bank priority order.
* @returns The IDs of the sound banks in the current order.
*/
get priorityOrder(): string[];
/**
* The current sound bank priority order.
* @param newList The new order of sound bank IDs.
*/
set priorityOrder(newList: string[]);
/**
* Deletes a given sound bank by its ID.
* @param id the ID of the sound bank to delete.
*/
deleteSoundBank(id: string): void;
/**
* Adds a new sound bank with a given ID, or replaces an existing one.
* @param font the sound bank to add.
* @param id the ID of the sound bank.
* @param bankOffset the bank offset of the sound bank.
*/
addSoundBank(font: BasicSoundBank, id: string, bankOffset?: number): void;
/**
* Gets a given preset from the sound bank stack.
* @param patch The MIDI patch to search for.
* @param system The MIDI system to select the preset for.
* @returns An object containing the preset and its bank offset.
*/
getPreset(patch: MIDIPatch, system: SynthSystem): BasicPreset;
destroy(): void;
private generatePresetList;
}
/**
* Kills the specified number of voices based on their priority.
* This function will remove the least important voices from all channels.
* @param amount The number of voices to remove.
*/
declare function killVoicesIntenral(this: SpessaSynthProcessor, amount: number): void;
type TypedArray = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Uint8ClampedArray | Float32Array | Float64Array;
/**
* Executes a system exclusive message for the synthesizer.
* @param syx The system exclusive message as an array of bytes.
* @param channelOffset The channel offset to apply (default is 0).
* @remarks
* This is a rather extensive method that handles various system exclusive messages,
* including Roland GS, MIDI Tuning Standard, and other non-realtime messages.
*/
declare function systemExclusiveInternal(this: SpessaSynthProcessor, syx: number[] | IndexedByteArray | TypedArray, channelOffset?: number): void;
/**
* Executes a data entry fine (LSB) change for the current channel.
* @param dataValue The value to set for the data entry fine controller (0-127).
*/
declare function dataEntryFine(this: MIDIChannel, dataValue: number): void;
/**
* Handles MIDI controller changes for a channel.
* @param controllerNumber The MIDI controller number (0-127).
* @param controllerValue The value of the controller (0-127).
* @param sendEvent If an event should be emitted.
* @remarks
* This function processes MIDI controller changes, updating the channel's
* midiControllers table and handling special cases like bank select,
* data entry, and sustain pedal. It also computes modulators for all voices
* in the channel based on the controller change.
* If the controller number is greater than 127, it is treated as a channel
* configuration controller, and the `force` parameter must be set to true
* to allow changes.
*/
declare function controllerChange(this: MIDIChannel, controllerNumber: MIDIController, controllerValue: number, sendEvent?: boolean): void;
/**
* Executes a data entry coarse (MSB) change for the current channel.
* @param dataValue The value to set for the data entry coarse controller (0-127).
*/
declare function dataEntryCoarse(this: MIDIChannel, dataValue: number): void;
/**
* Sends a "MIDI Note on" message and starts a note.
* @param midiNote The MIDI note number (0-127).
* @param velocity The velocity of the note (0-127). If less than 1, it will send a note off instead.
*/
declare function noteOn(this: MIDIChannel, midiNote: number, velocity: number): void;
/**
* Releases a note by its MIDI note number.
* If the note is in high performance mode and the channel is not a drum channel,
* it kills the note instead of releasing it.
* @param midiNote The MIDI note number to release (0-127).
*/
declare function noteOff(this: MIDIChannel, midiNote: number): void;
/**
* Changes the program (preset) of the channel.
* @param program The program number (0-127) to change to.
*/
declare function programChange(this: MIDIChannel, program: number): void;
/**
* A class for dynamic modulators
* that are assigned for more complex system exclusive messages
*/
declare class DynamicModulatorSystem {
/**
* The current dynamic modulator list.
*/
modulatorList: {
mod: Modulator;
id: string;
}[];
resetModulators(): void;
/**
* @param source Like in midiControllers: values below NON_CC_INDEX_OFFSET are CCs,
* above are regular modulator sources.
* @param destination The generator type to modulate.
* @param amount The amount of modulation to apply.
* @param isBipolar If true, the modulation is bipolar (ranges from -1 to 1 instead of from 0 to 1).
* @param isNegative If true, the modulation is negative (goes from 1 to 0 instead of from 0 to 1).
*/
setModulator(source: ModulatorSourceEnum, destination: GeneratorType, amount: number, isBipolar?: boolean, isNegative?: boolean): void;
private getModulatorID;
private deleteModulator;
}
declare class ProtectedSynthValues {
/**
* This.tunings[program][key] = tuning
*/
readonly tunings: MTSProgramTuning[];
masterParameters: MasterParameterType;
/**
* The volume gain, set by MIDI sysEx
*/
midiVolume: number;
/**
* Set via system exclusive.
*/
reverbSend: number;
/**
* Set via system exclusive.
*/
chorusSend: number;
/**
* The pan of the left channel
*/
panLeft: number;
/**
* The pan of the right channel
*/
panRight: number;
/**
* Synth's default (reset) preset
*/
defaultPreset: BasicPreset | undefined;
/**
* Synth's default (reset) drum preset
*/
drumPreset: BasicPreset | undefined;
readonly volumeEnvelopeSmoothingFactor: number;
readonly panSmoothingFactor: number;
readonly filterSmoothingFactor: number;
/**
* Calls when an event occurs.
* @param eventType The event type.
* @param eventData The event data.
*/
eventCallbackHandler: <K extends keyof SynthProcessorEventData>(eventType: K, eventData: SynthProcessorEventData[K]) => unknown;
getVoices: (channel: number, midiNote: number, velocity: number, realKey: number) => VoiceList;
voiceKilling: (amount: number) => unknown;
/**
* Cached voices for all presets for this synthesizer.
* Nesting goes like this:
* this.cachedVoices[bankMSB][bankLSB][programNumber][midiNote][velocity] = a list of voices for that.
*/
cachedVoices: VoiceList[][][][][];
constructor(eventCallbackHandler: <K extends keyof SynthProcessorEventData>(eventType: K, eventData: SynthProcessorEventData[K]) => unknown, getVoices: (channel: number, midiNote: number, velocity: number, realKey: number) => VoiceL