spessasynth_lib 3.16.5 → 3.17.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 (57) hide show
  1. package/@types/index.d.ts +5 -4
  2. package/@types/midi_parser/basic_midi.d.ts +125 -0
  3. package/@types/midi_parser/midi_builder.d.ts +69 -0
  4. package/@types/midi_parser/midi_data.d.ts +2 -2
  5. package/@types/midi_parser/midi_editor.d.ts +4 -4
  6. package/@types/midi_parser/midi_loader.d.ts +3 -100
  7. package/@types/midi_parser/midi_writer.d.ts +2 -2
  8. package/@types/midi_parser/rmidi_writer.d.ts +3 -3
  9. package/@types/midi_parser/used_keys_loaded.d.ts +2 -2
  10. package/@types/sequencer/sequencer.d.ts +1 -1
  11. package/@types/soundfont/basic_soundfont/write_sf2/soundfont_trimmer.d.ts +2 -2
  12. package/@types/soundfont/dls/dls_preset.d.ts +11 -0
  13. package/@types/soundfont/dls/dls_soundfont.d.ts +24 -0
  14. package/@types/soundfont/dls/read_instrument.d.ts +5 -0
  15. package/@types/soundfont/dls/read_instrument_list.d.ts +5 -0
  16. package/@types/soundfont/load_soundfont.d.ts +6 -0
  17. package/@types/soundfont/soundfont.d.ts +2 -1
  18. package/@types/synthetizer/synthetizer.d.ts +2 -2
  19. package/@types/utils/byte_functions/little_endian.d.ts +1 -1
  20. package/README.md +17 -15
  21. package/index.js +6 -4
  22. package/midi_parser/basic_midi.js +146 -0
  23. package/midi_parser/midi_builder.js +281 -0
  24. package/midi_parser/midi_data.js +1 -1
  25. package/midi_parser/midi_editor.js +2 -2
  26. package/midi_parser/midi_loader.js +8 -53
  27. package/midi_parser/midi_writer.js +1 -1
  28. package/midi_parser/rmidi_writer.js +2 -2
  29. package/midi_parser/used_keys_loaded.js +1 -1
  30. package/package.json +1 -1
  31. package/sequencer/sequencer.js +1 -1
  32. package/sequencer/worklet_sequencer/song_control.js +3 -3
  33. package/sequencer/worklet_sequencer/worklet_sequencer.js +1 -1
  34. package/soundfont/basic_soundfont/riff_chunk.js +2 -2
  35. package/soundfont/basic_soundfont/write_sf2/soundfont_trimmer.js +1 -1
  36. package/soundfont/dls/dls_preset.js +25 -0
  37. package/soundfont/dls/dls_soundfont.js +93 -0
  38. package/soundfont/dls/read_instrument.js +22 -0
  39. package/soundfont/dls/read_instrument_list.js +17 -0
  40. package/soundfont/load_soundfont.js +21 -0
  41. package/soundfont/read_sf2/instruments.js +2 -2
  42. package/soundfont/read_sf2/modulators.js +5 -5
  43. package/soundfont/read_sf2/presets.js +7 -7
  44. package/soundfont/read_sf2/samples.js +8 -8
  45. package/soundfont/read_sf2/zones.js +5 -5
  46. package/soundfont/soundfont.js +8 -3
  47. package/synthetizer/synthetizer.js +1 -1
  48. package/synthetizer/worklet_processor.min.js +7 -6
  49. package/synthetizer/worklet_system/main_processor.js +1 -2
  50. package/synthetizer/worklet_system/worklet_methods/program_control.js +6 -3
  51. package/synthetizer/worklet_system/worklet_methods/worklet_soundfont_manager/worklet_soundfont_manager.js +5 -5
  52. package/utils/byte_functions/little_endian.js +1 -1
  53. /package/@types/{midi_handler → external_midi}/midi_handler.d.ts +0 -0
  54. /package/@types/{midi_handler → external_midi}/web_midi_link.d.ts +0 -0
  55. /package/{midi_handler → external_midi}/README.md +0 -0
  56. /package/{midi_handler → external_midi}/midi_handler.js +0 -0
  57. /package/{midi_handler → external_midi}/web_midi_link.js +0 -0
@@ -0,0 +1,146 @@
1
+ export class BasicMIDI
2
+ {
3
+ constructor()
4
+ {
5
+ /**
6
+ * The time division of the sequence
7
+ * @type {number}
8
+ */
9
+ this.timeDivision = 0;
10
+ /**
11
+ * The duration of the sequence, in seconds
12
+ * @type {number}
13
+ */
14
+ this.duration = 0;
15
+ /**
16
+ * The tempo changes in the sequence, ordered from last to first
17
+ * @type {{ticks: number, tempo: number}[]}
18
+ */
19
+ this.tempoChanges = [{ticks: 0, tempo: 120}];
20
+ /**
21
+ * Contains the copyright strings
22
+ * @type {string}
23
+ */
24
+ this.copyright = "";
25
+
26
+ /**
27
+ * The amount of tracks in the sequence
28
+ * @type {number}
29
+ */
30
+ this.tracksAmount = 0;
31
+
32
+ /**
33
+ * The lyrics of the sequence as binary chunks
34
+ * @type {Uint8Array[]}
35
+ */
36
+ this.lyrics = [];
37
+
38
+ /**
39
+ * First note on of the MIDI file
40
+ * @type {number}
41
+ */
42
+ this.firstNoteOn = 0;
43
+
44
+ /**
45
+ * The MIDI's key range
46
+ * @type {{min: number, max: number}}
47
+ */
48
+ this.keyRange = { min: 0, max: 127 };
49
+
50
+ /**
51
+ * The last voice (note on, off, cc change etc.) event tick
52
+ * @type {number}
53
+ */
54
+ this.lastVoiceEventTick = 0;
55
+
56
+ /**
57
+ * Midi port numbers for each track
58
+ * @type {number[]}
59
+ */
60
+ this.midiPorts = [0];
61
+
62
+ /**
63
+ * Channel offsets for each port, using the SpessaSynth method
64
+ * @type {number[]}
65
+ */
66
+ this.midiPortChannelOffsets = [0];
67
+
68
+ /**
69
+ * All channels that each track uses
70
+ * @type {Set<number>[]}
71
+ */
72
+ this.usedChannelsOnTrack = [];
73
+
74
+ /**
75
+ * The loop points (in ticks) of the sequence
76
+ * @type {{start: number, end: number}}
77
+ */
78
+ this.loop = { start: 0, end: 0 };
79
+
80
+ /**
81
+ * The sequence's name
82
+ * @type {string}
83
+ */
84
+ this.midiName = "";
85
+
86
+ /**
87
+ * The file name of the sequence, if provided in the MIDI class
88
+ * @type {string}
89
+ */
90
+ this.fileName = "";
91
+
92
+ /**
93
+ * The raw, encoded MIDI name.
94
+ * @type {Uint8Array}
95
+ */
96
+ this.rawMidiName = undefined;
97
+
98
+ /**
99
+ * The MIDI's embedded soundfont
100
+ * @type {ArrayBuffer|undefined}
101
+ */
102
+ this.embeddedSoundFont = undefined;
103
+
104
+ /**
105
+ * The MIDI file's format
106
+ * @type {number}
107
+ */
108
+ this.format = 0;
109
+
110
+ /**
111
+ * The RMID Info data if RMID, otherwise undefined
112
+ * @type {Object<string, IndexedByteArray>}
113
+ */
114
+ this.RMIDInfo = {};
115
+ /**
116
+ * The bank offset for RMIDI
117
+ * @type {number}
118
+ */
119
+ this.bankOffset = 0;
120
+
121
+ /**
122
+ * The actual track data of the MIDI file
123
+ * @type {MidiMessage[][]}
124
+ */
125
+ this.tracks = [];
126
+ }
127
+
128
+ /**
129
+ * Coverts ticks to time in seconds
130
+ * @param ticks {number}
131
+ * @returns {number}
132
+ * @protected
133
+ */
134
+ _ticksToSeconds(ticks)
135
+ {
136
+ if (ticks <= 0) {
137
+ return 0;
138
+ }
139
+
140
+ // find the last tempo change that has occured
141
+ let tempo = this.tempoChanges.find(v => v.ticks < ticks);
142
+
143
+ let timeSinceLastTempo = ticks - tempo.ticks;
144
+ return this._ticksToSeconds(ticks - timeSinceLastTempo) + (timeSinceLastTempo * 60) / (tempo.tempo * this.timeDivision);
145
+ }
146
+ }
@@ -0,0 +1,281 @@
1
+ import { BasicMIDI } from './basic_midi.js'
2
+ import { messageTypes, MidiMessage } from './midi_message.js'
3
+ import { IndexedByteArray } from '../utils/indexed_array.js'
4
+ import { readBytesAsUintBigEndian } from '../utils/byte_functions/big_endian.js'
5
+ import { SpessaSynthWarn } from '../utils/loggin.js'
6
+
7
+ export class MIDIBuilder extends BasicMIDI
8
+ {
9
+ /**
10
+ * @param name {string} The MIDI's name
11
+ * @param timeDivision {number} the file's time division
12
+ * @param initialTempo {number} the file's initial tempo
13
+ */
14
+ constructor(name, timeDivision = 480, initialTempo = 120)
15
+ {
16
+ super();
17
+ this.timeDivision = timeDivision;
18
+ this.midiName = name;
19
+ this.encoder = new TextEncoder();
20
+ this.rawMidiName = this.encoder.encode(name);
21
+
22
+ // create the first track with the file name
23
+ this.addNewTrack(name);
24
+ this.addSetTempo(0, initialTempo);
25
+ }
26
+
27
+ /**
28
+ * Updates all internal values
29
+ */
30
+ flush()
31
+ {
32
+
33
+ // find first note on
34
+ const firstNoteOns = [];
35
+ for(const t of this.tracks)
36
+ {
37
+ // sost the track by ticks
38
+ t.sort((e1, e2) => e1.ticks - e2.ticks);
39
+ const firstNoteOn = t.find(e => (e.messageStatusByte & 0xF0) === messageTypes.noteOn);
40
+ if(firstNoteOn)
41
+ {
42
+ firstNoteOns.push(firstNoteOn.ticks);
43
+ }
44
+ }
45
+ this.firstNoteOn = Math.min(...firstNoteOns);
46
+
47
+ // find tempo changes
48
+ // and used channels on tracks
49
+ // and midi ports
50
+ // and last voice event tick
51
+ // and loop
52
+ this.lastVoiceEventTick = 0
53
+ this.tempoChanges = [{ticks: 0, tempo: 120}];
54
+ this.midiPorts = [];
55
+ this.midiPortChannelOffsets = [];
56
+ let portOffset = 0;
57
+ /**
58
+ * @type {Set<number>[]}
59
+ */
60
+ this.usedChannelsOnTrack = this.tracks.map(() => new Set());
61
+ this.tracks.forEach((t, trackNum) => {
62
+ this.midiPorts.push(-1);
63
+ t.forEach(e => {
64
+ // last voice event tick
65
+ if(e.messageStatusByte >= 0x80 && e.messageStatusByte < 0xF0)
66
+ {
67
+ if(e.ticks > this.lastVoiceEventTick)
68
+ {
69
+ this.lastVoiceEventTick = e.ticks;
70
+ }
71
+ }
72
+
73
+ // tempo, used channels, port
74
+ if(e.messageStatusByte === messageTypes.setTempo)
75
+ {
76
+ this.tempoChanges.push({
77
+ ticks: e.ticks,
78
+ tempo: 60000000 / readBytesAsUintBigEndian(e.messageData, 3)
79
+ });
80
+ }
81
+ else
82
+ if((e.messageStatusByte & 0xF0) === messageTypes.noteOn)
83
+ {
84
+ this.usedChannelsOnTrack[trackNum].add(e.messageData[0]);
85
+ }
86
+ else
87
+ if(e.messageStatusByte === messageTypes.midiPort)
88
+ {
89
+ const port = e.messageData[0];
90
+ this.midiPorts[trackNum] = port;
91
+ if(this.midiPortChannelOffsets[port] === undefined)
92
+ {
93
+ this.midiPortChannelOffsets[port] = portOffset;
94
+ portOffset += 16;
95
+ }
96
+ }
97
+ })
98
+ });
99
+
100
+ this.loop = {start: this.firstNoteOn, end: this.lastVoiceEventTick};
101
+
102
+ // reverse tempo and compute duration
103
+ this.tempoChanges.reverse();
104
+ this.duration = this._ticksToSeconds(this.lastVoiceEventTick);
105
+
106
+ // fix midi ports:
107
+ // midi tracks without ports will have a value of -1
108
+ // if all ports have a value of -1, set it to 0, otherwise take the first midi port and replace all -1 with it
109
+ // why do this? some midis (for some reason) specify all channels to port 1 or else, but leave the conductor track with no port pref.
110
+ // this spessasynth to reserve the first 16 channels for the conductor track (which doesn't play anything) and use additional 16 for the actual ports.
111
+ let defaultP = 0;
112
+ for(let port of this.midiPorts)
113
+ {
114
+ if(port !== -1)
115
+ {
116
+ defaultP = port;
117
+ break;
118
+ }
119
+ }
120
+ this.midiPorts = this.midiPorts.map(port => port === -1 ? defaultP : port);
121
+ // add dummy port if empty
122
+ if(this.midiPortChannelOffsets.length === 0)
123
+ {
124
+ this.midiPortChannelOffsets = [0];
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Adds a new "set tempo" message
130
+ * @param ticks {number} the tick number of the event
131
+ * @param tempo {number} the tempo in beats per minute (BPM)
132
+ */
133
+ addSetTempo(ticks, tempo)
134
+ {
135
+ const array = new IndexedByteArray(3);
136
+
137
+ tempo = 60000000 / tempo;
138
+
139
+ // Extract each byte in big-endian order
140
+ array[0] = (tempo >> 16) & 0xFF;
141
+ array[1] = (tempo >> 8) & 0xFF;
142
+ array[2] = tempo & 0xFF;
143
+
144
+ this.addEvent(ticks, 0, messageTypes.setTempo, array);
145
+ }
146
+
147
+ /**
148
+ * Adds a new MIDI track
149
+ * @param name {string} the new track's name
150
+ * @param port {number} the new track's port
151
+ */
152
+ addNewTrack(name, port = 0)
153
+ {
154
+ this.tracksAmount++;
155
+ if(this.tracksAmount > 1)
156
+ {
157
+ this.format = 1;
158
+ }
159
+ this.tracks.push([]);
160
+ this.tracks[this.tracksAmount - 1].push(
161
+ new MidiMessage(0, messageTypes.endOfTrack, new IndexedByteArray(0))
162
+ );
163
+ this.addEvent(0, this.tracksAmount - 1, messageTypes.trackName, this.encoder.encode(name));
164
+ this.addEvent(0, this.tracksAmount - 1, messageTypes.midiPort, [port]);
165
+ }
166
+
167
+ /**
168
+ * Adds a new MIDI Event
169
+ * @param ticks {number} the tick time of the event
170
+ * @param track {number} the track number to use
171
+ * @param event {number} the MIDI event number
172
+ * @param eventData {Uint8Array|Iterable<number>} the raw event data
173
+ */
174
+ addEvent(ticks, track, event, eventData)
175
+ {
176
+ if(!this.tracks[track])
177
+ {
178
+ throw new Error(`Track ${track} does not exist. Add it via addTrack method.`);
179
+ }
180
+ if(event === messageTypes.endOfTrack)
181
+ {
182
+ SpessaSynthWarn("The EndOfTrack is added automatically. Ignoring!");
183
+ return;
184
+ }
185
+ // remove end of track
186
+ this.tracks[track].pop();
187
+ this.tracks[track].push(new MidiMessage(
188
+ ticks,
189
+ event,
190
+ new IndexedByteArray(eventData)
191
+ ));
192
+ // add end of track
193
+ this.tracks[track].push(new MidiMessage(
194
+ ticks,
195
+ messageTypes.endOfTrack,
196
+ new IndexedByteArray(0)
197
+ ));
198
+ }
199
+
200
+ /**
201
+ * Adds a new Note On event
202
+ * @param ticks {number} the tick time of the event
203
+ * @param track {number} the track number to use
204
+ * @param channel {number} the channel to use
205
+ * @param midiNote {number} the midi note of the keypress
206
+ * @param velocity {number} the velocity of the keypress
207
+ */
208
+ addNoteOn(ticks, track, channel, midiNote, velocity)
209
+ {
210
+ channel %= 16;
211
+ midiNote %= 128;
212
+ velocity %= 128;
213
+ this.addEvent(
214
+ ticks,
215
+ track,
216
+ messageTypes.noteOn | channel,
217
+ [midiNote, velocity]
218
+ );
219
+ }
220
+
221
+ /**
222
+ * Adds a new Note Off event
223
+ * @param ticks {number} the tick time of the event
224
+ * @param track {number} the track number to use
225
+ * @param channel {number} the channel to use
226
+ * @param midiNote {number} the midi note of the key release
227
+ */
228
+ addNoteOff(ticks, track, channel, midiNote)
229
+ {
230
+ channel %= 16;
231
+ midiNote %= 128;
232
+ this.addEvent(
233
+ ticks,
234
+ track,
235
+ messageTypes.noteOff | channel,
236
+ [midiNote, 64]
237
+ );
238
+ }
239
+
240
+ /**
241
+ * Adds a new Controller Change event
242
+ * @param ticks {number} the tick time of the event
243
+ * @param track {number} the track number to use
244
+ * @param channel {number} the channel to use
245
+ * @param controllerNumber {number} the MIDI CC to use
246
+ * @param controllerValue {number} the new CC value
247
+ */
248
+ addControllerChange(ticks, track, channel, controllerNumber, controllerValue)
249
+ {
250
+ channel %= 16;
251
+ controllerNumber %= 128;
252
+ controllerValue %= 128;
253
+ this.addEvent(
254
+ ticks,
255
+ track,
256
+ messageTypes.controllerChange | channel,
257
+ [controllerNumber, controllerValue]
258
+ );
259
+ }
260
+
261
+ /**
262
+ * Adds a new Pitch Wheel event
263
+ * @param ticks {number} the tick time of the event
264
+ * @param track {number} the track to use
265
+ * @param channel {number} the channel to use
266
+ * @param MSB {number} SECOND byte of the MIDI pitchWheel message
267
+ * @param LSB {number} FIRST byte of the MIDI pitchWheel message
268
+ */
269
+ addPitchWheel(ticks, track, channel, MSB, LSB)
270
+ {
271
+ channel %= 16;
272
+ MSB %= 128;
273
+ LSB %= 128;
274
+ this.addEvent(
275
+ ticks,
276
+ track,
277
+ messageTypes.pitchBend | channel,
278
+ [LSB, MSB]
279
+ );
280
+ }
281
+ }
@@ -5,7 +5,7 @@
5
5
  export class MidiData
6
6
  {
7
7
  /**
8
- * @param midi {MIDI}
8
+ * @param midi {BasicMIDI}
9
9
  */
10
10
  constructor(midi)
11
11
  {
@@ -75,7 +75,7 @@ function getDrumChange(channel, ticks)
75
75
 
76
76
  /**
77
77
  * Allows easy editing of the file
78
- * @param midi {MIDI}
78
+ * @param midi {BasicMIDI}
79
79
  * @param desiredProgramChanges {{
80
80
  * channel: number,
81
81
  * program: number,
@@ -520,7 +520,7 @@ export function modifyMIDI(
520
520
 
521
521
  /**
522
522
  * Modifies the sequence according to the locked presets and controllers in the given snapshot
523
- * @param midi {MIDI}
523
+ * @param midi {BasicMIDI}
524
524
  * @param snapshot {SynthesizerSnapshot}
525
525
  */
526
526
  export function applySnapshotToMIDI(midi, snapshot)
@@ -6,56 +6,31 @@ import { readRIFFChunk } from '../soundfont/basic_soundfont/riff_chunk.js'
6
6
  import { readVariableLengthQuantity } from '../utils/byte_functions/variable_length_quantity.js'
7
7
  import { readBytesAsUintBigEndian } from '../utils/byte_functions/big_endian.js'
8
8
  import { readBytesAsString } from '../utils/byte_functions/string.js'
9
- import { readBytesAsUintLittleEndian } from '../utils/byte_functions/little_endian.js'
9
+ import { readLittleEndian } from '../utils/byte_functions/little_endian.js'
10
10
  import { RMIDINFOChunks } from './rmidi_writer.js'
11
+ import { BasicMIDI } from './basic_midi.js'
11
12
 
12
13
  /**
13
14
  * midi_loader.js
14
15
  * purpose: parses a midi file for the seqyencer, including things like marker or CC 2/4 loop detection, copyright detection etc.
15
16
  */
16
- class MIDI{
17
+ class MIDI extends BasicMIDI
18
+ {
17
19
  /**
18
20
  * Parses a given midi file
19
21
  * @param arrayBuffer {ArrayBuffer}
20
22
  * @param fileName {string} optional, replaces the decoded title if empty
21
23
  */
22
- constructor(arrayBuffer, fileName="") {
24
+ constructor(arrayBuffer, fileName="")
25
+ {
26
+ super();
23
27
  SpessaSynthGroupCollapsed(`%cParsing MIDI File...`, consoleColors.info);
24
28
  const binaryData = new IndexedByteArray(arrayBuffer);
25
29
  let fileByteArray;
26
30
 
27
31
  // check for rmid
28
- /**
29
- * If the RMI file has an embedded sf2 in it, it will appeear here, otherwise undefined
30
- * @type {ArrayBuffer}
31
- */
32
- this.embeddedSoundFont = undefined;
33
-
34
- /**
35
- * The RMID Info data if RMID, otherwise undefined
36
- * @type {Object<string, IndexedByteArray>}
37
- */
38
- this.RMIDInfo = undefined;
39
- /**
40
- * The bank offset for RMIDI
41
- * @type {number}
42
- */
43
- this.bankOffset = 0;
44
-
45
- /**
46
- * Contains the copyright strings
47
- * @type {string}
48
- */
49
- this.copyright = "";
50
32
  let copyrightDetected = false;
51
33
 
52
- /**
53
- * The MIDI name
54
- * @type {string}
55
- */
56
- this.midiName = "";
57
-
58
- this.rawMidiName = new Uint8Array(0);
59
34
  let nameDetected = false;
60
35
 
61
36
  const initialString = readBytesAsString(binaryData, 4);
@@ -129,7 +104,7 @@ class MIDI{
129
104
  this.bankOffset = 1; // defaults to 1
130
105
  if(this.RMIDInfo[RMIDINFOChunks.bankOffset])
131
106
  {
132
- this.bankOffset = readBytesAsUintLittleEndian(this.RMIDInfo[RMIDINFOChunks.bankOffset], 2);
107
+ this.bankOffset = readLittleEndian(this.RMIDInfo[RMIDINFOChunks.bankOffset], 2);
133
108
  }
134
109
  }
135
110
  }
@@ -564,25 +539,5 @@ class MIDI{
564
539
  fileByteArray.currentIndex += chunk.size;
565
540
  return chunk;
566
541
  }
567
-
568
-
569
- /**
570
- * Coverts ticks to time in seconds
571
- * @param ticks {number}
572
- * @returns {number}
573
- * @private
574
- */
575
- _ticksToSeconds(ticks)
576
- {
577
- if (ticks <= 0) {
578
- return 0;
579
- }
580
-
581
- // find the last tempo change that has occured
582
- let tempo = this.tempoChanges.find(v => v.ticks < ticks);
583
-
584
- let timeSinceLastTempo = ticks - tempo.ticks;
585
- return this._ticksToSeconds(ticks - timeSinceLastTempo) + (timeSinceLastTempo * 60) / (tempo.tempo * this.timeDivision);
586
- }
587
542
  }
588
543
  export { MIDI }
@@ -4,7 +4,7 @@ import { writeBytesAsUintBigEndian } from '../utils/byte_functions/big_endian.js
4
4
 
5
5
  /**
6
6
  * Exports the midi as a .mid file
7
- * @param midi {MIDI}
7
+ * @param midi {BasicMIDI}
8
8
  * @returns {Uint8Array} the binary .mid file data
9
9
  */
10
10
  export function writeMIDIFile(midi)
@@ -47,8 +47,8 @@ const DEFAULT_COPYRIGHT = "Created using SpessaSynth";
47
47
  /**
48
48
  * Writes an RMIDI file
49
49
  * @param soundfontBinary {Uint8Array}
50
- * @param mid {MIDI}
51
- * @param soundfont {SoundFont2}
50
+ * @param mid {BasicMIDI}
51
+ * @param soundfont {BasicSoundFont}
52
52
  * @param bankOffset {number} the bank offset for RMIDI
53
53
  * @param encoding {string} the encoding of the RMIDI info chunk
54
54
  * @param metadata {RMIDMetadata} the metadata of the file. Optional. If provided, the encoding is forced to utf-8/
@@ -4,7 +4,7 @@ import { DEFAULT_PERCUSSION } from '../synthetizer/synthetizer.js'
4
4
  import { messageTypes, midiControllers } from './midi_message.js'
5
5
 
6
6
  /**
7
- * @param mid {MIDI}
7
+ * @param mid {BasicMIDI}
8
8
  * @param soundfont {{getPreset: function(number, number): BasicPreset}}
9
9
  * @returns {Object<string, Set<string>>}
10
10
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.16.5",
3
+ "version": "3.17.0",
4
4
  "description": "No compromise MIDI and SoundFont2 Synthesizer library",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",
@@ -21,7 +21,7 @@ import { DUMMY_MIDI_DATA, MidiData } from '../midi_parser/midi_data.js'
21
21
  */
22
22
 
23
23
  /**
24
- * @typedef {MIDI|MidFile} MIDIFile
24
+ * @typedef {BasicMIDI|MidFile} MIDIFile
25
25
  */
26
26
 
27
27
  /**
@@ -35,7 +35,7 @@ export function assignMIDIPort(trackNum, port)
35
35
 
36
36
  /**
37
37
  * Loads a new sequence
38
- * @param parsedMidi {MIDI}
38
+ * @param parsedMidi {BasicMIDI}
39
39
  * @this {WorkletSequencer}
40
40
  */
41
41
  export function loadNewSequence(parsedMidi)
@@ -49,7 +49,7 @@ export function loadNewSequence(parsedMidi)
49
49
  this.oneTickToSeconds = 60 / (120 * parsedMidi.timeDivision)
50
50
 
51
51
  /**
52
- * @type {MIDI}
52
+ * @type {BasicMIDI}
53
53
  */
54
54
  this.midiData = parsedMidi;
55
55
 
@@ -135,7 +135,7 @@ export function loadNewSongList(midiBuffers)
135
135
  {
136
136
  /**
137
137
  * parse the MIDIs (only the array buffers, MIDI is unchanged)
138
- * @type {MIDI[]}
138
+ * @type {BasicMIDI[]}
139
139
  */
140
140
  this.songs = midiBuffers.reduce((mids, b) => {
141
141
  if(b.duration)
@@ -71,7 +71,7 @@ class WorkletSequencer
71
71
 
72
72
  /**
73
73
  * the current track data
74
- * @type {MIDI}
74
+ * @type {BasicMIDI}
75
75
  */
76
76
  this.midiData = undefined;
77
77
 
@@ -1,5 +1,5 @@
1
1
  import { IndexedByteArray } from '../../utils/indexed_array.js'
2
- import { readBytesAsUintLittleEndian, writeDword } from '../../utils/byte_functions/little_endian.js'
2
+ import { readLittleEndian, writeDword } from '../../utils/byte_functions/little_endian.js'
3
3
  import { readBytesAsString, writeStringAsBytes } from '../../utils/byte_functions/string.js'
4
4
 
5
5
  /**
@@ -33,7 +33,7 @@ export class RiffChunk
33
33
  export function readRIFFChunk(dataArray, readData = true, forceShift = false) {
34
34
  let header = readBytesAsString(dataArray, 4)
35
35
 
36
- let size = readBytesAsUintLittleEndian(dataArray, 4)
36
+ let size = readLittleEndian(dataArray, 4)
37
37
  let chunkData = undefined
38
38
  if (readData)
39
39
  {
@@ -9,7 +9,7 @@ import { getUsedProgramsAndKeys } from '../../../midi_parser/used_keys_loaded.js
9
9
 
10
10
  /**
11
11
  * @param soundfont {BasicSoundFont}
12
- * @param mid {MIDI}
12
+ * @param mid {BasicMIDI}
13
13
  * @returns {Uint8Array}
14
14
  */
15
15
  export function trimSoundfont(soundfont, mid)
@@ -0,0 +1,25 @@
1
+ import { BasicPreset } from '../basic_soundfont/basic_preset.js'
2
+
3
+ export class DLSPreset extends BasicPreset
4
+ {
5
+ /**
6
+ * Creates a new DLS preset
7
+ * @param ulBank {number} the ULONG value
8
+ * @param ulInstrument {number} the ULONG value
9
+ * @param regionsAmount {number}
10
+ */
11
+ constructor(ulBank, ulInstrument, regionsAmount)
12
+ {
13
+ super();
14
+ this.regionsAmount = regionsAmount;
15
+ this.program = ulInstrument & 127;
16
+ this.bank = (ulBank >> 8) & 127;
17
+ const isDrums = ulInstrument & (1 << 31);
18
+ if(isDrums)
19
+ {
20
+ console.log("DEUMS")
21
+ }
22
+ console.log(this.bank, this.program)
23
+
24
+ }
25
+ }