spessasynth_lib 3.21.4 → 3.21.6
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 +15 -4
- package/package.json +1 -1
- package/sequencer/sequencer.js +28 -9
- package/sequencer/worklet_sequencer/events.js +1 -1
- package/sequencer/worklet_sequencer/sequencer_message.js +2 -2
- package/sequencer/worklet_sequencer/song_control.js +17 -6
- package/sequencer/worklet_sequencer/worklet_sequencer.js +1 -1
- package/synthetizer/worklet_processor.min.js +7 -7
- package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +1 -1
|
@@ -68,6 +68,12 @@ export class Sequencer {
|
|
|
68
68
|
* @type {boolean}
|
|
69
69
|
*/
|
|
70
70
|
isFinished: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Indicates if the sequencer is paused.
|
|
73
|
+
* Paused if a number, undefined if playing
|
|
74
|
+
* @type {undefined|number}
|
|
75
|
+
*/
|
|
76
|
+
pausedTime: undefined | number;
|
|
71
77
|
/**
|
|
72
78
|
* The current sequence's length, in seconds
|
|
73
79
|
* @type {number}
|
|
@@ -146,7 +152,6 @@ export class Sequencer {
|
|
|
146
152
|
* @private
|
|
147
153
|
*/
|
|
148
154
|
private _handleMessage;
|
|
149
|
-
pausedTime: number;
|
|
150
155
|
/**
|
|
151
156
|
* @param time
|
|
152
157
|
* @private
|
|
@@ -157,9 +162,11 @@ export class Sequencer {
|
|
|
157
162
|
*/
|
|
158
163
|
getMIDI(): Promise<MIDI>;
|
|
159
164
|
/**
|
|
160
|
-
*
|
|
165
|
+
* Loads a new song list
|
|
166
|
+
* @param midiBuffers {MIDIFile[]} - the MIDI files to play
|
|
167
|
+
* @param autoPlay {boolean} - if true, the first sequence will automatically start playing
|
|
161
168
|
*/
|
|
162
|
-
loadNewSongList(midiBuffers: MIDIFile[]): void;
|
|
169
|
+
loadNewSongList(midiBuffers: MIDIFile[], autoPlay?: boolean): void;
|
|
163
170
|
songsAmount: number;
|
|
164
171
|
/**
|
|
165
172
|
* @param output {MIDIOutput}
|
|
@@ -199,7 +206,11 @@ export type SequencerOptions = {
|
|
|
199
206
|
/**
|
|
200
207
|
* - if true, the sequencer will skip to the first note
|
|
201
208
|
*/
|
|
202
|
-
skipToFirstNoteOn: boolean;
|
|
209
|
+
skipToFirstNoteOn: boolean | undefined;
|
|
210
|
+
/**
|
|
211
|
+
* - if true, the sequencer will automatically start playing the MIDI
|
|
212
|
+
*/
|
|
213
|
+
autoPlay: boolean | undefined;
|
|
203
214
|
};
|
|
204
215
|
import { MidiData } from "../midi_parser/midi_data.js";
|
|
205
216
|
import { Synthetizer } from "../synthetizer/synthetizer.js";
|
package/package.json
CHANGED
package/sequencer/sequencer.js
CHANGED
|
@@ -26,14 +26,16 @@ import { DUMMY_MIDI_DATA, MidiData } from "../midi_parser/midi_data.js";
|
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* @typedef {Object} SequencerOptions
|
|
29
|
-
* @property {boolean} skipToFirstNoteOn - if true, the sequencer will skip to the first note
|
|
29
|
+
* @property {boolean|undefined} skipToFirstNoteOn - if true, the sequencer will skip to the first note
|
|
30
|
+
* @property {boolean|undefined} autoPlay - if true, the sequencer will automatically start playing the MIDI
|
|
30
31
|
*/
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* @type {SequencerOptions}
|
|
34
35
|
*/
|
|
35
36
|
const DEFAULT_OPTIONS = {
|
|
36
|
-
skipToFirstNoteOn: true
|
|
37
|
+
skipToFirstNoteOn: true,
|
|
38
|
+
autoPlay: true
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
export class Sequencer
|
|
@@ -117,6 +119,13 @@ export class Sequencer
|
|
|
117
119
|
*/
|
|
118
120
|
this.isFinished = false;
|
|
119
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Indicates if the sequencer is paused.
|
|
124
|
+
* Paused if a number, undefined if playing
|
|
125
|
+
* @type {undefined|number}
|
|
126
|
+
*/
|
|
127
|
+
this.pausedTime = undefined;
|
|
128
|
+
|
|
120
129
|
/**
|
|
121
130
|
* The current sequence's length, in seconds
|
|
122
131
|
* @type {number}
|
|
@@ -137,7 +146,7 @@ export class Sequencer
|
|
|
137
146
|
this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, false);
|
|
138
147
|
}
|
|
139
148
|
|
|
140
|
-
this.loadNewSongList(midiBinaries);
|
|
149
|
+
this.loadNewSongList(midiBinaries, options?.autoPlay ?? false);
|
|
141
150
|
|
|
142
151
|
window.addEventListener("beforeunload", this.resetMIDIOut.bind(this));
|
|
143
152
|
}
|
|
@@ -167,7 +176,7 @@ export class Sequencer
|
|
|
167
176
|
get currentTime()
|
|
168
177
|
{
|
|
169
178
|
// return the paused time if it's set to something other than undefined
|
|
170
|
-
if (this.pausedTime)
|
|
179
|
+
if (this.pausedTime !== undefined)
|
|
171
180
|
{
|
|
172
181
|
return this.pausedTime;
|
|
173
182
|
}
|
|
@@ -198,7 +207,7 @@ export class Sequencer
|
|
|
198
207
|
*/
|
|
199
208
|
get currentHighResolutionTime()
|
|
200
209
|
{
|
|
201
|
-
if (this.pausedTime)
|
|
210
|
+
if (this.pausedTime !== undefined)
|
|
202
211
|
{
|
|
203
212
|
return this.pausedTime;
|
|
204
213
|
}
|
|
@@ -364,7 +373,11 @@ export class Sequencer
|
|
|
364
373
|
this.absoluteStartTime = 0;
|
|
365
374
|
this.duration = this.midiData.duration;
|
|
366
375
|
Object.entries(this.onSongChange).forEach((callback) => callback[1](songChangeData));
|
|
367
|
-
|
|
376
|
+
// if is auto played, unpause
|
|
377
|
+
if (messageData[2] === true)
|
|
378
|
+
{
|
|
379
|
+
this.unpause();
|
|
380
|
+
}
|
|
368
381
|
break;
|
|
369
382
|
|
|
370
383
|
case WorkletSequencerReturnMessageType.textEvent:
|
|
@@ -437,22 +450,28 @@ export class Sequencer
|
|
|
437
450
|
}
|
|
438
451
|
|
|
439
452
|
/**
|
|
440
|
-
*
|
|
453
|
+
* Loads a new song list
|
|
454
|
+
* @param midiBuffers {MIDIFile[]} - the MIDI files to play
|
|
455
|
+
* @param autoPlay {boolean} - if true, the first sequence will automatically start playing
|
|
441
456
|
*/
|
|
442
|
-
loadNewSongList(midiBuffers)
|
|
457
|
+
loadNewSongList(midiBuffers, autoPlay = true)
|
|
443
458
|
{
|
|
444
459
|
this.pause();
|
|
445
460
|
// add some dummy data
|
|
446
461
|
this.midiData = DUMMY_MIDI_DATA;
|
|
447
462
|
this.hasDummyData = true;
|
|
448
463
|
this.duration = 99999;
|
|
449
|
-
this._sendMessage(WorkletSequencerMessageType.loadNewSongList, midiBuffers);
|
|
464
|
+
this._sendMessage(WorkletSequencerMessageType.loadNewSongList, [midiBuffers, autoPlay]);
|
|
450
465
|
this.songIndex = 0;
|
|
451
466
|
this.songsAmount = midiBuffers.length;
|
|
452
467
|
if (this.songsAmount > 1)
|
|
453
468
|
{
|
|
454
469
|
this.loop = false;
|
|
455
470
|
}
|
|
471
|
+
if (autoPlay === false)
|
|
472
|
+
{
|
|
473
|
+
this.pausedTime = this.currentTime;
|
|
474
|
+
}
|
|
456
475
|
}
|
|
457
476
|
|
|
458
477
|
/**
|
|
@@ -16,7 +16,7 @@ export function processMessage(messageType, messageData)
|
|
|
16
16
|
break;
|
|
17
17
|
|
|
18
18
|
case WorkletSequencerMessageType.loadNewSongList:
|
|
19
|
-
this.loadNewSongList(messageData);
|
|
19
|
+
this.loadNewSongList(messageData[0], messageData[1]);
|
|
20
20
|
break;
|
|
21
21
|
|
|
22
22
|
case WorkletSequencerMessageType.pause:
|
|
@@ -32,10 +32,10 @@ export const WorkletSequencerMessageType = {
|
|
|
32
32
|
*/
|
|
33
33
|
export const WorkletSequencerReturnMessageType = {
|
|
34
34
|
midiEvent: 0, // [...midiEventBytes<number>]
|
|
35
|
-
songChange: 1, // [midiData<MidiData>, songIndex<number>]
|
|
35
|
+
songChange: 1, // [midiData<MidiData>, songIndex<number>, isAutoPlayed<boolean>]
|
|
36
36
|
textEvent: 2, // [messageData<number[]>, statusByte<number]
|
|
37
37
|
timeChange: 3, // newAbsoluteTime<number>
|
|
38
38
|
pause: 4, // no data
|
|
39
39
|
getMIDI: 5, // midiData<MIDI>
|
|
40
|
-
midiError: 6
|
|
40
|
+
midiError: 6 // errorMSG<string>
|
|
41
41
|
};
|
|
@@ -41,9 +41,10 @@ export function assignMIDIPort(trackNum, port)
|
|
|
41
41
|
/**
|
|
42
42
|
* Loads a new sequence
|
|
43
43
|
* @param parsedMidi {BasicMIDI}
|
|
44
|
+
* @param autoPlay {boolean}
|
|
44
45
|
* @this {WorkletSequencer}
|
|
45
46
|
*/
|
|
46
|
-
export function loadNewSequence(parsedMidi)
|
|
47
|
+
export function loadNewSequence(parsedMidi, autoPlay = true)
|
|
47
48
|
{
|
|
48
49
|
this.stop();
|
|
49
50
|
if (!parsedMidi.tracks)
|
|
@@ -122,9 +123,8 @@ export function loadNewSequence(parsedMidi)
|
|
|
122
123
|
this.firstNoteTime = MIDIticksToSeconds(this.midiData.firstNoteOn, this.midiData);
|
|
123
124
|
SpessaSynthInfo(`%cTotal song time: ${formatTime(Math.ceil(this.duration)).time}`, consoleColors.recognized);
|
|
124
125
|
|
|
125
|
-
this.post(WorkletSequencerReturnMessageType.songChange, [new MidiData(this.midiData), this.songIndex]);
|
|
126
|
+
this.post(WorkletSequencerReturnMessageType.songChange, [new MidiData(this.midiData), this.songIndex, autoPlay]);
|
|
126
127
|
|
|
127
|
-
this.synth.resetAllControllers();
|
|
128
128
|
if (this.duration <= 1)
|
|
129
129
|
{
|
|
130
130
|
SpessaSynthWarn(
|
|
@@ -133,14 +133,25 @@ export function loadNewSequence(parsedMidi)
|
|
|
133
133
|
);
|
|
134
134
|
this.loop = false;
|
|
135
135
|
}
|
|
136
|
-
|
|
136
|
+
if (autoPlay)
|
|
137
|
+
{
|
|
138
|
+
this.play(true);
|
|
139
|
+
}
|
|
140
|
+
else
|
|
141
|
+
{
|
|
142
|
+
// this shall not play: play to the first note and then wait
|
|
143
|
+
const targetTime = this._skipToFirstNoteOn ? this.midiData.firstNoteOn - 1 : 0;
|
|
144
|
+
this.setTimeTicks(targetTime);
|
|
145
|
+
this.pause();
|
|
146
|
+
}
|
|
137
147
|
}
|
|
138
148
|
|
|
139
149
|
/**
|
|
140
150
|
* @param midiBuffers {MIDIFile[]}
|
|
151
|
+
* @param autoPlay {boolean}
|
|
141
152
|
* @this {WorkletSequencer}
|
|
142
153
|
*/
|
|
143
|
-
export function loadNewSongList(midiBuffers)
|
|
154
|
+
export function loadNewSongList(midiBuffers, autoPlay = true)
|
|
144
155
|
{
|
|
145
156
|
/**
|
|
146
157
|
* parse the MIDIs (only the array buffers, MIDI is unchanged)
|
|
@@ -173,7 +184,7 @@ export function loadNewSongList(midiBuffers)
|
|
|
173
184
|
{
|
|
174
185
|
this.loop = false;
|
|
175
186
|
}
|
|
176
|
-
this.loadNewSequence(this.songs[this.songIndex]);
|
|
187
|
+
this.loadNewSequence(this.songs[this.songIndex], autoPlay);
|
|
177
188
|
}
|
|
178
189
|
|
|
179
190
|
/**
|