spessasynth_lib 3.25.23 → 3.26.1

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 (162) hide show
  1. package/README.md +29 -114
  2. package/external_midi/midi_handler.js +14 -14
  3. package/external_midi/web_midi_link.js +3 -3
  4. package/index.js +33 -33
  5. package/package.json +19 -6
  6. package/{midi → sequencer}/midi_data.js +1 -1
  7. package/sequencer/{worklet_wrapper/sequencer.js → sequencer.js} +13 -12
  8. package/sequencer/{worklet_wrapper/sequencer_message.js → sequencer_message.js} +1 -1
  9. package/synthetizer/README.md +29 -1
  10. package/synthetizer/audio_effects/reverb_as_binary.js +2 -2
  11. package/synthetizer/{worklet_wrapper/key_modifier_manager.js → key_modifier_manager.js} +11 -2
  12. package/synthetizer/{worklet_wrapper/synth_event_handler.js → synth_event_handler.js} +16 -13
  13. package/synthetizer/{worklet_wrapper/synth_soundfont_manager.js → synth_soundfont_manager.js} +8 -5
  14. package/synthetizer/{worklet_wrapper/synthetizer.js → synthetizer.js} +29 -23
  15. package/synthetizer/{audio_engine/message_protocol/worklet_message.js → worklet_message.js} +15 -2
  16. package/synthetizer/{worklet_wrapper/worklet_processor.js → worklet_processor.js} +214 -31
  17. package/synthetizer/worklet_processor.min.js +13 -12
  18. package/synthetizer/worklet_processor.min.js.map +7 -0
  19. package/synthetizer/{worklet_wrapper/worklet_url.js → worklet_url.js} +2 -0
  20. package/utils/buffer_to_wav.js +7 -165
  21. package/utils/other.js +3 -84
  22. package/externals/fflate/LICENSE +0 -21
  23. package/externals/fflate/fflate.min.js +0 -1
  24. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  25. package/externals/stbvorbis_sync/LICENSE +0 -202
  26. package/externals/stbvorbis_sync/NOTICE +0 -6
  27. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  28. package/midi/README.md +0 -32
  29. package/midi/basic_midi.js +0 -565
  30. package/midi/midi_builder.js +0 -202
  31. package/midi/midi_loader.js +0 -324
  32. package/midi/midi_message.js +0 -254
  33. package/midi/midi_sequence.js +0 -225
  34. package/midi/midi_tools/get_note_times.js +0 -154
  35. package/midi/midi_tools/midi_editor.js +0 -611
  36. package/midi/midi_tools/midi_writer.js +0 -99
  37. package/midi/midi_tools/rmidi_writer.js +0 -567
  38. package/midi/midi_tools/used_keys_loaded.js +0 -238
  39. package/midi/xmf_loader.js +0 -454
  40. package/sequencer/sequencer_engine/events.js +0 -104
  41. package/sequencer/sequencer_engine/play.js +0 -353
  42. package/sequencer/sequencer_engine/process_event.js +0 -169
  43. package/sequencer/sequencer_engine/process_tick.js +0 -106
  44. package/sequencer/sequencer_engine/sequencer_engine.js +0 -335
  45. package/sequencer/sequencer_engine/song_control.js +0 -229
  46. package/soundfont/README.md +0 -13
  47. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  48. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  49. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  50. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  51. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  52. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  53. package/soundfont/basic_soundfont/generator.js +0 -220
  54. package/soundfont/basic_soundfont/modulator.js +0 -378
  55. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  56. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  57. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  58. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  59. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  60. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  61. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  62. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  63. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  64. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  65. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  66. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  67. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  68. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  69. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  70. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  71. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  72. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  73. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  74. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  75. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  76. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  77. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  78. package/soundfont/dls/articulator_converter.js +0 -396
  79. package/soundfont/dls/dls_destinations.js +0 -38
  80. package/soundfont/dls/dls_preset.js +0 -44
  81. package/soundfont/dls/dls_sample.js +0 -75
  82. package/soundfont/dls/dls_soundfont.js +0 -186
  83. package/soundfont/dls/dls_sources.js +0 -62
  84. package/soundfont/dls/dls_zone.js +0 -95
  85. package/soundfont/dls/read_articulation.js +0 -299
  86. package/soundfont/dls/read_instrument.js +0 -121
  87. package/soundfont/dls/read_instrument_list.js +0 -17
  88. package/soundfont/dls/read_lart.js +0 -35
  89. package/soundfont/dls/read_region.js +0 -152
  90. package/soundfont/dls/read_samples.js +0 -270
  91. package/soundfont/load_soundfont.js +0 -21
  92. package/soundfont/read_sf2/generators.js +0 -46
  93. package/soundfont/read_sf2/instruments.js +0 -66
  94. package/soundfont/read_sf2/modulators.js +0 -36
  95. package/soundfont/read_sf2/presets.js +0 -80
  96. package/soundfont/read_sf2/samples.js +0 -304
  97. package/soundfont/read_sf2/soundfont.js +0 -305
  98. package/soundfont/read_sf2/zones.js +0 -263
  99. package/synthetizer/audio_engine/README.md +0 -25
  100. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  101. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  102. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  103. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  104. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  105. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  106. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  107. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  108. package/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -228
  109. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  110. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  111. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  112. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  113. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  114. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  115. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  116. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  117. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  118. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  119. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  120. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  121. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -175
  122. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  123. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  124. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  127. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  128. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  129. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  132. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  133. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  134. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  135. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -776
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  142. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  143. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  144. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  145. package/synthetizer/audio_engine/main_processor.js +0 -765
  146. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  147. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  148. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  149. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  150. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  151. package/synthetizer/synth_constants.js +0 -20
  152. package/utils/README.md +0 -5
  153. package/utils/byte_functions/big_endian.js +0 -32
  154. package/utils/byte_functions/little_endian.js +0 -77
  155. package/utils/byte_functions/string.js +0 -107
  156. package/utils/byte_functions/variable_length_quantity.js +0 -42
  157. package/utils/indexed_array.js +0 -52
  158. package/utils/loggin.js +0 -79
  159. package/utils/sysex_detector.js +0 -58
  160. package/utils/xg_hacks.js +0 -193
  161. /package/sequencer/{worklet_wrapper/default_sequencer_options.js → default_sequencer_options.js} +0 -0
  162. /package/synthetizer/{worklet_wrapper/sfman_message.js → sfman_message.js} +0 -0
@@ -1,401 +0,0 @@
1
- import { decibelAttenuationToGain, timecentsToSeconds } from "./unit_converter.js";
2
-
3
- import { generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
4
-
5
- /**
6
- * volume_envelope.js
7
- * purpose: applies a volume envelope for a given voice
8
- */
9
-
10
- export const VOLUME_ENVELOPE_SMOOTHING_FACTOR = 0.01;
11
-
12
- const DB_SILENCE = 100;
13
- const PERCEIVED_DB_SILENCE = 90;
14
- // around 96 dB of attenuation
15
- const PERCEIVED_GAIN_SILENCE = 0.000015; // can't go lower than that (see #50)
16
-
17
- /**
18
- * VOL ENV STATES:
19
- * 0 - delay
20
- * 1 - attack
21
- * 2 - hold/peak
22
- * 3 - decay
23
- * 4 - sustain
24
- * release indicates by isInRelease property
25
- */
26
-
27
- export class VolumeEnvelope
28
- {
29
- /**
30
- * The envelope's current time in samples
31
- * @type {number}
32
- */
33
- currentSampleTime = 0;
34
- /**
35
- * The sample rate in Hz
36
- * @type {number}
37
- */
38
- sampleRate;
39
- /**
40
- * The current attenuation of the envelope in dB
41
- * @type {number}
42
- */
43
- currentAttenuationDb = DB_SILENCE;
44
- /**
45
- * The current stage of the volume envelope
46
- * @type {0|1|2|3|4}
47
- */
48
- state = 0;
49
- /**
50
- * The dB attenuation of the envelope when it entered the release stage
51
- * @type {number}
52
- */
53
- releaseStartDb = DB_SILENCE;
54
- /**
55
- * The time in samples relative to the start of the envelope
56
- * @type {number}
57
- */
58
- releaseStartTimeSamples = 0;
59
- /**
60
- * The current gain applied to the voice in the release stage
61
- * @type {number}
62
- */
63
- currentReleaseGain = 1;
64
- /**
65
- * The attack duration in samples
66
- * @type {number}
67
- */
68
- attackDuration = 0;
69
- /**
70
- * The decay duration in samples
71
- * @type {number}
72
- */
73
- decayDuration = 0;
74
- /**
75
- * The release duration in samples
76
- * @type {number}
77
- */
78
- releaseDuration = 0;
79
- /**
80
- * The voice's absolute attenuation as linear gain
81
- * @type {number}
82
- */
83
- attenuation = 0;
84
- /**
85
- * The attenuation target, which the "attenuation" property is linearly interpolated towards (gain)
86
- * @type {number}
87
- */
88
- attenuationTargetGain = 0;
89
- /**
90
- * The attenuation target, which the "attenuation" property is linearly interpolated towards (dB)
91
- * @type {number}
92
- */
93
- attenuationTarget = 0;
94
- /**
95
- * The voice's sustain amount in dB, relative to attenuation
96
- * @type {number}
97
- */
98
- sustainDbRelative = 0;
99
- /**
100
- * The time in samples to the end of delay stage, relative to the start of the envelope
101
- * @type {number}
102
- */
103
- delayEnd = 0;
104
- /**
105
- * The time in samples to the end of attack stage, relative to the start of the envelope
106
- * @type {number}
107
- */
108
- attackEnd = 0;
109
- /**
110
- * The time in samples to the end of hold stage, relative to the start of the envelope
111
- * @type {number}
112
- */
113
- holdEnd = 0;
114
- /**
115
- * The time in samples to the end of decay stage, relative to the start of the envelope
116
- * @type {number}
117
- */
118
- decayEnd = 0;
119
-
120
- /**
121
- * @param sampleRate {number} Hz
122
- * @param initialDecay {number} cb
123
- */
124
- constructor(sampleRate, initialDecay)
125
- {
126
- this.sampleRate = sampleRate;
127
- /**
128
- * if sustain stge is silent,
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
131
- * @type {boolean}
132
- */
133
- this.canEndOnSilentSustain = initialDecay / 10 >= PERCEIVED_DB_SILENCE;
134
- }
135
-
136
- /**
137
- * Starts the release phase in the envelope
138
- * @param voice {Voice} the voice this envelope belongs to
139
- */
140
- static startRelease(voice)
141
- {
142
- voice.volumeEnvelope.releaseStartTimeSamples = voice.volumeEnvelope.currentSampleTime;
143
- voice.volumeEnvelope.currentReleaseGain = decibelAttenuationToGain(voice.volumeEnvelope.currentAttenuationDb);
144
- VolumeEnvelope.recalculate(voice);
145
- }
146
-
147
- /**
148
- * Recalculates the envelope
149
- * @param voice {Voice} the voice this envelope belongs to
150
- */
151
- static recalculate(voice)
152
- {
153
- const env = voice.volumeEnvelope;
154
- const timecentsToSamples = tc =>
155
- {
156
- return Math.max(0, Math.floor(timecentsToSeconds(tc) * env.sampleRate));
157
- };
158
- // calculate absolute times (they can change so we have to recalculate every time
159
- env.attenuationTarget = Math.max(
160
- 0,
161
- Math.min(voice.modulatedGenerators[generatorTypes.initialAttenuation], 1440)
162
- ) / 10; // divide by ten to get decibels
163
- env.attenuationTargetGain = decibelAttenuationToGain(env.attenuationTarget);
164
- env.sustainDbRelative = Math.min(DB_SILENCE, voice.modulatedGenerators[generatorTypes.sustainVolEnv] / 10);
165
- const sustainDb = Math.min(DB_SILENCE, env.sustainDbRelative);
166
-
167
- // calculate durations
168
- env.attackDuration = timecentsToSamples(voice.modulatedGenerators[generatorTypes.attackVolEnv]);
169
-
170
- // decay: sfspec page 35: the time is for change from attenuation to -100dB,
171
- // therefore, we need to calculate the real time
172
- // (changing from attenuation to sustain instead of -100dB)
173
- const fullChange = voice.modulatedGenerators[generatorTypes.decayVolEnv];
174
- const keyNumAddition = (60 - voice.targetKey) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvDecay];
175
- const fraction = sustainDb / DB_SILENCE;
176
- env.decayDuration = timecentsToSamples(fullChange + keyNumAddition) * fraction;
177
-
178
- env.releaseDuration = timecentsToSamples(voice.modulatedGenerators[generatorTypes.releaseVolEnv]);
179
-
180
- // calculate absolute end times for the values
181
- env.delayEnd = timecentsToSamples(voice.modulatedGenerators[generatorTypes.delayVolEnv]);
182
- env.attackEnd = env.attackDuration + env.delayEnd;
183
-
184
- // make sure to take keyNumToVolEnvHold into account!
185
- const holdExcursion = (60 - voice.targetKey) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvHold];
186
- env.holdEnd = timecentsToSamples(voice.modulatedGenerators[generatorTypes.holdVolEnv]
187
- + holdExcursion)
188
- + env.attackEnd;
189
-
190
- env.decayEnd = env.decayDuration + env.holdEnd;
191
-
192
- // if this is the first recalculation and the voice has no attack or delay time, set current db to peak
193
- if (env.state === 0 && env.attackEnd === 0)
194
- {
195
- // env.currentAttenuationDb = env.attenuationTarget;
196
- env.state = 2;
197
- }
198
-
199
- // check if voice is in release
200
- if (voice.isInRelease)
201
- {
202
- // no interpolation this time: force update to actual attenuation and calculate release start from there
203
- //env.attenuation = Math.min(DB_SILENCE, env.attenuationTarget);
204
- const sustainDb = Math.max(0, Math.min(DB_SILENCE, env.sustainDbRelative));
205
- const fraction = sustainDb / DB_SILENCE;
206
- env.decayDuration = timecentsToSamples(fullChange + keyNumAddition) * fraction;
207
-
208
- switch (env.state)
209
- {
210
- case 0:
211
- env.releaseStartDb = DB_SILENCE;
212
- break;
213
-
214
- case 1:
215
- // attack phase: get linear gain of the attack phase when release started
216
- // and turn it into db as we're ramping the db up linearly
217
- // (to make volume go down exponentially)
218
- // attack is linear (in gain) so we need to do get db from that
219
- let elapsed = 1 - ((env.attackEnd - env.releaseStartTimeSamples) / env.attackDuration);
220
- // calculate the gain that the attack would have, so
221
- // turn that into db
222
- env.releaseStartDb = 20 * Math.log10(elapsed) * -1;
223
- break;
224
-
225
- case 2:
226
- env.releaseStartDb = 0;
227
- break;
228
-
229
- case 3:
230
- env.releaseStartDb = (1 - (env.decayEnd - env.releaseStartTimeSamples) / env.decayDuration) * sustainDb;
231
- break;
232
-
233
- case 4:
234
- env.releaseStartDb = sustainDb;
235
- break;
236
- }
237
- env.releaseStartDb = Math.max(0, Math.min(env.releaseStartDb, DB_SILENCE));
238
- if (env.releaseStartDb >= PERCEIVED_DB_SILENCE)
239
- {
240
- voice.finished = true;
241
- }
242
- env.currentReleaseGain = decibelAttenuationToGain(env.releaseStartDb);
243
-
244
- // release: sfspec page 35: the time is for change from attenuation to -100dB,
245
- // therefore, we need to calculate the real time
246
- // (changing from release start to -100dB instead of from peak to -100dB)
247
- const releaseFraction = (DB_SILENCE - env.releaseStartDb) / DB_SILENCE;
248
- env.releaseDuration *= releaseFraction;
249
-
250
- }
251
- }
252
-
253
- /**
254
- * Applies volume envelope gain to the given output buffer
255
- * @param voice {Voice} the voice we're working on
256
- * @param audioBuffer {Float32Array} the audio buffer to modify
257
- * @param centibelOffset {number} the centibel offset of volume, for modLFOtoVolume
258
- * @param smoothingFactor {number} the adjusted smoothing factor for the envelope
259
- * @description essentially we use approach of 100dB is silence, 0dB is peak, and always add attenuation to that (which is interpolated)
260
- */
261
- static apply(voice, audioBuffer, centibelOffset, smoothingFactor)
262
- {
263
- const env = voice.volumeEnvelope;
264
- let decibelOffset = centibelOffset / 10;
265
-
266
- const attenuationSmoothing = smoothingFactor;
267
-
268
- // RELEASE PHASE
269
- if (voice.isInRelease)
270
- {
271
- let elapsedRelease = env.currentSampleTime - env.releaseStartTimeSamples;
272
- if (elapsedRelease >= env.releaseDuration)
273
- {
274
- for (let i = 0; i < audioBuffer.length; i++)
275
- {
276
- audioBuffer[i] = 0;
277
- }
278
- voice.finished = true;
279
- return;
280
- }
281
- let dbDifference = DB_SILENCE - env.releaseStartDb;
282
- for (let i = 0; i < audioBuffer.length; i++)
283
- {
284
- // attenuation interpolation
285
- env.attenuation += (env.attenuationTargetGain - env.attenuation) * attenuationSmoothing;
286
- let db = (elapsedRelease / env.releaseDuration) * dbDifference + env.releaseStartDb;
287
- env.currentReleaseGain = env.attenuation * decibelAttenuationToGain(db + decibelOffset);
288
- audioBuffer[i] *= env.currentReleaseGain;
289
- env.currentSampleTime++;
290
- elapsedRelease++;
291
- }
292
-
293
- if (env.currentReleaseGain <= PERCEIVED_GAIN_SILENCE)
294
- {
295
- voice.finished = true;
296
- }
297
- return;
298
- }
299
-
300
- let filledBuffer = 0;
301
- switch (env.state)
302
- {
303
- case 0:
304
- // delay phase, no sound is produced
305
- while (env.currentSampleTime < env.delayEnd)
306
- {
307
- env.currentAttenuationDb = DB_SILENCE;
308
- audioBuffer[filledBuffer] = 0;
309
-
310
- env.currentSampleTime++;
311
- if (++filledBuffer >= audioBuffer.length)
312
- {
313
- return;
314
- }
315
- }
316
- env.state++;
317
- // fallthrough
318
-
319
- case 1:
320
- // attack phase: ramp from 0 to attenuation
321
- while (env.currentSampleTime < env.attackEnd)
322
- {
323
- // attenuation interpolation
324
- env.attenuation += (env.attenuationTargetGain - env.attenuation) * attenuationSmoothing;
325
-
326
- // Special case: linear gain ramp instead of linear db ramp
327
- let linearAttenuation = 1 - (env.attackEnd - env.currentSampleTime) / env.attackDuration; // 0 to 1
328
- audioBuffer[filledBuffer] *= linearAttenuation * env.attenuation * decibelAttenuationToGain(
329
- decibelOffset);
330
- // set current attenuation to peak as its invalid during this phase
331
- env.currentAttenuationDb = 0;
332
-
333
- env.currentSampleTime++;
334
- if (++filledBuffer >= audioBuffer.length)
335
- {
336
- return;
337
- }
338
- }
339
- env.state++;
340
- // fallthrough
341
-
342
- case 2:
343
- // hold/peak phase: stay at attenuation
344
- while (env.currentSampleTime < env.holdEnd)
345
- {
346
- // attenuation interpolation
347
- env.attenuation += (env.attenuationTargetGain - env.attenuation) * attenuationSmoothing;
348
-
349
- audioBuffer[filledBuffer] *= env.attenuation * decibelAttenuationToGain(decibelOffset);
350
- env.currentAttenuationDb = 0;
351
-
352
- env.currentSampleTime++;
353
- if (++filledBuffer >= audioBuffer.length)
354
- {
355
- return;
356
- }
357
- }
358
- env.state++;
359
- // fallthrough
360
-
361
- case 3:
362
- // decay phase: linear ramp from attenuation to sustain
363
- while (env.currentSampleTime < env.decayEnd)
364
- {
365
- // attenuation interpolation
366
- env.attenuation += (env.attenuationTargetGain - env.attenuation) * attenuationSmoothing;
367
-
368
- env.currentAttenuationDb = (1 - (env.decayEnd - env.currentSampleTime) / env.decayDuration) * env.sustainDbRelative;
369
- audioBuffer[filledBuffer] *= env.attenuation * decibelAttenuationToGain(env.currentAttenuationDb + decibelOffset);
370
-
371
- env.currentSampleTime++;
372
- if (++filledBuffer >= audioBuffer.length)
373
- {
374
- return;
375
- }
376
- }
377
- env.state++;
378
- // fallthrough
379
-
380
- case 4:
381
- if (env.canEndOnSilentSustain && env.sustainDbRelative >= PERCEIVED_DB_SILENCE)
382
- {
383
- voice.finished = true;
384
- }
385
- // sustain phase: stay at sustain
386
- while (true)
387
- {
388
- // attenuation interpolation
389
- env.attenuation += (env.attenuationTargetGain - env.attenuation) * attenuationSmoothing;
390
-
391
- audioBuffer[filledBuffer] *= env.attenuation * decibelAttenuationToGain(env.sustainDbRelative + decibelOffset);
392
- env.currentAttenuationDb = env.sustainDbRelative;
393
- env.currentSampleTime++;
394
- if (++filledBuffer >= audioBuffer.length)
395
- {
396
- return;
397
- }
398
- }
399
- }
400
- }
401
- }
@@ -1,263 +0,0 @@
1
- /**
2
- * wavetable_oscillator.js
3
- * purpose: plays back raw audio data at an arbitrary playback rate
4
- */
5
-
6
- /**
7
- *
8
- * @enum {number}
9
- */
10
- export const interpolationTypes = {
11
- linear: 0,
12
- nearestNeighbor: 1,
13
- fourthOrder: 2
14
- };
15
-
16
-
17
- export class WavetableOscillator
18
- {
19
-
20
- /**
21
- * Fills the output buffer with raw sample data using linear interpolation
22
- * @param voice {Voice} the voice we're working on
23
- * @param outputBuffer {Float32Array} the output buffer to write to
24
- */
25
- static getSampleLinear(voice, outputBuffer)
26
- {
27
- const sample = voice.sample;
28
- let cur = sample.cursor;
29
- const sampleData = sample.sampleData;
30
-
31
- if (sample.isLooping)
32
- {
33
- const loopLength = sample.loopEnd - sample.loopStart;
34
- for (let i = 0; i < outputBuffer.length; i++)
35
- {
36
- // check for loop
37
- while (cur >= sample.loopEnd)
38
- {
39
- cur -= loopLength;
40
- }
41
-
42
- // grab the 2 nearest points
43
- const floor = ~~cur;
44
- let ceil = floor + 1;
45
-
46
- while (ceil >= sample.loopEnd)
47
- {
48
- ceil -= loopLength;
49
- }
50
-
51
- const fraction = cur - floor;
52
-
53
- // grab the samples and interpolate
54
- const upper = sampleData[ceil];
55
- const lower = sampleData[floor];
56
- outputBuffer[i] = (lower + (upper - lower) * fraction);
57
-
58
- cur += sample.playbackStep * voice.currentTuningCalculated;
59
- }
60
- }
61
- else
62
- {
63
- if (sample.loopingMode === 2 && !voice.isInRelease)
64
- {
65
- return;
66
- }
67
- for (let i = 0; i < outputBuffer.length; i++)
68
- {
69
-
70
- // linear interpolation
71
- const floor = ~~cur;
72
- const ceil = floor + 1;
73
-
74
- // flag the voice as finished if needed
75
- if (ceil >= sample.end)
76
- {
77
- voice.finished = true;
78
- return;
79
- }
80
-
81
- const fraction = cur - floor;
82
-
83
- // grab the samples and interpolate
84
- const upper = sampleData[ceil];
85
- const lower = sampleData[floor];
86
- outputBuffer[i] = (lower + (upper - lower) * fraction);
87
-
88
- cur += sample.playbackStep * voice.currentTuningCalculated;
89
- }
90
- }
91
- voice.sample.cursor = cur;
92
- }
93
-
94
- /**
95
- * Fills the output buffer with raw sample data using no interpolation (nearest neighbor)
96
- * @param voice {Voice} the voice we're working on
97
- * @param outputBuffer {Float32Array} the output buffer to write to
98
- */
99
- static getSampleNearest(voice, outputBuffer)
100
- {
101
- const sample = voice.sample;
102
- let cur = sample.cursor;
103
- const loopLength = sample.loopEnd - sample.loopStart;
104
- const sampleData = sample.sampleData;
105
- if (voice.sample.isLooping)
106
- {
107
- for (let i = 0; i < outputBuffer.length; i++)
108
- {
109
- // check for loop
110
- while (cur >= sample.loopEnd)
111
- {
112
- cur -= loopLength;
113
- }
114
-
115
- // grab the nearest neighbor
116
- let ceil = ~~cur + 1;
117
-
118
- while (ceil >= sample.loopEnd)
119
- {
120
- ceil -= loopLength;
121
- }
122
-
123
- outputBuffer[i] = sampleData[ceil];
124
- cur += sample.playbackStep * voice.currentTuningCalculated;
125
- }
126
- }
127
- else
128
- {
129
- if (sample.loopingMode === 2 && !voice.isInRelease)
130
- {
131
- return;
132
- }
133
- for (let i = 0; i < outputBuffer.length; i++)
134
- {
135
-
136
- // nearest neighbor
137
- const ceil = ~~cur + 1;
138
-
139
- // flag the voice as finished if needed
140
- if (ceil >= sample.end)
141
- {
142
- voice.finished = true;
143
- return;
144
- }
145
-
146
- //nearest neighbor (uncomment to use)
147
- outputBuffer[i] = sampleData[ceil];
148
- cur += sample.playbackStep * voice.currentTuningCalculated;
149
- }
150
- }
151
- sample.cursor = cur;
152
- }
153
-
154
-
155
- /**
156
- * Fills the output buffer with raw sample data using cubic interpolation
157
- * @param voice {Voice} the voice we're working on
158
- * @param outputBuffer {Float32Array} the output buffer to write to
159
- */
160
- static getSampleCubic(voice, outputBuffer)
161
- {
162
- const sample = voice.sample;
163
- let cur = sample.cursor;
164
- const sampleData = sample.sampleData;
165
-
166
- if (sample.isLooping)
167
- {
168
- const loopLength = sample.loopEnd - sample.loopStart;
169
- for (let i = 0; i < outputBuffer.length; i++)
170
- {
171
- // check for loop
172
- while (cur >= sample.loopEnd)
173
- {
174
- cur -= loopLength;
175
- }
176
-
177
- // math comes from
178
- // https://stackoverflow.com/questions/1125666/how-do-you-do-bicubic-or-other-non-linear-interpolation-of-re-sampled-audio-da
179
-
180
- // grab the 4 points
181
- const y0 = ~~cur; // point before the cursor. twice bitwise not is just a faster Math.floor
182
- let y1 = y0 + 1; // point after the cursor
183
- let y2 = y1 + 1; // point 1 after the cursor
184
- let y3 = y2 + 1; // point 2 after the cursor
185
- const t = cur - y0; // distance from y0 to cursor
186
- // y0 is not handled here
187
- // as it's math.floor of cur which is handled above
188
- if (y1 >= sample.loopEnd)
189
- {
190
- y1 -= loopLength;
191
- }
192
- if (y2 >= sample.loopEnd)
193
- {
194
- y2 -= loopLength;
195
- }
196
- if (y3 >= sample.loopEnd)
197
- {
198
- y3 -= loopLength;
199
- }
200
-
201
- // grab the samples
202
- const x0 = sampleData[y0];
203
- const x1 = sampleData[y1];
204
- const x2 = sampleData[y2];
205
- const x3 = sampleData[y3];
206
-
207
- // interpolate
208
- // const c0 = x1
209
- const c1 = 0.5 * (x2 - x0);
210
- const c2 = x0 - (2.5 * x1) + (2 * x2) - (0.5 * x3);
211
- const c3 = (0.5 * (x3 - x0)) + (1.5 * (x1 - x2));
212
- outputBuffer[i] = (((((c3 * t) + c2) * t) + c1) * t) + x1;
213
-
214
-
215
- cur += sample.playbackStep * voice.currentTuningCalculated;
216
- }
217
- }
218
- else
219
- {
220
- if (sample.loopingMode === 2 && !voice.isInRelease)
221
- {
222
- return;
223
- }
224
- for (let i = 0; i < outputBuffer.length; i++)
225
- {
226
-
227
- // math comes from
228
- // https://stackoverflow.com/questions/1125666/how-do-you-do-bicubic-or-other-non-linear-interpolation-of-re-sampled-audio-da
229
-
230
- // grab the 4 points
231
- const y0 = ~~cur; // point before the cursor. twice bitwise not is just a faster Math.floor
232
- let y1 = y0 + 1; // point after the cursor
233
- let y2 = y1 + 1; // point 1 after the cursor
234
- let y3 = y2 + 1; // point 2 after the cursor
235
- const t = cur - y0; // distance from y0 to cursor
236
-
237
- // flag as finished if needed
238
- if (y1 >= sample.end ||
239
- y2 >= sample.end ||
240
- y3 >= sample.end)
241
- {
242
- voice.finished = true;
243
- return;
244
- }
245
-
246
- // grab the samples
247
- const x0 = sampleData[y0];
248
- const x1 = sampleData[y1];
249
- const x2 = sampleData[y2];
250
- const x3 = sampleData[y3];
251
-
252
- // interpolate
253
- const c1 = 0.5 * (x2 - x0);
254
- const c2 = x0 - (2.5 * x1) + (2 * x2) - (0.5 * x3);
255
- const c3 = (0.5 * (x3 - x0)) + (1.5 * (x1 - x2));
256
- outputBuffer[i] = (((((c3 * t) + c2) * t) + c1) * t) + x1;
257
-
258
- cur += sample.playbackStep * voice.currentTuningCalculated;
259
- }
260
- }
261
- voice.sample.cursor = cur;
262
- }
263
- }