spessasynth_core 3.27.8 → 4.0.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 (157) hide show
  1. package/README.md +85 -51
  2. package/dist/index.d.ts +4057 -0
  3. package/dist/index.js +17178 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +24 -6
  6. package/index.js +0 -132
  7. package/src/externals/README.md +0 -6
  8. package/src/externals/fflate/LICENSE +0 -21
  9. package/src/externals/fflate/fflate.min.js +0 -1
  10. package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
  11. package/src/externals/stbvorbis_sync/LICENSE +0 -202
  12. package/src/externals/stbvorbis_sync/NOTICE +0 -6
  13. package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
  14. package/src/midi/README.md +0 -32
  15. package/src/midi/basic_midi.js +0 -587
  16. package/src/midi/midi_builder.js +0 -203
  17. package/src/midi/midi_loader.js +0 -321
  18. package/src/midi/midi_message.js +0 -254
  19. package/src/midi/midi_sequence.js +0 -230
  20. package/src/midi/midi_tools/get_note_times.js +0 -154
  21. package/src/midi/midi_tools/midi_editor.js +0 -611
  22. package/src/midi/midi_tools/midi_writer.js +0 -105
  23. package/src/midi/midi_tools/rmidi_writer.js +0 -566
  24. package/src/midi/midi_tools/used_keys_loaded.js +0 -256
  25. package/src/midi/xmf_loader.js +0 -454
  26. package/src/sequencer/README.md +0 -9
  27. package/src/sequencer/events.js +0 -81
  28. package/src/sequencer/play.js +0 -362
  29. package/src/sequencer/process_event.js +0 -165
  30. package/src/sequencer/process_tick.js +0 -104
  31. package/src/sequencer/sequencer_engine.js +0 -372
  32. package/src/sequencer/song_control.js +0 -196
  33. package/src/soundfont/README.md +0 -11
  34. package/src/soundfont/basic_soundfont/basic_global_zone.js +0 -6
  35. package/src/soundfont/basic_soundfont/basic_instrument.js +0 -115
  36. package/src/soundfont/basic_soundfont/basic_instrument_zone.js +0 -45
  37. package/src/soundfont/basic_soundfont/basic_preset.js +0 -313
  38. package/src/soundfont/basic_soundfont/basic_preset_zone.js +0 -39
  39. package/src/soundfont/basic_soundfont/basic_sample.js +0 -477
  40. package/src/soundfont/basic_soundfont/basic_soundbank.js +0 -740
  41. package/src/soundfont/basic_soundfont/basic_zone.js +0 -145
  42. package/src/soundfont/basic_soundfont/generator.js +0 -76
  43. package/src/soundfont/basic_soundfont/generator_types.js +0 -151
  44. package/src/soundfont/basic_soundfont/modulator.js +0 -581
  45. package/src/soundfont/basic_soundfont/riff_chunk.js +0 -195
  46. package/src/soundfont/basic_soundfont/write_dls/art2.js +0 -174
  47. package/src/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
  48. package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -374
  49. package/src/soundfont/basic_soundfont/write_dls/ins.js +0 -85
  50. package/src/soundfont/basic_soundfont/write_dls/lins.js +0 -15
  51. package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
  52. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +0 -120
  53. package/src/soundfont/basic_soundfont/write_dls/wave.js +0 -71
  54. package/src/soundfont/basic_soundfont/write_dls/write_dls.js +0 -124
  55. package/src/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
  56. package/src/soundfont/basic_soundfont/write_dls/wvpl.js +0 -35
  57. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +0 -60
  58. package/src/soundfont/basic_soundfont/write_sf2/igen.js +0 -91
  59. package/src/soundfont/basic_soundfont/write_sf2/imod.js +0 -62
  60. package/src/soundfont/basic_soundfont/write_sf2/inst.js +0 -42
  61. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +0 -57
  62. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +0 -92
  63. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +0 -61
  64. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +0 -62
  65. package/src/soundfont/basic_soundfont/write_sf2/sdta.js +0 -131
  66. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +0 -77
  67. package/src/soundfont/basic_soundfont/write_sf2/write.js +0 -287
  68. package/src/soundfont/dls/articulator_converter.js +0 -402
  69. package/src/soundfont/dls/dls_destinations.js +0 -38
  70. package/src/soundfont/dls/dls_instrument.js +0 -20
  71. package/src/soundfont/dls/dls_preset.js +0 -43
  72. package/src/soundfont/dls/dls_sample.js +0 -238
  73. package/src/soundfont/dls/dls_soundfont.js +0 -183
  74. package/src/soundfont/dls/dls_sources.js +0 -63
  75. package/src/soundfont/dls/dls_zone.js +0 -89
  76. package/src/soundfont/dls/read_articulation.js +0 -300
  77. package/src/soundfont/dls/read_instrument.js +0 -118
  78. package/src/soundfont/dls/read_instrument_list.js +0 -17
  79. package/src/soundfont/dls/read_lart.js +0 -35
  80. package/src/soundfont/dls/read_region.js +0 -157
  81. package/src/soundfont/dls/read_samples.js +0 -154
  82. package/src/soundfont/load_soundfont.js +0 -21
  83. package/src/soundfont/read_sf2/generators.js +0 -43
  84. package/src/soundfont/read_sf2/instrument_zones.js +0 -75
  85. package/src/soundfont/read_sf2/instruments.js +0 -71
  86. package/src/soundfont/read_sf2/modulators.js +0 -25
  87. package/src/soundfont/read_sf2/preset_zones.js +0 -79
  88. package/src/soundfont/read_sf2/presets.js +0 -80
  89. package/src/soundfont/read_sf2/samples.js +0 -317
  90. package/src/soundfont/read_sf2/soundfont.js +0 -452
  91. package/src/soundfont/read_sf2/zones.js +0 -28
  92. package/src/synthetizer/README.md +0 -7
  93. package/src/synthetizer/audio_engine/README.md +0 -9
  94. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -289
  95. package/src/synthetizer/audio_engine/engine_components/controller_tables.js +0 -90
  96. package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +0 -95
  97. package/src/synthetizer/audio_engine/engine_components/enums.js +0 -18
  98. package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -151
  99. package/src/synthetizer/audio_engine/engine_components/lfo.js +0 -26
  100. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
  101. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -551
  102. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
  103. package/src/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
  104. package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -265
  105. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -124
  106. package/src/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
  107. package/src/synthetizer/audio_engine/engine_components/voice.js +0 -525
  108. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -402
  109. package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -274
  110. package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -159
  111. package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -53
  112. package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -254
  113. package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -20
  114. package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +0 -198
  115. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -281
  116. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -109
  117. package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
  118. package/src/synthetizer/audio_engine/engine_methods/note_on.js +0 -220
  119. package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
  120. package/src/synthetizer/audio_engine/engine_methods/program_change.js +0 -35
  121. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +0 -214
  122. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +0 -42
  123. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -0
  124. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js +0 -19
  125. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -23
  126. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -56
  127. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
  128. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
  129. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
  130. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -1058
  131. package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -23
  132. package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -31
  133. package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -29
  134. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
  135. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -26
  136. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
  137. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
  138. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
  139. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
  140. package/src/synthetizer/audio_engine/main_processor.js +0 -817
  141. package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -16
  142. package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
  143. package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -116
  144. package/src/synthetizer/audio_engine/synth_processor_options.js +0 -18
  145. package/src/synthetizer/synth_constants.js +0 -26
  146. package/src/utils/README.md +0 -8
  147. package/src/utils/buffer_to_wav.js +0 -197
  148. package/src/utils/byte_functions/big_endian.js +0 -32
  149. package/src/utils/byte_functions/little_endian.js +0 -77
  150. package/src/utils/byte_functions/string.js +0 -92
  151. package/src/utils/byte_functions/variable_length_quantity.js +0 -42
  152. package/src/utils/fill_with_defaults.js +0 -21
  153. package/src/utils/indexed_array.js +0 -34
  154. package/src/utils/loggin.js +0 -71
  155. package/src/utils/other.js +0 -92
  156. package/src/utils/sysex_detector.js +0 -58
  157. package/src/utils/xg_hacks.js +0 -193
@@ -1,73 +0,0 @@
1
- /**
2
- * unit_converter.js
3
- * purpose: converts soundfont units into more useable values with the use of lookup tables to improve performance
4
- */
5
-
6
-
7
- // timecent lookup table
8
- const MIN_TIMECENT = -15000;
9
- const MAX_TIMECENT = 15000;
10
- const timecentLookupTable = new Float32Array(MAX_TIMECENT - MIN_TIMECENT + 1);
11
- for (let i = 0; i < timecentLookupTable.length; i++)
12
- {
13
- const timecents = MIN_TIMECENT + i;
14
- timecentLookupTable[i] = Math.pow(2, timecents / 1200);
15
- }
16
-
17
- /**
18
- * Converts timecents to seconds
19
- * @param timecents {number} timecents
20
- * @returns {number} seconds
21
- */
22
- export function timecentsToSeconds(timecents)
23
- {
24
- if (timecents <= -32767)
25
- {
26
- return 0;
27
- }
28
- return timecentLookupTable[timecents - MIN_TIMECENT];
29
- }
30
-
31
- // abs cent lookup table
32
- const MIN_ABS_CENT = -20000; // freqVibLfo
33
- const MAX_ABS_CENT = 16500; // filterFc
34
- const absoluteCentLookupTable = new Float32Array(MAX_ABS_CENT - MIN_ABS_CENT + 1);
35
- for (let i = 0; i < absoluteCentLookupTable.length; i++)
36
- {
37
- const absoluteCents = MIN_ABS_CENT + i;
38
- absoluteCentLookupTable[i] = 440 * Math.pow(2, (absoluteCents - 6900) / 1200);
39
- }
40
-
41
- /**
42
- * Converts absolute cents to hertz
43
- * @param cents {number} absolute cents
44
- * @returns {number} hertz
45
- */
46
- export function absCentsToHz(cents)
47
- {
48
- if (cents < MIN_ABS_CENT || cents > MAX_ABS_CENT)
49
- {
50
- return 440 * Math.pow(2, (cents - 6900) / 1200);
51
- }
52
- return absoluteCentLookupTable[~~(cents) - MIN_ABS_CENT];
53
- }
54
-
55
- // decibel lookup table (2 points of precision)
56
- const MIN_DECIBELS = -1660;
57
- const MAX_DECIBELS = 1600;
58
- const decibelLookUpTable = new Float32Array((MAX_DECIBELS - MIN_DECIBELS) * 100 + 1);
59
- for (let i = 0; i < decibelLookUpTable.length; i++)
60
- {
61
- const decibels = (MIN_DECIBELS * 100 + i) / 100;
62
- decibelLookUpTable[i] = Math.pow(10, -decibels / 20);
63
- }
64
-
65
- /**
66
- * convers decibel attenuation to gain
67
- * @param decibels {number} the decibel attenuation
68
- * @returns {number} gain
69
- */
70
- export function decibelAttenuationToGain(decibels)
71
- {
72
- return decibelLookUpTable[Math.floor((decibels - MIN_DECIBELS) * 100)];
73
- }
@@ -1,525 +0,0 @@
1
- /**
2
- * voice.js
3
- * purpose: prepares Voices from sample and generator data
4
- */
5
- import { MIN_EXCLUSIVE_LENGTH, MIN_NOTE_LENGTH } from "../main_processor.js";
6
- import { SpessaSynthWarn } from "../../../utils/loggin.js";
7
- import { LowpassFilter } from "./lowpass_filter.js";
8
- import { VolumeEnvelope } from "./volume_envelope.js";
9
- import { ModulationEnvelope } from "./modulation_envelope.js";
10
- import { addAndClampGenerator } from "../../../soundfont/basic_soundfont/generator.js";
11
- import { Modulator } from "../../../soundfont/basic_soundfont/modulator.js";
12
- import { GENERATORS_AMOUNT, generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
13
-
14
- const EXCLUSIVE_CUTOFF_TIME = -2320;
15
- const EXCLUSIVE_MOD_CUTOFF_TIME = -1130; // less because filter shenanigans
16
-
17
- class AudioSample
18
- {
19
- /**
20
- * the sample's audio data
21
- * @type {Float32Array}
22
- */
23
- sampleData;
24
- /**
25
- * Current playback step (rate)
26
- * @type {number}
27
- */
28
- playbackStep = 0;
29
- /**
30
- * Current position in the sample
31
- * @type {number}
32
- */
33
- cursor = 0;
34
- /**
35
- * MIDI root key of the sample
36
- * @type {number}
37
- */
38
- rootKey = 0;
39
- /**
40
- * Start position of the loop
41
- * @type {number}
42
- */
43
- loopStart = 0;
44
- /**
45
- * End position of the loop
46
- * @type {number}
47
- */
48
- loopEnd = 0;
49
- /**
50
- * End position of the sample
51
- * @type {number}
52
- */
53
- end = 0;
54
- /**
55
- * Looping mode of the sample:
56
- * 0 - no loop
57
- * 1 - loop
58
- * 2 - UNOFFICIAL: polyphone 2.4 added start on release
59
- * 3 - loop then play when released
60
- * @type {0|1|2|3}
61
- */
62
- loopingMode = 0;
63
- /**
64
- * Indicates if the sample is currently looping
65
- * @type {boolean}
66
- */
67
- isLooping = false;
68
-
69
- /**
70
- * @param data {Float32Array}
71
- * @param playbackStep {number} the playback step, a single increment
72
- * @param cursorStart {number} the sample id which starts the playback
73
- * @param rootKey {number} MIDI root key
74
- * @param loopStart {number} loop start index
75
- * @param loopEnd {number} loop end index
76
- * @param endIndex {number} sample end index (for end offset)
77
- * @param loopingMode {number} sample looping mode
78
- */
79
- constructor(
80
- data,
81
- playbackStep,
82
- cursorStart,
83
- rootKey,
84
- loopStart,
85
- loopEnd,
86
- endIndex,
87
- loopingMode
88
- )
89
- {
90
- this.sampleData = data;
91
- this.playbackStep = playbackStep;
92
- this.cursor = cursorStart;
93
- this.rootKey = rootKey;
94
- this.loopStart = loopStart;
95
- this.loopEnd = loopEnd;
96
- this.end = endIndex;
97
- this.loopingMode = loopingMode;
98
- this.isLooping = this.loopingMode === 1 || this.loopingMode === 3;
99
- }
100
- }
101
-
102
-
103
- /**
104
- * Voice represents a single instance of the
105
- * SoundFont2 synthesis model.
106
- * That is:
107
- * A wavetable oscillator (sample)
108
- * A volume envelope (volumeEnvelope)
109
- * A modulation envelope (modulationEnvelope)
110
- * Generators (generators and modulatedGenerators)
111
- * Modulators (modulators)
112
- * And MIDI params such as channel, MIDI note, velocity
113
- */
114
- class Voice
115
- {
116
- /**
117
- * The sample of the voice.
118
- * @type {AudioSample}
119
- */
120
- sample;
121
-
122
- /**
123
- * Lowpass filter applied to the voice.
124
- * @type {LowpassFilter}
125
- */
126
- filter;
127
-
128
- /**
129
- * Linear gain of the voice. Used with Key Modifiers.
130
- * @type {number}
131
- */
132
- gain = 1;
133
-
134
- /**
135
- * The unmodulated (copied to) generators of the voice.
136
- * @type {Int16Array}
137
- */
138
- generators;
139
-
140
- /**
141
- * The voice's modulators.
142
- * @type {Modulator[]}
143
- */
144
- modulators = [];
145
-
146
- /**
147
- * Resonance offset, it is affected by the default resonant modulator
148
- * @type {number}
149
- */
150
- resonanceOffset = 0;
151
-
152
- /**
153
- * The generators in real-time, affected by modulators.
154
- * This is used during rendering.
155
- * @type {Int16Array}
156
- */
157
- modulatedGenerators;
158
-
159
- /**
160
- * Indicates if the voice is finished.
161
- * @type {boolean}
162
- */
163
- finished = false;
164
-
165
- /**
166
- * Indicates if the voice is in the release phase.
167
- * @type {boolean}
168
- */
169
- isInRelease = false;
170
-
171
- /**
172
- * Velocity of the note.
173
- * @type {number}
174
- */
175
- velocity = 0;
176
-
177
- /**
178
- * MIDI note number.
179
- * @type {number}
180
- */
181
- midiNote = 0;
182
-
183
- /**
184
- * The pressure of the voice
185
- * @type {number}
186
- */
187
- pressure = 0;
188
-
189
- /**
190
- * Target key for the note.
191
- * @type {number}
192
- */
193
- targetKey = 0;
194
-
195
- /**
196
- * Modulation envelope.
197
- * @type {ModulationEnvelope}
198
- */
199
- modulationEnvelope = new ModulationEnvelope();
200
-
201
- /**
202
- * Volume envelope.
203
- * @type {VolumeEnvelope}
204
- */
205
- volumeEnvelope;
206
-
207
- /**
208
- * Start time of the voice, absolute.
209
- * @type {number}
210
- */
211
- startTime = 0;
212
-
213
- /**
214
- * Start time of the release phase, absolute.
215
- * @type {number}
216
- */
217
- releaseStartTime = Infinity;
218
-
219
- /**
220
- * Current tuning in cents.
221
- * @type {number}
222
- */
223
- currentTuningCents = 0;
224
-
225
- /**
226
- * Current calculated tuning. (as in ratio)
227
- * @type {number}
228
- */
229
- currentTuningCalculated = 1;
230
-
231
- /**
232
- * From -500 to 500.
233
- * @param {number}
234
- */
235
- currentPan = 0;
236
-
237
- /**
238
- * If MIDI Tuning Standard is already applied (at note-on time),
239
- * this will be used to take the values at real-time tuning as "midiNote"
240
- * property contains the tuned number.
241
- * see #29 comment by @paulikaro
242
- * @type {number}
243
- */
244
- realKey;
245
-
246
- /**
247
- * @type {number} Initial key to glide from, MIDI Note number. If -1, the portamento is OFF.
248
- */
249
- portamentoFromKey = -1;
250
-
251
- /**
252
- * Duration of the linear glide, in seconds.
253
- * @type {number}
254
- */
255
- portamentoDuration = 0;
256
-
257
- /**
258
- * From -500 to 500, where zero means disabled (use the channel pan). Used for random pan.
259
- * @type {number}
260
- */
261
- overridePan = 0;
262
-
263
- /**
264
- * Exclusive class number for hi-hats etc.
265
- * @type {number}
266
- */
267
- exclusiveClass = 0;
268
-
269
- /**
270
- * Creates a Voice
271
- * @param sampleRate {number}
272
- * @param audioSample {AudioSample}
273
- * @param midiNote {number}
274
- * @param velocity {number}
275
- * @param currentTime {number}
276
- * @param targetKey {number}
277
- * @param realKey {number}
278
- * @param generators {Int16Array}
279
- * @param modulators {Modulator[]}
280
- */
281
- constructor(
282
- sampleRate,
283
- audioSample,
284
- midiNote,
285
- velocity,
286
- currentTime,
287
- targetKey,
288
- realKey,
289
- generators,
290
- modulators
291
- )
292
- {
293
- this.sample = audioSample;
294
- this.generators = generators;
295
- this.exclusiveClass = this.generators[generatorTypes.exclusiveClass];
296
- this.modulatedGenerators = new Int16Array(generators);
297
- this.modulators = modulators;
298
- this.filter = new LowpassFilter(sampleRate);
299
- this.velocity = velocity;
300
- this.midiNote = midiNote;
301
- this.startTime = currentTime;
302
- this.targetKey = targetKey;
303
- this.realKey = realKey;
304
- this.volumeEnvelope = new VolumeEnvelope(sampleRate, generators[generatorTypes.sustainVolEnv]);
305
- }
306
-
307
- /**
308
- * copies the voice
309
- * @param voice {Voice}
310
- * @param currentTime {number}
311
- * @param realKey {number}
312
- * @returns Voice
313
- */
314
- static copy(voice, currentTime, realKey)
315
- {
316
- const sampleToCopy = voice.sample;
317
- const sample = new AudioSample(
318
- sampleToCopy.sampleData,
319
- sampleToCopy.playbackStep,
320
- sampleToCopy.cursor,
321
- sampleToCopy.rootKey,
322
- sampleToCopy.loopStart,
323
- sampleToCopy.loopEnd,
324
- sampleToCopy.end,
325
- sampleToCopy.loopingMode
326
- );
327
- return new Voice(
328
- voice.volumeEnvelope.sampleRate,
329
- sample,
330
- voice.midiNote,
331
- voice.velocity,
332
- currentTime,
333
- voice.targetKey,
334
- realKey,
335
- new Int16Array(voice.generators),
336
- voice.modulators.map(m => Modulator.copy(m))
337
- );
338
- }
339
-
340
- /**
341
- * Releases the voice as exclusiveClass
342
- * @param currentTime {number}
343
- */
344
- exclusiveRelease(currentTime)
345
- {
346
- this.release(currentTime, MIN_EXCLUSIVE_LENGTH);
347
- this.modulatedGenerators[generatorTypes.releaseVolEnv] = EXCLUSIVE_CUTOFF_TIME; // make the release nearly instant
348
- this.modulatedGenerators[generatorTypes.releaseModEnv] = EXCLUSIVE_MOD_CUTOFF_TIME;
349
- VolumeEnvelope.recalculate(this);
350
- ModulationEnvelope.recalculate(this);
351
- }
352
-
353
- /**
354
- * Stops the voice
355
- * @param currentTime {number}
356
- * @param minNoteLength {number} minimum note length in seconds
357
- */
358
- release(currentTime, minNoteLength = MIN_NOTE_LENGTH)
359
- {
360
- this.releaseStartTime = currentTime;
361
- // check if the note is shorter than the min note time, if so, extend it
362
- if (this.releaseStartTime - this.startTime < minNoteLength)
363
- {
364
- this.releaseStartTime = this.startTime + minNoteLength;
365
- }
366
- }
367
- }
368
-
369
- /**
370
- * @param preset {BasicPreset} the preset to get voices for
371
- * @param bank {number} the bank to cache the voices in
372
- * @param program {number} program to cache the voices in
373
- * @param midiNote {number} the MIDI note to use
374
- * @param velocity {number} the velocity to use
375
- * @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
376
- * @this {SpessaSynthProcessor}
377
- * @returns {Voice[]} output is an array of Voices
378
- */
379
- export function getVoicesForPreset(preset, bank, program, midiNote, velocity, realKey)
380
- {
381
- /**
382
- * @type {Voice[]}
383
- */
384
- const voices = preset.getSamplesAndGenerators(midiNote, velocity)
385
- .reduce((voices, sampleAndGenerators) =>
386
- {
387
- if (sampleAndGenerators.sample.getAudioData() === undefined)
388
- {
389
- SpessaSynthWarn(`Discarding invalid sample: ${sampleAndGenerators.sample.sampleName}`);
390
- return voices;
391
- }
392
-
393
- // create the generator list
394
- const generators = new Int16Array(GENERATORS_AMOUNT);
395
- // apply and sum the gens
396
- for (let i = 0; i < 60; i++)
397
- {
398
- generators[i] = addAndClampGenerator(
399
- i,
400
- sampleAndGenerators.presetGenerators,
401
- sampleAndGenerators.instrumentGenerators
402
- );
403
- }
404
-
405
- // EMU initial attenuation correction, multiply initial attenuation by 0.4!
406
- // all EMU sound cards have this quirk, and all sf2 editors and players emulate it too
407
- generators[generatorTypes.initialAttenuation] = Math.floor(generators[generatorTypes.initialAttenuation] * 0.4);
408
-
409
- // key override
410
- let rootKey = sampleAndGenerators.sample.samplePitch;
411
- if (generators[generatorTypes.overridingRootKey] > -1)
412
- {
413
- rootKey = generators[generatorTypes.overridingRootKey];
414
- }
415
-
416
- let targetKey = midiNote;
417
- if (generators[generatorTypes.keyNum] > -1)
418
- {
419
- targetKey = generators[generatorTypes.keyNum];
420
- }
421
-
422
- // determine looping mode now. if the loop is too small, disable
423
- let loopStart = sampleAndGenerators.sample.sampleLoopStartIndex;
424
- let loopEnd = sampleAndGenerators.sample.sampleLoopEndIndex;
425
- let loopingMode = generators[generatorTypes.sampleModes];
426
- /**
427
- * create the sample
428
- * offsets are calculated at note on time (to allow for modulation of them)
429
- * @type {AudioSample}
430
- */
431
- const audioSample = new AudioSample(
432
- sampleAndGenerators.sample.sampleData,
433
- (sampleAndGenerators.sample.sampleRate / this.sampleRate) * Math.pow(
434
- 2,
435
- sampleAndGenerators.sample.samplePitchCorrection / 1200
436
- ), // cent tuning
437
- 0,
438
- rootKey,
439
- loopStart,
440
- loopEnd,
441
- Math.floor(sampleAndGenerators.sample.sampleData.length) - 1,
442
- loopingMode
443
- );
444
- // velocity override
445
- if (generators[generatorTypes.velocity] > -1)
446
- {
447
- velocity = generators[generatorTypes.velocity];
448
- }
449
-
450
- // uncomment to print debug info
451
- // SpessaSynthTable([{
452
- // Sample: sampleAndGenerators.sample.sampleName,
453
- // Generators: generators,
454
- // Modulators: sampleAndGenerators.modulators.map(m => Modulator.debugString(m)),
455
- // Velocity: velocity,
456
- // TargetKey: targetKey,
457
- // MidiNote: midiNote,
458
- // AudioSample: audioSample
459
- // }]);
460
- voices.push(
461
- new Voice(
462
- this.sampleRate,
463
- audioSample,
464
- midiNote,
465
- velocity,
466
- this.currentSynthTime,
467
- targetKey,
468
- realKey,
469
- generators,
470
- sampleAndGenerators.modulators.map(m => Modulator.copy(m))
471
- )
472
- );
473
- return voices;
474
- }, []);
475
- // cache the voice
476
- this.setCachedVoice(bank, program, midiNote, velocity, voices);
477
- return voices.map(v =>
478
- Voice.copy(v, this.currentSynthTime, realKey));
479
- }
480
-
481
- /**
482
- * @param channel {number} a hint for the processor to recalculate sample cursors when sample dumping
483
- * @param midiNote {number} the MIDI note to use
484
- * @param velocity {number} the velocity to use
485
- * @param realKey {number} the real MIDI note if the "midiNote" was changed by MIDI Tuning Standard
486
- * @this {SpessaSynthProcessor}
487
- * @returns {Voice[]} output is an array of Voices
488
- */
489
- export function getVoices(channel, midiNote, velocity, realKey)
490
- {
491
- const channelObject = this.midiAudioChannels[channel];
492
-
493
- // override patch
494
- const overridePatch = this.keyModifierManager.hasOverridePatch(channel, midiNote);
495
-
496
- let bank = channelObject.getBankSelect();
497
-
498
- let preset = channelObject.preset;
499
- if (!preset)
500
- {
501
- SpessaSynthWarn(`No preset for channel ${channel}!`);
502
- return [];
503
- }
504
- let program = preset.program;
505
- if (overridePatch)
506
- {
507
- const override = this.keyModifierManager.getPatch(channel, midiNote);
508
- bank = override.bank;
509
- program = override.program;
510
- }
511
-
512
- const cached = this.getCachedVoice(bank, program, midiNote, velocity);
513
- // if cached, return it!
514
- if (cached !== undefined)
515
- {
516
- return cached.map(v => Voice.copy(v, this.currentSynthTime, realKey));
517
- }
518
-
519
- // not cached...
520
- if (overridePatch)
521
- {
522
- preset = this.getPreset(bank, program);
523
- }
524
- return this.getVoicesForPreset(preset, bank, program, midiNote, velocity, realKey);
525
- }