spessasynth_core 1.1.2 → 1.1.4

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 (189) hide show
  1. package/LICENSE +3 -26
  2. package/README.md +156 -474
  3. package/index.js +73 -8
  4. package/package.json +21 -8
  5. package/src/externals/fflate/LICENSE +21 -0
  6. package/src/externals/fflate/fflate.min.js +1 -0
  7. package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +12 -0
  8. package/src/externals/stbvorbis_sync/LICENSE +202 -0
  9. package/src/externals/stbvorbis_sync/NOTICE +6 -0
  10. package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +1 -0
  11. package/src/midi/README.md +32 -0
  12. package/src/midi/basic_midi.js +567 -0
  13. package/src/midi/midi_builder.js +202 -0
  14. package/src/midi/midi_loader.js +324 -0
  15. package/{spessasynth_core/midi_parser → src/midi}/midi_message.js +58 -35
  16. package/src/midi/midi_sequence.js +224 -0
  17. package/src/midi/midi_tools/get_note_times.js +154 -0
  18. package/src/midi/midi_tools/midi_editor.js +611 -0
  19. package/src/midi/midi_tools/midi_writer.js +99 -0
  20. package/src/midi/midi_tools/rmidi_writer.js +567 -0
  21. package/src/midi/midi_tools/used_keys_loaded.js +238 -0
  22. package/src/midi/xmf_loader.js +454 -0
  23. package/src/sequencer/README.md +5 -0
  24. package/src/sequencer/events.js +81 -0
  25. package/src/sequencer/play.js +349 -0
  26. package/src/sequencer/process_event.js +165 -0
  27. package/{spessasynth_core/sequencer/worklet_sequencer → src/sequencer}/process_tick.js +103 -84
  28. package/src/sequencer/sequencer_engine.js +367 -0
  29. package/src/sequencer/song_control.js +201 -0
  30. package/src/soundfont/README.md +13 -0
  31. package/src/soundfont/basic_soundfont/basic_instrument.js +77 -0
  32. package/src/soundfont/basic_soundfont/basic_preset.js +336 -0
  33. package/src/soundfont/basic_soundfont/basic_sample.js +206 -0
  34. package/src/soundfont/basic_soundfont/basic_soundfont.js +565 -0
  35. package/src/soundfont/basic_soundfont/basic_zone.js +64 -0
  36. package/src/soundfont/basic_soundfont/basic_zones.js +43 -0
  37. package/src/soundfont/basic_soundfont/generator.js +220 -0
  38. package/src/soundfont/basic_soundfont/modulator.js +378 -0
  39. package/src/soundfont/basic_soundfont/riff_chunk.js +149 -0
  40. package/src/soundfont/basic_soundfont/write_dls/art2.js +173 -0
  41. package/src/soundfont/basic_soundfont/write_dls/articulator.js +49 -0
  42. package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +400 -0
  43. package/src/soundfont/basic_soundfont/write_dls/ins.js +103 -0
  44. package/src/soundfont/basic_soundfont/write_dls/lins.js +18 -0
  45. package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +330 -0
  46. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +121 -0
  47. package/src/soundfont/basic_soundfont/write_dls/wave.js +94 -0
  48. package/src/soundfont/basic_soundfont/write_dls/write_dls.js +119 -0
  49. package/src/soundfont/basic_soundfont/write_dls/wsmp.js +78 -0
  50. package/src/soundfont/basic_soundfont/write_dls/wvpl.js +32 -0
  51. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +39 -0
  52. package/src/soundfont/basic_soundfont/write_sf2/igen.js +80 -0
  53. package/src/soundfont/basic_soundfont/write_sf2/imod.js +46 -0
  54. package/src/soundfont/basic_soundfont/write_sf2/inst.js +34 -0
  55. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +39 -0
  56. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +82 -0
  57. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +42 -0
  58. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +46 -0
  59. package/src/soundfont/basic_soundfont/write_sf2/sdta.js +80 -0
  60. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +55 -0
  61. package/src/soundfont/basic_soundfont/write_sf2/write.js +222 -0
  62. package/src/soundfont/dls/articulator_converter.js +396 -0
  63. package/src/soundfont/dls/dls_destinations.js +38 -0
  64. package/src/soundfont/dls/dls_preset.js +44 -0
  65. package/src/soundfont/dls/dls_sample.js +75 -0
  66. package/src/soundfont/dls/dls_soundfont.js +186 -0
  67. package/src/soundfont/dls/dls_sources.js +62 -0
  68. package/src/soundfont/dls/dls_zone.js +95 -0
  69. package/src/soundfont/dls/read_articulation.js +299 -0
  70. package/src/soundfont/dls/read_instrument.js +121 -0
  71. package/src/soundfont/dls/read_instrument_list.js +17 -0
  72. package/src/soundfont/dls/read_lart.js +35 -0
  73. package/src/soundfont/dls/read_region.js +152 -0
  74. package/src/soundfont/dls/read_samples.js +270 -0
  75. package/src/soundfont/load_soundfont.js +21 -0
  76. package/src/soundfont/read_sf2/generators.js +46 -0
  77. package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/instruments.js +20 -14
  78. package/src/soundfont/read_sf2/modulators.js +36 -0
  79. package/src/soundfont/read_sf2/presets.js +80 -0
  80. package/src/soundfont/read_sf2/samples.js +304 -0
  81. package/src/soundfont/read_sf2/soundfont.js +305 -0
  82. package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/zones.js +68 -69
  83. package/src/synthetizer/README.md +7 -0
  84. package/src/synthetizer/audio_engine/README.md +9 -0
  85. package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +266 -0
  86. package/src/synthetizer/audio_engine/engine_components/controller_tables.js +88 -0
  87. package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +150 -0
  88. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/lfo.js +9 -6
  89. package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +282 -0
  90. package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +467 -0
  91. package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +181 -0
  92. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/modulator_curves.js +33 -30
  93. package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +221 -0
  94. package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +120 -0
  95. package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/unit_converter.js +11 -4
  96. package/src/synthetizer/audio_engine/engine_components/voice.js +519 -0
  97. package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +401 -0
  98. package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +263 -0
  99. package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +132 -0
  100. package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +48 -0
  101. package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +241 -0
  102. package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +27 -0
  103. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +253 -0
  104. package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +66 -0
  105. package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +17 -0
  106. package/src/synthetizer/audio_engine/engine_methods/note_on.js +175 -0
  107. package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +92 -0
  108. package/src/synthetizer/audio_engine/engine_methods/program_change.js +61 -0
  109. package/src/synthetizer/audio_engine/engine_methods/render_voice.js +196 -0
  110. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +30 -0
  111. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +22 -0
  112. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +28 -0
  113. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +31 -0
  114. package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +21 -0
  115. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +20 -0
  116. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +55 -0
  117. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +16 -0
  118. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +30 -0
  119. package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +63 -0
  120. package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +776 -0
  121. package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +24 -0
  122. package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +33 -0
  123. package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +31 -0
  124. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +15 -0
  125. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +27 -0
  126. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +19 -0
  127. package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +27 -0
  128. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +15 -0
  129. package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +34 -0
  130. package/src/synthetizer/audio_engine/main_processor.js +804 -0
  131. package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +15 -0
  132. package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +175 -0
  133. package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +116 -0
  134. package/src/synthetizer/synth_constants.js +22 -0
  135. package/{spessasynth_core → src}/utils/README.md +1 -0
  136. package/src/utils/buffer_to_wav.js +185 -0
  137. package/src/utils/byte_functions/big_endian.js +32 -0
  138. package/src/utils/byte_functions/little_endian.js +77 -0
  139. package/src/utils/byte_functions/string.js +107 -0
  140. package/src/utils/byte_functions/variable_length_quantity.js +42 -0
  141. package/src/utils/fill_with_defaults.js +21 -0
  142. package/src/utils/indexed_array.js +52 -0
  143. package/{spessasynth_core → src}/utils/loggin.js +70 -78
  144. package/src/utils/other.js +92 -0
  145. package/src/utils/sysex_detector.js +58 -0
  146. package/src/utils/xg_hacks.js +193 -0
  147. package/.idea/inspectionProfiles/Project_Default.xml +0 -10
  148. package/.idea/jsLibraryMappings.xml +0 -6
  149. package/.idea/modules.xml +0 -8
  150. package/.idea/spessasynth_core.iml +0 -12
  151. package/.idea/vcs.xml +0 -6
  152. package/spessasynth_core/midi_parser/README.md +0 -3
  153. package/spessasynth_core/midi_parser/midi_loader.js +0 -386
  154. package/spessasynth_core/sequencer/sequencer.js +0 -202
  155. package/spessasynth_core/sequencer/worklet_sequencer/play.js +0 -209
  156. package/spessasynth_core/sequencer/worklet_sequencer/process_event.js +0 -120
  157. package/spessasynth_core/sequencer/worklet_sequencer/song_control.js +0 -112
  158. package/spessasynth_core/soundfont/README.md +0 -4
  159. package/spessasynth_core/soundfont/chunk/generators.js +0 -205
  160. package/spessasynth_core/soundfont/chunk/modulators.js +0 -232
  161. package/spessasynth_core/soundfont/chunk/presets.js +0 -264
  162. package/spessasynth_core/soundfont/chunk/riff_chunk.js +0 -46
  163. package/spessasynth_core/soundfont/chunk/samples.js +0 -250
  164. package/spessasynth_core/soundfont/soundfont_parser.js +0 -301
  165. package/spessasynth_core/synthetizer/README.md +0 -6
  166. package/spessasynth_core/synthetizer/synthesizer.js +0 -303
  167. package/spessasynth_core/synthetizer/worklet_system/README.md +0 -3
  168. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -290
  169. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -280
  170. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_off.js +0 -102
  171. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_on.js +0 -77
  172. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/program_control.js +0 -140
  173. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/system_exclusive.js +0 -266
  174. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -104
  175. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/vibrato_control.js +0 -29
  176. package/spessasynth_core/synthetizer/worklet_system/worklet_methods/voice_control.js +0 -222
  177. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -95
  178. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +0 -73
  179. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +0 -76
  180. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +0 -194
  181. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +0 -83
  182. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +0 -173
  183. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +0 -106
  184. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +0 -313
  185. package/spessasynth_core/utils/buffer_to_wav.js +0 -70
  186. package/spessasynth_core/utils/byte_functions.js +0 -141
  187. package/spessasynth_core/utils/other.js +0 -49
  188. package/spessasynth_core/utils/shiftable_array.js +0 -26
  189. package/spessasynth_core/utils/stbvorbis_sync.js +0 -1877
@@ -0,0 +1,220 @@
1
+ /**
2
+ * @enum {number}
3
+ */
4
+ export const generatorTypes = {
5
+ INVALID: -1, // invalid generator
6
+ startAddrsOffset: 0, // sample control - moves sample start point
7
+ endAddrOffset: 1, // sample control - moves sample end point
8
+ startloopAddrsOffset: 2, // loop control - moves loop start point
9
+ endloopAddrsOffset: 3, // loop control - moves loop end point
10
+ startAddrsCoarseOffset: 4, // sample control - moves sample start point in 32,768 increments
11
+ modLfoToPitch: 5, // pitch modulation - modulation lfo pitch modulation in cents
12
+ vibLfoToPitch: 6, // pitch modulation - vibrato lfo pitch modulation in cents
13
+ modEnvToPitch: 7, // pitch modulation - modulation envelope pitch modulation in cents
14
+ initialFilterFc: 8, // filter - lowpass filter cutoff in cents
15
+ initialFilterQ: 9, // filter - lowpass filter resonance
16
+ modLfoToFilterFc: 10, // filter modulation - modulation lfo lowpass filter cutoff in cents
17
+ modEnvToFilterFc: 11, // filter modulation - modulation envelope lowpass filter cutoff in cents
18
+ endAddrsCoarseOffset: 12, // ample control - move sample end point in 32,768 increments
19
+ modLfoToVolume: 13, // modulation lfo - volume (tremolo), where 100 = 10dB
20
+ unused1: 14, // unused
21
+ chorusEffectsSend: 15, // effect send - how much is sent to chorus 0 - 1000
22
+ reverbEffectsSend: 16, // effect send - how much is sent to reverb 0 - 1000
23
+ pan: 17, // panning - where -500 = left, 0 = center, 500 = right
24
+ unused2: 18, // unused
25
+ unused3: 19, // unused
26
+ unused4: 20, // unused
27
+ delayModLFO: 21, // mod lfo - delay for mod lfo to start from zero
28
+ freqModLFO: 22, // mod lfo - frequency of mod lfo, 0 = 8.176 Hz, units: f => 1200log2(f/8.176)
29
+ delayVibLFO: 23, // vib lfo - delay for vibrato lfo to start from zero
30
+ freqVibLFO: 24, // vib lfo - frequency of vibrato lfo, 0 = 8.176Hz, unit: f => 1200log2(f/8.176)
31
+ delayModEnv: 25, // mod env - 0 = 1 s decay till mod env starts
32
+ attackModEnv: 26, // mod env - attack of mod env
33
+ holdModEnv: 27, // mod env - hold of mod env
34
+ decayModEnv: 28, // mod env - decay of mod env
35
+ sustainModEnv: 29, // mod env - sustain of mod env
36
+ releaseModEnv: 30, // mod env - release of mod env
37
+ keyNumToModEnvHold: 31, // mod env - also modulating mod envelope hold with key number
38
+ keyNumToModEnvDecay: 32, // mod env - also modulating mod envelope decay with key number
39
+ delayVolEnv: 33, // vol env - delay of envelope from zero (weird scale)
40
+ attackVolEnv: 34, // vol env - attack of envelope
41
+ holdVolEnv: 35, // vol env - hold of envelope
42
+ decayVolEnv: 36, // vol env - decay of envelope
43
+ sustainVolEnv: 37, // vol env - sustain of envelope
44
+ releaseVolEnv: 38, // vol env - release of envelope
45
+ keyNumToVolEnvHold: 39, // vol env - key number to volume envelope hold
46
+ keyNumToVolEnvDecay: 40, // vol env - key number to volume envelope decay
47
+ instrument: 41, // zone - instrument index to use for preset zone
48
+ reserved1: 42, // reserved
49
+ keyRange: 43, // zone - key range for which preset / instrument zone is active
50
+ velRange: 44, // zone - velocity range for which preset / instrument zone is active
51
+ startloopAddrsCoarseOffset: 45, // sample control - moves sample loop start point in 32,768 increments
52
+ keyNum: 46, // zone - instrument only: always use this midi number (ignore what's pressed)
53
+ velocity: 47, // zone - instrument only: always use this velocity (ignore what's pressed)
54
+ initialAttenuation: 48, // zone - allows turning down the volume, 10 = -1dB
55
+ reserved2: 49, // reserved
56
+ endloopAddrsCoarseOffset: 50, // sample control - moves sample loop end point in 32,768 increments
57
+ coarseTune: 51, // tune - pitch offset in semitones
58
+ fineTune: 52, // tune - pitch offset in cents
59
+ sampleID: 53, // sample - instrument zone only: which sample to use
60
+ sampleModes: 54, // sample - 0 = no loop, 1 = loop, 2 = reserved, 3 = loop and play till the end in release phase
61
+ reserved3: 55, // reserved
62
+ scaleTuning: 56, // sample - the degree to which MIDI key number influences pitch, 100 = default
63
+ exclusiveClass: 57, // sample - = cut = choke group
64
+ overridingRootKey: 58, // sample - can override the sample's original pitch
65
+ unused5: 59, // unused
66
+ endOper: 60 // end marker
67
+ };
68
+ /**
69
+ * @type {{min: number, max: number, def: number}[]}
70
+ */
71
+ export const generatorLimits = [];
72
+ // offsets
73
+ generatorLimits[generatorTypes.startAddrsOffset] = { min: 0, max: 32768, def: 0 };
74
+ generatorLimits[generatorTypes.endAddrOffset] = { min: -32768, max: 32768, def: 0 };
75
+ generatorLimits[generatorTypes.startloopAddrsOffset] = { min: -32768, max: 32768, def: 0 };
76
+ generatorLimits[generatorTypes.endloopAddrsOffset] = { min: -32768, max: 32768, def: 0 };
77
+ generatorLimits[generatorTypes.startAddrsCoarseOffset] = { min: 0, max: 32768, def: 0 };
78
+
79
+ // pitch influence
80
+ generatorLimits[generatorTypes.modLfoToPitch] = { min: -12000, max: 12000, def: 0 };
81
+ generatorLimits[generatorTypes.vibLfoToPitch] = { min: -12000, max: 12000, def: 0 };
82
+ generatorLimits[generatorTypes.modEnvToPitch] = { min: -12000, max: 12000, def: 0 };
83
+
84
+ // lowpass
85
+ generatorLimits[generatorTypes.initialFilterFc] = { min: 1500, max: 13500, def: 13500 };
86
+ generatorLimits[generatorTypes.initialFilterQ] = { min: 0, max: 960, def: 0 };
87
+ generatorLimits[generatorTypes.modLfoToFilterFc] = { min: -12000, max: 12000, def: 0 };
88
+ generatorLimits[generatorTypes.modEnvToFilterFc] = { min: -12000, max: 12000, def: 0 };
89
+
90
+ generatorLimits[generatorTypes.endAddrsCoarseOffset] = { min: -32768, max: 32768, def: 0 };
91
+
92
+ generatorLimits[generatorTypes.modLfoToVolume] = { min: -960, max: 960, def: 0 };
93
+
94
+ // effects, pan
95
+ generatorLimits[generatorTypes.chorusEffectsSend] = { min: 0, max: 1000, def: 0 };
96
+ generatorLimits[generatorTypes.reverbEffectsSend] = { min: 0, max: 1000, def: 0 };
97
+ generatorLimits[generatorTypes.pan] = { min: -500, max: 500, def: 0 };
98
+
99
+ // lfo
100
+ generatorLimits[generatorTypes.delayModLFO] = { min: -12000, max: 5000, def: -12000 };
101
+ generatorLimits[generatorTypes.freqModLFO] = { min: -16000, max: 4500, def: 0 };
102
+ generatorLimits[generatorTypes.delayVibLFO] = { min: -12000, max: 5000, def: -12000 };
103
+ generatorLimits[generatorTypes.freqVibLFO] = { min: -16000, max: 4500, def: 0 };
104
+
105
+ // mod env
106
+ generatorLimits[generatorTypes.delayModEnv] = { min: -32768, max: 5000, def: -32768 }; // -32,768 indicates instant phase,
107
+ // this is done to prevent click at the start of filter modenv
108
+ generatorLimits[generatorTypes.attackModEnv] = { min: -32768, max: 8000, def: -32768 };
109
+ generatorLimits[generatorTypes.holdModEnv] = { min: -12000, max: 5000, def: -12000 };
110
+ generatorLimits[generatorTypes.decayModEnv] = { min: -12000, max: 8000, def: -12000 };
111
+ generatorLimits[generatorTypes.sustainModEnv] = { min: 0, max: 1000, def: 0 };
112
+ generatorLimits[generatorTypes.releaseModEnv] = { min: -7200, max: 8000, def: -12000 }; // min is set to -7200 to prevent lowpass clicks
113
+ // key num to mod env
114
+ generatorLimits[generatorTypes.keyNumToModEnvHold] = { min: -1200, max: 1200, def: 0 };
115
+ generatorLimits[generatorTypes.keyNumToModEnvDecay] = { min: -1200, max: 1200, def: 0 };
116
+
117
+ // vol env
118
+ generatorLimits[generatorTypes.delayVolEnv] = { min: -12000, max: 5000, def: -12000 };
119
+ generatorLimits[generatorTypes.attackVolEnv] = { min: -12000, max: 8000, def: -12000 };
120
+ generatorLimits[generatorTypes.holdVolEnv] = { min: -12000, max: 5000, def: -12000 };
121
+ generatorLimits[generatorTypes.decayVolEnv] = { min: -12000, max: 8000, def: -12000 };
122
+ generatorLimits[generatorTypes.sustainVolEnv] = { min: 0, max: 1440, def: 0 };
123
+ generatorLimits[generatorTypes.releaseVolEnv] = { min: -7200, max: 8000, def: -12000 }; // min is set to -7200 prevent clicks
124
+ // key num to vol env
125
+ generatorLimits[generatorTypes.keyNumToVolEnvHold] = { min: -1200, max: 1200, def: 0 };
126
+ generatorLimits[generatorTypes.keyNumToVolEnvDecay] = { min: -1200, max: 1200, def: 0 };
127
+
128
+ generatorLimits[generatorTypes.startloopAddrsCoarseOffset] = { min: -32768, max: 32768, def: 0 };
129
+ generatorLimits[generatorTypes.keyNum] = { min: -1, max: 127, def: -1 };
130
+ generatorLimits[generatorTypes.velocity] = { min: -1, max: 127, def: -1 };
131
+
132
+ generatorLimits[generatorTypes.initialAttenuation] = { min: 0, max: 1440, def: 0 };
133
+
134
+ generatorLimits[generatorTypes.endloopAddrsCoarseOffset] = { min: -32768, max: 32768, def: 0 };
135
+
136
+ generatorLimits[generatorTypes.coarseTune] = { min: -120, max: 120, def: 0 };
137
+ generatorLimits[generatorTypes.fineTune] = { min: -12700, max: 12700, def: 0 }; // this generator is used as initial pitch, hence this range
138
+ generatorLimits[generatorTypes.scaleTuning] = { min: 0, max: 1200, def: 100 };
139
+ generatorLimits[generatorTypes.exclusiveClass] = { min: 0, max: 99999, def: 0 };
140
+ generatorLimits[generatorTypes.overridingRootKey] = { min: 0 - 1, max: 127, def: -1 };
141
+ generatorLimits[generatorTypes.sampleModes] = { min: 0, max: 3, def: 0 };
142
+
143
+ export class Generator
144
+ {
145
+ /**
146
+ * The generator's enum number
147
+ * @type {generatorTypes|number}
148
+ */
149
+ generatorType = generatorTypes.INVALID;
150
+ /**
151
+ * The generator's 16-bit value
152
+ * @type {number}
153
+ */
154
+ generatorValue = 0;
155
+
156
+ /**
157
+ * Constructs a new generator
158
+ * @param type {generatorTypes|number}
159
+ * @param value {number}
160
+ * @param validate {boolean}
161
+ */
162
+ constructor(type = generatorTypes.INVALID, value = 0, validate = true)
163
+ {
164
+ this.generatorType = type;
165
+ if (value === undefined)
166
+ {
167
+ throw new Error("No value provided.");
168
+ }
169
+ this.generatorValue = Math.round(value);
170
+ if (validate)
171
+ {
172
+ const lim = generatorLimits[type];
173
+
174
+ if (lim !== undefined)
175
+ {
176
+ this.generatorValue = Math.max(lim.min, Math.min(lim.max, this.generatorValue));
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ /**
183
+ * generator.js
184
+ * purpose: contains enums for generators,
185
+ * and their limis parses reads soundfont generators, sums them and applies limits
186
+ */
187
+ /**
188
+ * @param generatorType {number}
189
+ * @param presetGens {Generator[]}
190
+ * @param instrumentGens {Generator[]}
191
+ */
192
+ export function addAndClampGenerator(generatorType, presetGens, instrumentGens)
193
+ {
194
+ const limits = generatorLimits[generatorType] || { min: 0, max: 32768, def: 0 };
195
+ let presetGen = presetGens.find(g => g.generatorType === generatorType);
196
+ let presetValue = 0;
197
+ if (presetGen)
198
+ {
199
+ presetValue = presetGen.generatorValue;
200
+ }
201
+
202
+ let instruGen = instrumentGens.find(g => g.generatorType === generatorType);
203
+ let instruValue = limits.def;
204
+ if (instruGen)
205
+ {
206
+ instruValue = instruGen.generatorValue;
207
+ }
208
+
209
+ let value = instruValue + presetValue;
210
+
211
+ // Special case, initial attenuation.
212
+ // Shall get clamped in the volume envelope,
213
+ // so the modulators can be affected by negative generators (the "Brass" patch was problematic...)
214
+ if (generatorType === generatorTypes.initialAttenuation)
215
+ {
216
+ return value;
217
+ }
218
+
219
+ return Math.max(limits.min, Math.min(limits.max, value));
220
+ }
@@ -0,0 +1,378 @@
1
+ import { generatorTypes } from "./generator.js";
2
+ import { midiControllers } from "../../midi/midi_message.js";
3
+
4
+ /**
5
+ * modulators.js
6
+ * purpose: parses soundfont modulators and the source enums, also includes the default modulators list
7
+ **/
8
+
9
+ export const modulatorSources = {
10
+ noController: 0,
11
+ noteOnVelocity: 2,
12
+ noteOnKeyNum: 3,
13
+ polyPressure: 10,
14
+ channelPressure: 13,
15
+ pitchWheel: 14,
16
+ pitchWheelRange: 16,
17
+ link: 127
18
+
19
+ };
20
+ export const modulatorCurveTypes = {
21
+ linear: 0,
22
+ concave: 1,
23
+ convex: 2,
24
+ switch: 3
25
+ };
26
+
27
+ export class Modulator
28
+ {
29
+ /**
30
+ * The current computed value of this modulator
31
+ * @type {number}
32
+ */
33
+ currentValue = 0;
34
+
35
+ /**
36
+ * The source enumeration for this modulator
37
+ * @type {number}
38
+ */
39
+ sourceEnum;
40
+
41
+ /**
42
+ * The secondary source enumeration for this modulator
43
+ * @type {number}
44
+ */
45
+ secondarySourceEnum;
46
+
47
+ /**
48
+ * The generator destination of this modulator
49
+ * @type {generatorTypes}
50
+ */
51
+ modulatorDestination;
52
+
53
+ /**
54
+ * The transform amount for this modulator
55
+ * @type {number}
56
+ */
57
+ transformAmount;
58
+
59
+ /**
60
+ * The transform type for this modulator
61
+ * @type {0|2}
62
+ */
63
+ transformType;
64
+
65
+ /**
66
+ * creates a modulator
67
+ * @param srcEnum {number}
68
+ * @param secSrcEnum {number}
69
+ * @param destination {generatorTypes|number}
70
+ * @param amount {number}
71
+ * @param transformType {number}
72
+ */
73
+ constructor(srcEnum, secSrcEnum, destination, amount, transformType)
74
+ {
75
+ this.sourceEnum = srcEnum;
76
+ this.modulatorDestination = destination;
77
+ this.secondarySourceEnum = secSrcEnum;
78
+ this.transformAmount = amount;
79
+ this.transformType = transformType;
80
+
81
+
82
+ if (this.modulatorDestination > 58)
83
+ {
84
+ this.modulatorDestination = generatorTypes.INVALID; // flag as invalid (for linked ones)
85
+ }
86
+
87
+ // decode the source
88
+ this.sourcePolarity = this.sourceEnum >> 9 & 1;
89
+ this.sourceDirection = this.sourceEnum >> 8 & 1;
90
+ this.sourceUsesCC = this.sourceEnum >> 7 & 1;
91
+ this.sourceIndex = this.sourceEnum & 127;
92
+ this.sourceCurveType = this.sourceEnum >> 10 & 3;
93
+
94
+ // decode the secondary source
95
+ this.secSrcPolarity = this.secondarySourceEnum >> 9 & 1;
96
+ this.secSrcDirection = this.secondarySourceEnum >> 8 & 1;
97
+ this.secSrcUsesCC = this.secondarySourceEnum >> 7 & 1;
98
+ this.secSrcIndex = this.secondarySourceEnum & 127;
99
+ this.secSrcCurveType = this.secondarySourceEnum >> 10 & 3;
100
+
101
+ /**
102
+ * Indicates if the given modulator is chorus or reverb effects modulator.
103
+ * This is done to simulate BASSMIDI effects behavior:
104
+ * - defaults to 1000 transform amount rather than 200
105
+ * - values can be changed, but anything above 200 is 1000
106
+ * (except for values above 1000, they are copied directly)
107
+ * - all values below are multiplied by 5 (200 * 5 = 1000)
108
+ * - still can be disabled if the soundfont has its own modulator curve
109
+ * - this fixes the very low amount of reverb by default and doesn't break soundfonts
110
+ * @type {boolean}
111
+ */
112
+ this.isEffectModulator =
113
+ (
114
+ this.sourceEnum === 0x00DB
115
+ || this.sourceEnum === 0x00DD
116
+ )
117
+ && this.secondarySourceEnum === 0x0
118
+ && (
119
+ this.modulatorDestination === generatorTypes.reverbEffectsSend
120
+ || this.modulatorDestination === generatorTypes.chorusEffectsSend
121
+ );
122
+ }
123
+
124
+ /**
125
+ * @param modulator {Modulator}
126
+ * @returns {Modulator}
127
+ */
128
+ static copy(modulator)
129
+ {
130
+ return new Modulator(
131
+ modulator.sourceEnum,
132
+ modulator.secondarySourceEnum,
133
+ modulator.modulatorDestination,
134
+ modulator.transformAmount,
135
+ modulator.transformType
136
+ );
137
+ }
138
+
139
+ /**
140
+ * @param mod1 {Modulator}
141
+ * @param mod2 {Modulator}
142
+ * @param checkAmount {boolean}
143
+ * @returns {boolean}
144
+ */
145
+ static isIdentical(mod1, mod2, checkAmount = false)
146
+ {
147
+ return (mod1.sourceEnum === mod2.sourceEnum)
148
+ && (mod1.modulatorDestination === mod2.modulatorDestination)
149
+ && (mod1.secondarySourceEnum === mod2.secondarySourceEnum)
150
+ && (mod1.transformType === mod2.transformType)
151
+ && (!checkAmount || (mod1.transformAmount === mod2.transformAmount));
152
+ }
153
+
154
+ /**
155
+ * @param mod {Modulator}
156
+ * @returns {string}
157
+ */
158
+ static debugString(mod)
159
+ {
160
+ function getKeyByValue(object, value)
161
+ {
162
+ return Object.keys(object).find(key => object[key] === value);
163
+ }
164
+
165
+ let sourceString = getKeyByValue(modulatorCurveTypes, mod.sourceCurveType);
166
+ sourceString += mod.sourcePolarity === 0 ? " unipolar " : " bipolar ";
167
+ sourceString += mod.sourceDirection === 0 ? "forwards " : "backwards ";
168
+ if (mod.sourceUsesCC)
169
+ {
170
+ sourceString += getKeyByValue(midiControllers, mod.sourceIndex);
171
+ }
172
+ else
173
+ {
174
+ sourceString += getKeyByValue(modulatorSources, mod.sourceIndex);
175
+ }
176
+
177
+ let secSrcString = getKeyByValue(modulatorCurveTypes, mod.secSrcCurveType);
178
+ secSrcString += mod.secSrcPolarity === 0 ? " unipolar " : " bipolar ";
179
+ secSrcString += mod.secSrcCurveType === 0 ? "forwards " : "backwards ";
180
+ if (mod.secSrcUsesCC)
181
+ {
182
+ secSrcString += getKeyByValue(midiControllers, mod.secSrcIndex);
183
+ }
184
+ else
185
+ {
186
+ secSrcString += getKeyByValue(modulatorSources, mod.secSrcIndex);
187
+ }
188
+ return `Modulator:
189
+ Source: ${sourceString}
190
+ Secondary source: ${secSrcString}
191
+ Destination: ${getKeyByValue(generatorTypes, mod.modulatorDestination)}
192
+ Trasform amount: ${mod.transformAmount}
193
+ Transform type: ${mod.transformType}
194
+ \n\n`;
195
+ }
196
+
197
+ /**
198
+ * Sum transform and create a NEW modulator
199
+ * @param modulator {Modulator}
200
+ * @returns {Modulator}
201
+ */
202
+ sumTransform(modulator)
203
+ {
204
+ return new Modulator(
205
+ this.sourceEnum,
206
+ this.secondarySourceEnum,
207
+ this.modulatorDestination,
208
+ this.transformAmount + modulator.transformAmount,
209
+ this.transformType
210
+ );
211
+ }
212
+ }
213
+
214
+ export const DEFAULT_ATTENUATION_MOD_AMOUNT = 960;
215
+ export const DEFAULT_ATTENUATION_MOD_CURVE_TYPE = modulatorCurveTypes.concave;
216
+
217
+ export function getModSourceEnum(curveType, polarity, direction, isCC, index)
218
+ {
219
+ return (curveType << 10) | (polarity << 9) | (direction << 8) | (isCC << 7) | index;
220
+ }
221
+
222
+ const soundFontModulators = [
223
+ // vel to attenuation
224
+ new Modulator(
225
+ getModSourceEnum(
226
+ DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
227
+ 0,
228
+ 1,
229
+ 0,
230
+ modulatorSources.noteOnVelocity
231
+ ),
232
+ 0x0,
233
+ generatorTypes.initialAttenuation,
234
+ DEFAULT_ATTENUATION_MOD_AMOUNT,
235
+ 0
236
+ ),
237
+
238
+ // mod wheel to vibrato
239
+ new Modulator(0x0081, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
240
+
241
+ // vol to attenuation
242
+ new Modulator(
243
+ getModSourceEnum(
244
+ DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
245
+ 0,
246
+ 1,
247
+ 1,
248
+ midiControllers.mainVolume
249
+ ),
250
+ 0x0,
251
+ generatorTypes.initialAttenuation,
252
+ DEFAULT_ATTENUATION_MOD_AMOUNT,
253
+ 0
254
+ ),
255
+
256
+ // channel pressure to vibrato
257
+ new Modulator(0x000D, 0x0, generatorTypes.vibLfoToPitch, 50, 0),
258
+
259
+ // pitch wheel to tuning
260
+ new Modulator(0x020E, 0x0010, generatorTypes.fineTune, 12700, 0),
261
+
262
+ // pan to uhh, pan
263
+ // amount is 500 instead of 1000, see #59
264
+ new Modulator(0x028A, 0x0, generatorTypes.pan, 500, 0),
265
+
266
+ // expression to attenuation
267
+ new Modulator(
268
+ getModSourceEnum(
269
+ DEFAULT_ATTENUATION_MOD_CURVE_TYPE,
270
+ 0,
271
+ 1,
272
+ 1,
273
+ midiControllers.expressionController
274
+ ),
275
+ 0x0,
276
+ generatorTypes.initialAttenuation,
277
+ DEFAULT_ATTENUATION_MOD_AMOUNT,
278
+ 0
279
+ ),
280
+
281
+ // reverb effects to send
282
+ new Modulator(0x00DB, 0x0, generatorTypes.reverbEffectsSend, 200, 0),
283
+
284
+ // chorus effects to send
285
+ new Modulator(0x00DD, 0x0, generatorTypes.chorusEffectsSend, 200, 0)
286
+ ];
287
+
288
+ const customModulators = [
289
+ // custom modulators heck yeah
290
+ // poly pressure to vibrato
291
+ new Modulator(
292
+ getModSourceEnum(modulatorCurveTypes.linear, 0, 0, 0, modulatorSources.polyPressure),
293
+ 0x0,
294
+ generatorTypes.vibLfoToPitch,
295
+ 50,
296
+ 0
297
+ ),
298
+
299
+ // cc 92 (tremolo) to modLFO volume
300
+ new Modulator(
301
+ getModSourceEnum(
302
+ modulatorCurveTypes.linear,
303
+ 0,
304
+ 0,
305
+ 1,
306
+ midiControllers.tremoloDepth
307
+ ), /*linear forward unipolar cc 92 */
308
+ 0x0, // no controller
309
+ generatorTypes.modLfoToVolume,
310
+ 24,
311
+ 0
312
+ ),
313
+
314
+ // cc 73 (attack time) to volEnv attack
315
+ new Modulator(
316
+ getModSourceEnum(
317
+ modulatorCurveTypes.convex,
318
+ 1,
319
+ 0,
320
+ 1,
321
+ midiControllers.attackTime
322
+ ), // linear forward bipolar cc 72
323
+ 0x0, // no controller
324
+ generatorTypes.attackVolEnv,
325
+ 6000,
326
+ 0
327
+ ),
328
+
329
+ // cc 72 (release time) to volEnv release
330
+ new Modulator(
331
+ getModSourceEnum(
332
+ modulatorCurveTypes.linear,
333
+ 1,
334
+ 0,
335
+ 1,
336
+ midiControllers.releaseTime
337
+ ), // linear forward bipolar cc 72
338
+ 0x0, // no controller
339
+ generatorTypes.releaseVolEnv,
340
+ 3600,
341
+ 0
342
+ ),
343
+
344
+ // cc 74 (brightness) to filterFc
345
+ new Modulator(
346
+ getModSourceEnum(
347
+ modulatorCurveTypes.linear,
348
+ 1,
349
+ 0,
350
+ 1,
351
+ midiControllers.brightness
352
+ ), // linear forwards bipolar cc 74
353
+ 0x0, // no controller
354
+ generatorTypes.initialFilterFc,
355
+ 6000,
356
+ 0
357
+ ),
358
+
359
+ // cc 71 (filter Q) to filter Q
360
+ new Modulator(
361
+ getModSourceEnum(
362
+ modulatorCurveTypes.linear,
363
+ 1,
364
+ 0,
365
+ 1,
366
+ midiControllers.filterResonance
367
+ ), // linear forwards bipolar cc 74
368
+ 0x0, // no controller
369
+ generatorTypes.initialFilterQ,
370
+ 250,
371
+ 0
372
+ )
373
+ ];
374
+
375
+ /**
376
+ * @type {Modulator[]}
377
+ */
378
+ export const defaultModulators = soundFontModulators.concat(customModulators);