spessasynth_lib 3.23.12 → 3.23.14
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.
- package/@types/index.d.ts +8 -1
- package/@types/midi_parser/midi_data.d.ts +2 -0
- package/@types/midi_parser/midi_sequence.d.ts +11 -0
- package/@types/sequencer/sequencer.d.ts +3 -1
- package/@types/utils/other.d.ts +5 -0
- package/index.js +17 -3
- package/midi_parser/basic_midi.js +2 -0
- package/midi_parser/midi_data.js +2 -0
- package/midi_parser/midi_loader.js +108 -4
- package/midi_parser/midi_sequence.js +13 -0
- package/package.json +1 -1
- package/sequencer/sequencer.js +3 -6
- package/sequencer/worklet_sequencer/process_event.js +32 -1
- package/sequencer/worklet_sequencer/sequencer_message.js +1 -1
- package/sequencer/worklet_sequencer/worklet_sequencer.js +0 -1
- package/synthetizer/worklet_processor.min.js +12 -11
- package/synthetizer/worklet_system/main_processor.js +1 -1
- package/synthetizer/worklet_system/snapshot/snapshot.js +311 -0
- package/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -14
- package/synthetizer/worklet_system/worklet_methods/note_off.js +1 -1
- package/utils/other.js +28 -1
- package/synthetizer/worklet_system/worklet_methods/snapshot.js +0 -145
package/@types/index.d.ts
CHANGED
|
@@ -3,6 +3,13 @@ import { Synthetizer } from './synthetizer/synthetizer.js';
|
|
|
3
3
|
import { DEFAULT_PERCUSSION } from './synthetizer/synthetizer.js';
|
|
4
4
|
import { VOICE_CAP } from './synthetizer/synthetizer.js';
|
|
5
5
|
import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
|
|
6
|
+
import { BasicSample } from "./soundfont/basic_soundfont/basic_sample.js";
|
|
7
|
+
import { BasicInstrumentZone } from "./soundfont/basic_soundfont/basic_zones.js";
|
|
8
|
+
import { BasicInstrument } from "./soundfont/basic_soundfont/basic_instrument.js";
|
|
9
|
+
import { BasicPreset } from "./soundfont/basic_soundfont/basic_preset.js";
|
|
10
|
+
import { BasicPresetZone } from "./soundfont/basic_soundfont/basic_zones.js";
|
|
11
|
+
import { Generator } from "./soundfont/basic_soundfont/generator.js";
|
|
12
|
+
import { Modulator } from "./soundfont/basic_soundfont/modulator.js";
|
|
6
13
|
import { loadSoundFont } from "./soundfont/load_soundfont.js";
|
|
7
14
|
import { trimSoundfont } from "./soundfont/basic_soundfont/write_sf2/soundfont_trimmer.js";
|
|
8
15
|
import { modulatorSources } from "./soundfont/basic_soundfont/modulator.js";
|
|
@@ -34,4 +41,4 @@ import { readBytesAsUintBigEndian } from './utils/byte_functions/big_endian.js';
|
|
|
34
41
|
import { NON_CC_INDEX_OFFSET } from "./synthetizer/worklet_system/worklet_utilities/controller_tables.js";
|
|
35
42
|
import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from './synthetizer/worklet_system/message_protocol/worklet_message.js';
|
|
36
43
|
import { WORKLET_URL_ABSOLUTE } from './synthetizer/worklet_url.js';
|
|
37
|
-
export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, BasicSoundFont, loadSoundFont, trimSoundfont, modulatorSources, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, MIDIticksToSeconds, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
|
|
44
|
+
export { Sequencer, Synthetizer, DEFAULT_PERCUSSION, VOICE_CAP, BasicSoundFont, BasicSample, BasicInstrumentZone, BasicInstrument, BasicPreset, BasicPresetZone, Generator, Modulator, loadSoundFont, trimSoundfont, modulatorSources, MIDI, MIDIBuilder, IndexedByteArray, writeMIDIFile, writeRMIDI, applySnapshotToMIDI, modifyMIDI, MIDIticksToSeconds, audioBufferToWav, SpessaSynthLogging, SpessaSynthGroup, SpessaSynthTable, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn, SpessaSynthGroupCollapsed, midiControllers, messageTypes, MIDIDeviceHandler, WebMidiLinkHandler, arrayToHexString, consoleColors, formatTitle, formatTime, readBytesAsUintBigEndian, NON_CC_INDEX_OFFSET, ALL_CHANNELS_OR_DIFFERENT_ACTION, WORKLET_URL_ABSOLUTE };
|
|
@@ -21,6 +21,7 @@ export class MidiData extends MIDISequenceData {
|
|
|
21
21
|
copyright: any;
|
|
22
22
|
tracksAmount: any;
|
|
23
23
|
lyrics: any;
|
|
24
|
+
lyricsTicks: any;
|
|
24
25
|
firstNoteOn: any;
|
|
25
26
|
keyRange: any;
|
|
26
27
|
lastVoiceEventTick: any;
|
|
@@ -35,6 +36,7 @@ export class MidiData extends MIDISequenceData {
|
|
|
35
36
|
format: any;
|
|
36
37
|
RMIDInfo: any;
|
|
37
38
|
bankOffset: any;
|
|
39
|
+
isKaraokeFile: any;
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
42
|
* Temporary MIDI data used when the MIDI is not loaded.
|
|
@@ -40,6 +40,11 @@ export class MIDISequenceData {
|
|
|
40
40
|
* @type {Uint8Array[]}
|
|
41
41
|
*/
|
|
42
42
|
lyrics: Uint8Array[];
|
|
43
|
+
/**
|
|
44
|
+
* An array of tick positions where lyrics events occur in the sequence.
|
|
45
|
+
* @type {number[]}
|
|
46
|
+
*/
|
|
47
|
+
lyricsTicks: number[];
|
|
43
48
|
/**
|
|
44
49
|
* The tick position of the first note-on event in the MIDI sequence.
|
|
45
50
|
* @type {number}
|
|
@@ -121,4 +126,10 @@ export class MIDISequenceData {
|
|
|
121
126
|
* @type {number}
|
|
122
127
|
*/
|
|
123
128
|
bankOffset: number;
|
|
129
|
+
/**
|
|
130
|
+
* If the MIDI file is a Soft Karaoke file (.kar), this flag is set to true.
|
|
131
|
+
* https://www.mixagesoftware.com/en/midikit/help/HTML/karaoke_formats.html
|
|
132
|
+
* @type {boolean}
|
|
133
|
+
*/
|
|
134
|
+
isKaraokeFile: boolean;
|
|
124
135
|
}
|
|
@@ -23,10 +23,12 @@ export class Sequencer {
|
|
|
23
23
|
private onSongChange;
|
|
24
24
|
/**
|
|
25
25
|
* Fires on text event
|
|
26
|
+
* @type {function}
|
|
26
27
|
* @param data {Uint8Array} the data text
|
|
27
28
|
* @param type {number} the status byte of the message (the meta status byte)
|
|
29
|
+
* @param lyricsIndex {number} if the text is a lyric, the index of the lyric in midiData.lyrics, otherwise -1
|
|
28
30
|
*/
|
|
29
|
-
onTextEvent:
|
|
31
|
+
onTextEvent: Function;
|
|
30
32
|
/**
|
|
31
33
|
* Fires when CurrentTime changes
|
|
32
34
|
* @type {Object<string, function(number)>} the time that was changed to
|
package/@types/utils/other.d.ts
CHANGED
|
@@ -23,6 +23,11 @@ export function formatTitle(fileName: string): string;
|
|
|
23
23
|
* @returns {string}
|
|
24
24
|
*/
|
|
25
25
|
export function arrayToHexString(arr: number[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* @param eventData {Uint8Array}
|
|
28
|
+
* @returns {Uint8Array}
|
|
29
|
+
*/
|
|
30
|
+
export function sanitizeKarLyrics(eventData: Uint8Array): Uint8Array;
|
|
26
31
|
export namespace consoleColors {
|
|
27
32
|
let warn: string;
|
|
28
33
|
let unrecognized: string;
|
package/index.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
// Import modules
|
|
2
2
|
import { loadSoundFont } from "./soundfont/load_soundfont.js";
|
|
3
3
|
import { BasicSoundFont } from "./soundfont/basic_soundfont/basic_soundfont.js";
|
|
4
|
+
import { BasicSample } from "./soundfont/basic_soundfont/basic_sample.js";
|
|
5
|
+
import { BasicInstrumentZone } from "./soundfont/basic_soundfont/basic_zones.js";
|
|
6
|
+
import { BasicInstrument } from "./soundfont/basic_soundfont/basic_instrument.js";
|
|
7
|
+
import { Generator } from "./soundfont/basic_soundfont/generator.js";
|
|
8
|
+
import { Modulator } from "./soundfont/basic_soundfont/modulator.js";
|
|
9
|
+
import { BasicPresetZone } from "./soundfont/basic_soundfont/basic_zones.js";
|
|
10
|
+
import { BasicPreset } from "./soundfont/basic_soundfont/basic_preset.js";
|
|
4
11
|
import { MIDI } from './midi_parser/midi_loader.js';
|
|
5
12
|
import { MIDIticksToSeconds } from './midi_parser/basic_midi.js';
|
|
6
13
|
import { MIDIBuilder } from "./midi_parser/midi_builder.js";
|
|
@@ -38,13 +45,20 @@ export {
|
|
|
38
45
|
Synthetizer,
|
|
39
46
|
DEFAULT_PERCUSSION,
|
|
40
47
|
VOICE_CAP,
|
|
41
|
-
|
|
48
|
+
|
|
42
49
|
// SoundFont
|
|
43
50
|
BasicSoundFont,
|
|
51
|
+
BasicSample,
|
|
52
|
+
BasicInstrumentZone,
|
|
53
|
+
BasicInstrument,
|
|
54
|
+
BasicPreset,
|
|
55
|
+
BasicPresetZone,
|
|
56
|
+
Generator,
|
|
57
|
+
Modulator,
|
|
44
58
|
loadSoundFont,
|
|
45
59
|
trimSoundfont,
|
|
46
60
|
modulatorSources,
|
|
47
|
-
|
|
61
|
+
|
|
48
62
|
// MIDI
|
|
49
63
|
MIDI,
|
|
50
64
|
MIDIBuilder,
|
|
@@ -54,7 +68,7 @@ export {
|
|
|
54
68
|
applySnapshotToMIDI,
|
|
55
69
|
modifyMIDI,
|
|
56
70
|
MIDIticksToSeconds,
|
|
57
|
-
|
|
71
|
+
|
|
58
72
|
// Utilities
|
|
59
73
|
audioBufferToWav,
|
|
60
74
|
SpessaSynthLogging,
|
|
@@ -45,10 +45,12 @@ export class BasicMIDI extends MIDISequenceData
|
|
|
45
45
|
m.loop = { ...mid.loop }; // Deep copy of loop
|
|
46
46
|
m.format = mid.format;
|
|
47
47
|
m.bankOffset = mid.bankOffset;
|
|
48
|
+
m.isKaraokeFile = mid.isKaraokeFile;
|
|
48
49
|
|
|
49
50
|
// Copying arrays
|
|
50
51
|
m.tempoChanges = [...mid.tempoChanges]; // Shallow copy
|
|
51
52
|
m.lyrics = mid.lyrics.map(arr => new Uint8Array(arr)); // Deep copy of each binary chunk
|
|
53
|
+
m.lyricsTicks = [...mid.lyricsTicks]; // Shallow copy
|
|
52
54
|
m.midiPorts = [...mid.midiPorts]; // Shallow copy
|
|
53
55
|
m.midiPortChannelOffsets = [...mid.midiPortChannelOffsets]; // Shallow copy
|
|
54
56
|
m.usedChannelsOnTrack = mid.usedChannelsOnTrack.map(set => new Set(set)); // Deep copy
|
package/midi_parser/midi_data.js
CHANGED
|
@@ -28,6 +28,7 @@ export class MidiData extends MIDISequenceData
|
|
|
28
28
|
this.copyright = midi.copyright;
|
|
29
29
|
this.tracksAmount = midi.tracksAmount;
|
|
30
30
|
this.lyrics = midi.lyrics;
|
|
31
|
+
this.lyricsTicks = midi.lyricsTicks;
|
|
31
32
|
this.firstNoteOn = midi.firstNoteOn;
|
|
32
33
|
this.keyRange = midi.keyRange;
|
|
33
34
|
this.lastVoiceEventTick = midi.lastVoiceEventTick;
|
|
@@ -42,6 +43,7 @@ export class MidiData extends MIDISequenceData
|
|
|
42
43
|
this.format = midi.format;
|
|
43
44
|
this.RMIDInfo = midi.RMIDInfo;
|
|
44
45
|
this.bankOffset = midi.bankOffset;
|
|
46
|
+
this.isKaraokeFile = midi.isKaraokeFile;
|
|
45
47
|
|
|
46
48
|
// Set isEmbedded based on the presence of an embeddedSoundFont
|
|
47
49
|
this.isEmbedded = midi.embeddedSoundFont !== undefined;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { dataBytesAmount, getChannel, messageTypes, MidiMessage } from "./midi_message.js";
|
|
2
2
|
import { IndexedByteArray } from "../utils/indexed_array.js";
|
|
3
|
-
import { consoleColors, formatTitle } from "../utils/other.js";
|
|
3
|
+
import { consoleColors, formatTitle, sanitizeKarLyrics } from "../utils/other.js";
|
|
4
4
|
import { SpessaSynthGroupCollapsed, SpessaSynthGroupEnd, SpessaSynthInfo, SpessaSynthWarn } from "../utils/loggin.js";
|
|
5
5
|
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
|
-
import { readBytesAsString } from "../utils/byte_functions/string.js";
|
|
8
|
+
import { getStringBytes, readBytesAsString } from "../utils/byte_functions/string.js";
|
|
9
9
|
import { readLittleEndian } from "../utils/byte_functions/little_endian.js";
|
|
10
10
|
import { RMIDINFOChunks } from "./rmidi_writer.js";
|
|
11
11
|
import { BasicMIDI, MIDIticksToSeconds } from "./basic_midi.js";
|
|
@@ -193,6 +193,13 @@ class MIDI extends BasicMIDI
|
|
|
193
193
|
let loopStart = null;
|
|
194
194
|
let loopEnd = null;
|
|
195
195
|
|
|
196
|
+
/**
|
|
197
|
+
* For karaoke files, text events starting with @T are considered titles
|
|
198
|
+
* usually the first one is the title, and the latter are things such as "sequenced by" etc.
|
|
199
|
+
* @type {boolean}
|
|
200
|
+
*/
|
|
201
|
+
let karaokeHasTitle = false;
|
|
202
|
+
|
|
196
203
|
this.lastVoiceEventTick = 0;
|
|
197
204
|
|
|
198
205
|
/**
|
|
@@ -332,6 +339,7 @@ class MIDI extends BasicMIDI
|
|
|
332
339
|
{
|
|
333
340
|
case -2:
|
|
334
341
|
// since this is a meta message
|
|
342
|
+
const eventText = readBytesAsString(eventData, eventData.length);
|
|
335
343
|
switch (statusByte)
|
|
336
344
|
{
|
|
337
345
|
case messageTypes.setTempo:
|
|
@@ -344,7 +352,7 @@ class MIDI extends BasicMIDI
|
|
|
344
352
|
|
|
345
353
|
case messageTypes.marker:
|
|
346
354
|
// check for loop markers
|
|
347
|
-
const text =
|
|
355
|
+
const text = eventText.trim().toLowerCase();
|
|
348
356
|
switch (text)
|
|
349
357
|
{
|
|
350
358
|
default:
|
|
@@ -384,7 +392,71 @@ class MIDI extends BasicMIDI
|
|
|
384
392
|
break;
|
|
385
393
|
|
|
386
394
|
case messageTypes.lyric:
|
|
387
|
-
|
|
395
|
+
|
|
396
|
+
// note here: .kar files sometimes just use...
|
|
397
|
+
// lyrics instead of text because why not (of course)
|
|
398
|
+
// perform the same check for @KMIDI KARAOKE FILE
|
|
399
|
+
if (eventText.trim() === "@KMIDI KARAOKE FILE")
|
|
400
|
+
{
|
|
401
|
+
this.isKaraokeFile = true;
|
|
402
|
+
SpessaSynthInfo("%cKaraoke MIDI detected!", consoleColors.recognized);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (this.isKaraokeFile)
|
|
406
|
+
{
|
|
407
|
+
// replace the type of the message with text
|
|
408
|
+
message.messageStatusByte = messageTypes.text;
|
|
409
|
+
statusByte = messageTypes.text;
|
|
410
|
+
}
|
|
411
|
+
else
|
|
412
|
+
{
|
|
413
|
+
// add lyrics like a regular midi file
|
|
414
|
+
this.lyrics.push(eventData);
|
|
415
|
+
this.lyricsTicks.push(totalTicks);
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// kar: treat the same as text
|
|
420
|
+
// fallthrough
|
|
421
|
+
case messageTypes.text:
|
|
422
|
+
// possibly Soft Karaoke MIDI file
|
|
423
|
+
// it has a text event at the start of the file
|
|
424
|
+
// "@KMIDI KARAOKE FILE"
|
|
425
|
+
const checkedText = eventText.trim();
|
|
426
|
+
if (checkedText === "@KMIDI KARAOKE FILE")
|
|
427
|
+
{
|
|
428
|
+
this.isKaraokeFile = true;
|
|
429
|
+
|
|
430
|
+
SpessaSynthInfo("%cKaraoke MIDI detected!", consoleColors.recognized);
|
|
431
|
+
}
|
|
432
|
+
else if (this.isKaraokeFile)
|
|
433
|
+
{
|
|
434
|
+
// check for @T (title)
|
|
435
|
+
// or @A because it is a title too sometimes??? idk it's weird
|
|
436
|
+
if (checkedText.startsWith("@T") || checkedText.startsWith("@A"))
|
|
437
|
+
{
|
|
438
|
+
if (!karaokeHasTitle)
|
|
439
|
+
{
|
|
440
|
+
this.midiName = checkedText.substring(2).trim();
|
|
441
|
+
karaokeHasTitle = true;
|
|
442
|
+
nameDetected = true;
|
|
443
|
+
// encode to rawMidiName
|
|
444
|
+
this.rawMidiName = getStringBytes(this.midiName);
|
|
445
|
+
}
|
|
446
|
+
else
|
|
447
|
+
{
|
|
448
|
+
// append to copyright
|
|
449
|
+
this.copyright += checkedText.substring(2).trim() + " \n";
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
else if (checkedText[0] !== "@")
|
|
453
|
+
{
|
|
454
|
+
// non @: the lyrics
|
|
455
|
+
this.lyrics.push(sanitizeKarLyrics(eventData));
|
|
456
|
+
this.lyricsTicks.push(totalTicks);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
break;
|
|
388
460
|
}
|
|
389
461
|
break;
|
|
390
462
|
|
|
@@ -612,6 +684,38 @@ class MIDI extends BasicMIDI
|
|
|
612
684
|
consoleColors.recognized
|
|
613
685
|
);
|
|
614
686
|
}
|
|
687
|
+
|
|
688
|
+
// lyrics fix:
|
|
689
|
+
// sometimes, all lyrics events lack spaces at the start or end of the lyric
|
|
690
|
+
// then, and only then, add space at the end of each lyric
|
|
691
|
+
// space ASCII is 32
|
|
692
|
+
let lacksSpaces = true;
|
|
693
|
+
for (const lyric of this.lyrics)
|
|
694
|
+
{
|
|
695
|
+
if (lyric[0] === 32 || lyric[lyric.length - 1] === 32)
|
|
696
|
+
{
|
|
697
|
+
lacksSpaces = false;
|
|
698
|
+
break;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
if (lacksSpaces)
|
|
703
|
+
{
|
|
704
|
+
this.lyrics = this.lyrics.map(lyric =>
|
|
705
|
+
{
|
|
706
|
+
// one exception: hyphens at the end. Don't add a space to them
|
|
707
|
+
if (lyric[lyric.length - 1] === 45)
|
|
708
|
+
{
|
|
709
|
+
return lyric;
|
|
710
|
+
}
|
|
711
|
+
const withSpaces = new Uint8Array(lyric.length + 1);
|
|
712
|
+
withSpaces.set(lyric, 0);
|
|
713
|
+
withSpaces[lyric.length] = 32;
|
|
714
|
+
return withSpaces;
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
|
|
615
719
|
// reverse the tempo changes
|
|
616
720
|
this.tempoChanges.reverse();
|
|
617
721
|
|
|
@@ -44,6 +44,12 @@ export class MIDISequenceData
|
|
|
44
44
|
*/
|
|
45
45
|
lyrics = [];
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* An array of tick positions where lyrics events occur in the sequence.
|
|
49
|
+
* @type {number[]}
|
|
50
|
+
*/
|
|
51
|
+
lyricsTicks = [];
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* The tick position of the first note-on event in the MIDI sequence.
|
|
49
55
|
* @type {number}
|
|
@@ -130,4 +136,11 @@ export class MIDISequenceData
|
|
|
130
136
|
* @type {number}
|
|
131
137
|
*/
|
|
132
138
|
bankOffset = 0;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* If the MIDI file is a Soft Karaoke file (.kar), this flag is set to true.
|
|
142
|
+
* https://www.mixagesoftware.com/en/midikit/help/HTML/karaoke_formats.html
|
|
143
|
+
* @type {boolean}
|
|
144
|
+
*/
|
|
145
|
+
isKaraokeFile = false;
|
|
133
146
|
}
|
package/package.json
CHANGED
package/sequencer/sequencer.js
CHANGED
|
@@ -61,8 +61,10 @@ export class Sequencer
|
|
|
61
61
|
onSongChange = {};
|
|
62
62
|
/**
|
|
63
63
|
* Fires on text event
|
|
64
|
+
* @type {function}
|
|
64
65
|
* @param data {Uint8Array} the data text
|
|
65
66
|
* @param type {number} the status byte of the message (the meta status byte)
|
|
67
|
+
* @param lyricsIndex {number} if the text is a lyric, the index of the lyric in midiData.lyrics, otherwise -1
|
|
66
68
|
*/
|
|
67
69
|
onTextEvent;
|
|
68
70
|
/**
|
|
@@ -304,7 +306,6 @@ export class Sequencer
|
|
|
304
306
|
addOnSongChangeEvent(callback, id)
|
|
305
307
|
{
|
|
306
308
|
this.onSongChange[id] = callback;
|
|
307
|
-
callback(this.midiData);
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
/**
|
|
@@ -419,13 +420,9 @@ export class Sequencer
|
|
|
419
420
|
break;
|
|
420
421
|
|
|
421
422
|
case WorkletSequencerReturnMessageType.textEvent:
|
|
422
|
-
/**
|
|
423
|
-
* @type {[Uint8Array, number]}
|
|
424
|
-
*/
|
|
425
|
-
let textEventData = messageData;
|
|
426
423
|
if (this.onTextEvent)
|
|
427
424
|
{
|
|
428
|
-
this.onTextEvent(
|
|
425
|
+
this.onTextEvent(...(messageData));
|
|
429
426
|
}
|
|
430
427
|
break;
|
|
431
428
|
|
|
@@ -117,7 +117,38 @@ export function _processEvent(event, trackIndex)
|
|
|
117
117
|
case messageTypes.cuePoint:
|
|
118
118
|
case messageTypes.instrumentName:
|
|
119
119
|
case messageTypes.programName:
|
|
120
|
-
|
|
120
|
+
let lyricsIndex = -1;
|
|
121
|
+
if (statusByteData.status === messageTypes.lyric)
|
|
122
|
+
{
|
|
123
|
+
lyricsIndex = Math.min(
|
|
124
|
+
this.midiData.lyricsTicks.indexOf(event.ticks) + 1,
|
|
125
|
+
this.midiData.lyrics.length - 1
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
let sentStatus = statusByteData.status;
|
|
129
|
+
// if MIDI is a karaoke file, it uses the "text" event type or "lyrics" for lyrics (duh)
|
|
130
|
+
// why?
|
|
131
|
+
// because the MIDI standard is a messy pile of garbage and it's not my fault that it's like this :(
|
|
132
|
+
// I'm just trying to make the best out of a bad situation
|
|
133
|
+
// I'm sorry
|
|
134
|
+
// okay i should get back to work
|
|
135
|
+
// anyways,
|
|
136
|
+
// check for karaoke file and change the status byte to "lyric" if it's a karaoke file
|
|
137
|
+
if (this.midiData.isKaraokeFile && (
|
|
138
|
+
statusByteData.status === messageTypes.text ||
|
|
139
|
+
statusByteData.status === messageTypes.lyric
|
|
140
|
+
))
|
|
141
|
+
{
|
|
142
|
+
lyricsIndex = Math.min(
|
|
143
|
+
this.midiData.lyricsTicks.indexOf(event.ticks) + 1,
|
|
144
|
+
this.midiData.lyricsTicks.length
|
|
145
|
+
);
|
|
146
|
+
sentStatus = messageTypes.lyric;
|
|
147
|
+
}
|
|
148
|
+
this.post(
|
|
149
|
+
WorkletSequencerReturnMessageType.textEvent,
|
|
150
|
+
[event.messageData, sentStatus, lyricsIndex]
|
|
151
|
+
);
|
|
121
152
|
break;
|
|
122
153
|
|
|
123
154
|
case messageTypes.midiPort:
|
|
@@ -35,7 +35,7 @@ export const WorkletSequencerMessageType = {
|
|
|
35
35
|
export const WorkletSequencerReturnMessageType = {
|
|
36
36
|
midiEvent: 0, // [...midiEventBytes<number>]
|
|
37
37
|
songChange: 1, // [midiData<MidiData>, songIndex<number>, isAutoPlayed<boolean>]
|
|
38
|
-
textEvent: 2, // [messageData<number[]>, statusByte<number]
|
|
38
|
+
textEvent: 2, // [messageData<number[]>, statusByte<number>, lyricsIndex<number>]
|
|
39
39
|
timeChange: 3, // newAbsoluteTime<number>
|
|
40
40
|
pause: 4, // no data
|
|
41
41
|
getMIDI: 5, // midiData<MIDI>
|