spessasynth_lib 3.25.21 → 3.25.22

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 (80) hide show
  1. package/index.js +7 -7
  2. package/{midi_parser → midi}/basic_midi.js +6 -4
  3. package/{midi_parser → midi}/midi_loader.js +1 -1
  4. package/midi/midi_tools/get_note_times.js +154 -0
  5. package/{midi_parser → midi/midi_tools}/midi_editor.js +8 -8
  6. package/{midi_parser → midi/midi_tools}/midi_writer.js +3 -3
  7. package/{midi_parser → midi/midi_tools}/rmidi_writer.js +10 -10
  8. package/{midi_parser → midi/midi_tools}/used_keys_loaded.js +7 -7
  9. package/{midi_parser → midi}/xmf_loader.js +1 -1
  10. package/package.json +1 -1
  11. package/sequencer/sequencer_engine/events.js +1 -1
  12. package/sequencer/sequencer_engine/play.js +3 -5
  13. package/sequencer/sequencer_engine/process_event.js +1 -1
  14. package/sequencer/sequencer_engine/sequencer_engine.js +1 -1
  15. package/sequencer/sequencer_engine/song_control.js +3 -3
  16. package/sequencer/worklet_wrapper/sequencer.js +3 -3
  17. package/soundfont/basic_soundfont/modulator.js +1 -1
  18. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +1 -1
  19. package/soundfont/dls/articulator_converter.js +1 -1
  20. package/synthetizer/audio_engine/README.md +5 -5
  21. package/synthetizer/audio_engine/{worklet_utilities/worklet_modulator.js → engine_components/compute_modulator.js} +12 -12
  22. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/controller_tables.js +1 -1
  23. package/synthetizer/audio_engine/{worklet_methods/worklet_key_modifier.js → engine_components/key_modifier_manager.js} +24 -32
  24. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/lowpass_filter.js +1 -1
  25. package/synthetizer/audio_engine/{worklet_utilities/worklet_processor_channel.js → engine_components/midi_audio_channel.js} +43 -43
  26. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/modulation_envelope.js +6 -6
  27. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/stereo_panner.js +3 -3
  28. package/synthetizer/audio_engine/{worklet_utilities/worklet_voice.js → engine_components/voice.js} +43 -37
  29. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/volume_envelope.js +17 -17
  30. package/synthetizer/audio_engine/{worklet_utilities → engine_components}/wavetable_oscillator.js +3 -3
  31. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/controller_control/controller_change.js +4 -4
  32. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +48 -0
  33. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/controller_control/reset_controllers.js +6 -6
  34. package/synthetizer/audio_engine/{worklet_methods/create_worklet_channel.js → engine_methods/create_midi_channel.js} +4 -4
  35. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/data_entry/data_entry_coarse.js +3 -3
  36. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/data_entry/data_entry_fine.js +3 -3
  37. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/mute_channel.js +1 -1
  38. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/note_on.js +10 -4
  39. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/program_change.js +1 -1
  40. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/render_voice.js +13 -13
  41. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/stopping_notes/kill_note.js +1 -1
  42. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/stopping_notes/note_off.js +1 -1
  43. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/stopping_notes/stop_all_notes.js +1 -1
  44. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/stopping_notes/voice_killing.js +2 -2
  45. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/system_exclusive.js +4 -3
  46. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/channel_pressure.js +3 -3
  47. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/pitch_wheel.js +3 -3
  48. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/poly_pressure.js +2 -2
  49. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/set_master_tuning.js +1 -1
  50. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/set_modulation_depth.js +2 -2
  51. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/set_octave_tuning.js +1 -1
  52. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/set_tuning.js +2 -2
  53. package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/transpose_channel.js +3 -3
  54. package/synthetizer/audio_engine/main_processor.js +49 -44
  55. package/synthetizer/audio_engine/message_protocol/worklet_message.js +1 -12
  56. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +3 -2
  57. package/synthetizer/worklet_processor.min.js +12 -12
  58. package/synthetizer/worklet_wrapper/key_modifier_manager.js +6 -4
  59. package/synthetizer/worklet_wrapper/synth_soundfont_manager.js +1 -1
  60. package/synthetizer/worklet_wrapper/synthetizer.js +6 -6
  61. package/synthetizer/worklet_wrapper/worklet_processor.js +26 -24
  62. package/synthetizer/audio_engine/worklet_methods/controller_control/master_parameters.js +0 -36
  63. /package/{midi_parser → midi}/README.md +0 -0
  64. /package/{midi_parser → midi}/midi_builder.js +0 -0
  65. /package/{midi_parser → midi}/midi_data.js +0 -0
  66. /package/{midi_parser → midi}/midi_message.js +0 -0
  67. /package/{midi_parser → midi}/midi_sequence.js +0 -0
  68. /package/synthetizer/audio_engine/{worklet_utilities → engine_components}/lfo.js +0 -0
  69. /package/synthetizer/audio_engine/{worklet_utilities → engine_components}/modulator_curves.js +0 -0
  70. /package/synthetizer/audio_engine/{worklet_methods/worklet_soundfont_manager → engine_components/soundfont_manager}/sfman_message.js +0 -0
  71. /package/synthetizer/audio_engine/{worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js → engine_components/soundfont_manager/soundfont_manager.js} +0 -0
  72. /package/synthetizer/audio_engine/{worklet_utilities → engine_components}/unit_converter.js +0 -0
  73. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/portamento_time.js +0 -0
  74. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/soundfont_management/clear_sound_font.js +0 -0
  75. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/soundfont_management/get_preset.js +0 -0
  76. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/soundfont_management/reload_sound_font.js +0 -0
  77. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/soundfont_management/send_preset_list.js +0 -0
  78. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/soundfont_management/set_embedded_sound_font.js +0 -0
  79. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/stopping_notes/stop_all_channels.js +0 -0
  80. /package/synthetizer/audio_engine/{worklet_methods → engine_methods}/tuning_control/transpose_all_channels.js +0 -0
@@ -9,25 +9,25 @@ import {
9
9
  resetControllers,
10
10
  resetControllersRP15Compliant,
11
11
  resetParameters
12
- } from "../worklet_methods/controller_control/reset_controllers.js";
13
- import { renderVoice } from "../worklet_methods/render_voice.js";
12
+ } from "../engine_methods/controller_control/reset_controllers.js";
13
+ import { renderVoice } from "../engine_methods/render_voice.js";
14
14
  import { panVoice } from "./stereo_panner.js";
15
- import { killNote } from "../worklet_methods/stopping_notes/kill_note.js";
16
- import { setTuning } from "../worklet_methods/tuning_control/set_tuning.js";
17
- import { setModulationDepth } from "../worklet_methods/tuning_control/set_modulation_depth.js";
18
- import { dataEntryFine } from "../worklet_methods/data_entry/data_entry_fine.js";
19
- import { controllerChange } from "../worklet_methods/controller_control/controller_change.js";
20
- import { stopAllNotes } from "../worklet_methods/stopping_notes/stop_all_notes.js";
21
- import { muteChannel } from "../worklet_methods/mute_channel.js";
22
- import { transposeChannel } from "../worklet_methods/tuning_control/transpose_channel.js";
23
- import { dataEntryCoarse } from "../worklet_methods/data_entry/data_entry_coarse.js";
24
- import { noteOn } from "../worklet_methods/note_on.js";
25
- import { noteOff } from "../worklet_methods/stopping_notes/note_off.js";
26
- import { polyPressure } from "../worklet_methods/tuning_control/poly_pressure.js";
27
- import { channelPressure } from "../worklet_methods/tuning_control/channel_pressure.js";
28
- import { pitchWheel } from "../worklet_methods/tuning_control/pitch_wheel.js";
29
- import { setOctaveTuning } from "../worklet_methods/tuning_control/set_octave_tuning.js";
30
- import { programChange } from "../worklet_methods/program_change.js";
15
+ import { killNote } from "../engine_methods/stopping_notes/kill_note.js";
16
+ import { setTuning } from "../engine_methods/tuning_control/set_tuning.js";
17
+ import { setModulationDepth } from "../engine_methods/tuning_control/set_modulation_depth.js";
18
+ import { dataEntryFine } from "../engine_methods/data_entry/data_entry_fine.js";
19
+ import { controllerChange } from "../engine_methods/controller_control/controller_change.js";
20
+ import { stopAllNotes } from "../engine_methods/stopping_notes/stop_all_notes.js";
21
+ import { muteChannel } from "../engine_methods/mute_channel.js";
22
+ import { transposeChannel } from "../engine_methods/tuning_control/transpose_channel.js";
23
+ import { dataEntryCoarse } from "../engine_methods/data_entry/data_entry_coarse.js";
24
+ import { noteOn } from "../engine_methods/note_on.js";
25
+ import { noteOff } from "../engine_methods/stopping_notes/note_off.js";
26
+ import { polyPressure } from "../engine_methods/tuning_control/poly_pressure.js";
27
+ import { channelPressure } from "../engine_methods/tuning_control/channel_pressure.js";
28
+ import { pitchWheel } from "../engine_methods/tuning_control/pitch_wheel.js";
29
+ import { setOctaveTuning } from "../engine_methods/tuning_control/set_octave_tuning.js";
30
+ import { programChange } from "../engine_methods/program_change.js";
31
31
  import { chooseBank, isSystemXG, parseBankSelect } from "../../../utils/xg_hacks.js";
32
32
  import { DEFAULT_PERCUSSION } from "../../synth_constants.js";
33
33
  import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
@@ -36,7 +36,7 @@ import { returnMessageType } from "../message_protocol/worklet_message.js";
36
36
  /**
37
37
  * This class represents a single MIDI Channel within the synthesizer.
38
38
  */
39
- class WorkletProcessorChannel
39
+ class MidiAudioChannel
40
40
  {
41
41
  /**
42
42
  * An array of MIDI controller values and values used by modulators as the source (e.g., pitch bend, bend range, etc.).
@@ -177,13 +177,13 @@ class WorkletProcessorChannel
177
177
 
178
178
  /**
179
179
  * An array of voices currently active on the channel.
180
- * @type {WorkletVoice[]}
180
+ * @type {Voice[]}
181
181
  */
182
182
  voices = [];
183
183
 
184
184
  /**
185
185
  * An array of voices that are sustained on the channel.
186
- * @type {WorkletVoice[]}
186
+ * @type {Voice[]}
187
187
  */
188
188
  sustainedVoices = [];
189
189
 
@@ -440,32 +440,32 @@ class WorkletProcessorChannel
440
440
  }
441
441
 
442
442
  // voice
443
- WorkletProcessorChannel.prototype.renderVoice = renderVoice;
444
- WorkletProcessorChannel.prototype.panVoice = panVoice;
445
- WorkletProcessorChannel.prototype.killNote = killNote;
446
- WorkletProcessorChannel.prototype.stopAllNotes = stopAllNotes;
447
- WorkletProcessorChannel.prototype.muteChannel = muteChannel;
443
+ MidiAudioChannel.prototype.renderVoice = renderVoice;
444
+ MidiAudioChannel.prototype.panVoice = panVoice;
445
+ MidiAudioChannel.prototype.killNote = killNote;
446
+ MidiAudioChannel.prototype.stopAllNotes = stopAllNotes;
447
+ MidiAudioChannel.prototype.muteChannel = muteChannel;
448
448
 
449
449
  // MIDI messages
450
- WorkletProcessorChannel.prototype.noteOn = noteOn;
451
- WorkletProcessorChannel.prototype.noteOff = noteOff;
452
- WorkletProcessorChannel.prototype.polyPressure = polyPressure;
453
- WorkletProcessorChannel.prototype.channelPressure = channelPressure;
454
- WorkletProcessorChannel.prototype.pitchWheel = pitchWheel;
455
- WorkletProcessorChannel.prototype.programChange = programChange;
450
+ MidiAudioChannel.prototype.noteOn = noteOn;
451
+ MidiAudioChannel.prototype.noteOff = noteOff;
452
+ MidiAudioChannel.prototype.polyPressure = polyPressure;
453
+ MidiAudioChannel.prototype.channelPressure = channelPressure;
454
+ MidiAudioChannel.prototype.pitchWheel = pitchWheel;
455
+ MidiAudioChannel.prototype.programChange = programChange;
456
456
 
457
457
  // Tuning
458
- WorkletProcessorChannel.prototype.setTuning = setTuning;
459
- WorkletProcessorChannel.prototype.setOctaveTuning = setOctaveTuning;
460
- WorkletProcessorChannel.prototype.setModulationDepth = setModulationDepth;
461
- WorkletProcessorChannel.prototype.transposeChannel = transposeChannel;
458
+ MidiAudioChannel.prototype.setTuning = setTuning;
459
+ MidiAudioChannel.prototype.setOctaveTuning = setOctaveTuning;
460
+ MidiAudioChannel.prototype.setModulationDepth = setModulationDepth;
461
+ MidiAudioChannel.prototype.transposeChannel = transposeChannel;
462
462
 
463
463
  // CC
464
- WorkletProcessorChannel.prototype.controllerChange = controllerChange;
465
- WorkletProcessorChannel.prototype.resetControllers = resetControllers;
466
- WorkletProcessorChannel.prototype.resetControllersRP15Compliant = resetControllersRP15Compliant;
467
- WorkletProcessorChannel.prototype.resetParameters = resetParameters;
468
- WorkletProcessorChannel.prototype.dataEntryFine = dataEntryFine;
469
- WorkletProcessorChannel.prototype.dataEntryCoarse = dataEntryCoarse;
464
+ MidiAudioChannel.prototype.controllerChange = controllerChange;
465
+ MidiAudioChannel.prototype.resetControllers = resetControllers;
466
+ MidiAudioChannel.prototype.resetControllersRP15Compliant = resetControllersRP15Compliant;
467
+ MidiAudioChannel.prototype.resetParameters = resetParameters;
468
+ MidiAudioChannel.prototype.dataEntryFine = dataEntryFine;
469
+ MidiAudioChannel.prototype.dataEntryCoarse = dataEntryCoarse;
470
470
 
471
- export { WorkletProcessorChannel };
471
+ export { MidiAudioChannel };
@@ -17,7 +17,7 @@ for (let i = 0; i < CONVEX_ATTACK.length; i++)
17
17
  CONVEX_ATTACK[i] = getModulatorCurveValue(0, modulatorCurveTypes.convex, i / 1000, 0);
18
18
  }
19
19
 
20
- export class WorkletModulationEnvelope
20
+ export class ModulationEnvelope
21
21
  {
22
22
  /**
23
23
  * The attack duration, in seconds
@@ -83,15 +83,15 @@ export class WorkletModulationEnvelope
83
83
 
84
84
  /**
85
85
  * Starts the release phase in the envelope
86
- * @param voice {WorkletVoice} the voice this envelope belongs to
86
+ * @param voice {Voice} the voice this envelope belongs to
87
87
  */
88
88
  static startRelease(voice)
89
89
  {
90
- WorkletModulationEnvelope.recalculate(voice);
90
+ ModulationEnvelope.recalculate(voice);
91
91
  }
92
92
 
93
93
  /**
94
- * @param voice {WorkletVoice} the voice to recalculate
94
+ * @param voice {Voice} the voice to recalculate
95
95
  */
96
96
  static recalculate(voice)
97
97
  {
@@ -100,7 +100,7 @@ export class WorkletModulationEnvelope
100
100
  // in release? Might need to recalculate the value as it can be modulated
101
101
  if (voice.isInRelease)
102
102
  {
103
- env.releaseStartLevel = WorkletModulationEnvelope.getValue(voice, voice.releaseStartTime, true);
103
+ env.releaseStartLevel = ModulationEnvelope.getValue(voice, voice.releaseStartTime, true);
104
104
  }
105
105
 
106
106
  env.sustainLevel = 1 - (voice.modulatedGenerators[generatorTypes.sustainModEnv] / 1000);
@@ -130,7 +130,7 @@ export class WorkletModulationEnvelope
130
130
 
131
131
  /**
132
132
  * Calculates the current modulation envelope value for the given time and voice
133
- * @param voice {WorkletVoice} the voice we are working on
133
+ * @param voice {Voice} the voice we are working on
134
134
  * @param currentTime {number} in seconds
135
135
  * @param ignoreRelease {boolean} if true, it will compute the value as if the voice was not released
136
136
  * @returns {number} modenv value, from 0 to 1
@@ -29,7 +29,7 @@ for (let pan = MIN_PAN; pan <= MAX_PAN; pan++)
29
29
 
30
30
  /**
31
31
  * Pans the voice to the given output buffers
32
- * @param voice {WorkletVoice} the voice to pan
32
+ * @param voice {Voice} the voice to pan
33
33
  * @param inputBuffer {Float32Array} the input buffer in mono
34
34
  * @param outputLeft {Float32Array} left output buffer
35
35
  * @param outputRight {Float32Array} right output buffer
@@ -37,7 +37,7 @@ for (let pan = MIN_PAN; pan <= MAX_PAN; pan++)
37
37
  * @param reverbRight {Float32Array} right reverb input
38
38
  * @param chorusLeft {Float32Array} left chorus buffer
39
39
  * @param chorusRight {Float32Array} right chorus buffer
40
- * @this {WorkletProcessorChannel}
40
+ * @this {MidiAudioChannel}
41
41
  */
42
42
  export function panVoice(voice,
43
43
  inputBuffer,
@@ -65,7 +65,7 @@ export function panVoice(voice,
65
65
  pan = voice.currentPan;
66
66
  }
67
67
 
68
- const gain = this.synth.currentGain;
68
+ const gain = this.synth.currentGain * voice.gain;
69
69
  const index = ~~(pan + 500);
70
70
  // get voice's gain levels for each channel
71
71
  const gainLeft = panTableLeft[index] * gain * this.synth.panLeft;
@@ -1,13 +1,13 @@
1
1
  /**
2
- * worklet_voice.js
3
- * purpose: prepares workletvoices from sample and generator data and manages sample dumping
2
+ * voice.js
3
+ * purpose: prepares Voices from sample and generator data and manages sample dumping
4
4
  * note: sample dumping means sending it over to the AudioWorkletGlobalScope
5
5
  */
6
6
  import { MIN_EXCLUSIVE_LENGTH, MIN_NOTE_LENGTH } from "../main_processor.js";
7
7
  import { SpessaSynthWarn } from "../../../utils/loggin.js";
8
8
  import { WorkletLowpassFilter } from "./lowpass_filter.js";
9
- import { WorkletVolumeEnvelope } from "./volume_envelope.js";
10
- import { WorkletModulationEnvelope } from "./modulation_envelope.js";
9
+ import { VolumeEnvelope } from "./volume_envelope.js";
10
+ import { ModulationEnvelope } from "./modulation_envelope.js";
11
11
  import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
12
12
  import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
13
13
  import { isSystemXG } from "../../../utils/xg_hacks.js";
@@ -15,7 +15,7 @@ import { isSystemXG } from "../../../utils/xg_hacks.js";
15
15
  const EXCLUSIVE_CUTOFF_TIME = -2320;
16
16
  const EXCLUSIVE_MOD_CUTOFF_TIME = -1130; // less because filter shenanigans
17
17
 
18
- class WorkletSample
18
+ class AudioSample
19
19
  {
20
20
  /**
21
21
  * the sample's audio data
@@ -102,7 +102,7 @@ class WorkletSample
102
102
 
103
103
 
104
104
  /**
105
- * WorkletVoice represents a single instance of the
105
+ * Voice represents a single instance of the
106
106
  * SoundFont2 synthesis model.
107
107
  * That is:
108
108
  * A wavetable oscillator (sample)
@@ -112,11 +112,11 @@ class WorkletSample
112
112
  * Modulators (modulators)
113
113
  * And MIDI params such as channel, MIDI note, velocity
114
114
  */
115
- class WorkletVoice
115
+ class Voice
116
116
  {
117
117
  /**
118
118
  * The sample of the voice.
119
- * @type {WorkletSample}
119
+ * @type {AudioSample}
120
120
  */
121
121
  sample;
122
122
 
@@ -126,6 +126,12 @@ class WorkletVoice
126
126
  */
127
127
  filter;
128
128
 
129
+ /**
130
+ * Linear gain of the voice. Used with Key Modifiers.
131
+ * @type {number}
132
+ */
133
+ gain = 1;
134
+
129
135
  /**
130
136
  * The unmodulated (copied to) generators of the voice.
131
137
  * @type {Int16Array}
@@ -189,13 +195,13 @@ class WorkletVoice
189
195
 
190
196
  /**
191
197
  * Modulation envelope.
192
- * @type {WorkletModulationEnvelope}
198
+ * @type {ModulationEnvelope}
193
199
  */
194
- modulationEnvelope = new WorkletModulationEnvelope();
200
+ modulationEnvelope = new ModulationEnvelope();
195
201
 
196
202
  /**
197
203
  * Volume envelope.
198
- * @type {WorkletVolumeEnvelope}
204
+ * @type {VolumeEnvelope}
199
205
  */
200
206
  volumeEnvelope;
201
207
 
@@ -262,9 +268,9 @@ class WorkletVoice
262
268
  exclusiveClass = 0;
263
269
 
264
270
  /**
265
- * Creates a workletVoice
271
+ * Creates a Voice
266
272
  * @param sampleRate {number}
267
- * @param workletSample {WorkletSample}
273
+ * @param workletSample {AudioSample}
268
274
  * @param midiNote {number}
269
275
  * @param velocity {number}
270
276
  * @param channel {number}
@@ -300,19 +306,19 @@ class WorkletVoice
300
306
  this.startTime = currentTime;
301
307
  this.targetKey = targetKey;
302
308
  this.realKey = realKey;
303
- this.volumeEnvelope = new WorkletVolumeEnvelope(sampleRate, generators[generatorTypes.sustainVolEnv]);
309
+ this.volumeEnvelope = new VolumeEnvelope(sampleRate, generators[generatorTypes.sustainVolEnv]);
304
310
  }
305
311
 
306
312
  /**
307
313
  * copies the voice
308
- * @param voice {WorkletVoice}
314
+ * @param voice {Voice}
309
315
  * @param currentTime {number}
310
- * @returns WorkletVoice
316
+ * @returns Voice
311
317
  */
312
318
  static copy(voice, currentTime)
313
319
  {
314
320
  const sampleToCopy = voice.sample;
315
- const sample = new WorkletSample(
321
+ const sample = new AudioSample(
316
322
  sampleToCopy.sampleData,
317
323
  sampleToCopy.playbackStep,
318
324
  sampleToCopy.cursor,
@@ -322,7 +328,7 @@ class WorkletVoice
322
328
  sampleToCopy.end,
323
329
  sampleToCopy.loopingMode
324
330
  );
325
- return new WorkletVoice(
331
+ return new Voice(
326
332
  voice.volumeEnvelope.sampleRate,
327
333
  sample,
328
334
  voice.midiNote,
@@ -345,8 +351,8 @@ class WorkletVoice
345
351
  this.release(currentTime, MIN_EXCLUSIVE_LENGTH);
346
352
  this.modulatedGenerators[generatorTypes.releaseVolEnv] = EXCLUSIVE_CUTOFF_TIME; // make the release nearly instant
347
353
  this.modulatedGenerators[generatorTypes.releaseModEnv] = EXCLUSIVE_MOD_CUTOFF_TIME;
348
- WorkletVolumeEnvelope.recalculate(this);
349
- WorkletModulationEnvelope.recalculate(this);
354
+ VolumeEnvelope.recalculate(this);
355
+ ModulationEnvelope.recalculate(this);
350
356
  }
351
357
 
352
358
  /**
@@ -371,17 +377,17 @@ class WorkletVoice
371
377
  * @param velocity {number} the velocity to use
372
378
  * @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
373
379
  * @this {SpessaSynthProcessor}
374
- * @returns {WorkletVoice[]} output is an array of WorkletVoices
380
+ * @returns {Voice[]} output is an array of Voices
375
381
  */
376
- export function getWorkletVoices(channel,
377
- midiNote,
378
- velocity,
379
- realKey)
382
+ export function getVoices(channel,
383
+ midiNote,
384
+ velocity,
385
+ realKey)
380
386
  {
381
387
  /**
382
- * @type {WorkletVoice[]}
388
+ * @type {Voice[]}
383
389
  */
384
- let workletVoices;
390
+ let voices;
385
391
  const channelObject = this.midiAudioChannels[channel];
386
392
 
387
393
  // override patch
@@ -401,7 +407,7 @@ export function getWorkletVoices(channel,
401
407
  // if cached, return it!
402
408
  if (cached !== undefined)
403
409
  {
404
- return cached.map(v => WorkletVoice.copy(v, this.currentSynthTime));
410
+ return cached.map(v => Voice.copy(v, this.currentSynthTime));
405
411
  }
406
412
 
407
413
  // not cached...
@@ -411,9 +417,9 @@ export function getWorkletVoices(channel,
411
417
  preset = this.soundfontManager.getPreset(bank, program, isSystemXG(this.system));
412
418
  }
413
419
  /**
414
- * @returns {WorkletVoice[]}
420
+ * @returns {Voice[]}
415
421
  */
416
- workletVoices = preset.getSamplesAndGenerators(midiNote, velocity)
422
+ voices = preset.getSamplesAndGenerators(midiNote, velocity)
417
423
  .reduce((voices, sampleAndGenerators) =>
418
424
  {
419
425
  if (sampleAndGenerators.sample.getAudioData() === undefined)
@@ -457,9 +463,9 @@ export function getWorkletVoices(channel,
457
463
  /**
458
464
  * create the worklet sample
459
465
  * offsets are calculated at note on time (to allow for modulation of them)
460
- * @type {WorkletSample}
466
+ * @type {AudioSample}
461
467
  */
462
- const workletSample = new WorkletSample(
468
+ const workletSample = new AudioSample(
463
469
  sampleAndGenerators.sample.sampleData,
464
470
  (sampleAndGenerators.sample.sampleRate / this.sampleRate) * Math.pow(
465
471
  2,
@@ -486,12 +492,12 @@ export function getWorkletVoices(channel,
486
492
  // Velocity: velocity,
487
493
  // TargetKey: targetKey,
488
494
  // MidiNote: midiNote,
489
- // WorkletSample: workletSample
495
+ // AudioSample: workletSample
490
496
  // }]);
491
497
 
492
498
 
493
499
  voices.push(
494
- new WorkletVoice(
500
+ new Voice(
495
501
  this.sampleRate,
496
502
  workletSample,
497
503
  midiNote,
@@ -507,7 +513,7 @@ export function getWorkletVoices(channel,
507
513
  return voices;
508
514
  }, []);
509
515
  // cache the voice
510
- this.setCachedVoice(bank, program, midiNote, velocity, workletVoices.map(v =>
511
- WorkletVoice.copy(v, this.currentSynthTime)));
512
- return workletVoices;
516
+ this.setCachedVoice(bank, program, midiNote, velocity, voices.map(v =>
517
+ Voice.copy(v, this.currentSynthTime)));
518
+ return voices;
513
519
  }
@@ -21,10 +21,10 @@ const PERCEIVED_GAIN_SILENCE = 0.000015; // can't go lower than that (see #50)
21
21
  * 2 - hold/peak
22
22
  * 3 - decay
23
23
  * 4 - sustain
24
- * release is indicated by isInRelease property
24
+ * release indicates by isInRelease property
25
25
  */
26
26
 
27
- export class WorkletVolumeEnvelope
27
+ export class VolumeEnvelope
28
28
  {
29
29
  /**
30
30
  * The envelope's current time in samples
@@ -97,22 +97,22 @@ export class WorkletVolumeEnvelope
97
97
  */
98
98
  sustainDbRelative = 0;
99
99
  /**
100
- * The time in samples to the end of delay stage, relative to start of the envelope
100
+ * The time in samples to the end of delay stage, relative to the start of the envelope
101
101
  * @type {number}
102
102
  */
103
103
  delayEnd = 0;
104
104
  /**
105
- * The time in samples to the end of attack stage, relative to start of the envelope
105
+ * The time in samples to the end of attack stage, relative to the start of the envelope
106
106
  * @type {number}
107
107
  */
108
108
  attackEnd = 0;
109
109
  /**
110
- * The time in samples to the end of hold stage, relative to start of the envelope
110
+ * The time in samples to the end of hold stage, relative to the start of the envelope
111
111
  * @type {number}
112
112
  */
113
113
  holdEnd = 0;
114
114
  /**
115
- * The time in samples to the end of decay stage, relative to start of the envelope
115
+ * The time in samples to the end of decay stage, relative to the start of the envelope
116
116
  * @type {number}
117
117
  */
118
118
  decayEnd = 0;
@@ -127,7 +127,7 @@ export class WorkletVolumeEnvelope
127
127
  /**
128
128
  * if sustain stge is silent,
129
129
  * then we can turn off the voice when it is silent.
130
- * We can't do that with modulated as it can silence the volume and then raise it again and the voice must keep playing
130
+ * We can't do that with modulated as it can silence the volume and then raise it again, and the voice must keep playing
131
131
  * @type {boolean}
132
132
  */
133
133
  this.canEndOnSilentSustain = initialDecay / 10 >= PERCEIVED_DB_SILENCE;
@@ -135,18 +135,18 @@ export class WorkletVolumeEnvelope
135
135
 
136
136
  /**
137
137
  * Starts the release phase in the envelope
138
- * @param voice {WorkletVoice} the voice this envelope belongs to
138
+ * @param voice {Voice} the voice this envelope belongs to
139
139
  */
140
140
  static startRelease(voice)
141
141
  {
142
142
  voice.volumeEnvelope.releaseStartTimeSamples = voice.volumeEnvelope.currentSampleTime;
143
143
  voice.volumeEnvelope.currentReleaseGain = decibelAttenuationToGain(voice.volumeEnvelope.currentAttenuationDb);
144
- WorkletVolumeEnvelope.recalculate(voice);
144
+ VolumeEnvelope.recalculate(voice);
145
145
  }
146
146
 
147
147
  /**
148
148
  * Recalculates the envelope
149
- * @param voice {WorkletVoice} the voice this envelope belongs to
149
+ * @param voice {Voice} the voice this envelope belongs to
150
150
  */
151
151
  static recalculate(voice)
152
152
  {
@@ -167,8 +167,8 @@ export class WorkletVolumeEnvelope
167
167
  // calculate durations
168
168
  env.attackDuration = timecentsToSamples(voice.modulatedGenerators[generatorTypes.attackVolEnv]);
169
169
 
170
- // decay: sfspec page 35: the time is for change from attenuation to -100dB
171
- // therefore we need to calculate the real time
170
+ // decay: sfspec page 35: the time is for change from attenuation to -100dB,
171
+ // therefore, we need to calculate the real time
172
172
  // (changing from attenuation to sustain instead of -100dB)
173
173
  const fullChange = voice.modulatedGenerators[generatorTypes.decayVolEnv];
174
174
  const keyNumAddition = (60 - voice.targetKey) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvDecay];
@@ -181,7 +181,7 @@ export class WorkletVolumeEnvelope
181
181
  env.delayEnd = timecentsToSamples(voice.modulatedGenerators[generatorTypes.delayVolEnv]);
182
182
  env.attackEnd = env.attackDuration + env.delayEnd;
183
183
 
184
- // make sure to take keyNumToVolEnvHold into account!!!
184
+ // make sure to take keyNumToVolEnvHold into account!
185
185
  const holdExcursion = (60 - voice.targetKey) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvHold];
186
186
  env.holdEnd = timecentsToSamples(voice.modulatedGenerators[generatorTypes.holdVolEnv]
187
187
  + holdExcursion)
@@ -217,7 +217,7 @@ export class WorkletVolumeEnvelope
217
217
  // (to make volume go down exponentially)
218
218
  // attack is linear (in gain) so we need to do get db from that
219
219
  let elapsed = 1 - ((env.attackEnd - env.releaseStartTimeSamples) / env.attackDuration);
220
- // calculate the gain that the attack would have
220
+ // calculate the gain that the attack would have, so
221
221
  // turn that into db
222
222
  env.releaseStartDb = 20 * Math.log10(elapsed) * -1;
223
223
  break;
@@ -241,8 +241,8 @@ export class WorkletVolumeEnvelope
241
241
  }
242
242
  env.currentReleaseGain = decibelAttenuationToGain(env.releaseStartDb);
243
243
 
244
- // release: sfspec page 35: the time is for change from attenuation to -100dB
245
- // therefore we need to calculate the real time
244
+ // release: sfspec page 35: the time is for change from attenuation to -100dB,
245
+ // therefore, we need to calculate the real time
246
246
  // (changing from release start to -100dB instead of from peak to -100dB)
247
247
  const releaseFraction = (DB_SILENCE - env.releaseStartDb) / DB_SILENCE;
248
248
  env.releaseDuration *= releaseFraction;
@@ -252,7 +252,7 @@ export class WorkletVolumeEnvelope
252
252
 
253
253
  /**
254
254
  * Applies volume envelope gain to the given output buffer
255
- * @param voice {WorkletVoice} the voice we're working on
255
+ * @param voice {Voice} the voice we're working on
256
256
  * @param audioBuffer {Float32Array} the audio buffer to modify
257
257
  * @param centibelOffset {number} the centibel offset of volume, for modLFOtoVolume
258
258
  * @param smoothingFactor {number} the adjusted smoothing factor for the envelope
@@ -19,7 +19,7 @@ export class WavetableOscillator
19
19
 
20
20
  /**
21
21
  * Fills the output buffer with raw sample data using linear interpolation
22
- * @param voice {WorkletVoice} the voice we're working on
22
+ * @param voice {Voice} the voice we're working on
23
23
  * @param outputBuffer {Float32Array} the output buffer to write to
24
24
  */
25
25
  static getSampleLinear(voice, outputBuffer)
@@ -93,7 +93,7 @@ export class WavetableOscillator
93
93
 
94
94
  /**
95
95
  * Fills the output buffer with raw sample data using no interpolation (nearest neighbor)
96
- * @param voice {WorkletVoice} the voice we're working on
96
+ * @param voice {Voice} the voice we're working on
97
97
  * @param outputBuffer {Float32Array} the output buffer to write to
98
98
  */
99
99
  static getSampleNearest(voice, outputBuffer)
@@ -154,7 +154,7 @@ export class WavetableOscillator
154
154
 
155
155
  /**
156
156
  * Fills the output buffer with raw sample data using cubic interpolation
157
- * @param voice {WorkletVoice} the voice we're working on
157
+ * @param voice {Voice} the voice we're working on
158
158
  * @param outputBuffer {Float32Array} the output buffer to write to
159
159
  */
160
160
  static getSampleCubic(voice, outputBuffer)
@@ -1,12 +1,12 @@
1
- import { midiControllers } from "../../../../midi_parser/midi_message.js";
2
- import { computeModulators } from "../../worklet_utilities/worklet_modulator.js";
3
- import { channelConfiguration, dataEntryStates } from "../../worklet_utilities/controller_tables.js";
1
+ import { midiControllers } from "../../../../midi/midi_message.js";
2
+ import { computeModulators } from "../../engine_components/compute_modulator.js";
3
+ import { channelConfiguration, dataEntryStates } from "../../engine_components/controller_tables.js";
4
4
 
5
5
  /**
6
6
  * @param controllerNumber {number}
7
7
  * @param controllerValue {number}
8
8
  * @param force {boolean}
9
- * @this {WorkletProcessorChannel}
9
+ * @this {MidiAudioChannel}
10
10
  */
11
11
  export function controllerChange(controllerNumber, controllerValue, force = false)
12
12
  {
@@ -0,0 +1,48 @@
1
+ import { SYNTHESIZER_GAIN } from "../../main_processor.js";
2
+
3
+ /**
4
+ * @enum {number}
5
+ */
6
+ export const masterParameterType = {
7
+ mainVolume: 0,
8
+ masterPan: 1,
9
+ voicesCap: 2,
10
+ interpolationType: 3,
11
+ midiSystem: 4
12
+ };
13
+
14
+ /**
15
+ * @this {SpessaSynthProcessor}
16
+ * @param type {masterParameterType}
17
+ * @param value {number|string|interpolationTypes}
18
+ */
19
+ export function setMasterParameter(type, value)
20
+ {
21
+ switch (type)
22
+ {
23
+ case masterParameterType.masterPan:
24
+ let pan = value;
25
+ this.pan = pan;
26
+ // clamp to 0-1 (0 is left)
27
+ pan = (pan / 2) + 0.5;
28
+ this.panLeft = (1 - pan);
29
+ this.panRight = (pan);
30
+ break;
31
+
32
+ case masterParameterType.mainVolume:
33
+ this.masterGain = value * SYNTHESIZER_GAIN;
34
+ this.setMasterParameter(masterParameterType.masterPan, this.pan);
35
+ break;
36
+
37
+ case masterParameterType.voicesCap:
38
+ this.voiceCap = value;
39
+ break;
40
+
41
+ case masterParameterType.interpolationType:
42
+ this.interpolationType = value;
43
+ break;
44
+
45
+ case masterParameterType.midiSystem:
46
+ this.setSystem(value);
47
+ }
48
+ }