spessasynth_lib 3.25.22 → 3.26.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 (168) hide show
  1. package/README.md +29 -114
  2. package/index.js +33 -33
  3. package/package.json +16 -6
  4. package/external_midi/README.md +0 -4
  5. package/external_midi/midi_handler.js +0 -130
  6. package/external_midi/web_midi_link.js +0 -43
  7. package/externals/fflate/LICENSE +0 -21
  8. package/externals/fflate/fflate.min.js +0 -1
  9. package/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  10. package/externals/stbvorbis_sync/LICENSE +0 -202
  11. package/externals/stbvorbis_sync/NOTICE +0 -6
  12. package/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  13. package/midi/README.md +0 -32
  14. package/midi/basic_midi.js +0 -565
  15. package/midi/midi_builder.js +0 -202
  16. package/midi/midi_data.js +0 -63
  17. package/midi/midi_loader.js +0 -324
  18. package/midi/midi_message.js +0 -254
  19. package/midi/midi_sequence.js +0 -225
  20. package/midi/midi_tools/get_note_times.js +0 -154
  21. package/midi/midi_tools/midi_editor.js +0 -611
  22. package/midi/midi_tools/midi_writer.js +0 -99
  23. package/midi/midi_tools/rmidi_writer.js +0 -567
  24. package/midi/midi_tools/used_keys_loaded.js +0 -238
  25. package/midi/xmf_loader.js +0 -454
  26. package/sequencer/README.md +0 -32
  27. package/sequencer/sequencer_engine/events.js +0 -207
  28. package/sequencer/sequencer_engine/play.js +0 -353
  29. package/sequencer/sequencer_engine/process_event.js +0 -169
  30. package/sequencer/sequencer_engine/process_tick.js +0 -106
  31. package/sequencer/sequencer_engine/sequencer_engine.js +0 -337
  32. package/sequencer/sequencer_engine/song_control.js +0 -229
  33. package/sequencer/worklet_wrapper/default_sequencer_options.js +0 -8
  34. package/sequencer/worklet_wrapper/sequencer.js +0 -807
  35. package/sequencer/worklet_wrapper/sequencer_message.js +0 -53
  36. package/soundfont/README.md +0 -13
  37. package/soundfont/basic_soundfont/basic_instrument.js +0 -77
  38. package/soundfont/basic_soundfont/basic_preset.js +0 -336
  39. package/soundfont/basic_soundfont/basic_sample.js +0 -197
  40. package/soundfont/basic_soundfont/basic_soundfont.js +0 -565
  41. package/soundfont/basic_soundfont/basic_zone.js +0 -64
  42. package/soundfont/basic_soundfont/basic_zones.js +0 -43
  43. package/soundfont/basic_soundfont/generator.js +0 -220
  44. package/soundfont/basic_soundfont/modulator.js +0 -378
  45. package/soundfont/basic_soundfont/riff_chunk.js +0 -149
  46. package/soundfont/basic_soundfont/write_dls/art2.js +0 -173
  47. package/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  48. package/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -400
  49. package/soundfont/basic_soundfont/write_dls/ins.js +0 -103
  50. package/soundfont/basic_soundfont/write_dls/lins.js +0 -18
  51. package/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  52. package/soundfont/basic_soundfont/write_dls/rgn2.js +0 -121
  53. package/soundfont/basic_soundfont/write_dls/wave.js +0 -94
  54. package/soundfont/basic_soundfont/write_dls/write_dls.js +0 -119
  55. package/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  56. package/soundfont/basic_soundfont/write_dls/wvpl.js +0 -32
  57. package/soundfont/basic_soundfont/write_sf2/ibag.js +0 -39
  58. package/soundfont/basic_soundfont/write_sf2/igen.js +0 -80
  59. package/soundfont/basic_soundfont/write_sf2/imod.js +0 -46
  60. package/soundfont/basic_soundfont/write_sf2/inst.js +0 -34
  61. package/soundfont/basic_soundfont/write_sf2/pbag.js +0 -39
  62. package/soundfont/basic_soundfont/write_sf2/pgen.js +0 -82
  63. package/soundfont/basic_soundfont/write_sf2/phdr.js +0 -42
  64. package/soundfont/basic_soundfont/write_sf2/pmod.js +0 -46
  65. package/soundfont/basic_soundfont/write_sf2/sdta.js +0 -80
  66. package/soundfont/basic_soundfont/write_sf2/shdr.js +0 -55
  67. package/soundfont/basic_soundfont/write_sf2/write.js +0 -222
  68. package/soundfont/dls/articulator_converter.js +0 -396
  69. package/soundfont/dls/dls_destinations.js +0 -38
  70. package/soundfont/dls/dls_preset.js +0 -44
  71. package/soundfont/dls/dls_sample.js +0 -75
  72. package/soundfont/dls/dls_soundfont.js +0 -186
  73. package/soundfont/dls/dls_sources.js +0 -62
  74. package/soundfont/dls/dls_zone.js +0 -95
  75. package/soundfont/dls/read_articulation.js +0 -299
  76. package/soundfont/dls/read_instrument.js +0 -121
  77. package/soundfont/dls/read_instrument_list.js +0 -17
  78. package/soundfont/dls/read_lart.js +0 -35
  79. package/soundfont/dls/read_region.js +0 -152
  80. package/soundfont/dls/read_samples.js +0 -270
  81. package/soundfont/load_soundfont.js +0 -21
  82. package/soundfont/read_sf2/generators.js +0 -46
  83. package/soundfont/read_sf2/instruments.js +0 -66
  84. package/soundfont/read_sf2/modulators.js +0 -36
  85. package/soundfont/read_sf2/presets.js +0 -80
  86. package/soundfont/read_sf2/samples.js +0 -304
  87. package/soundfont/read_sf2/soundfont.js +0 -305
  88. package/soundfont/read_sf2/zones.js +0 -263
  89. package/synthetizer/README.md +0 -10
  90. package/synthetizer/audio_effects/effects_config.js +0 -25
  91. package/synthetizer/audio_effects/fancy_chorus.js +0 -162
  92. package/synthetizer/audio_effects/rb_compressed.min.js +0 -1
  93. package/synthetizer/audio_effects/reverb.js +0 -35
  94. package/synthetizer/audio_effects/reverb_as_binary.js +0 -18
  95. package/synthetizer/audio_engine/README.md +0 -25
  96. package/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -266
  97. package/synthetizer/audio_engine/engine_components/controller_tables.js +0 -88
  98. package/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -149
  99. package/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  100. package/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  101. package/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -471
  102. package/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  103. package/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  104. package/synthetizer/audio_engine/engine_components/soundfont_manager/sfman_message.js +0 -9
  105. package/synthetizer/audio_engine/engine_components/soundfont_manager/soundfont_manager.js +0 -254
  106. package/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -120
  107. package/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  108. package/synthetizer/audio_engine/engine_components/voice.js +0 -519
  109. package/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -401
  110. package/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -263
  111. package/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -132
  112. package/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
  113. package/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -241
  114. package/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -27
  115. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -253
  116. package/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -66
  117. package/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  118. package/synthetizer/audio_engine/engine_methods/note_on.js +0 -174
  119. package/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  120. package/synthetizer/audio_engine/engine_methods/program_change.js +0 -61
  121. package/synthetizer/audio_engine/engine_methods/render_voice.js +0 -196
  122. package/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +0 -30
  123. package/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -22
  124. package/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +0 -40
  125. package/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +0 -34
  126. package/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +0 -21
  127. package/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -20
  128. package/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -55
  129. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  130. package/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  131. package/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  132. package/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -744
  133. package/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -24
  134. package/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -33
  135. package/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -31
  136. package/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  137. package/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -27
  138. package/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  139. package/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  140. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  141. package/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  142. package/synthetizer/audio_engine/main_processor.js +0 -765
  143. package/synthetizer/audio_engine/message_protocol/README.md +0 -13
  144. package/synthetizer/audio_engine/message_protocol/message_sending.js +0 -22
  145. package/synthetizer/audio_engine/message_protocol/worklet_message.js +0 -107
  146. package/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -14
  147. package/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  148. package/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -122
  149. package/synthetizer/synth_constants.js +0 -20
  150. package/synthetizer/worklet_processor.min.js +0 -21
  151. package/synthetizer/worklet_wrapper/key_modifier_manager.js +0 -104
  152. package/synthetizer/worklet_wrapper/synth_event_handler.js +0 -214
  153. package/synthetizer/worklet_wrapper/synth_soundfont_manager.js +0 -111
  154. package/synthetizer/worklet_wrapper/synthetizer.js +0 -1027
  155. package/synthetizer/worklet_wrapper/worklet_processor.js +0 -340
  156. package/synthetizer/worklet_wrapper/worklet_url.js +0 -16
  157. package/utils/README.md +0 -5
  158. package/utils/buffer_to_wav.js +0 -186
  159. package/utils/byte_functions/big_endian.js +0 -32
  160. package/utils/byte_functions/little_endian.js +0 -77
  161. package/utils/byte_functions/string.js +0 -107
  162. package/utils/byte_functions/variable_length_quantity.js +0 -42
  163. package/utils/fill_with_defaults.js +0 -21
  164. package/utils/indexed_array.js +0 -52
  165. package/utils/loggin.js +0 -79
  166. package/utils/other.js +0 -92
  167. package/utils/sysex_detector.js +0 -58
  168. package/utils/xg_hacks.js +0 -193
@@ -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
- }