spessasynth_core 3.27.7 → 4.0.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 (157) hide show
  1. package/README.md +188 -116
  2. package/dist/index.d.ts +4057 -0
  3. package/dist/index.js +17188 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +23 -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 -48
  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 -214
  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 -27
  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 -813
  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,181 +0,0 @@
1
- import { timecentsToSeconds } from "./unit_converter.js";
2
- import { getModulatorCurveValue } from "./modulator_curves.js";
3
- import { modulatorCurveTypes } from "../../../soundfont/basic_soundfont/modulator.js";
4
- import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
5
-
6
- /**
7
- * modulation_envelope.js
8
- * purpose: calculates the modulation envelope for the given voice
9
- */
10
- const MODENV_PEAK = 1;
11
-
12
- // 1000 should be precise enough
13
- const CONVEX_ATTACK = new Float32Array(1000);
14
- for (let i = 0; i < CONVEX_ATTACK.length; i++)
15
- {
16
- // this makes the db linear (I think)
17
- CONVEX_ATTACK[i] = getModulatorCurveValue(0, modulatorCurveTypes.convex, i / 1000, 0);
18
- }
19
-
20
- export class ModulationEnvelope
21
- {
22
- /**
23
- * The attack duration, in seconds
24
- * @type {number}
25
- */
26
- attackDuration = 0;
27
- /**
28
- * The decay duration, in seconds
29
- * @type {number}
30
- */
31
- decayDuration = 0;
32
-
33
- /**
34
- * The hold duration, in seconds
35
- * @type {number}
36
- */
37
- holdDuration = 0;
38
-
39
- /**
40
- * Release duration, in seconds
41
- * @type {number}
42
- */
43
- releaseDuration = 0;
44
-
45
- /**
46
- * The sustain level 0-1
47
- * @type {number}
48
- */
49
- sustainLevel = 0;
50
-
51
- /**
52
- * Delay phase end time in seconds, absolute (audio context time)
53
- * @type {number}
54
- */
55
- delayEnd = 0;
56
- /**
57
- * Attack phase end time in seconds, absolute (audio context time)
58
- * @type {number}
59
- */
60
- attackEnd = 0;
61
- /**
62
- * Hold phase end time in seconds, absolute (audio context time)
63
- * @type {number}
64
- */
65
- holdEnd = 0;
66
- /**
67
- * Decay phase end time in seconds, absolute (audio context time)
68
- * @type {number}
69
- */
70
- decayEnd = 0;
71
-
72
- /**
73
- * The level of the envelope when the release phase starts
74
- * @type {number}
75
- */
76
- releaseStartLevel = 0;
77
-
78
- /**
79
- * The current modulation envelope value
80
- * @type {number}
81
- */
82
- currentValue = 0;
83
-
84
- /**
85
- * Starts the release phase in the envelope
86
- * @param voice {Voice} the voice this envelope belongs to
87
- */
88
- static startRelease(voice)
89
- {
90
- ModulationEnvelope.recalculate(voice);
91
- }
92
-
93
- /**
94
- * @param voice {Voice} the voice to recalculate
95
- */
96
- static recalculate(voice)
97
- {
98
- const env = voice.modulationEnvelope;
99
-
100
- // in release? Might need to recalculate the value as it can be modulated
101
- if (voice.isInRelease)
102
- {
103
- env.releaseStartLevel = ModulationEnvelope.getValue(voice, voice.releaseStartTime, true);
104
- }
105
-
106
- env.sustainLevel = 1 - (voice.modulatedGenerators[generatorTypes.sustainModEnv] / 1000);
107
-
108
- env.attackDuration = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.attackModEnv]);
109
-
110
- const decayKeyExcursionCents = ((60 - voice.midiNote) * voice.modulatedGenerators[generatorTypes.keyNumToModEnvDecay]);
111
- const decayTime = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.decayModEnv] + decayKeyExcursionCents);
112
- // according to the specification, the decay time is the time it takes to reach 0% from 100%.
113
- // calculate the time to reach actual sustain level,
114
- // for example, sustain 0.6 will be 0.4 of the decay time
115
- env.decayDuration = decayTime * (1 - env.sustainLevel);
116
-
117
- const holdKeyExcursionCents = ((60 - voice.midiNote) * voice.modulatedGenerators[generatorTypes.keyNumToModEnvHold]);
118
- env.holdDuration = timecentsToSeconds(holdKeyExcursionCents + voice.modulatedGenerators[generatorTypes.holdModEnv]);
119
-
120
- const releaseTime = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.releaseModEnv]);
121
- // release time is from the full level to 0%
122
- // to get the actual time, multiply by the release start level
123
- env.releaseDuration = releaseTime * env.releaseStartLevel;
124
-
125
- env.delayEnd = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayModEnv]);
126
- env.attackEnd = env.delayEnd + env.attackDuration;
127
- env.holdEnd = env.attackEnd + env.holdDuration;
128
- env.decayEnd = env.holdEnd + env.decayDuration;
129
- }
130
-
131
- /**
132
- * Calculates the current modulation envelope value for the given time and voice
133
- * @param voice {Voice} the voice we are working on
134
- * @param currentTime {number} in seconds
135
- * @param ignoreRelease {boolean} if true, it will compute the value as if the voice was not released
136
- * @returns {number} modenv value, from 0 to 1
137
- */
138
- static getValue(voice, currentTime, ignoreRelease = false)
139
- {
140
- const env = voice.modulationEnvelope;
141
- if (voice.isInRelease && !ignoreRelease)
142
- {
143
- // if the voice is still in the delay phase,
144
- // start level will be 0 that will result in divide by zero
145
- if (env.releaseStartLevel === 0)
146
- {
147
- return 0;
148
- }
149
- return Math.max(
150
- 0,
151
- (1 - (currentTime - voice.releaseStartTime) / env.releaseDuration) * env.releaseStartLevel
152
- );
153
- }
154
-
155
- if (currentTime < env.delayEnd)
156
- {
157
- env.currentValue = 0; // delay
158
- }
159
- else if (currentTime < env.attackEnd)
160
- {
161
- // modulation envelope uses convex curve for attack
162
- env.currentValue = CONVEX_ATTACK[~~((1 - (env.attackEnd - currentTime) / env.attackDuration) * 1000)];
163
- }
164
- else if (currentTime < env.holdEnd)
165
- {
166
- // hold: stay at 1
167
- env.currentValue = MODENV_PEAK;
168
- }
169
- else if (currentTime < env.decayEnd)
170
- {
171
- // decay: linear ramp from 1 to sustain level
172
- env.currentValue = (1 - (env.decayEnd - currentTime) / env.decayDuration) * (env.sustainLevel - MODENV_PEAK) + MODENV_PEAK;
173
- }
174
- else
175
- {
176
- // sustain: stay at sustain level
177
- env.currentValue = env.sustainLevel;
178
- }
179
- return env.currentValue;
180
- }
181
- }
@@ -1,89 +0,0 @@
1
- import { modulatorCurveTypes } from "../../../soundfont/basic_soundfont/modulator.js";
2
-
3
- /**
4
- * modulator_curves.js
5
- * precomputes modulator concave and conves curves and calculates a curve value for a given polarity, direction and type
6
- */
7
-
8
- // the length of the precomputed curve tables
9
- export const MOD_PRECOMPUTED_LENGTH = 16384;
10
-
11
- // Precalculate lookup tables for concave and convex curves
12
- const concave = new Float32Array(MOD_PRECOMPUTED_LENGTH + 1);
13
- const convex = new Float32Array(MOD_PRECOMPUTED_LENGTH + 1);
14
- // the equation is taken from FluidSynth as it's the standard for soundFonts
15
- // more precisely, the gen_conv.c file
16
- concave[0] = 0;
17
- concave[concave.length - 1] = 1;
18
-
19
- convex[0] = 0;
20
- convex[convex.length - 1] = 1;
21
- for (let i = 1; i < MOD_PRECOMPUTED_LENGTH - 1; i++)
22
- {
23
- let x = (-200 * 2 / 960) * Math.log(i / (concave.length - 1)) / Math.LN10;
24
- convex[i] = 1 - x;
25
- concave[concave.length - 1 - i] = x;
26
- }
27
-
28
- /**
29
- * Transforms a value with a given curve type
30
- * @param polarity {number} 0 or 1
31
- * @param direction {number} 0 or 1
32
- * @param curveType {number} see modulatorCurveTypes in modulators.js
33
- * @param value {number} the linear value, 0 to 1
34
- * @returns {number} the transformed value, 0 to 1, or -1 to 1
35
- */
36
- export function getModulatorCurveValue(direction, curveType, value, polarity)
37
- {
38
- // inverse the value if needed
39
- if (direction)
40
- {
41
- value = 1 - value;
42
- }
43
- switch (curveType)
44
- {
45
- case modulatorCurveTypes.linear:
46
- if (polarity)
47
- {
48
- // bipolar curve
49
- return value * 2 - 1;
50
- }
51
- return value;
52
-
53
- case modulatorCurveTypes.switch:
54
- // switch
55
- value = value > 0.5 ? 1 : 0;
56
- if (polarity)
57
- {
58
- // multiply
59
- return value * 2 - 1;
60
- }
61
- return value;
62
-
63
- case modulatorCurveTypes.concave:
64
- // look up the value
65
- if (polarity)
66
- {
67
- value = value * 2 - 1;
68
- if (value < 0)
69
- {
70
- return -concave[~~(value * -MOD_PRECOMPUTED_LENGTH)];
71
- }
72
- return concave[~~(value * MOD_PRECOMPUTED_LENGTH)];
73
- }
74
- return concave[~~(value * MOD_PRECOMPUTED_LENGTH)];
75
-
76
- case modulatorCurveTypes.convex:
77
- // look up the value
78
- if (polarity)
79
- {
80
- value = value * 2 - 1;
81
- if (value < 0)
82
- {
83
- return -convex[~~(value * -MOD_PRECOMPUTED_LENGTH)];
84
- }
85
- return convex[~~(value * MOD_PRECOMPUTED_LENGTH)];
86
- }
87
- return convex[~~(value * MOD_PRECOMPUTED_LENGTH)];
88
- }
89
- }
@@ -1,265 +0,0 @@
1
- import { SpessaSynthInfo, SpessaSynthWarn } from "../../../utils/loggin.js";
2
- import { isXGDrums } from "../../../utils/xg_hacks.js";
3
- import { EMBEDDED_SOUND_BANK_ID } from "../../synth_constants.js";
4
-
5
- /**
6
- * @typedef {Object} SoundFontType
7
- * @property {string} id - unique id for the soundfont
8
- * @property {BasicSoundBank} soundfont - the soundfont itself
9
- * @property {number} bankOffset - the soundfont's bank offset
10
- */
11
-
12
- export class SoundFontManager
13
- {
14
- /**
15
- * All the soundfonts, ordered from the most important to the least.
16
- * @type {SoundFontType[]}
17
- */
18
- soundfontList = [];
19
- /**
20
- * @type {{bank: number, presetName: string, program: number}[]}
21
- */
22
- presetList = [];
23
-
24
- /**
25
- * @param presetListChangeCallback {function} to call when stuff changes
26
- */
27
- constructor(presetListChangeCallback)
28
- {
29
- this.presetListChangeCallback = presetListChangeCallback;
30
- }
31
-
32
- generatePresetList()
33
- {
34
- /**
35
- * <"bank-program", "presetName">
36
- * @type {Record<string, string>}
37
- */
38
- const presetList = {};
39
- // gather the presets in reverse and replace if necessary
40
- for (let i = this.soundfontList.length - 1; i >= 0; i--)
41
- {
42
- const font = this.soundfontList[i];
43
- /**
44
- * prevent preset names from the same soudfont from being overriden
45
- * if the soundfont has two presets with matching bank and program
46
- * @type {Set<string>}
47
- */
48
- const presets = new Set();
49
- for (const p of font.soundfont.presets)
50
- {
51
- const bank = Math.min(128, p.bank + font.bankOffset);
52
- const presetString = `${bank}-${p.program}`;
53
- if (presets.has(presetString))
54
- {
55
- continue;
56
- }
57
- presets.add(presetString);
58
- presetList[presetString] = p.presetName;
59
- }
60
- }
61
-
62
- this.presetList = [];
63
- for (const [string, name] of Object.entries(presetList))
64
- {
65
- const pb = string.split("-");
66
- this.presetList.push({
67
- presetName: name,
68
- program: parseInt(pb[1]),
69
- bank: parseInt(pb[0])
70
- });
71
- }
72
- this.presetListChangeCallback();
73
- }
74
-
75
- /**
76
- * Get the final preset list
77
- * @returns {{bank: number, presetName: string, program: number}[]}
78
- */
79
- getPresetList()
80
- {
81
- return this.presetList.slice();
82
- }
83
-
84
- // noinspection JSUnusedGlobalSymbols
85
- /**
86
- * Clears all soundfonts and adds a new one with an ID "main"
87
- * @param soundFont {BasicSoundBank}
88
- */
89
- reloadManager(soundFont)
90
- {
91
- // do not clear the embedded bank
92
- this.soundfontList = this.soundfontList.filter(sf => sf.id === EMBEDDED_SOUND_BANK_ID);
93
- this.soundfontList.push({
94
- id: "main",
95
- bankOffset: 0,
96
- soundfont: soundFont
97
- });
98
- this.generatePresetList();
99
- }
100
-
101
- // noinspection JSUnusedGlobalSymbols
102
- /**
103
- * Deletes a given soundfont.
104
- * @param id {string}
105
- */
106
- deleteSoundFont(id)
107
- {
108
- if (this.soundfontList.length === 0)
109
- {
110
- SpessaSynthWarn("1 soundfont left. Aborting!");
111
- return;
112
- }
113
- const index = this.soundfontList.findIndex(s => s.id === id);
114
- if (index === -1)
115
- {
116
- SpessaSynthInfo(`No soundfont with id of "${id}" found. Aborting!`);
117
- return;
118
- }
119
- this.soundfontList.splice(index, 1);
120
- this.generatePresetList();
121
- }
122
-
123
- // noinspection JSUnusedGlobalSymbols
124
- /**
125
- * Adds a new soundfont with a given ID, or replaces an existing one.
126
- * @param font {BasicSoundBank}
127
- * @param id {string}
128
- * @param bankOffset {number}
129
- */
130
- addNewSoundFont(font, id, bankOffset)
131
- {
132
- if (this.soundfontList.find(s => s.id === id) !== undefined)
133
- {
134
- // replace
135
- const soundfont = this.soundfontList.find(s => s.id === id);
136
- soundfont.soundfont = font;
137
- soundfont.bankOffset = bankOffset;
138
- }
139
- else
140
- {
141
- this.soundfontList.push({
142
- id: id,
143
- soundfont: font,
144
- bankOffset: bankOffset
145
- });
146
- }
147
- this.generatePresetList();
148
- }
149
-
150
- /**
151
- * Gets the current soundfont order
152
- * @returns {string[]}
153
- */
154
- getCurrentSoundFontOrder()
155
- {
156
- return this.soundfontList.map(s => s.id);
157
- }
158
-
159
- // noinspection JSUnusedGlobalSymbols
160
- /**
161
- * Rearranges the soundfonts
162
- * @param newList {string[]} the order of soundfonts, a list of strings, first overwrites second
163
- */
164
- rearrangeSoundFonts(newList)
165
- {
166
- this.soundfontList.sort((a, b) =>
167
- newList.indexOf(a.id) - newList.indexOf(b.id)
168
- );
169
- this.generatePresetList();
170
- }
171
-
172
- /**
173
- * Gets a given preset from the soundfont stack
174
- * @param bankNumber {number}
175
- * @param programNumber {number}
176
- * @param allowXGDrums {boolean} if true, allows XG drum banks (120, 126 and 127) as drum preset
177
- * @returns {{preset: BasicPreset, bankOffset: number}} the preset and its bank offset
178
- */
179
- getPreset(bankNumber, programNumber, allowXGDrums = false)
180
- {
181
- if (this.soundfontList.length < 1)
182
- {
183
- throw new Error("No soundfonts! Did you forget to add one?");
184
- }
185
- const isDrum = bankNumber === 128 || (allowXGDrums && isXGDrums(bankNumber));
186
- for (const sf of this.soundfontList)
187
- {
188
- // check for the preset (with given offset)
189
- const preset = sf.soundfont.getPresetNoFallback(
190
- bankNumber === 128 ? 128 : bankNumber - sf.bankOffset,
191
- programNumber,
192
- allowXGDrums
193
- );
194
- if (preset !== undefined)
195
- {
196
- return {
197
- preset: preset,
198
- bankOffset: sf.bankOffset
199
- };
200
- }
201
- // if not found, advance to the next soundfont
202
- }
203
- // if none found, return the first correct preset found
204
- if (!isDrum)
205
- {
206
- for (const sf of this.soundfontList)
207
- {
208
- const preset = sf.soundfont.presets.find(p => p.program === programNumber && !p.isDrumPreset(
209
- allowXGDrums));
210
- if (preset)
211
- {
212
- return {
213
- preset: preset,
214
- bankOffset: sf.bankOffset
215
- };
216
- }
217
- }
218
- // if nothing at all, use the first preset
219
- const sf = this.soundfontList[0];
220
- return {
221
- preset: sf.soundfont.presets[0],
222
- bankOffset: sf.bankOffset
223
- };
224
- }
225
- else
226
- {
227
- for (const sf of this.soundfontList)
228
- {
229
- // check for any drum type (127/128) and matching program
230
- const p = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums) && p.program === programNumber);
231
- if (p)
232
- {
233
- return {
234
- preset: p,
235
- bankOffset: sf.bankOffset
236
- };
237
- }
238
- // check for any drum preset
239
- const preset = sf.soundfont.presets.find(p => p.isDrumPreset(allowXGDrums));
240
- if (preset)
241
- {
242
- return {
243
- preset: preset,
244
- bankOffset: sf.bankOffset
245
- };
246
- }
247
- }
248
- // if nothing at all, use the first preset
249
- const sf = this.soundfontList[0];
250
- return {
251
- preset: sf.soundfont.presets[0],
252
- bankOffset: sf.bankOffset
253
- };
254
- }
255
- }
256
-
257
- destroyManager()
258
- {
259
- this.soundfontList.forEach(s =>
260
- {
261
- s.soundfont.destroySoundBank();
262
- });
263
- delete this.soundfontList;
264
- }
265
- }
@@ -1,124 +0,0 @@
1
- import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
2
-
3
- /**
4
- * stereo_panner.js
5
- * purpose: pans a given voice out to the stereo output and to the effects' outputs
6
- */
7
-
8
- export const PAN_SMOOTHING_FACTOR = 0.05;
9
-
10
- // optimized for spessasynth_lib's effects
11
- export const REVERB_DIVIDER = 3070;
12
- export const CHORUS_DIVIDER = 2000;
13
- const HALF_PI = Math.PI / 2;
14
-
15
- const MIN_PAN = -500;
16
- const MAX_PAN = 500;
17
- const PAN_RESOLUTION = MAX_PAN - MIN_PAN;
18
-
19
- // initialize pan lookup tables
20
- const panTableLeft = new Float32Array(PAN_RESOLUTION + 1);
21
- const panTableRight = new Float32Array(PAN_RESOLUTION + 1);
22
- for (let pan = MIN_PAN; pan <= MAX_PAN; pan++)
23
- {
24
- // clamp to 0-1
25
- const realPan = (pan - MIN_PAN) / PAN_RESOLUTION;
26
- const tableIndex = pan - MIN_PAN;
27
- panTableLeft[tableIndex] = Math.cos(HALF_PI * realPan);
28
- panTableRight[tableIndex] = Math.sin(HALF_PI * realPan);
29
- }
30
-
31
- /**
32
- * Pans the voice to the given output buffers
33
- * @param voice {Voice} the voice to pan
34
- * @param inputBuffer {Float32Array} the input buffer in mono
35
- * @param outputLeft {Float32Array} left output buffer
36
- * @param outputRight {Float32Array} right output buffer
37
- * @param reverbLeft {Float32Array} left reverb input
38
- * @param reverbRight {Float32Array} right reverb input
39
- * @param chorusLeft {Float32Array} left chorus buffer
40
- * @param chorusRight {Float32Array} right chorus buffer
41
- * @param startIndex {number}
42
- * @this {MidiAudioChannel}
43
- */
44
- export function panAndMixVoice(voice,
45
- inputBuffer,
46
- outputLeft, outputRight,
47
- reverbLeft, reverbRight,
48
- chorusLeft, chorusRight,
49
- startIndex)
50
- {
51
- if (isNaN(inputBuffer[0]))
52
- {
53
- return;
54
- }
55
- /**
56
- * clamp -500 to 500
57
- * @type {number}
58
- */
59
- let pan;
60
- if (voice.overridePan)
61
- {
62
- pan = voice.overridePan;
63
- }
64
- else
65
- {
66
- // smooth out pan to prevent clicking
67
- voice.currentPan += (voice.modulatedGenerators[generatorTypes.pan] - voice.currentPan) * this.synth.panSmoothingFactor;
68
- pan = voice.currentPan;
69
- }
70
-
71
- const gain = this.synth.currentGain * voice.gain;
72
- const index = ~~(pan + 500);
73
- // get voice's gain levels for each channel
74
- const gainLeft = panTableLeft[index] * gain * this.synth.panLeft;
75
- const gainRight = panTableRight[index] * gain * this.synth.panRight;
76
-
77
- // disable reverb and chorus if necessary
78
- if (this.synth.effectsEnabled)
79
- {
80
- const reverbSend = voice.modulatedGenerators[generatorTypes.reverbEffectsSend];
81
- if (reverbSend > 0)
82
- {
83
- // reverb is mono so we need to multiply by gain
84
- const reverbGain = this.synth.reverbGain * this.synth.reverbSend * gain * (reverbSend / REVERB_DIVIDER);
85
- for (let i = 0; i < inputBuffer.length; i++)
86
- {
87
- const idx = i + startIndex;
88
- reverbLeft[idx] += reverbGain * inputBuffer[i];
89
- reverbRight[idx] += reverbGain * inputBuffer[i];
90
- }
91
- }
92
-
93
- const chorusSend = voice.modulatedGenerators[generatorTypes.chorusEffectsSend];
94
- if (chorusSend > 0)
95
- {
96
- // chorus is stereo so we do not need to
97
- const chorusGain = this.synth.chorusGain * this.synth.chorusSend * (chorusSend / CHORUS_DIVIDER);
98
- const chorusLeftGain = gainLeft * chorusGain;
99
- const chorusRightGain = gainRight * chorusGain;
100
- for (let i = 0; i < inputBuffer.length; i++)
101
- {
102
- const idx = i + startIndex;
103
- chorusLeft[idx] += chorusLeftGain * inputBuffer[i];
104
- chorusRight[idx] += chorusRightGain * inputBuffer[i];
105
- }
106
- }
107
- }
108
-
109
- // mix down the audio data
110
- if (gainLeft > 0)
111
- {
112
- for (let i = 0; i < inputBuffer.length; i++)
113
- {
114
- outputLeft[i + startIndex] += gainLeft * inputBuffer[i];
115
- }
116
- }
117
- if (gainRight > 0)
118
- {
119
- for (let i = 0; i < inputBuffer.length; i++)
120
- {
121
- outputRight[i + startIndex] += gainRight * inputBuffer[i];
122
- }
123
- }
124
- }