spessasynth_core 1.1.3 → 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 -313
  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 -223
  177. package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -133
  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 -272
  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 -175
  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 -285
  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
@@ -1,202 +0,0 @@
1
- import { _addNewMidiPort, _processEvent } from './worklet_sequencer/process_event.js'
2
- import { _findFirstEventIndex, _processTick } from './worklet_sequencer/process_tick.js'
3
- import { loadNewSequence, loadNewSongList, nextSong, previousSong } from './worklet_sequencer/song_control.js'
4
- import { _playTo, _recalculateStartTime, play, setTimeTicks } from './worklet_sequencer/play.js'
5
- import { midiControllers } from '../midi_parser/midi_message.js'
6
- import { SpessaSynthWarn } from '../utils/loggin.js'
7
-
8
- class Sequencer
9
- {
10
- /**
11
- * @param Synthesizer {Synthesizer}
12
- */
13
- constructor(Synthesizer)
14
- {
15
- this.synth = Synthesizer;
16
- this.ignoreEvents = false;
17
-
18
- // event's number in this.events
19
- /**
20
- * @type {number[]}
21
- */
22
- this.eventIndex = [];
23
- this.songIndex = 0;
24
-
25
- // tracks the time that we have already played
26
- /**
27
- * @type {number}
28
- */
29
- this.playedTime = 0;
30
-
31
- /**
32
- * The (relative) time when the sequencer was paused. If it's not paused then it's undefined.
33
- * @type {number}
34
- */
35
- this.pausedTime = undefined;
36
-
37
- /**
38
- * Absolute playback startTime, bases on the synth's time
39
- * @type {number}
40
- */
41
- this.absoluteStartTime = this.currentTime;
42
-
43
- /**
44
- * Controls the playback's rate
45
- * @type {number}
46
- */
47
- this._playbackRate = 1;
48
-
49
- /**
50
- * Currently playing notes (for pausing and resuming)
51
- * @type {{
52
- * midiNote: number,
53
- * channel: number,
54
- * velocity: number
55
- * }[]}
56
- */
57
- this.playingNotes = [];
58
-
59
- /**
60
- * The current song's lenght, in seconds
61
- * @type {number}
62
- */
63
- this.duration = 0;
64
-
65
- // controls if the sequencer loops (defaults to true)
66
- this.loop = true;
67
-
68
- /**
69
- * the current track data
70
- * @type {MIDI}
71
- */
72
- this.midiData = undefined;
73
-
74
- /**
75
- * midi port number for the corresponding track
76
- * @type {number[]}
77
- */
78
- this.midiPorts = [];
79
-
80
- this.midiPortChannelOffset = 0;
81
-
82
- /**
83
- * midi port: channel offset
84
- * @type {Object<number, number>}
85
- */
86
- this.midiPortChannelOffsets = {};
87
- }
88
-
89
- /**
90
- * @param value {number}
91
- */
92
- set playbackRate(value)
93
- {
94
- const time = this.currentTime;
95
- this._playbackRate = value;
96
- this.currentTime = time;
97
- }
98
-
99
- /**
100
- * The current playback time, in seconds
101
- * @return {number}
102
- */
103
- get currentTime()
104
- {
105
- // return the paused time if it's set to something other than undefined
106
- if(this.pausedTime)
107
- {
108
- return this.pausedTime;
109
- }
110
-
111
- return (this.synth.currentTime - this.absoluteStartTime) * this._playbackRate;
112
- }
113
-
114
- set currentTime(time)
115
- {
116
- if(time < 0 || time > this.duration || time === 0)
117
- {
118
- // time is 0
119
- this.setTimeTicks(this.midiData.firstNoteOn - 1);
120
- return;
121
- }
122
- this.stop();
123
- this.playingNotes = [];
124
- this.pausedTime = undefined;
125
- const isNotFinished = this._playTo(time);
126
- this._recalculateStartTime(time);
127
- if(!isNotFinished)
128
- {
129
- return;
130
- }
131
- this.play();
132
- }
133
-
134
- /**
135
- * Pauses the playback
136
- */
137
- pause()
138
- {
139
- if(this.paused)
140
- {
141
- SpessaSynthWarn("Already paused");
142
- return;
143
- }
144
- this.pausedTime = this.currentTime;
145
- this.stop();
146
- }
147
-
148
- /**
149
- * Stops the playback
150
- */
151
- stop()
152
- {
153
- this.clearProcessHandler()
154
- // disable sustain
155
- for (let i = 0; i < 16; i++) {
156
- this.synth.controllerChange(i, midiControllers.sustainPedal, 0);
157
- }
158
- this.synth.stopAllChannels();
159
- }
160
-
161
- _resetTimers()
162
- {
163
- this.playedTime = 0
164
- this.eventIndex = Array(this.tracks.length).fill(0);
165
- }
166
-
167
- /**
168
- * true if paused, false if playing or stopped
169
- * @returns {boolean}
170
- */
171
- get paused()
172
- {
173
- return this.pausedTime !== undefined;
174
- }
175
-
176
- setProcessHandler()
177
- {
178
- this.synth.processTickCallback = this._processTick.bind(this);
179
- }
180
-
181
- clearProcessHandler()
182
- {
183
- this.synth.processTickCallback = undefined;
184
- }
185
- }
186
-
187
- Sequencer.prototype._processEvent = _processEvent;
188
- Sequencer.prototype._addNewMidiPort = _addNewMidiPort;
189
- Sequencer.prototype._processTick = _processTick;
190
- Sequencer.prototype._findFirstEventIndex = _findFirstEventIndex;
191
-
192
- Sequencer.prototype.loadNewSequence = loadNewSequence;
193
- Sequencer.prototype.loadNewSongList = loadNewSongList;
194
- Sequencer.prototype.nextSong = nextSong;
195
- Sequencer.prototype.previousSong = previousSong;
196
-
197
- Sequencer.prototype.play = play;
198
- Sequencer.prototype._playTo = _playTo;
199
- Sequencer.prototype.setTimeTicks = setTimeTicks;
200
- Sequencer.prototype._recalculateStartTime = _recalculateStartTime;
201
-
202
- export { Sequencer }
@@ -1,209 +0,0 @@
1
- import { getEvent, messageTypes, midiControllers } from '../../midi_parser/midi_message.js'
2
-
3
-
4
- // an array with preset default values
5
- const defaultControllerArray = new Int16Array(127);
6
- // default values
7
- defaultControllerArray[midiControllers.mainVolume] = 100;
8
- defaultControllerArray[midiControllers.expressionController] = 127;
9
- defaultControllerArray[midiControllers.pan] = 64;
10
- defaultControllerArray[midiControllers.releaseTime] = 64;
11
- defaultControllerArray[midiControllers.brightness] = 64;
12
- defaultControllerArray[midiControllers.effects1Depth] = 40;
13
-
14
- /**
15
- * plays from start to the target time, excluding note messages (to get the synth to the correct state)
16
- * @private
17
- * @param time {number} in seconds
18
- * @param ticks {number} optional MIDI ticks, when given is used instead of time
19
- * @returns {boolean} true if the midi file is not finished
20
- * @this {Sequencer}
21
- */
22
- export function _playTo(time, ticks = undefined)
23
- {
24
- this.oneTickToSeconds = 60 / (120 * this.midiData.timeDivision);
25
- // process every non note message from the start
26
- this.synth.resetAllControllers();
27
-
28
- this._resetTimers()
29
- /**
30
- * save pitch bends here and send them only after
31
- * @type {number[]}
32
- */
33
- const pitchBends = Array(16).fill(8192);
34
-
35
- /**
36
- * Save controllers here and send them only after
37
- * @type {number[][]}
38
- */
39
- const savedControllers = [];
40
- for (let i = 0; i < 16; i++)
41
- {
42
- savedControllers.push(Array.from(defaultControllerArray));
43
- }
44
-
45
- while(true)
46
- {
47
- // find next event
48
- let trackIndex = this._findFirstEventIndex();
49
- let event = this.tracks[trackIndex][this.eventIndex[trackIndex]];
50
- if(ticks !== undefined)
51
- {
52
- if(event.ticks >= ticks)
53
- {
54
- break;
55
- }
56
- }
57
- else
58
- {
59
- if(this.playedTime >= time)
60
- {
61
- break;
62
- }
63
- }
64
-
65
- // skip note ons
66
- const info = getEvent(event.messageStatusByte);
67
- switch(info.status)
68
- {
69
- // skip note messages
70
- case messageTypes.noteOn:
71
- case messageTypes.noteOff:
72
- break;
73
-
74
- // skip pitch bend
75
- case messageTypes.pitchBend:
76
- pitchBends[info.channel] = event.messageData[1] << 7 | event.messageData[0];
77
- break;
78
-
79
- case messageTypes.controllerChange:
80
-
81
- // do not skip data entries
82
- const controllerNumber = event.messageData[0];
83
- // Keep in mind midi ports to determine channel!!
84
- const channel = info.channel + (this.midiPortChannelOffsets[this.midiPorts[trackIndex]] || 0);
85
- if(
86
- controllerNumber === midiControllers.dataDecrement ||
87
- controllerNumber === midiControllers.dataEntryMsb ||
88
- controllerNumber === midiControllers.dataDecrement ||
89
- controllerNumber === midiControllers.lsbForControl6DataEntry ||
90
- controllerNumber === midiControllers.RPNLsb ||
91
- controllerNumber === midiControllers.RPNMsb ||
92
- controllerNumber === midiControllers.NRPNLsb ||
93
- controllerNumber === midiControllers.NRPNMsb ||
94
- controllerNumber === midiControllers.bankSelect ||
95
- controllerNumber === midiControllers.lsbForControl0BankSelect||
96
- controllerNumber === midiControllers.resetAllControllers
97
- )
98
- {
99
- this.synth.controllerChange(channel, controllerNumber, event.messageData[1]);
100
- }
101
- else
102
- {
103
- if(savedControllers[channel] === undefined)
104
- {
105
- savedControllers[channel] = Array.from(defaultControllerArray);
106
- }
107
- savedControllers[channel][controllerNumber] = event.messageData[1];
108
- }
109
- break;
110
- default:
111
- this._processEvent(event, trackIndex);
112
- break;
113
- }
114
-
115
- this.eventIndex[trackIndex]++;
116
- // find next event
117
- trackIndex = this._findFirstEventIndex();
118
- let nextEvent = this.tracks[trackIndex][this.eventIndex[trackIndex]];
119
- if(nextEvent === undefined)
120
- {
121
- this.stop();
122
- return false;
123
- }
124
- this.playedTime += this.oneTickToSeconds * (nextEvent.ticks - event.ticks);
125
- }
126
-
127
- // restoring saved controllers
128
- // for all synth channels
129
- for (let channelNumber = 0; channelNumber < this.synth.workletProcessorChannels.length; channelNumber++) {
130
- // restore pitch bends
131
- if(pitchBends[channelNumber] !== undefined) {
132
- this.synth.pitchWheel(channelNumber, pitchBends[channelNumber] >> 7, pitchBends[channelNumber] & 0x7F);
133
- }
134
- if(savedControllers[channelNumber] !== undefined)
135
- {
136
- // every controller that has changed
137
- savedControllers[channelNumber].forEach((value, index) => {
138
- if(value !== defaultControllerArray[index])
139
- {
140
- this.synth.controllerChange(channelNumber, index, value);
141
- }
142
- })
143
- }
144
- }
145
- return true;
146
- }
147
-
148
- /**
149
- * Starts the playback
150
- * @param resetTime {boolean} If true, time is set to 0s
151
- * @this {Sequencer}
152
- */
153
- export function play(resetTime = false)
154
- {
155
-
156
- // reset the time if necesarry
157
- if(resetTime)
158
- {
159
- this.currentTime = 0;
160
- return;
161
- }
162
-
163
- if(this.currentTime >= this.duration)
164
- {
165
- this.currentTime = 0;
166
- return;
167
- }
168
-
169
- // unpause if paused
170
- if(this.paused)
171
- {
172
- // adjust the start time
173
- this._recalculateStartTime(this.pausedTime)
174
- this.pausedTime = undefined;
175
- }
176
-
177
- this.playingNotes.forEach(n => {
178
- this.synth.noteOn(n.channel, n.midiNote, n.velocity);
179
- });
180
- this.setProcessHandler();
181
- }
182
-
183
- /**
184
- * @this {Sequencer}
185
- * @param ticks {number}
186
- */
187
- export function setTimeTicks(ticks)
188
- {
189
- this.stop();
190
- this.playingNotes = [];
191
- this.pausedTime = undefined;
192
- const isNotFinished = this._playTo(0, ticks);
193
- this._recalculateStartTime(this.playedTime);
194
- if(!isNotFinished)
195
- {
196
- return;
197
- }
198
- this.play();
199
- }
200
-
201
- /**
202
- * @param time
203
- * @private
204
- * @this {Sequencer}
205
- */
206
- export function _recalculateStartTime(time)
207
- {
208
- this.absoluteStartTime = this.synth.currentTime - time / this._playbackRate;
209
- }
@@ -1,120 +0,0 @@
1
- import { getEvent, messageTypes } from '../../midi_parser/midi_message.js'
2
- import { consoleColors } from '../../utils/other.js'
3
- import { readBytesAsUintBigEndian } from '../../utils/byte_functions.js'
4
- import { SpessaSynthWarn } from '../../utils/loggin.js'
5
-
6
- /**
7
- * Processes a single event
8
- * @param event {MidiMessage}
9
- * @param trackIndex {number}
10
- * @this {Sequencer}
11
- * @private
12
- */
13
- export function _processEvent(event, trackIndex)
14
- {
15
- if(this.ignoreEvents) return;
16
- const statusByteData = getEvent(event.messageStatusByte);
17
- const offset = this.midiPortChannelOffsets[this.midiPorts[trackIndex]] || 0;
18
- statusByteData.channel += offset;
19
- // process the event
20
- switch (statusByteData.status) {
21
- case messageTypes.noteOn:
22
- const velocity = event.messageData[1];
23
- if(velocity > 0) {
24
- this.synth.noteOn(statusByteData.channel, event.messageData[0], velocity);
25
- this.playingNotes.push({
26
- midiNote: event.messageData[0],
27
- channel: statusByteData.channel,
28
- velocity: velocity
29
- });
30
- }
31
- else
32
- {
33
- this.synth.noteOff(statusByteData.channel, event.messageData[0]);
34
- this.playingNotes.splice(this.playingNotes.findIndex(n =>
35
- n.midiNote === event.messageData[0] && n.channel === statusByteData.channel), 1);
36
- }
37
- break;
38
-
39
- case messageTypes.noteOff:
40
- this.synth.noteOff(statusByteData.channel, event.messageData[0]);
41
- this.playingNotes.splice(this.playingNotes.findIndex(n =>
42
- n.midiNote === event.messageData[0] && n.channel === statusByteData.channel), 1);
43
- break;
44
-
45
- case messageTypes.setTempo:
46
- this.oneTickToSeconds = 60 / (getTempo(event) * this.midiData.timeDivision);
47
- if(this.oneTickToSeconds === 0)
48
- {
49
- this.oneTickToSeconds = 60 / (120 * this.midiData.timeDivision);
50
- SpessaSynthWarn("invalid tempo! falling back to 120 BPM");
51
- }
52
- break;
53
-
54
- // recognized but ignored
55
- case messageTypes.midiPort:
56
- case messageTypes.endOfTrack:
57
- case messageTypes.midiChannelPrefix:
58
- case messageTypes.timeSignature:
59
- case messageTypes.songPosition:
60
- case messageTypes.activeSensing:
61
- case messageTypes.keySignature:
62
- break;
63
-
64
- default:
65
- SpessaSynthWarn(`%cUnrecognized Event: %c${event.messageStatusByte}%c status byte: %c${Object.keys(messageTypes).find(k => messageTypes[k] === statusByteData.status)}`,
66
- consoleColors.warn,
67
- consoleColors.unrecognized,
68
- consoleColors.warn,
69
- consoleColors.value);
70
- break;
71
-
72
- case messageTypes.pitchBend:
73
- this.synth.pitchWheel(statusByteData.channel, event.messageData[1], event.messageData[0]);
74
- break;
75
-
76
- case messageTypes.controllerChange:
77
- this.synth.controllerChange(statusByteData.channel, event.messageData[0], event.messageData[1]);
78
- break;
79
-
80
- case messageTypes.programChange:
81
- this.synth.programChange(statusByteData.channel, event.messageData[0]);
82
- break;
83
-
84
- case messageTypes.systemExclusive:
85
- this.synth.systemExclusive(event.messageData, offset);
86
- break;
87
-
88
- case messageTypes.reset:
89
- this.synth.stopAllChannels();
90
- this.synth.resetAllControllers();
91
- break;
92
- }
93
- }
94
-
95
- /**
96
- * Adds 16 channels to the synth
97
- * @this {Sequencer}
98
- * @private
99
- */
100
- export function _addNewMidiPort()
101
- {
102
- for (let i = 0; i < 16; i++) {
103
- this.synth.addNewChannel(true);
104
- if(i === 9)
105
- {
106
- this.synth.setDrums(this.synth.workletProcessorChannels.length - 1, true);
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * gets tempo from the midi message
113
- * @param event {MidiMessage}
114
- * @return {number} the tempo in bpm
115
- */
116
- function getTempo(event)
117
- {
118
- event.messageData.currentIndex = 0;
119
- return 60000000 / readBytesAsUintBigEndian(event.messageData, 3);
120
- }
@@ -1,112 +0,0 @@
1
- import { consoleColors, formatTime } from '../../utils/other.js'
2
- import { SpessaSynthInfo, SpessaSynthWarn } from '../../utils/loggin.js'
3
-
4
- /**
5
- * Loads a new sequence
6
- * @param parsedMidi {MIDI}
7
- * @this {Sequencer}
8
- */
9
- export function loadNewSequence(parsedMidi)
10
- {
11
- this.stop();
12
- if (!parsedMidi.tracks) {
13
- throw "No tracks supplied!";
14
- }
15
-
16
- this.oneTickToSeconds = 60 / (120 * parsedMidi.timeDivision)
17
-
18
- /**
19
- * @type {MIDI}
20
- */
21
- this.midiData = parsedMidi;
22
-
23
- /**
24
- * merge the tracks
25
- * @type {MidiMessage[]}
26
- */
27
- //this.events = this.midiData.tracks.flat();
28
- //this.events.sort((e1, e2) => e1.ticks - e2.ticks);
29
-
30
- /**
31
- * the midi track data
32
- * @type {MidiMessage[][]}
33
- */
34
- this.tracks = this.midiData.tracks;
35
-
36
- // clear last port data
37
- this.midiPortChannelOffset = 0;
38
- this.midiPortChannelOffsets = {};
39
- // copy over the port data
40
- this.midiPorts = this.midiData.midiPorts;
41
-
42
- // assign port offsets
43
- this.midiData.midiPorts.forEach((port, trackIndex) => {
44
- // assign new 16 channels if the port is not occupied yet
45
- if(this.midiPortChannelOffset === 0)
46
- {
47
- this.midiPortChannelOffset += 16;
48
- this.midiPortChannelOffsets[port] = 0;
49
- }
50
-
51
- if(this.midiPortChannelOffsets[port] === undefined)
52
- {
53
- if(this.synth.workletProcessorChannels.length < this.midiPortChannelOffset + 15) {
54
- this._addNewMidiPort();
55
- }
56
- this.midiPortChannelOffsets[port] = this.midiPortChannelOffset;
57
- this.midiPortChannelOffset += 16;
58
- }
59
-
60
- this.midiPorts[trackIndex] = port;
61
- });
62
-
63
- /**
64
- * Same as Audio.duration (seconds)
65
- * @type {number}
66
- */
67
- this.duration = this.midiData.duration;
68
- SpessaSynthInfo(`%cTotal song time: ${formatTime(Math.ceil(this.duration)).time}`, consoleColors.recognized);
69
-
70
- this.synth.resetAllControllers();
71
- if(this.duration <= 1)
72
- {
73
- SpessaSynthWarn(`%cVery short song: (${formatTime(Math.round(this.duration)).time}). Disabling loop!`,
74
- consoleColors.warn);
75
- this.loop = false;
76
- }
77
- this.play(true);
78
- }
79
-
80
- /**
81
- * @param parsedMidis {MIDI[]}
82
- * @this {Sequencer}
83
- */
84
- export function loadNewSongList(parsedMidis)
85
- {
86
- this.songs = parsedMidis;
87
- this.songIndex = 0;
88
- this.loadNewSequence(this.songs[this.songIndex]);
89
- }
90
-
91
- /**
92
- * @this {Sequencer}
93
- */
94
- export function nextSong()
95
- {
96
- this.songIndex++;
97
- this.songIndex %= this.songs.length;
98
- this.loadNewSequence(this.songs[this.songIndex]);
99
- }
100
-
101
- /**
102
- * @this {Sequencer}
103
- */
104
- export function previousSong()
105
- {
106
- this.songIndex--;
107
- if(this.songIndex < 0)
108
- {
109
- this.songIndex = this.songs.length - 1;
110
- }
111
- this.loadNewSequence(this.songs[this.songIndex]);
112
- }
@@ -1,4 +0,0 @@
1
- ## This is the SoundFont2 parsing library.
2
- The code here is responsible for parsing the SoundFont2 file and
3
- providing an easy way to get the data out.
4
- Default modulators are also stored here (in `modulators.js`)