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,104 +0,0 @@
1
- /**
2
- * Processes a single tick
3
- * @this {SpessaSynthSequencer}
4
- */
5
- export function processTick()
6
- {
7
- if (!this.isActive)
8
- {
9
- return;
10
- }
11
- let current = this.currentTime;
12
- while (this.playedTime < current)
13
- {
14
- // find the next event
15
- let trackIndex = this._findFirstEventIndex();
16
- let event = this.tracks[trackIndex][this.eventIndex[trackIndex]];
17
- this._processEvent(event, trackIndex);
18
-
19
- this.eventIndex[trackIndex]++;
20
-
21
- // find the next event
22
- trackIndex = this._findFirstEventIndex();
23
- if (this.tracks[trackIndex].length <= this.eventIndex[trackIndex])
24
- {
25
- // the song has ended
26
- if (this.loop)
27
- {
28
- this.setTimeTicks(this.midiData.loop.start);
29
- return;
30
- }
31
- this.eventIndex[trackIndex]--;
32
- this.pause(true);
33
- if (this.songs.length > 1)
34
- {
35
- this.nextSong();
36
- }
37
- return;
38
- }
39
- let eventNext = this.tracks[trackIndex][this.eventIndex[trackIndex]];
40
- this.playedTime += this.oneTickToSeconds * (eventNext.ticks - event.ticks);
41
-
42
- const canLoop = this.loop && (this.loopCount > 0 || this.loopCount === -1);
43
-
44
- // if we reached loop.end
45
- if ((this.midiData.loop.end <= event.ticks) && canLoop)
46
- {
47
- // loop
48
- if (this.loopCount !== Infinity)
49
- {
50
- this.loopCount--;
51
- this?.onLoopCountChange?.(this.loopCount);
52
- }
53
- this.setTimeTicks(this.midiData.loop.start);
54
- return;
55
- }
56
- // if the song has ended
57
- else if (current >= this.duration)
58
- {
59
- if (canLoop)
60
- {
61
- // loop
62
- if (this.loopCount !== Infinity)
63
- {
64
- this.loopCount--;
65
- this?.onLoopCountChange?.(this.loopCount);
66
- }
67
- this.setTimeTicks(this.midiData.loop.start);
68
- return;
69
- }
70
- // stop the playback
71
- this.eventIndex[trackIndex]--;
72
- this.pause(true);
73
- if (this.songs.length > 1)
74
- {
75
- this.nextSong();
76
- }
77
- return;
78
- }
79
- }
80
- }
81
-
82
-
83
- /**
84
- * @returns {number} the index of the first to the current played time
85
- * @this {SpessaSynthSequencer}
86
- */
87
- export function _findFirstEventIndex()
88
- {
89
- let index = 0;
90
- let ticks = Infinity;
91
- this.tracks.forEach((track, i) =>
92
- {
93
- if (this.eventIndex[i] >= track.length)
94
- {
95
- return;
96
- }
97
- if (track[this.eventIndex[i]].ticks < ticks)
98
- {
99
- index = i;
100
- ticks = track[this.eventIndex[i]].ticks;
101
- }
102
- });
103
- return index;
104
- }
@@ -1,372 +0,0 @@
1
- import { _addNewMidiPort, _processEvent } from "./process_event.js";
2
- import { _findFirstEventIndex, processTick } from "./process_tick.js";
3
- import { assignMIDIPort, loadNewSequence, loadNewSongList, nextSong, previousSong } from "./song_control.js";
4
- import { _playTo, _recalculateStartTime, play, setTimeTicks } from "./play.js";
5
- import { messageTypes, midiControllers } from "../midi/midi_message.js";
6
- import { sendMIDICC, sendMIDIMessage, sendMIDIPitchWheel, sendMIDIProgramChange, sendMIDIReset } from "./events.js";
7
- import { SpessaSynthWarn } from "../utils/loggin.js";
8
-
9
- import { MIDI_CHANNEL_COUNT } from "../synthetizer/synth_constants.js";
10
-
11
- class SpessaSynthSequencer
12
- {
13
- /**
14
- * All the sequencer's songs
15
- * @type {BasicMIDI[]}
16
- */
17
- songs = [];
18
-
19
- /**
20
- * Current song index
21
- * @type {number}
22
- */
23
- songIndex = 0;
24
-
25
- /**
26
- * shuffled song indexes
27
- * @type {number[]}
28
- */
29
- shuffledSongIndexes = [];
30
-
31
- /**
32
- * the synth to use
33
- * @type {SpessaSynthProcessor}
34
- */
35
- synth;
36
-
37
- /**
38
- * if the sequencer is active
39
- * @type {boolean}
40
- */
41
- isActive = false;
42
-
43
- /**
44
- * If the event should instead be sent back to the main thread instead of synth
45
- * @type {boolean}
46
- */
47
- sendMIDIMessages = false;
48
-
49
- /**
50
- * sequencer's loop count
51
- * @type {number}
52
- */
53
- loopCount = Infinity;
54
-
55
- /**
56
- * event's number in this.events
57
- * @type {number[]}
58
- */
59
- eventIndex = [];
60
-
61
- /**
62
- * tracks the time that has already been played
63
- * @type {number}
64
- */
65
- playedTime = 0;
66
-
67
- /**
68
- * The (relative) time when the sequencer was paused. If it's not paused, then it's undefined.
69
- * @type {number}
70
- */
71
- pausedTime = undefined;
72
-
73
- /**
74
- * Absolute playback startTime, bases on the synth's time
75
- * @type {number}
76
- */
77
- absoluteStartTime = 0;
78
- /**
79
- * Currently playing notes (for pausing and resuming)
80
- * @type {{
81
- * midiNote: number,
82
- * channel: number,
83
- * velocity: number
84
- * }[]}
85
- */
86
- playingNotes = [];
87
-
88
- /**
89
- * controls if the sequencer loops (defaults to true)
90
- * @type {boolean}
91
- */
92
- loop = true;
93
-
94
- /**
95
- * controls if the songs are ordered randomly
96
- * @type {boolean}
97
- */
98
- shuffleMode = false;
99
-
100
- /**
101
- * the current track data
102
- * @type {BasicMIDI}
103
- */
104
- midiData = undefined;
105
-
106
- /**
107
- * midi port number for the corresponding track
108
- * @type {number[]}
109
- */
110
- midiPorts = [];
111
- midiPortChannelOffset = 0;
112
- /**
113
- * stored as:
114
- * Record<midi port, channel offset>
115
- * @type {Record<number, number>}
116
- */
117
- midiPortChannelOffsets = {};
118
-
119
- /**
120
- * @type {boolean}
121
- */
122
- skipToFirstNoteOn = true;
123
-
124
- /**
125
- * If true, seq will stay paused when seeking or changing the playback rate
126
- * @type {boolean}
127
- */
128
- preservePlaybackState = false;
129
-
130
- /**
131
- * Called on a MIDI message if sending MIDI messages is enabled
132
- * @type {function(message: number[])}
133
- */
134
- onMIDIMessage;
135
-
136
- /**
137
- * Called when the time changes
138
- * @type {function(newTime: number)}
139
- */
140
- onTimeChange;
141
-
142
- /**
143
- * Calls when sequencer stops the playback
144
- * @type {function(isFinished: boolean)}
145
- */
146
- onPlaybackStop;
147
-
148
- /**
149
- * Calls after the songs have been processed but before the playback begins
150
- * @type {function(newSongList: BasicMIDI[])}
151
- */
152
- onSongListChange;
153
-
154
- /**
155
- * Calls when the song is changed (for example, in a playlist)
156
- * @type {function(songIndex: number, autoPlay: boolean)}
157
- */
158
- onSongChange;
159
-
160
- /**
161
- * Calls when a meta-event occurs
162
- * @type {function(e: MIDIMessage, trackIndex: number)}
163
- */
164
- onMetaEvent;
165
-
166
- /**
167
- * Calls when the loop count changes (usually decreases)
168
- * @type {function(count: number)}
169
- */
170
- onLoopCountChange;
171
-
172
- /**
173
- * @param spessasynthProcessor {SpessaSynthProcessor}
174
- */
175
- constructor(spessasynthProcessor)
176
- {
177
- this.synth = spessasynthProcessor;
178
- this.absoluteStartTime = this.synth.currentSynthTime;
179
- }
180
-
181
- /**
182
- * Controls the playback's rate
183
- * @type {number}
184
- * @private
185
- */
186
- _playbackRate = 1;
187
-
188
- // noinspection JSUnusedGlobalSymbols
189
- /**
190
- * @param value {number}
191
- */
192
- set playbackRate(value)
193
- {
194
- const time = this.currentTime;
195
- this._playbackRate = value;
196
- this.currentTime = time;
197
- }
198
-
199
- get currentTime()
200
- {
201
- // return the paused time if it's set to something other than undefined
202
- if (this.pausedTime !== undefined)
203
- {
204
- return this.pausedTime;
205
- }
206
-
207
- return (this.synth.currentSynthTime - this.absoluteStartTime) * this._playbackRate;
208
- }
209
-
210
- set currentTime(time)
211
- {
212
- if (!this.midiData)
213
- {
214
- return;
215
- }
216
- if (time > this.duration || time < 0)
217
- {
218
- // time is 0
219
- if (this.skipToFirstNoteOn)
220
- {
221
- this.setTimeTicks(this.midiData.firstNoteOn - 1);
222
- }
223
- else
224
- {
225
- this.setTimeTicks(0);
226
- }
227
- return;
228
- }
229
- if (this.skipToFirstNoteOn)
230
- {
231
- if (time < this.firstNoteTime)
232
- {
233
- this.setTimeTicks(this.midiData.firstNoteOn - 1);
234
- return;
235
- }
236
- }
237
- this.stop();
238
- this.playingNotes = [];
239
- const wasPaused = this.paused && this.preservePlaybackState;
240
- this.pausedTime = undefined;
241
- this?.onTimeChange?.(time);
242
- if (this.midiData.duration === 0)
243
- {
244
- SpessaSynthWarn("No duration!");
245
- this?.onPlaybackStop?.(true);
246
- return;
247
- }
248
- this._playTo(time);
249
- this._recalculateStartTime(time);
250
- if (wasPaused)
251
- {
252
- this.pause();
253
- }
254
- else
255
- {
256
- this.play();
257
- }
258
- }
259
-
260
- /**
261
- * true if paused, false if playing or stopped
262
- * @returns {boolean}
263
- */
264
- get paused()
265
- {
266
- return this.pausedTime !== undefined;
267
- }
268
-
269
- /**
270
- * Pauses the playback
271
- * @param isFinished {boolean}
272
- */
273
- pause(isFinished = false)
274
- {
275
- if (this.paused)
276
- {
277
- SpessaSynthWarn("Already paused");
278
- return;
279
- }
280
- this.pausedTime = this.currentTime;
281
- this.stop();
282
- this?.onPlaybackStop?.(isFinished);
283
- }
284
-
285
- /**
286
- * Stops the playback
287
- */
288
- stop()
289
- {
290
- this.clearProcessHandler();
291
- // disable sustain
292
- for (let i = 0; i < 16; i++)
293
- {
294
- this.synth.controllerChange(i, midiControllers.sustainPedal, 0);
295
- }
296
- this.synth.stopAllChannels();
297
- if (this.sendMIDIMessages)
298
- {
299
- for (let note of this.playingNotes)
300
- {
301
- this.sendMIDIMessage([messageTypes.noteOff | (note.channel % 16), note.midiNote]);
302
- }
303
- for (let c = 0; c < MIDI_CHANNEL_COUNT; c++)
304
- {
305
- this.sendMIDICC(c, midiControllers.allNotesOff, 0);
306
- }
307
- }
308
- }
309
-
310
- loadCurrentSong(autoPlay = true)
311
- {
312
- let index = this.songIndex;
313
- if (this.shuffleMode)
314
- {
315
- index = this.shuffledSongIndexes[this.songIndex];
316
- }
317
- this.loadNewSequence(this.songs[index], autoPlay);
318
- }
319
-
320
- _resetTimers()
321
- {
322
- this.playedTime = 0;
323
- this.eventIndex = Array(this.tracks.length).fill(0);
324
- }
325
-
326
- setProcessHandler()
327
- {
328
- this.isActive = true;
329
- }
330
-
331
- clearProcessHandler()
332
- {
333
- this.isActive = false;
334
- }
335
-
336
- shuffleSongIndexes()
337
- {
338
- const indexes = this.songs.map((_, i) => i);
339
- this.shuffledSongIndexes = [];
340
- while (indexes.length > 0)
341
- {
342
- const index = indexes[Math.floor(Math.random() * indexes.length)];
343
- this.shuffledSongIndexes.push(index);
344
- indexes.splice(indexes.indexOf(index), 1);
345
- }
346
- }
347
- }
348
-
349
- // Web MIDI sending
350
- SpessaSynthSequencer.prototype.sendMIDIMessage = sendMIDIMessage;
351
- SpessaSynthSequencer.prototype.sendMIDIReset = sendMIDIReset;
352
- SpessaSynthSequencer.prototype.sendMIDICC = sendMIDICC;
353
- SpessaSynthSequencer.prototype.sendMIDIProgramChange = sendMIDIProgramChange;
354
- SpessaSynthSequencer.prototype.sendMIDIPitchWheel = sendMIDIPitchWheel;
355
- SpessaSynthSequencer.prototype.assignMIDIPort = assignMIDIPort;
356
-
357
- SpessaSynthSequencer.prototype._processEvent = _processEvent;
358
- SpessaSynthSequencer.prototype._addNewMidiPort = _addNewMidiPort;
359
- SpessaSynthSequencer.prototype.processTick = processTick;
360
- SpessaSynthSequencer.prototype._findFirstEventIndex = _findFirstEventIndex;
361
-
362
- SpessaSynthSequencer.prototype.loadNewSequence = loadNewSequence;
363
- SpessaSynthSequencer.prototype.loadNewSongList = loadNewSongList;
364
- SpessaSynthSequencer.prototype.nextSong = nextSong;
365
- SpessaSynthSequencer.prototype.previousSong = previousSong;
366
-
367
- SpessaSynthSequencer.prototype.play = play;
368
- SpessaSynthSequencer.prototype._playTo = _playTo;
369
- SpessaSynthSequencer.prototype.setTimeTicks = setTimeTicks;
370
- SpessaSynthSequencer.prototype._recalculateStartTime = _recalculateStartTime;
371
-
372
- export { SpessaSynthSequencer };
@@ -1,196 +0,0 @@
1
- import { consoleColors, formatTime } from "../utils/other.js";
2
- import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn } from "../utils/loggin.js";
3
- import { BasicMIDI } from "../midi/basic_midi.js";
4
-
5
- /**
6
- * @param trackNum {number}
7
- * @param port {number}
8
- * @this {SpessaSynthSequencer}
9
- */
10
- export function assignMIDIPort(trackNum, port)
11
- {
12
- // do not assign ports to empty tracks
13
- if (this.midiData.usedChannelsOnTrack[trackNum].size === 0)
14
- {
15
- return;
16
- }
17
-
18
- // assign new 16 channels if the port is not occupied yet
19
- if (this.midiPortChannelOffset === 0)
20
- {
21
- this.midiPortChannelOffset += 16;
22
- this.midiPortChannelOffsets[port] = 0;
23
- }
24
-
25
- if (this.midiPortChannelOffsets[port] === undefined)
26
- {
27
- if (this.synth.midiAudioChannels.length < this.midiPortChannelOffset + 15)
28
- {
29
- this._addNewMidiPort();
30
- }
31
- this.midiPortChannelOffsets[port] = this.midiPortChannelOffset;
32
- this.midiPortChannelOffset += 16;
33
- }
34
-
35
- this.midiPorts[trackNum] = port;
36
- }
37
-
38
- /**
39
- * Loads a new sequence
40
- * @param parsedMidi {BasicMIDI}
41
- * @param autoPlay {boolean}
42
- * @this {SpessaSynthSequencer}
43
- * @private
44
- */
45
- export function loadNewSequence(parsedMidi, autoPlay = true)
46
- {
47
- this.stop();
48
- if (!parsedMidi.tracks)
49
- {
50
- throw new Error("This MIDI has no tracks!");
51
- }
52
-
53
- this.oneTickToSeconds = 60 / (120 * parsedMidi.timeDivision);
54
-
55
- /**
56
- * @type {BasicMIDI}
57
- */
58
- this.midiData = parsedMidi;
59
-
60
- // clear old embedded bank if exists
61
- this.synth.clearEmbeddedBank();
62
-
63
- // check for embedded soundfont
64
- if (this.midiData.embeddedSoundFont !== undefined)
65
- {
66
- SpessaSynthInfo("%cEmbedded soundfont detected! Using it.", consoleColors.recognized);
67
- this.synth.setEmbeddedSoundFont(this.midiData.embeddedSoundFont, this.midiData.bankOffset);
68
- }
69
-
70
- SpessaSynthGroupCollapsed("%cPreloading samples...", consoleColors.info);
71
- // smart preloading: load only samples used in the midi!
72
- const used = this.midiData.getUsedProgramsAndKeys(this.synth.soundfontManager);
73
- for (const [programBank, combos] of Object.entries(used))
74
- {
75
- const [bank, program] = programBank.split(":").map(Number);
76
- const preset = this.synth.getPreset(bank, program);
77
- SpessaSynthInfo(
78
- `%cPreloading used samples on %c${preset.presetName}%c...`,
79
- consoleColors.info,
80
- consoleColors.recognized,
81
- consoleColors.info
82
- );
83
- for (const combo of combos)
84
- {
85
- const [midiNote, velocity] = combo.split("-").map(Number);
86
- this.synth.getVoicesForPreset(preset, bank, program, midiNote, velocity, midiNote);
87
- }
88
- }
89
- SpessaSynthGroupEnd();
90
-
91
- /**
92
- * the midi track data
93
- * @type {MIDIMessage[][]}
94
- */
95
- this.tracks = this.midiData.tracks;
96
-
97
- // copy over the port data
98
- this.midiPorts = this.midiData.midiPorts.slice();
99
-
100
- // clear last port data
101
- this.midiPortChannelOffset = 0;
102
- this.midiPortChannelOffsets = {};
103
- // assign port offsets
104
- this.midiData.midiPorts.forEach((port, trackIndex) =>
105
- {
106
- this.assignMIDIPort(trackIndex, port);
107
- });
108
-
109
- /**
110
- * Same as "audio.duration" property (seconds)
111
- * @type {number}
112
- */
113
- this.duration = this.midiData.duration;
114
- this.firstNoteTime = this.midiData.MIDIticksToSeconds(this.midiData.firstNoteOn);
115
- SpessaSynthInfo(`%cTotal song time: ${formatTime(Math.ceil(this.duration)).time}`, consoleColors.recognized);
116
- this?.onSongChange?.(this.songIndex, autoPlay);
117
-
118
- if (this.duration <= 1)
119
- {
120
- SpessaSynthWarn(
121
- `%cVery short song: (${formatTime(Math.round(this.duration)).time}). Disabling loop!`,
122
- consoleColors.warn
123
- );
124
- this.loop = false;
125
- }
126
- if (autoPlay)
127
- {
128
- this.play(true);
129
- }
130
- else
131
- {
132
- // this shall not play: play to the first note and then wait
133
- const targetTime = this.skipToFirstNoteOn ? this.midiData.firstNoteOn - 1 : 0;
134
- this.setTimeTicks(targetTime);
135
- this.pause();
136
- }
137
- }
138
-
139
- /**
140
- * @param midiBuffers {BasicMIDI[]}
141
- * @param autoPlay {boolean}
142
- * @this {SpessaSynthSequencer}
143
- */
144
- export function loadNewSongList(midiBuffers, autoPlay = true)
145
- {
146
- /**
147
- * parse the MIDIs (only the array buffers, MIDI is unchanged)
148
- * @type {BasicMIDI[]}
149
- */
150
- this.songs = midiBuffers;
151
- if (this.songs.length < 1)
152
- {
153
- return;
154
- }
155
- this.songIndex = 0;
156
- if (this.songs.length > 1)
157
- {
158
- this.loop = false;
159
- }
160
- this.shuffleSongIndexes();
161
- this?.onSongListChange?.(this.songs);
162
- this.loadCurrentSong(autoPlay);
163
- }
164
-
165
- /**
166
- * @this {SpessaSynthSequencer}
167
- */
168
- export function nextSong()
169
- {
170
- if (this.songs.length === 1)
171
- {
172
- this.currentTime = 0;
173
- return;
174
- }
175
- this.songIndex++;
176
- this.songIndex %= this.songs.length;
177
- this.loadCurrentSong();
178
- }
179
-
180
- /**
181
- * @this {SpessaSynthSequencer}
182
- */
183
- export function previousSong()
184
- {
185
- if (this.songs.length === 1)
186
- {
187
- this.currentTime = 0;
188
- return;
189
- }
190
- this.songIndex--;
191
- if (this.songIndex < 0)
192
- {
193
- this.songIndex = this.songs.length - 1;
194
- }
195
- this.loadCurrentSong();
196
- }
@@ -1,11 +0,0 @@
1
- ## This is the SoundFont and DLS parsing library.
2
-
3
- The code here is responsible for parsing the SoundFont2/DLS file and
4
- providing an easy way to get the data out.
5
-
6
- - `basic_soundfont` folder contains the classes that represent a sound bank file.
7
- It also contains the code for writing the files.
8
-
9
- - `read_sf2` folder contains the code for reading a `.sf2` file.
10
-
11
- - `dls` folder contains the code for reading a `.dls` file (and converting in into a soundfont representation).
@@ -1,6 +0,0 @@
1
- import { BasicZone } from "./basic_zone.js";
2
-
3
- export class BasicGlobalZone extends BasicZone
4
- {
5
- // nothing here, just a different instance...
6
- }