spessasynth_lib 3.24.0 → 3.24.2
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/sequencer/sequencer.d.ts +63 -28
- package/@types/sequencer/worklet_sequencer/sequencer_message.d.ts +1 -0
- package/package.json +1 -1
- package/sequencer/sequencer.js +134 -77
- package/sequencer/worklet_sequencer/process_event.js +4 -1
- package/sequencer/worklet_sequencer/process_tick.js +4 -4
- package/sequencer/worklet_sequencer/sequencer_message.js +2 -1
- package/synthetizer/audio_effects/effects_config.js +0 -0
- package/synthetizer/worklet_processor.min.js +8 -8
|
@@ -25,7 +25,7 @@ export class Sequencer {
|
|
|
25
25
|
* Fires on text event
|
|
26
26
|
* @type {function}
|
|
27
27
|
* @param data {Uint8Array} the data text
|
|
28
|
-
* @param type {number} the status byte of the message (the meta
|
|
28
|
+
* @param type {number} the status byte of the message (the meta-status byte)
|
|
29
29
|
* @param lyricsIndex {number} if the text is a lyric, the index of the lyric in midiData.lyrics, otherwise -1
|
|
30
30
|
*/
|
|
31
31
|
onTextEvent: Function;
|
|
@@ -40,47 +40,58 @@ export class Sequencer {
|
|
|
40
40
|
* @private
|
|
41
41
|
*/
|
|
42
42
|
private onSongEnded;
|
|
43
|
-
ignoreEvents: boolean;
|
|
44
|
-
synth: Synthetizer;
|
|
45
|
-
highResTimeOffset: number;
|
|
46
43
|
/**
|
|
47
|
-
*
|
|
48
|
-
* @type {number}
|
|
44
|
+
* Fires on tempo change
|
|
45
|
+
* @type {Object<string, function(number)>}
|
|
49
46
|
*/
|
|
50
|
-
|
|
47
|
+
onTempoChange: {
|
|
48
|
+
[x: string]: (arg0: number) => any;
|
|
49
|
+
};
|
|
51
50
|
/**
|
|
52
|
-
*
|
|
53
|
-
* @
|
|
51
|
+
* Current song's tempo in BPM
|
|
52
|
+
* @type {number}
|
|
54
53
|
*/
|
|
55
|
-
|
|
54
|
+
currentTempo: number;
|
|
56
55
|
/**
|
|
57
|
-
*
|
|
56
|
+
* Current song index
|
|
58
57
|
* @type {number}
|
|
59
58
|
*/
|
|
60
|
-
_playbackRate: number;
|
|
61
59
|
songIndex: number;
|
|
62
60
|
/**
|
|
63
|
-
*
|
|
61
|
+
* @type {function(BasicMIDI)}
|
|
62
|
+
* @private
|
|
63
|
+
*/
|
|
64
|
+
private _getMIDIResolve;
|
|
65
|
+
/**
|
|
66
|
+
* Indicates if the current midiData property has fake data in it (not yet loaded)
|
|
64
67
|
* @type {boolean}
|
|
65
68
|
*/
|
|
66
69
|
hasDummyData: boolean;
|
|
67
|
-
_loop: boolean;
|
|
68
70
|
/**
|
|
69
71
|
* Indicates whether the sequencer has finished playing a sequence
|
|
70
72
|
* @type {boolean}
|
|
71
73
|
*/
|
|
72
74
|
isFinished: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The current sequence's length, in seconds
|
|
77
|
+
* @type {number}
|
|
78
|
+
*/
|
|
79
|
+
duration: number;
|
|
73
80
|
/**
|
|
74
81
|
* Indicates if the sequencer is paused.
|
|
75
82
|
* Paused if a number, undefined if playing
|
|
76
83
|
* @type {undefined|number}
|
|
84
|
+
* @private
|
|
77
85
|
*/
|
|
78
|
-
pausedTime
|
|
86
|
+
private pausedTime;
|
|
87
|
+
ignoreEvents: boolean;
|
|
88
|
+
synth: Synthetizer;
|
|
89
|
+
highResTimeOffset: number;
|
|
79
90
|
/**
|
|
80
|
-
*
|
|
91
|
+
* Absolute playback startTime, bases on the synth's time
|
|
81
92
|
* @type {number}
|
|
82
93
|
*/
|
|
83
|
-
|
|
94
|
+
absoluteStartTime: number;
|
|
84
95
|
/**
|
|
85
96
|
* @type {boolean}
|
|
86
97
|
* @private
|
|
@@ -91,6 +102,28 @@ export class Sequencer {
|
|
|
91
102
|
* @private
|
|
92
103
|
*/
|
|
93
104
|
private _preservePlaybackState;
|
|
105
|
+
/**
|
|
106
|
+
* Internal loop marker
|
|
107
|
+
* @type {boolean}
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
private _loop;
|
|
111
|
+
set loop(value: boolean);
|
|
112
|
+
get loop(): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Controls the playback's rate
|
|
115
|
+
* @type {number}
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
private _playbackRate;
|
|
119
|
+
/**
|
|
120
|
+
* @param value {number}
|
|
121
|
+
*/
|
|
122
|
+
set playbackRate(value: number);
|
|
123
|
+
/**
|
|
124
|
+
* @returns {number}
|
|
125
|
+
*/
|
|
126
|
+
get playbackRate(): number;
|
|
94
127
|
/**
|
|
95
128
|
* Indicates if the sequencer should skip to first note on
|
|
96
129
|
* @param val {boolean}
|
|
@@ -118,21 +151,11 @@ export class Sequencer {
|
|
|
118
151
|
* @returns {number} Current playback time, in seconds
|
|
119
152
|
*/
|
|
120
153
|
get currentTime(): number;
|
|
121
|
-
set loop(value: boolean);
|
|
122
|
-
get loop(): boolean;
|
|
123
154
|
/**
|
|
124
155
|
* Use for visualization as it's not affected by the audioContext stutter
|
|
125
156
|
* @returns {number}
|
|
126
157
|
*/
|
|
127
158
|
get currentHighResolutionTime(): number;
|
|
128
|
-
/**
|
|
129
|
-
* @param value {number}
|
|
130
|
-
*/
|
|
131
|
-
set playbackRate(value: number);
|
|
132
|
-
/**
|
|
133
|
-
* @returns {number}
|
|
134
|
-
*/
|
|
135
|
-
get playbackRate(): number;
|
|
136
159
|
/**
|
|
137
160
|
* true if paused, false if playing or stopped
|
|
138
161
|
* @returns {boolean}
|
|
@@ -156,6 +179,12 @@ export class Sequencer {
|
|
|
156
179
|
* @param id {string} must be unique
|
|
157
180
|
*/
|
|
158
181
|
addOnTimeChangeEvent(callback: (arg0: number) => any, id: string): void;
|
|
182
|
+
/**
|
|
183
|
+
* Adds a new event that gets called when the tempo changes
|
|
184
|
+
* @param callback {function(number)} the new tempo, in BPM
|
|
185
|
+
* @param id {string} must be unique
|
|
186
|
+
*/
|
|
187
|
+
addOnTempoChangeEvent(callback: (arg0: number) => any, id: string): void;
|
|
159
188
|
resetMIDIOut(): void;
|
|
160
189
|
/**
|
|
161
190
|
* @param messageType {WorkletSequencerMessageType}
|
|
@@ -165,6 +194,12 @@ export class Sequencer {
|
|
|
165
194
|
private _sendMessage;
|
|
166
195
|
nextSong(): void;
|
|
167
196
|
previousSong(): void;
|
|
197
|
+
/**
|
|
198
|
+
* @param type {Object<string, function>}
|
|
199
|
+
* @param params {any}
|
|
200
|
+
* @private
|
|
201
|
+
*/
|
|
202
|
+
private _callEvents;
|
|
168
203
|
/**
|
|
169
204
|
* @param {WorkletSequencerReturnMessageType} messageType
|
|
170
205
|
* @param {any} messageData
|
|
@@ -199,7 +234,7 @@ export class Sequencer {
|
|
|
199
234
|
unpause(): void;
|
|
200
235
|
/**
|
|
201
236
|
* Starts the playback
|
|
202
|
-
* @param resetTime {boolean} If true, time is set to
|
|
237
|
+
* @param resetTime {boolean} If true, time is set to 0 s
|
|
203
238
|
*/
|
|
204
239
|
play(resetTime?: boolean): void;
|
|
205
240
|
/**
|
package/package.json
CHANGED
package/sequencer/sequencer.js
CHANGED
|
@@ -12,7 +12,8 @@ import { BasicMIDI } from "../midi_parser/basic_midi.js";
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* sequencer.js
|
|
15
|
-
* purpose: plays back the midi file decoded by midi_loader.js, including support for
|
|
15
|
+
* purpose: plays back the midi file decoded by midi_loader.js, including support for multichannel midis
|
|
16
|
+
* (adding channels when more than one midi port is detected)
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -63,7 +64,7 @@ export class Sequencer
|
|
|
63
64
|
* Fires on text event
|
|
64
65
|
* @type {function}
|
|
65
66
|
* @param data {Uint8Array} the data text
|
|
66
|
-
* @param type {number} the status byte of the message (the meta
|
|
67
|
+
* @param type {number} the status byte of the message (the meta-status byte)
|
|
67
68
|
* @param lyricsIndex {number} if the text is a lyric, the index of the lyric in midiData.lyrics, otherwise -1
|
|
68
69
|
*/
|
|
69
70
|
onTextEvent;
|
|
@@ -79,6 +80,51 @@ export class Sequencer
|
|
|
79
80
|
*/
|
|
80
81
|
onSongEnded = {};
|
|
81
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Fires on tempo change
|
|
85
|
+
* @type {Object<string, function(number)>}
|
|
86
|
+
*/
|
|
87
|
+
onTempoChange = {};
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Current song's tempo in BPM
|
|
91
|
+
* @type {number}
|
|
92
|
+
*/
|
|
93
|
+
currentTempo = 120;
|
|
94
|
+
/**
|
|
95
|
+
* Current song index
|
|
96
|
+
* @type {number}
|
|
97
|
+
*/
|
|
98
|
+
songIndex = 0;
|
|
99
|
+
/**
|
|
100
|
+
* @type {function(BasicMIDI)}
|
|
101
|
+
* @private
|
|
102
|
+
*/
|
|
103
|
+
_getMIDIResolve = undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Indicates if the current midiData property has fake data in it (not yet loaded)
|
|
106
|
+
* @type {boolean}
|
|
107
|
+
*/
|
|
108
|
+
hasDummyData = true;
|
|
109
|
+
/**
|
|
110
|
+
* Indicates whether the sequencer has finished playing a sequence
|
|
111
|
+
* @type {boolean}
|
|
112
|
+
*/
|
|
113
|
+
isFinished = false;
|
|
114
|
+
/**
|
|
115
|
+
* The current sequence's length, in seconds
|
|
116
|
+
* @type {number}
|
|
117
|
+
*/
|
|
118
|
+
duration = 0;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Indicates if the sequencer is paused.
|
|
122
|
+
* Paused if a number, undefined if playing
|
|
123
|
+
* @type {undefined|number}
|
|
124
|
+
* @private
|
|
125
|
+
*/
|
|
126
|
+
pausedTime = undefined;
|
|
127
|
+
|
|
82
128
|
/**
|
|
83
129
|
* Creates a new Midi sequencer for playing back MIDI files
|
|
84
130
|
* @param midiBinaries {MIDIFile[]} List of the buffers of the MIDI files
|
|
@@ -97,47 +143,6 @@ export class Sequencer
|
|
|
97
143
|
*/
|
|
98
144
|
this.absoluteStartTime = this.synth.currentTime;
|
|
99
145
|
|
|
100
|
-
/**
|
|
101
|
-
* @type {function(BasicMIDI)}
|
|
102
|
-
* @private
|
|
103
|
-
*/
|
|
104
|
-
this._getMIDIResolve = undefined;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Controls the playback's rate
|
|
108
|
-
* @type {number}
|
|
109
|
-
*/
|
|
110
|
-
this._playbackRate = 1;
|
|
111
|
-
|
|
112
|
-
this.songIndex = 0;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Indicates if the current midiData property has dummy data in it (not yet loaded)
|
|
116
|
-
* @type {boolean}
|
|
117
|
-
*/
|
|
118
|
-
this.hasDummyData = true;
|
|
119
|
-
|
|
120
|
-
this._loop = true;
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Indicates whether the sequencer has finished playing a sequence
|
|
124
|
-
* @type {boolean}
|
|
125
|
-
*/
|
|
126
|
-
this.isFinished = false;
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Indicates if the sequencer is paused.
|
|
130
|
-
* Paused if a number, undefined if playing
|
|
131
|
-
* @type {undefined|number}
|
|
132
|
-
*/
|
|
133
|
-
this.pausedTime = undefined;
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* The current sequence's length, in seconds
|
|
137
|
-
* @type {number}
|
|
138
|
-
*/
|
|
139
|
-
this.duration = 0;
|
|
140
|
-
|
|
141
146
|
this.synth.sequencerCallbackFunction = this._handleMessage.bind(this);
|
|
142
147
|
|
|
143
148
|
/**
|
|
@@ -167,6 +172,49 @@ export class Sequencer
|
|
|
167
172
|
window.addEventListener("beforeunload", this.resetMIDIOut.bind(this));
|
|
168
173
|
}
|
|
169
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Internal loop marker
|
|
177
|
+
* @type {boolean}
|
|
178
|
+
* @private
|
|
179
|
+
*/
|
|
180
|
+
_loop = true;
|
|
181
|
+
|
|
182
|
+
get loop()
|
|
183
|
+
{
|
|
184
|
+
return this._loop;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
set loop(value)
|
|
188
|
+
{
|
|
189
|
+
this._sendMessage(WorkletSequencerMessageType.setLoop, value);
|
|
190
|
+
this._loop = value;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Controls the playback's rate
|
|
195
|
+
* @type {number}
|
|
196
|
+
* @private
|
|
197
|
+
*/
|
|
198
|
+
_playbackRate = 1;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* @returns {number}
|
|
202
|
+
*/
|
|
203
|
+
get playbackRate()
|
|
204
|
+
{
|
|
205
|
+
return this._playbackRate;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @param value {number}
|
|
210
|
+
*/
|
|
211
|
+
set playbackRate(value)
|
|
212
|
+
{
|
|
213
|
+
this._sendMessage(WorkletSequencerMessageType.setPlaybackRate, value);
|
|
214
|
+
this.highResTimeOffset *= (value / this._playbackRate);
|
|
215
|
+
this._playbackRate = value;
|
|
216
|
+
}
|
|
217
|
+
|
|
170
218
|
/**
|
|
171
219
|
* Indicates if the sequencer should skip to first note on
|
|
172
220
|
* @return {boolean}
|
|
@@ -230,17 +278,6 @@ export class Sequencer
|
|
|
230
278
|
this._sendMessage(WorkletSequencerMessageType.setTime, time);
|
|
231
279
|
}
|
|
232
280
|
|
|
233
|
-
get loop()
|
|
234
|
-
{
|
|
235
|
-
return this._loop;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
set loop(value)
|
|
239
|
-
{
|
|
240
|
-
this._sendMessage(WorkletSequencerMessageType.setLoop, value);
|
|
241
|
-
this._loop = value;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
281
|
/**
|
|
245
282
|
* Use for visualization as it's not affected by the audioContext stutter
|
|
246
283
|
* @returns {number}
|
|
@@ -271,24 +308,6 @@ export class Sequencer
|
|
|
271
308
|
return currentPerformanceTime;
|
|
272
309
|
}
|
|
273
310
|
|
|
274
|
-
/**
|
|
275
|
-
* @returns {number}
|
|
276
|
-
*/
|
|
277
|
-
get playbackRate()
|
|
278
|
-
{
|
|
279
|
-
return this._playbackRate;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* @param value {number}
|
|
284
|
-
*/
|
|
285
|
-
set playbackRate(value)
|
|
286
|
-
{
|
|
287
|
-
this._sendMessage(WorkletSequencerMessageType.setPlaybackRate, value);
|
|
288
|
-
this.highResTimeOffset *= (value / this._playbackRate);
|
|
289
|
-
this._playbackRate = value;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
311
|
/**
|
|
293
312
|
* true if paused, false if playing or stopped
|
|
294
313
|
* @returns {boolean}
|
|
@@ -328,6 +347,16 @@ export class Sequencer
|
|
|
328
347
|
this.onTimeChange[id] = callback;
|
|
329
348
|
}
|
|
330
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Adds a new event that gets called when the tempo changes
|
|
352
|
+
* @param callback {function(number)} the new tempo, in BPM
|
|
353
|
+
* @param id {string} must be unique
|
|
354
|
+
*/
|
|
355
|
+
addOnTempoChangeEvent(callback, id)
|
|
356
|
+
{
|
|
357
|
+
this.onTempoChange[id] = callback;
|
|
358
|
+
}
|
|
359
|
+
|
|
331
360
|
resetMIDIOut()
|
|
332
361
|
{
|
|
333
362
|
if (!this.MIDIout)
|
|
@@ -369,6 +398,26 @@ export class Sequencer
|
|
|
369
398
|
this._sendMessage(WorkletSequencerMessageType.changeSong, false);
|
|
370
399
|
}
|
|
371
400
|
|
|
401
|
+
/**
|
|
402
|
+
* @param type {Object<string, function>}
|
|
403
|
+
* @param params {any}
|
|
404
|
+
* @private
|
|
405
|
+
*/
|
|
406
|
+
_callEvents(type, params)
|
|
407
|
+
{
|
|
408
|
+
Object.entries(type).forEach((callback) =>
|
|
409
|
+
{
|
|
410
|
+
try
|
|
411
|
+
{
|
|
412
|
+
callback[1](params);
|
|
413
|
+
}
|
|
414
|
+
catch (e)
|
|
415
|
+
{
|
|
416
|
+
SpessaSynthWarn(`Failed to execute callback for ${callback[0]}:`, e);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
|
|
372
421
|
/**
|
|
373
422
|
* @param {WorkletSequencerReturnMessageType} messageType
|
|
374
423
|
* @param {any} messageData
|
|
@@ -411,7 +460,7 @@ export class Sequencer
|
|
|
411
460
|
this.hasDummyData = false;
|
|
412
461
|
this.absoluteStartTime = 0;
|
|
413
462
|
this.duration = this.midiData.duration;
|
|
414
|
-
|
|
463
|
+
this._callEvents(this.onSongChange, songChangeData);
|
|
415
464
|
// if is auto played, unpause
|
|
416
465
|
if (messageData[2] === true)
|
|
417
466
|
{
|
|
@@ -429,7 +478,7 @@ export class Sequencer
|
|
|
429
478
|
case WorkletSequencerReturnMessageType.timeChange:
|
|
430
479
|
// message data is absolute time
|
|
431
480
|
const time = this.synth.currentTime - messageData;
|
|
432
|
-
|
|
481
|
+
this._callEvents(this.onTimeChange, time);
|
|
433
482
|
this._recalculateStartTime(time);
|
|
434
483
|
if (this.paused && this._preservePlaybackState)
|
|
435
484
|
{
|
|
@@ -446,7 +495,7 @@ export class Sequencer
|
|
|
446
495
|
this.isFinished = messageData;
|
|
447
496
|
if (this.isFinished)
|
|
448
497
|
{
|
|
449
|
-
|
|
498
|
+
this._callEvents(this.onSongEnded, undefined);
|
|
450
499
|
}
|
|
451
500
|
break;
|
|
452
501
|
|
|
@@ -466,6 +515,14 @@ export class Sequencer
|
|
|
466
515
|
{
|
|
467
516
|
this._getMIDIResolve(BasicMIDI.copyFrom(messageData));
|
|
468
517
|
}
|
|
518
|
+
break;
|
|
519
|
+
|
|
520
|
+
case WorkletSequencerReturnMessageType.tempoChange:
|
|
521
|
+
this.currentTempo = messageData;
|
|
522
|
+
if (this.onTempoChange)
|
|
523
|
+
{
|
|
524
|
+
this._callEvents(this.onTempoChange, this.currentTempo);
|
|
525
|
+
}
|
|
469
526
|
}
|
|
470
527
|
}
|
|
471
528
|
|
|
@@ -499,7 +556,7 @@ export class Sequencer
|
|
|
499
556
|
loadNewSongList(midiBuffers, autoPlay = true)
|
|
500
557
|
{
|
|
501
558
|
this.pause();
|
|
502
|
-
// add some
|
|
559
|
+
// add some fake data
|
|
503
560
|
this.midiData = DUMMY_MIDI_DATA;
|
|
504
561
|
this.hasDummyData = true;
|
|
505
562
|
this.duration = 99999;
|
|
@@ -549,7 +606,7 @@ export class Sequencer
|
|
|
549
606
|
|
|
550
607
|
/**
|
|
551
608
|
* Starts the playback
|
|
552
|
-
* @param resetTime {boolean} If true, time is set to
|
|
609
|
+
* @param resetTime {boolean} If true, time is set to 0 s
|
|
553
610
|
*/
|
|
554
611
|
play(resetTime = false)
|
|
555
612
|
{
|
|
@@ -90,12 +90,15 @@ export function _processEvent(event, trackIndex)
|
|
|
90
90
|
break;
|
|
91
91
|
|
|
92
92
|
case messageTypes.setTempo:
|
|
93
|
-
|
|
93
|
+
let tempoBPM = getTempo(event);
|
|
94
|
+
this.oneTickToSeconds = 60 / (tempoBPM * this.midiData.timeDivision);
|
|
94
95
|
if (this.oneTickToSeconds === 0)
|
|
95
96
|
{
|
|
96
97
|
this.oneTickToSeconds = 60 / (120 * this.midiData.timeDivision);
|
|
97
98
|
SpessaSynthWarn("invalid tempo! falling back to 120 BPM");
|
|
99
|
+
tempoBPM = 120;
|
|
98
100
|
}
|
|
101
|
+
this.post(WorkletSequencerReturnMessageType.tempoChange, Math.floor(tempoBPM * 100) / 100);
|
|
99
102
|
break;
|
|
100
103
|
|
|
101
104
|
// recongized but ignored
|
|
@@ -8,18 +8,18 @@ export function _processTick()
|
|
|
8
8
|
let current = this.currentTime;
|
|
9
9
|
while (this.playedTime < current)
|
|
10
10
|
{
|
|
11
|
-
// find next event
|
|
11
|
+
// find the next event
|
|
12
12
|
let trackIndex = this._findFirstEventIndex();
|
|
13
13
|
let event = this.tracks[trackIndex][this.eventIndex[trackIndex]];
|
|
14
14
|
this._processEvent(event, trackIndex);
|
|
15
15
|
|
|
16
16
|
this.eventIndex[trackIndex]++;
|
|
17
17
|
|
|
18
|
-
// find next event
|
|
18
|
+
// find the next event
|
|
19
19
|
trackIndex = this._findFirstEventIndex();
|
|
20
20
|
if (this.tracks[trackIndex].length <= this.eventIndex[trackIndex])
|
|
21
21
|
{
|
|
22
|
-
// song has ended
|
|
22
|
+
// the song has ended
|
|
23
23
|
if (this.loop)
|
|
24
24
|
{
|
|
25
25
|
this.setTimeTicks(this.midiData.loop.start);
|
|
@@ -43,7 +43,7 @@ export function _processTick()
|
|
|
43
43
|
this.setTimeTicks(this.midiData.loop.start);
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
-
// if song has ended
|
|
46
|
+
// if the song has ended
|
|
47
47
|
else if (current >= this.duration)
|
|
48
48
|
{
|
|
49
49
|
if (this.loop && this.currentLoopCount > 0)
|
|
@@ -39,5 +39,6 @@ export const WorkletSequencerReturnMessageType = {
|
|
|
39
39
|
timeChange: 3, // newAbsoluteTime<number>
|
|
40
40
|
pause: 4, // no data
|
|
41
41
|
getMIDI: 5, // midiData<MIDI>
|
|
42
|
-
midiError: 6
|
|
42
|
+
midiError: 6, // errorMSG<string>
|
|
43
|
+
tempoChange: 7 // newTempoBPM<number>
|
|
43
44
|
};
|
|
File without changes
|