spessasynth_lib 3.15.0 → 3.16.0

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.
Files changed (32) hide show
  1. package/@types/midi_parser/used_keys_loaded.d.ts +4 -2
  2. package/@types/soundfont/read/presets.d.ts +1 -0
  3. package/@types/soundfont/soundfont.d.ts +12 -0
  4. package/@types/synthetizer/synth_soundfont_manager.d.ts +52 -0
  5. package/@types/synthetizer/synthetizer.d.ts +13 -1
  6. package/@types/synthetizer/worklet_system/message_protocol/worklet_message.d.ts +2 -2
  7. package/@types/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/sfman_message.d.ts +7 -0
  8. package/README.md +1 -0
  9. package/midi_parser/midi_loader.js +1 -1
  10. package/midi_parser/used_keys_loaded.js +1 -1
  11. package/package.json +1 -1
  12. package/sequencer/worklet_sequencer/song_control.js +2 -2
  13. package/soundfont/read/presets.js +2 -0
  14. package/soundfont/soundfont.js +25 -0
  15. package/synthetizer/synth_soundfont_manager.js +111 -0
  16. package/synthetizer/synthetizer.js +19 -12
  17. package/synthetizer/worklet_processor.min.js +6 -6
  18. package/synthetizer/worklet_system/main_processor.js +132 -9
  19. package/synthetizer/worklet_system/message_protocol/handle_message.js +6 -5
  20. package/synthetizer/worklet_system/message_protocol/message_sending.js +0 -13
  21. package/synthetizer/worklet_system/message_protocol/worklet_message.js +4 -3
  22. package/synthetizer/worklet_system/worklet_methods/note_off.js +5 -4
  23. package/synthetizer/worklet_system/worklet_methods/note_on.js +0 -1
  24. package/synthetizer/worklet_system/worklet_methods/program_control.js +11 -16
  25. package/synthetizer/worklet_system/worklet_methods/voice_control.js +20 -12
  26. package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/sfman_message.js +9 -0
  27. package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +231 -0
  28. package/synthetizer/worklet_system/worklet_processor.js +1 -1
  29. package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +5 -5
  30. package/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +1 -3
  31. package/utils/buffer_to_wav.js +42 -38
  32. package/synthetizer/worklet_system/combine_class.js +0 -104
@@ -3,10 +3,42 @@ import { SoundFont2 } from '../../soundfont/soundfont.js'
3
3
  import { WorkletSequencer } from '../../sequencer/worklet_sequencer/worklet_sequencer.js'
4
4
  import { SpessaSynthInfo } from '../../utils/loggin.js'
5
5
  import { consoleColors } from '../../utils/other.js'
6
- import { PAN_SMOOTHING_FACTOR } from './worklet_methods/voice_control.js'
6
+ import { PAN_SMOOTHING_FACTOR, releaseVoice, renderVoice, voiceKilling } from './worklet_methods/voice_control.js'
7
7
  import { ALL_CHANNELS_OR_DIFFERENT_ACTION, returnMessageType } from './message_protocol/worklet_message.js'
8
8
  import { stbvorbis } from '../../externals/stbvorbis_sync/stbvorbis_sync.min.js'
9
9
  import { VOLUME_ENVELOPE_SMOOTHING_FACTOR } from './worklet_utilities/volume_envelope.js'
10
+ import { handleMessage } from './message_protocol/handle_message.js'
11
+ import { callEvent, sendChannelProperties } from './message_protocol/message_sending.js'
12
+ import { systemExclusive } from './worklet_methods/system_exclusive.js'
13
+ import { noteOn } from './worklet_methods/note_on.js'
14
+ import { killNote, noteOff, stopAll, stopAllChannels } from './worklet_methods/note_off.js'
15
+ import {
16
+ channelPressure, pitchWheel,
17
+ polyPressure, setChannelTuning, setChannelTuningSemitones, setMasterTuning, setModulationDepth, setOctaveTuning,
18
+ transposeAllChannels,
19
+ transposeChannel,
20
+ } from './worklet_methods/tuning_control.js'
21
+ import {
22
+ controllerChange,
23
+ muteChannel,
24
+ setMasterGain,
25
+ setMasterPan,
26
+ setMIDIVolume,
27
+ } from './worklet_methods/controller_control.js'
28
+ import { disableAndLockVibrato, setVibrato } from './worklet_methods/vibrato_control.js'
29
+ import { dataEntryCoarse, dataEntryFine } from './worklet_methods/data_entry.js'
30
+ import { createWorkletChannel } from './worklet_utilities/worklet_processor_channel.js'
31
+ import { resetAllControllers, resetControllers, resetParameters } from './worklet_methods/reset_controllers.js'
32
+ import {
33
+ clearSoundFont,
34
+ getPreset,
35
+ programChange,
36
+ reloadSoundFont, sampleDump, sendPresetList,
37
+ setDrums,
38
+ setPreset,
39
+ } from './worklet_methods/program_control.js'
40
+ import { applySynthesizerSnapshot, sendSynthesizerSnapshot } from './worklet_methods/snapshot.js'
41
+ import { WorkletSoundfontManager } from './worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js'
10
42
 
11
43
 
12
44
  /**
@@ -18,7 +50,7 @@ export const MIN_NOTE_LENGTH = 0.07; // if the note is released faster than that
18
50
 
19
51
  export const SYNTHESIZER_GAIN = 1.0;
20
52
 
21
- export class SpessaSynthProcessor extends AudioWorkletProcessor
53
+ class SpessaSynthProcessor extends AudioWorkletProcessor
22
54
  {
23
55
  /**
24
56
  * Creates a new worklet synthesis system. contains all channels
@@ -114,9 +146,9 @@ export class SpessaSynthProcessor extends AudioWorkletProcessor
114
146
  try
115
147
  {
116
148
  /**
117
- * @type {SoundFont2}
149
+ * @type {WorkletSoundfontManager}
118
150
  */
119
- this.soundfont = new SoundFont2(options.processorOptions.soundfont);
151
+ this.soundfontManager = new WorkletSoundfontManager(options.processorOptions.soundfont, this.postReady.bind(this));
120
152
  }
121
153
  catch (e)
122
154
  {
@@ -186,14 +218,35 @@ export class SpessaSynthProcessor extends AudioWorkletProcessor
186
218
  }
187
219
 
188
220
  stbvorbis.isInitialized.then(() => {
189
- this.post({
190
- messageType: returnMessageType.ready,
191
- messageData: undefined
192
- });
221
+ this.postReady();
193
222
  SpessaSynthInfo("%cSpessaSynth is ready!", consoleColors.recognized);
194
223
  });
195
224
  }
196
225
 
226
+ /**
227
+ * @param data {WorkletReturnMessage}
228
+ */
229
+ post(data)
230
+ {
231
+ if(!this.enableEventSystem)
232
+ {
233
+ return;
234
+ }
235
+ this.port.postMessage(data);
236
+ }
237
+
238
+ postReady()
239
+ {
240
+ if(!this.enableEventSystem)
241
+ {
242
+ return;
243
+ }
244
+ this.port.postMessage({
245
+ messageType: returnMessageType.ready,
246
+ messageData: undefined
247
+ });
248
+ }
249
+
197
250
  /**
198
251
  * @returns {number}
199
252
  */
@@ -289,4 +342,74 @@ export class SpessaSynthProcessor extends AudioWorkletProcessor
289
342
  }
290
343
  return true;
291
344
  }
292
- }
345
+ }
346
+
347
+ // include other methods
348
+ // voice related
349
+ SpessaSynthProcessor.prototype.renderVoice = renderVoice;
350
+ SpessaSynthProcessor.prototype.releaseVoice = releaseVoice;
351
+ SpessaSynthProcessor.prototype.voiceKilling = voiceKilling;
352
+
353
+ // message port related
354
+ SpessaSynthProcessor.prototype.handleMessage = handleMessage;
355
+ SpessaSynthProcessor.prototype.sendChannelProperties = sendChannelProperties;
356
+ SpessaSynthProcessor.prototype.callEvent = callEvent;
357
+
358
+ // system exlcusive related
359
+ SpessaSynthProcessor.prototype.systemExclusive = systemExclusive;
360
+
361
+ // note messages related
362
+ SpessaSynthProcessor.prototype.noteOn = noteOn;
363
+ SpessaSynthProcessor.prototype.noteOff = noteOff;
364
+ SpessaSynthProcessor.prototype.polyPressure = polyPressure;
365
+ SpessaSynthProcessor.prototype.killNote = killNote;
366
+ SpessaSynthProcessor.prototype.stopAll = stopAll;
367
+ SpessaSynthProcessor.prototype.stopAllChannels = stopAllChannels;
368
+ SpessaSynthProcessor.prototype.muteChannel = muteChannel;
369
+
370
+ // custom vibrato related
371
+ SpessaSynthProcessor.prototype.setVibrato = setVibrato;
372
+ SpessaSynthProcessor.prototype.disableAndLockVibrato = disableAndLockVibrato;
373
+
374
+ // data entry related
375
+ SpessaSynthProcessor.prototype.dataEntryCoarse = dataEntryCoarse;
376
+ SpessaSynthProcessor.prototype.dataEntryFine = dataEntryFine;
377
+
378
+ // channel related
379
+ SpessaSynthProcessor.prototype.createWorkletChannel = createWorkletChannel;
380
+ SpessaSynthProcessor.prototype.controllerChange = controllerChange;
381
+ SpessaSynthProcessor.prototype.channelPressure = channelPressure;
382
+ SpessaSynthProcessor.prototype.resetAllControllers = resetAllControllers;
383
+ SpessaSynthProcessor.prototype.resetControllers = resetControllers;
384
+ SpessaSynthProcessor.prototype.resetParameters = resetParameters;
385
+
386
+ // master parameter related
387
+ SpessaSynthProcessor.prototype.setMasterGain = setMasterGain;
388
+ SpessaSynthProcessor.prototype.setMasterPan = setMasterPan;
389
+ SpessaSynthProcessor.prototype.setMIDIVolume = setMIDIVolume;
390
+
391
+ // tuning related
392
+ SpessaSynthProcessor.prototype.transposeAllChannels = transposeAllChannels;
393
+ SpessaSynthProcessor.prototype.transposeChannel = transposeChannel;
394
+ SpessaSynthProcessor.prototype.setChannelTuning = setChannelTuning;
395
+ SpessaSynthProcessor.prototype.setChannelTuningSemitones = setChannelTuningSemitones;
396
+ SpessaSynthProcessor.prototype.setMasterTuning = setMasterTuning;
397
+ SpessaSynthProcessor.prototype.setModulationDepth = setModulationDepth;
398
+ SpessaSynthProcessor.prototype.pitchWheel = pitchWheel;
399
+ SpessaSynthProcessor.prototype.setOctaveTuning = setOctaveTuning;
400
+
401
+ // program related
402
+ SpessaSynthProcessor.prototype.programChange = programChange;
403
+ SpessaSynthProcessor.prototype.getPreset = getPreset;
404
+ SpessaSynthProcessor.prototype.setPreset = setPreset;
405
+ SpessaSynthProcessor.prototype.setDrums = setDrums;
406
+ SpessaSynthProcessor.prototype.reloadSoundFont = reloadSoundFont;
407
+ SpessaSynthProcessor.prototype.clearSoundFont = clearSoundFont;
408
+ SpessaSynthProcessor.prototype.sampleDump = sampleDump;
409
+ SpessaSynthProcessor.prototype.sendPresetList = sendPresetList;
410
+
411
+ // snapshot related
412
+ SpessaSynthProcessor.prototype.sendSynthesizerSnapshot = sendSynthesizerSnapshot;
413
+ SpessaSynthProcessor.prototype.applySynthesizerSnapshot = applySynthesizerSnapshot;
414
+
415
+ export { SpessaSynthProcessor }
@@ -3,7 +3,7 @@ import { SpessaSynthLogging, SpessaSynthWarn } from '../../../utils/loggin.js'
3
3
 
4
4
  /**
5
5
  * @this {SpessaSynthProcessor}
6
- * @param message
6
+ * @param message {WorkletMessage}
7
7
  */
8
8
  export function handleMessage(message)
9
9
  {
@@ -95,10 +95,6 @@ export function handleMessage(message)
95
95
  }
96
96
  break;
97
97
 
98
- case workletMessageType.reloadSoundFont:
99
- this.reloadSoundFont(data);
100
- break;
101
-
102
98
  case workletMessageType.stopAll:
103
99
  if(channel === ALL_CHANNELS_OR_DIFFERENT_ACTION)
104
100
  {
@@ -182,6 +178,11 @@ export function handleMessage(message)
182
178
  this.sequencer.processMessage(data.messageType, data.messageData);
183
179
  break;
184
180
 
181
+ case workletMessageType.soundFontManager:
182
+ this.soundfontManager.handleMessage(data[0], data[1]);
183
+ this.clearSoundFont(true, false);
184
+ break;
185
+
185
186
  case workletMessageType.requestSynthesizerSnapshot:
186
187
  this.sendSynthesizerSnapshot();
187
188
  break;
@@ -23,19 +23,6 @@ export function callEvent(eventName, eventData)
23
23
  })
24
24
  }
25
25
 
26
- /**
27
- * @param data {WorkletReturnMessage}
28
- * @this {SpessaSynthProcessor}
29
- */
30
- export function post(data)
31
- {
32
- if(!this.enableEventSystem)
33
- {
34
- return;
35
- }
36
- this.port.postMessage(data);
37
- }
38
-
39
26
  /**
40
27
  * @typedef {Object} ChannelProperty
41
28
  * @property {number} voicesAmount
@@ -10,7 +10,7 @@
10
10
  * @property {number} killNote - 6 -> midiNote<number>
11
11
  * @property {number} ccReset - 7 -> (no data) note: if channel is -1 then reset all channels
12
12
  * @property {number} setChannelVibrato - 8 -> {frequencyHz: number, depthCents: number, delaySeconds: number} note: if channel is -1 then stop all channels note 2: if rate is -1, it means locking
13
- * @property {number} reloadSoundFont - 9 -> (no data)
13
+ * @property {number} soundFontManager - 9 -> [messageType<WorkletSoundfontManagerMessageType> messageData<any>] note: refer to sfman_message.js
14
14
  * @property {number} stopAll - 10 -> force<number> (0 false, 1 true) note: if channel is -1 then stop all channels
15
15
  * @property {number} killNotes - 11 -> amount<number>
16
16
  * @property {number} muteChannel - 12 -> isMuted<boolean>
@@ -38,7 +38,7 @@ export const workletMessageType = {
38
38
  killNote: 6,
39
39
  ccReset: 7,
40
40
  setChannelVibrato: 8,
41
- reloadSoundFont: 9,
41
+ soundFontManager: 9,
42
42
  stopAll: 10,
43
43
  killNotes: 11,
44
44
  muteChannel: 12,
@@ -96,7 +96,8 @@ export const ALL_CHANNELS_OR_DIFFERENT_ACTION = -1;
96
96
  * |PresetListElement[]
97
97
  * |string
98
98
  * |{messageType: WorkletSequencerReturnMessageType, messageData: any}
99
- * |SynthesizerSnapshot} messageData - the message's data
99
+ * |SynthesizerSnapshot
100
+ * |[WorkletSoundfontManagerMessageType, any]} messageData - the message's data
100
101
  *
101
102
  * 0 - channel properties -> [...<ChannelProperty>] see message_sending.js line 29
102
103
  * 1 - event call -> {eventName<string>, eventData:<the event's data>}
@@ -15,7 +15,8 @@ export function noteOff(channel, midiNote)
15
15
  SpessaSynthWarn(`Received a noteOn for note`, midiNote, "Ignoring.");
16
16
  return;
17
17
  }
18
- midiNote += this.workletProcessorChannels[channel].channelTransposeKeyShift;
18
+ const channelObject = this.workletProcessorChannels[channel];
19
+ const actualNote = midiNote + channelObject.channelTransposeKeyShift;
19
20
 
20
21
  // if high performance mode, kill notes instead of stopping them
21
22
  if(this.highPerformanceMode)
@@ -23,14 +24,14 @@ export function noteOff(channel, midiNote)
23
24
  // if the channel is percussion channel, do not kill the notes
24
25
  if(!this.workletProcessorChannels[channel].drumChannel)
25
26
  {
26
- this.killNote(channel, midiNote);
27
+ this.killNote(channel, actualNote);
27
28
  return;
28
29
  }
29
30
  }
30
31
 
31
32
  const channelVoices = this.workletProcessorChannels[channel].voices;
32
33
  channelVoices.forEach(v => {
33
- if(v.midiNote !== midiNote || v.isInRelease === true)
34
+ if(v.midiNote !== actualNote || v.isInRelease === true)
34
35
  {
35
36
  return;
36
37
  }
@@ -44,7 +45,7 @@ export function noteOff(channel, midiNote)
44
45
  }
45
46
  });
46
47
  this.callEvent("noteoff", {
47
- midiNote: midiNote - this.workletProcessorChannels[channel].channelTransposeKeyShift,
48
+ midiNote: midiNote,
48
49
  channel: channel
49
50
  });
50
51
  }
@@ -57,7 +57,6 @@ export function noteOn(channel, midiNote, velocity, enableDebugging = false, sen
57
57
  data.sampleData
58
58
  ),
59
59
  channelObject.cachedVoices,
60
- channelObject.presetUsesOverride ? this.soundfont.samples.length : 0, // this is done to prevent samples overlapping
61
60
  enableDebugging
62
61
  );
63
62
 
@@ -43,21 +43,21 @@ export function programChange(channel, programNumber, userChange=false)
43
43
  if(this.soundfontBankOffset === 0)
44
44
  {
45
45
  preset = this.overrideSoundfont.getPreset(0, programNumber);
46
+ sentBank = preset.bank;
46
47
  }
47
48
  else
48
49
  {
49
- preset = this.soundfont.getPreset(bank, programNumber);
50
+ preset = this.soundfontManager.getPreset(bank, programNumber);
50
51
  sentBank = preset.bank;
51
52
  channelObject.presetUsesOverride = false;
52
53
  }
53
54
  }
54
55
  else
55
56
  {
56
- preset = this.soundfont.getPreset(bank, programNumber);
57
+ preset = this.soundfontManager.getPreset(bank, programNumber);
57
58
  sentBank = preset.bank;
58
59
  channelObject.presetUsesOverride = false;
59
60
  }
60
-
61
61
  this.setPreset(channel, preset);
62
62
  this.callEvent("programchange",{
63
63
  channel: channel,
@@ -90,7 +90,7 @@ export function getPreset(bank, program)
90
90
  return this.overrideSoundfont.getPreset(0, program);
91
91
  }
92
92
  }
93
- return this.soundfont.getPreset(bank, program);
93
+ return this.soundfontManager.getPreset(bank, program);
94
94
  }
95
95
 
96
96
 
@@ -159,9 +159,10 @@ export function setDrums(channel, isDrum)
159
159
  */
160
160
  export function sendPresetList()
161
161
  {
162
- const mainFont = this.soundfont.presets.map(p => {
163
- return {presetName: p.presetName, bank: p.bank, program: p.program};
164
- });
162
+ /**
163
+ * @type {{bank: number, presetName: string, program: number}[]}
164
+ */
165
+ const mainFont = this.soundfontManager.getPresetList();
165
166
  if(this.overrideSoundfont !== undefined)
166
167
  {
167
168
  this.overrideSoundfont.presets.forEach(p => {
@@ -223,23 +224,17 @@ export function clearSoundFont(sendPresets = true, clearOverride = true)
223
224
  export function reloadSoundFont(buffer, isOverride = false)
224
225
  {
225
226
  this.clearSoundFont(false, isOverride);
226
- if(!isOverride)
227
- {
228
- delete this.soundfont.dataArray;
229
- this.soundfont.samples.length = 0;
230
- this.soundfont.instruments.length = 0;
231
- this.soundfont.presets.length = 0;
232
- delete this.soundfont;
233
- }
234
227
  try
235
228
  {
236
229
  if(isOverride)
237
230
  {
238
231
  this.overrideSoundfont = new SoundFont2(buffer);
232
+ // assign sample offset
233
+ this.overrideSoundfont.setSampleIDOffset(this.soundfontManager.totalSoundfontOffset)
239
234
  }
240
235
  else
241
236
  {
242
- this.soundfont = new SoundFont2(buffer);
237
+ this.soundfontManager.reloadManager(buffer);
243
238
  }
244
239
  }
245
240
  catch (e)
@@ -58,36 +58,37 @@ export function renderVoice(
58
58
  let targetKey = voice.targetKey;
59
59
 
60
60
  // calculate tuning
61
- let cents = voice.modulatedGenerators[generatorTypes.fineTune]
62
- + channel.customControllers[customControllers.channelTuning]
63
- + channel.customControllers[customControllers.channelTransposeFine]
64
- + channel.customControllers[customControllers.masterTuning]
65
- + channel.channelOctaveTuning[voice.midiNote % 12];
66
- let semitones = voice.modulatedGenerators[generatorTypes.coarseTune]
67
- + channel.customControllers[customControllers.channelTuningSemitones];
61
+ let cents = voice.modulatedGenerators[generatorTypes.fineTune] // soundfont fine tune
62
+ + channel.customControllers[customControllers.channelTuning] // RPN channel fine tuning
63
+ + channel.customControllers[customControllers.channelTransposeFine] // custom tuning (synth.transpose)
64
+ + channel.customControllers[customControllers.masterTuning] // master tuning, set by sysEx
65
+ + channel.channelOctaveTuning[voice.midiNote % 12]; // MTS octave tuning
66
+ let semitones = voice.modulatedGenerators[generatorTypes.coarseTune] // soundfont coarse tuning
67
+ + channel.customControllers[customControllers.channelTuningSemitones]; // RPN channel coarse tuning
68
68
 
69
69
  // midi tuning standard
70
70
  const tuning = this.tunings[channel.preset.program]?.[targetKey];
71
71
  if(tuning?.midiNote >= 0)
72
72
  {
73
+ // override key
73
74
  targetKey = tuning.midiNote;
75
+ // add microtonal tuning
74
76
  cents += tuning.centTuning;
75
77
  }
76
78
 
77
- // calculate tuning by key
79
+ // calculate tuning by key using soundfont's scale tuning
78
80
  cents += (targetKey - voice.sample.rootKey) * voice.modulatedGenerators[generatorTypes.scaleTuning];
79
81
 
80
82
  // vibrato LFO
81
83
  const vibratoDepth = voice.modulatedGenerators[generatorTypes.vibLfoToPitch];
82
84
  if(vibratoDepth !== 0)
83
85
  {
86
+ // calculate start time and lfo value
84
87
  const vibStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayVibLFO]);
85
88
  const vibFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqVibLFO]);
86
89
  const lfoVal = getLFOValue(vibStart, vibFreqHz, currentTime);
87
- if(lfoVal)
88
- {
89
- cents += lfoVal * (vibratoDepth * channel.customControllers[customControllers.modulationMultiplier]);
90
- }
90
+ // use modulation multiplier (RPN modulation depth)
91
+ cents += lfoVal * (vibratoDepth * channel.customControllers[customControllers.modulationMultiplier]);
91
92
  }
92
93
 
93
94
  // lowpass frequency
@@ -100,17 +101,22 @@ export function renderVoice(
100
101
  let modLfoCentibels = 0;
101
102
  if(modPitchDepth + modFilterDepth + modVolDepth !== 0)
102
103
  {
104
+ // calculate start time and lfo value
103
105
  const modStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayModLFO]);
104
106
  const modFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqModLFO]);
105
107
  const modLfoValue = getLFOValue(modStart, modFreqHz, currentTime);
108
+ // use modulation multiplier (RPN modulation depth)
106
109
  cents += modLfoValue * (modPitchDepth * channel.customControllers[customControllers.modulationMultiplier]);
110
+ // volenv volume offset
107
111
  modLfoCentibels = modLfoValue * modVolDepth;
112
+ // lowpass frequency
108
113
  lowpassCents += modLfoValue * modFilterDepth;
109
114
  }
110
115
 
111
116
  // channel vibrato (GS NRPN)
112
117
  if(channel.channelVibrato.depth > 0)
113
118
  {
119
+ // same as others
114
120
  const channelVibrato = getLFOValue(voice.startTime + channel.channelVibrato.delay, channel.channelVibrato.rate, currentTime);
115
121
  if(channelVibrato)
116
122
  {
@@ -122,6 +128,7 @@ export function renderVoice(
122
128
  const modEnvPitchDepth = voice.modulatedGenerators[generatorTypes.modEnvToPitch];
123
129
  const modEnvFilterDepth = voice.modulatedGenerators[generatorTypes.modEnvToFilterFc];
124
130
  const modEnv = getModEnvValue(voice, currentTime);
131
+ // apply values
125
132
  lowpassCents += modEnv * modEnvFilterDepth;
126
133
  cents += modEnv * modEnvPitchDepth;
127
134
 
@@ -152,6 +159,7 @@ export function renderVoice(
152
159
  voice.currentPan += (pan - voice.currentPan) * this.panSmoothingFactor; // smooth out pan to prevent clicking
153
160
  const panLeft = Math.cos(HALF_PI * voice.currentPan) * this.panLeft;
154
161
  const panRight = Math.sin(HALF_PI * voice.currentPan) * this.panRight;
162
+ // disable reverb and chorus in one output mode
155
163
  const reverb = this.oneOutputMode ? 0 : voice.modulatedGenerators[generatorTypes.reverbEffectsSend];
156
164
  const chorus = this.oneOutputMode ? 0 : voice.modulatedGenerators[generatorTypes.chorusEffectsSend];
157
165
  panVoice(
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @enum {number}
3
+ */
4
+ export const WorkletSoundfontManagerMessageType = {
5
+ reloadSoundFont: 0, // buffer<ArrayBuffer>
6
+ addNewSoundFont: 2, // [buffer<ArrayBuffer>, id<string>, bankOffset<number>]
7
+ deleteSoundFont: 3, // id<string>
8
+ rearrangeSoundFonts: 4, // newOrder<string[]> // where string is the id
9
+ }