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,92 +0,0 @@
1
- // Tests were performed by John Novak
2
- // https://github.com/dosbox-staging/dosbox-staging/pull/2705
3
-
4
- /*
5
- CC 5 value Portamento time
6
- ---------- ---------------
7
- 0 0.000 s
8
- 1 0.006 s
9
- 2 0.023 s
10
- 4 0.050 s
11
- 8 0.110 s
12
- 16 0.250 s
13
- 32 0.500 s
14
- 64 2.060 s
15
- 80 4.200 s
16
- 96 8.400 s
17
- 112 19.500 s
18
- 116 26.700 s
19
- 120 40.000 s
20
- 124 80.000 s
21
- 127 480.000 s
22
- */
23
-
24
- const portamentoLookup = {
25
- 0: 0.000,
26
- 1: 0.006,
27
- 2: 0.023,
28
- 4: 0.050,
29
- 8: 0.110,
30
- 16: 0.250,
31
- 32: 0.500,
32
- 64: 2.060,
33
- 80: 4.200,
34
- 96: 8.400,
35
- 112: 19.500,
36
- 116: 26.700,
37
- 120: 40.000,
38
- 124: 80.000,
39
- 127: 480.000
40
- };
41
-
42
- /**
43
- * @param value {number}
44
- * @returns {number}
45
- */
46
- function getLookup(value)
47
- {
48
- if (portamentoLookup[value] !== undefined)
49
- {
50
- return portamentoLookup[value];
51
- }
52
- // get the nearest lower and upper points from the lookup table
53
- let lower = null;
54
- let upper = null;
55
-
56
- for (let key of Object.keys(portamentoLookup))
57
- {
58
- key = parseInt(key);
59
- if (key < value && (lower === null || key > lower))
60
- {
61
- lower = key;
62
- }
63
- if (key > value && (upper === null || key < upper))
64
- {
65
- upper = key;
66
- }
67
- }
68
-
69
- // if we have found both lower and upper points, perform linear interpolation
70
- if (lower !== null && upper !== null)
71
- {
72
- let lowerTime = portamentoLookup[lower];
73
- let upperTime = portamentoLookup[upper];
74
-
75
- // linear interpolation
76
- return lowerTime + ((value - lower) * (upperTime - lowerTime)) / (upper - lower);
77
- }
78
- return 0;
79
- }
80
-
81
-
82
- /**
83
- * Converts portamento time to seconds
84
- * @param time {number} 0 - 127
85
- * @param distance {number} distance in keys
86
- * @returns {number} seconds
87
- */
88
- export function portamentoTimeToSeconds(time, distance)
89
- {
90
- // this seems to work fine for the MIDIs I have
91
- return getLookup(time) * (distance / 30);
92
- }
@@ -1,35 +0,0 @@
1
- import { SpessaSynthWarn } from "../../../utils/loggin.js";
2
- import { BasicPreset } from "../../../soundfont/basic_soundfont/basic_preset.js";
3
-
4
- /**
5
- * executes a program change
6
- * @param programNumber {number}
7
- * @this {MidiAudioChannel}
8
- */
9
- export function programChange(programNumber)
10
- {
11
- if (this.lockPreset)
12
- {
13
- return;
14
- }
15
- // always 128 for percussion
16
- let bank = this.getBankSelect();
17
-
18
- const isXG = this.isXGChannel;
19
- const p = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
20
- let preset = p.preset;
21
- if (!preset)
22
- {
23
- SpessaSynthWarn("No presets! Using empty fallback.");
24
- preset = new BasicPreset(this.synth.soundfontManager.soundfontList[0].soundfont);
25
- preset.presetName = "SPESSA EMPTY FALLBACK PRESET";
26
- }
27
- this.setPreset(preset);
28
- this.sentBank = Math.min(128, preset.bank + p.bankOffset);
29
- this.synth.callEvent("programchange", {
30
- channel: this.channelNumber,
31
- program: preset.program,
32
- bank: this.sentBank
33
- });
34
- this.sendChannelProperty();
35
- }
@@ -1,214 +0,0 @@
1
- import { VolumeEnvelope } from "../engine_components/volume_envelope.js";
2
- import { ModulationEnvelope } from "../engine_components/modulation_envelope.js";
3
- import { customControllers } from "../engine_components/controller_tables.js";
4
- import { absCentsToHz, timecentsToSeconds } from "../engine_components/unit_converter.js";
5
- import { getLFOValue } from "../engine_components/lfo.js";
6
- import { WavetableOscillator } from "../engine_components/wavetable_oscillator.js";
7
- import { LowpassFilter } from "../engine_components/lowpass_filter.js";
8
- import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
9
-
10
- /**
11
- * Renders a voice to the stereo output buffer
12
- * @param voice {Voice} the voice to render
13
- * @param timeNow {number} current time in seconds
14
- * @param outputLeft {Float32Array} the left output buffer
15
- * @param outputRight {Float32Array} the right output buffer
16
- * @param reverbOutputLeft {Float32Array} left output for reverb
17
- * @param reverbOutputRight {Float32Array} right output for reverb
18
- * @param chorusOutputLeft {Float32Array} left output for chorus
19
- * @param chorusOutputRight {Float32Array} right output for chorus
20
- * @param startIndex {number}
21
- * @param sampleCount {number}
22
- * @this {MidiAudioChannel}
23
- * @returns {boolean} true if the voice is finished
24
- */
25
- export function renderVoice(
26
- voice, timeNow,
27
- outputLeft, outputRight,
28
- reverbOutputLeft, reverbOutputRight,
29
- chorusOutputLeft, chorusOutputRight,
30
- startIndex, sampleCount
31
- )
32
- {
33
- // check if release
34
- if (!voice.isInRelease)
35
- {
36
- // if not in release, check if the release time is
37
- if (timeNow >= voice.releaseStartTime)
38
- {
39
- // release the voice here
40
- voice.isInRelease = true;
41
- VolumeEnvelope.startRelease(voice);
42
- ModulationEnvelope.startRelease(voice);
43
- if (voice.sample.loopingMode === 3)
44
- {
45
- voice.sample.isLooping = false;
46
- }
47
- }
48
- }
49
-
50
-
51
- // if the initial attenuation is more than 100dB, skip the voice (it's silent anyway)
52
- if (voice.modulatedGenerators[generatorTypes.initialAttenuation] > 2500)
53
- {
54
- if (voice.isInRelease)
55
- {
56
- voice.finished = true;
57
- }
58
- return voice.finished;
59
- }
60
-
61
- // TUNING
62
- let targetKey = voice.targetKey;
63
-
64
- // calculate tuning
65
- let cents = voice.modulatedGenerators[generatorTypes.fineTune] // soundfont fine tune
66
- + this.channelOctaveTuning[voice.midiNote] // MTS octave tuning
67
- + this.channelTuningCents; // channel tuning
68
- let semitones = voice.modulatedGenerators[generatorTypes.coarseTune]; // soundfont coarse tuning
69
-
70
- // midi tuning standard
71
- const tuning = this.synth.tunings[this.preset?.program]?.[voice.realKey];
72
- if (tuning !== undefined && tuning?.midiNote >= 0)
73
- {
74
- // override key
75
- targetKey = tuning.midiNote;
76
- // add micro-tonal tuning
77
- cents += tuning.centTuning;
78
- }
79
-
80
- // portamento
81
- if (voice.portamentoFromKey > -1)
82
- {
83
- // 0 to 1
84
- const elapsed = Math.min((timeNow - voice.startTime) / voice.portamentoDuration, 1);
85
- const diff = targetKey - voice.portamentoFromKey;
86
- // zero progress means the pitch being in fromKey, full progress means the normal pitch
87
- semitones -= diff * (1 - elapsed);
88
- }
89
-
90
- // calculate tuning by key using soundfont's scale tuning
91
- cents += (targetKey - voice.sample.rootKey) * voice.modulatedGenerators[generatorTypes.scaleTuning];
92
-
93
- // low pass excursion with LFO and mod envelope
94
- let lowpassExcursion = 0;
95
- let volumeExcursionCentibels = 0;
96
-
97
- // vibrato LFO
98
- const vibPitchDepth = voice.modulatedGenerators[generatorTypes.vibLfoToPitch];
99
- const vibVolDepth = voice.modulatedGenerators[generatorTypes.vibLfoToVolume];
100
- const vibFilterDepth = voice.modulatedGenerators[generatorTypes.vibLfoToFilterFc];
101
- if (vibPitchDepth !== 0 || vibVolDepth !== 0 || vibFilterDepth !== 0)
102
- {
103
- // calculate start time and lfo value
104
- const vibStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayVibLFO]);
105
- const vibFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqVibLFO]);
106
- const vibLfoValue = getLFOValue(vibStart, vibFreqHz, timeNow);
107
- // use modulation multiplier (RPN modulation depth)
108
- cents += vibLfoValue * (vibPitchDepth * this.customControllers[customControllers.modulationMultiplier]);
109
- // vol env volume offset
110
- // negate the lfo value because audigy starts with increase rather than decrease
111
- volumeExcursionCentibels += -vibLfoValue * vibVolDepth;
112
- // low pass frequency
113
- lowpassExcursion += vibLfoValue * vibFilterDepth;
114
- }
115
-
116
- // mod LFO
117
- const modPitchDepth = voice.modulatedGenerators[generatorTypes.modLfoToPitch];
118
- const modVolDepth = voice.modulatedGenerators[generatorTypes.modLfoToVolume];
119
- const modFilterDepth = voice.modulatedGenerators[generatorTypes.modLfoToFilterFc];
120
- // don't compute mod lfo unless necessary
121
- if (modPitchDepth !== 0 || modFilterDepth !== 0 || modVolDepth !== 0)
122
- {
123
- // calculate start time and lfo value
124
- const modStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayModLFO]);
125
- const modFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqModLFO]);
126
- const modLfoValue = getLFOValue(modStart, modFreqHz, timeNow);
127
- // use modulation multiplier (RPN modulation depth)
128
- cents += modLfoValue * (modPitchDepth * this.customControllers[customControllers.modulationMultiplier]);
129
- // vol env volume offset
130
- // negate the lfo value because audigy starts with increase rather than decrease
131
- volumeExcursionCentibels += -modLfoValue * modVolDepth;
132
- // low pass frequency
133
- lowpassExcursion += modLfoValue * modFilterDepth;
134
- }
135
-
136
- // channel vibrato (GS NRPN)
137
- if (this.channelVibrato.depth > 0)
138
- {
139
- // same as others
140
- const channelVibrato = getLFOValue(
141
- voice.startTime + this.channelVibrato.delay,
142
- this.channelVibrato.rate,
143
- timeNow
144
- );
145
- if (channelVibrato)
146
- {
147
- cents += channelVibrato * this.channelVibrato.depth;
148
- }
149
- }
150
-
151
- // mod env
152
- const modEnvPitchDepth = voice.modulatedGenerators[generatorTypes.modEnvToPitch];
153
- const modEnvFilterDepth = voice.modulatedGenerators[generatorTypes.modEnvToFilterFc];
154
- // don't compute mod env unless necessary
155
- if (modEnvFilterDepth !== 0 || modEnvPitchDepth !== 0)
156
- {
157
- const modEnv = ModulationEnvelope.getValue(voice, timeNow);
158
- // apply values
159
- lowpassExcursion += modEnv * modEnvFilterDepth;
160
- cents += modEnv * modEnvPitchDepth;
161
- }
162
-
163
- // default resonant modulator: it does not affect the filter gain (neither XG nor GS did that)
164
- volumeExcursionCentibels -= voice.resonanceOffset;
165
-
166
- // finally, calculate the playback rate
167
- const centsTotal = ~~(cents + semitones * 100);
168
- if (centsTotal !== voice.currentTuningCents)
169
- {
170
- voice.currentTuningCents = centsTotal;
171
- voice.currentTuningCalculated = Math.pow(2, centsTotal / 1200);
172
- }
173
-
174
-
175
- // SYNTHESIS
176
- const bufferOut = new Float32Array(sampleCount);
177
-
178
-
179
- // looping mode 2: start on release. process only volEnv
180
- if (voice.sample.loopingMode === 2 && !voice.isInRelease)
181
- {
182
- VolumeEnvelope.apply(
183
- voice,
184
- bufferOut,
185
- volumeExcursionCentibels,
186
- this.synth.volumeEnvelopeSmoothingFactor
187
- );
188
- return voice.finished;
189
- }
190
-
191
- // wave table oscillator
192
- WavetableOscillator.getSample(voice, bufferOut, this.synth.interpolationType);
193
-
194
- // low pass filter
195
- LowpassFilter.apply(voice, bufferOut, lowpassExcursion, this.synth.filterSmoothingFactor);
196
-
197
- // vol env
198
- VolumeEnvelope.apply(
199
- voice,
200
- bufferOut,
201
- volumeExcursionCentibels,
202
- this.synth.volumeEnvelopeSmoothingFactor
203
- );
204
-
205
- this.panAndMixVoice(
206
- voice,
207
- bufferOut,
208
- outputLeft, outputRight,
209
- reverbOutputLeft, reverbOutputRight,
210
- chorusOutputLeft, chorusOutputRight,
211
- startIndex
212
- );
213
- return voice.finished;
214
- }
@@ -1,42 +0,0 @@
1
- import { loadSoundFont } from "../../../../soundfont/load_soundfont.js";
2
- import { SpessaSynthInfo } from "../../../../utils/loggin.js";
3
- import { consoleColors } from "../../../../utils/other.js";
4
- import { EMBEDDED_SOUND_BANK_ID } from "../../../synth_constants.js";
5
-
6
- /**
7
- * @this {SpessaSynthProcessor}
8
- */
9
- export function clearEmbeddedBank()
10
- {
11
- if (this.soundfontManager.soundfontList.some(s => s.id === EMBEDDED_SOUND_BANK_ID))
12
- {
13
- this.soundfontManager.deleteSoundFont(EMBEDDED_SOUND_BANK_ID);
14
- }
15
- }
16
-
17
- /**
18
- * Sets the embedded (RMI soundfont)
19
- * @param font {ArrayBuffer}
20
- * @param offset {number}
21
- * @this {SpessaSynthProcessor}
22
- */
23
- export function setEmbeddedSoundFont(font, offset)
24
- {
25
- // the embedded bank is set as the first bank in the manager,
26
- // with a special ID that does not clear when reloadManager is performed.
27
- const loadedFont = loadSoundFont(font);
28
- this.soundfontManager.addNewSoundFont(loadedFont, EMBEDDED_SOUND_BANK_ID, offset);
29
- // rearrange so the embedded is first (most important as it overrides all others)
30
- const order = this.soundfontManager.getCurrentSoundFontOrder();
31
- order.pop();
32
- order.unshift(EMBEDDED_SOUND_BANK_ID);
33
- this.soundfontManager.rearrangeSoundFonts(order);
34
-
35
-
36
- // apply snapshot again if applicable
37
- if (this._snapshot !== undefined)
38
- {
39
- this.applySynthesizerSnapshot(this._snapshot);
40
- }
41
- SpessaSynthInfo(`%cEmbedded sound bank set at offset %c${offset}`, consoleColors.recognized, consoleColors.value);
42
- }
@@ -1,19 +0,0 @@
1
- /**
2
- * @this {SpessaSynthProcessor}
3
- */
4
- export function updatePresetList()
5
- {
6
- /**
7
- * @type {{bank: number, presetName: string, program: number}[]}
8
- */
9
- const mainFont = this.soundfontManager.getPresetList();
10
- this.clearCache();
11
- this.callEvent("presetlistchange", mainFont);
12
- this.getDefaultPresets();
13
- // unlock presets
14
- this.midiAudioChannels.forEach(c =>
15
- {
16
- c.setPresetLock(false);
17
- });
18
- this.resetAllControllers(false);
19
- }
@@ -1,23 +0,0 @@
1
- import { customControllers } from "../../engine_components/controller_tables.js";
2
- import { generatorTypes } from "../../../../soundfont/basic_soundfont/generator_types.js";
3
-
4
- /**
5
- * Stops a note nearly instantly
6
- * @param midiNote {number}
7
- * @param releaseTime {number} ticks
8
- * @this {MidiAudioChannel}
9
- */
10
- export function killNote(midiNote, releaseTime = -12000)
11
- {
12
- midiNote += this.customControllers[customControllers.channelKeyShift];
13
-
14
- this.voices.forEach(v =>
15
- {
16
- if (v.realKey !== midiNote)
17
- {
18
- return;
19
- }
20
- v.modulatedGenerators[generatorTypes.releaseVolEnv] = releaseTime; // set release to be very short
21
- v.release(this.synth.currentSynthTime);
22
- });
23
- }
@@ -1,56 +0,0 @@
1
- import { SpessaSynthWarn } from "../../../../utils/loggin.js";
2
- import { customControllers } from "../../engine_components/controller_tables.js";
3
-
4
- /**
5
- * Release a note
6
- * @param midiNote {number}
7
- * @this {MidiAudioChannel}
8
- */
9
- export function noteOff(midiNote)
10
- {
11
- if (midiNote > 127 || midiNote < 0)
12
- {
13
- SpessaSynthWarn(`Received a noteOn for note`, midiNote, "Ignoring.");
14
- return;
15
- }
16
-
17
- let realKey = midiNote + this.channelTransposeKeyShift + this.customControllers[customControllers.channelKeyShift];
18
-
19
- // if high performance mode, kill notes instead of stopping them
20
- if (this.synth.highPerformanceMode)
21
- {
22
- // if the channel is percussion channel, do not kill the notes
23
- if (!this.drumChannel)
24
- {
25
- this.killNote(realKey, -6950);
26
- this.synth.callEvent("noteoff", {
27
- midiNote: midiNote,
28
- channel: this.channelNumber
29
- });
30
- return;
31
- }
32
- }
33
-
34
- const channelVoices = this.voices;
35
- channelVoices.forEach(v =>
36
- {
37
- if (v.realKey !== realKey || v.isInRelease === true)
38
- {
39
- return;
40
- }
41
- // if hold pedal, move to sustain
42
- if (this.holdPedal)
43
- {
44
- this.sustainedVoices.push(v);
45
- }
46
- else
47
- {
48
- v.release(this.synth.currentSynthTime);
49
- }
50
- });
51
- this.synth.callEvent("noteoff", {
52
- midiNote: midiNote,
53
- channel: this.channelNumber
54
- });
55
- }
56
-
@@ -1,16 +0,0 @@
1
- import { SpessaSynthInfo } from "../../../../utils/loggin.js";
2
- import { consoleColors } from "../../../../utils/other.js";
3
-
4
- /**
5
- * @this {SpessaSynthProcessor}
6
- * @param force {boolean}
7
- */
8
- export function stopAllChannels(force = false)
9
- {
10
- SpessaSynthInfo("%cStop all received!", consoleColors.info);
11
- for (let i = 0; i < this.midiAudioChannels.length; i++)
12
- {
13
- this.midiAudioChannels[i].stopAllNotes(force);
14
- }
15
- this.callEvent("stopall", undefined);
16
- }
@@ -1,30 +0,0 @@
1
- /**
2
- * stops all notes on a given channel
3
- * @param force {boolean}
4
- * @this {MidiAudioChannel}
5
- */
6
- export function stopAllNotes(force = false)
7
- {
8
- if (force)
9
- {
10
- // force stop all
11
- this.voices.length = 0;
12
- this.sustainedVoices.length = 0;
13
- this.sendChannelProperty();
14
- }
15
- else
16
- {
17
- this.voices.forEach(v =>
18
- {
19
- if (v.isInRelease)
20
- {
21
- return;
22
- }
23
- v.release(this.synth.currentSynthTime);
24
- });
25
- this.sustainedVoices.forEach(v =>
26
- {
27
- v.release(this.synth.currentSynthTime);
28
- });
29
- }
30
- }
@@ -1,63 +0,0 @@
1
- /**
2
- * @param channel {MidiAudioChannel}
3
- * @param voice {Voice}
4
- * @return {number}
5
- */
6
- function getPriority(channel, voice)
7
- {
8
- let priority = 0;
9
- if (channel.drumChannel)
10
- {
11
- // important
12
- priority += 5;
13
- }
14
- if (voice.isInRelease)
15
- {
16
- // not important
17
- priority -= 5;
18
- }
19
- // less velocity = less important
20
- priority += voice.velocity / 25; // map to 0-5
21
- // the newer, more important
22
- priority -= voice.volumeEnvelope.state;
23
- if (voice.isInRelease)
24
- {
25
- priority -= 5;
26
- }
27
- priority -= voice.volumeEnvelope.currentAttenuationDb / 50;
28
- return priority;
29
- }
30
-
31
- /**
32
- * @this {SpessaSynthProcessor}
33
- * @param amount {number}
34
- */
35
- export function voiceKilling(amount)
36
- {
37
- let allVoices = [];
38
- for (const channel of this.midiAudioChannels)
39
- {
40
- for (const voice of channel.voices)
41
- {
42
- if (!voice.finished)
43
- {
44
- const priority = getPriority(channel, voice);
45
- allVoices.push({ channel, voice, priority });
46
- }
47
- }
48
- }
49
-
50
- // Step 2: Sort voices by priority (ascending order)
51
- allVoices.sort((a, b) => a.priority - b.priority);
52
- const voicesToRemove = allVoices.slice(0, amount);
53
-
54
- for (const { channel, voice } of voicesToRemove)
55
- {
56
- const index = channel.voices.indexOf(voice);
57
- if (index > -1)
58
- {
59
- channel.voices.splice(index, 1);
60
- }
61
- }
62
- }
63
-