spessasynth_lib 3.21.9 → 3.21.11
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 +22 -0
- package/@types/sequencer/worklet_sequencer/sequencer_message.d.ts +1 -0
- package/@types/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.d.ts +15 -0
- package/package.json +1 -1
- package/sequencer/sequencer.js +49 -5
- package/sequencer/worklet_sequencer/events.js +3 -0
- package/sequencer/worklet_sequencer/play.js +2 -0
- package/sequencer/worklet_sequencer/sequencer_message.js +3 -1
- package/sequencer/worklet_sequencer/worklet_sequencer.js +14 -4
- package/synthetizer/worklet_processor.min.js +10 -10
- package/synthetizer/worklet_system/main_processor.js +0 -0
- package/synthetizer/worklet_system/worklet_methods/controller_control.js +6 -10
- package/synthetizer/worklet_system/worklet_methods/program_control.js +5 -5
- package/synthetizer/worklet_system/worklet_methods/reset_controllers.js +3 -2
- package/synthetizer/worklet_system/worklet_methods/snapshot.js +3 -3
- package/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +0 -0
- package/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +0 -0
- package/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +26 -0
|
@@ -84,6 +84,11 @@ export class Sequencer {
|
|
|
84
84
|
* @private
|
|
85
85
|
*/
|
|
86
86
|
private _skipToFirstNoteOn;
|
|
87
|
+
/**
|
|
88
|
+
* @type {boolean}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
91
|
+
private _preservePlaybackState;
|
|
87
92
|
/**
|
|
88
93
|
* Indicates if the sequencer should skip to first note on
|
|
89
94
|
* @param val {boolean}
|
|
@@ -94,6 +99,18 @@ export class Sequencer {
|
|
|
94
99
|
* @return {boolean}
|
|
95
100
|
*/
|
|
96
101
|
get skipToFirstNoteOn(): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* if true,
|
|
104
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
105
|
+
* @param val {boolean}
|
|
106
|
+
*/
|
|
107
|
+
set preservePlaybackState(val: boolean);
|
|
108
|
+
/**
|
|
109
|
+
* if true,
|
|
110
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
111
|
+
* @returns {boolean}
|
|
112
|
+
*/
|
|
113
|
+
get preservePlaybackState(): boolean;
|
|
97
114
|
set currentTime(time: number);
|
|
98
115
|
/**
|
|
99
116
|
* @returns {number} Current playback time, in seconds
|
|
@@ -211,6 +228,11 @@ export type SequencerOptions = {
|
|
|
211
228
|
* - if true, the sequencer will automatically start playing the MIDI
|
|
212
229
|
*/
|
|
213
230
|
autoPlay: boolean | undefined;
|
|
231
|
+
/**
|
|
232
|
+
* - if true,
|
|
233
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
234
|
+
*/
|
|
235
|
+
preservePlaybackState: boolean | typeof unescape;
|
|
214
236
|
};
|
|
215
237
|
import { MidiData } from "../midi_parser/midi_data.js";
|
|
216
238
|
import { Synthetizer } from "../synthetizer/synthetizer.js";
|
|
@@ -14,6 +14,7 @@ export namespace WorkletSequencerMessageType {
|
|
|
14
14
|
let changeSong: number;
|
|
15
15
|
let getMIDI: number;
|
|
16
16
|
let setSkipToFirstNote: number;
|
|
17
|
+
let setPreservePlaybackState: number;
|
|
17
18
|
}
|
|
18
19
|
export type WorkletSequencerReturnMessageType = number;
|
|
19
20
|
export namespace WorkletSequencerReturnMessageType {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* @property {number} NRPFine - the current fine value of the Non-Registered Parameter
|
|
17
17
|
* @property {number} RPValue - the current value of the Registered Parameter
|
|
18
18
|
*
|
|
19
|
+
* @property {number} bank - the channel's bank number
|
|
19
20
|
* @property {BasicPreset} preset - the channel's preset
|
|
20
21
|
* @property {boolean} lockPreset - indicates whether the program on the channel is locked
|
|
21
22
|
* @property {boolean} presetUsesOverride - indcates if the channel uses a preset from the override soundfont.
|
|
@@ -36,6 +37,16 @@
|
|
|
36
37
|
* @this {SpessaSynthProcessor}
|
|
37
38
|
*/
|
|
38
39
|
export function createWorkletChannel(this: SpessaSynthProcessor, sendEvent?: boolean): void;
|
|
40
|
+
/**
|
|
41
|
+
* @param channel {WorkletProcessorChannel}
|
|
42
|
+
* @param bank {number}
|
|
43
|
+
*/
|
|
44
|
+
export function setBankSelect(channel: WorkletProcessorChannel, bank: number): void;
|
|
45
|
+
/**
|
|
46
|
+
* @param channel {WorkletProcessorChannel}
|
|
47
|
+
* @returns {number}
|
|
48
|
+
*/
|
|
49
|
+
export function getBankSelect(channel: WorkletProcessorChannel): number;
|
|
39
50
|
/**
|
|
40
51
|
* This is a channel configuration enum, it is internally sent from Synthetizer via controller change
|
|
41
52
|
*/
|
|
@@ -96,6 +107,10 @@ export type WorkletProcessorChannel = {
|
|
|
96
107
|
* - the current value of the Registered Parameter
|
|
97
108
|
*/
|
|
98
109
|
RPValue: number;
|
|
110
|
+
/**
|
|
111
|
+
* - the channel's bank number
|
|
112
|
+
*/
|
|
113
|
+
bank: number;
|
|
99
114
|
/**
|
|
100
115
|
* - the channel's preset
|
|
101
116
|
*/
|
package/package.json
CHANGED
package/sequencer/sequencer.js
CHANGED
|
@@ -28,6 +28,8 @@ import { DUMMY_MIDI_DATA, MidiData } from "../midi_parser/midi_data.js";
|
|
|
28
28
|
* @typedef {Object} SequencerOptions
|
|
29
29
|
* @property {boolean|undefined} skipToFirstNoteOn - if true, the sequencer will skip to the first note
|
|
30
30
|
* @property {boolean|undefined} autoPlay - if true, the sequencer will automatically start playing the MIDI
|
|
31
|
+
* @property {boolean|unescape} preservePlaybackState - if true,
|
|
32
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
31
33
|
*/
|
|
32
34
|
|
|
33
35
|
/**
|
|
@@ -35,7 +37,8 @@ import { DUMMY_MIDI_DATA, MidiData } from "../midi_parser/midi_data.js";
|
|
|
35
37
|
*/
|
|
36
38
|
const DEFAULT_OPTIONS = {
|
|
37
39
|
skipToFirstNoteOn: true,
|
|
38
|
-
autoPlay: true
|
|
40
|
+
autoPlay: true,
|
|
41
|
+
preservePlaybackState: false
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
export class Sequencer
|
|
@@ -138,7 +141,12 @@ export class Sequencer
|
|
|
138
141
|
* @type {boolean}
|
|
139
142
|
* @private
|
|
140
143
|
*/
|
|
141
|
-
this._skipToFirstNoteOn = options?.skipToFirstNoteOn
|
|
144
|
+
this._skipToFirstNoteOn = options?.skipToFirstNoteOn || true;
|
|
145
|
+
/**
|
|
146
|
+
* @type {boolean}
|
|
147
|
+
* @private
|
|
148
|
+
*/
|
|
149
|
+
this._preservePlaybackState = options?.preservePlaybackState || false;
|
|
142
150
|
|
|
143
151
|
if (this._skipToFirstNoteOn === false)
|
|
144
152
|
{
|
|
@@ -146,7 +154,12 @@ export class Sequencer
|
|
|
146
154
|
this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, false);
|
|
147
155
|
}
|
|
148
156
|
|
|
149
|
-
this.
|
|
157
|
+
if (this._preservePlaybackState === true)
|
|
158
|
+
{
|
|
159
|
+
this._sendMessage(WorkletSequencerMessageType.setPreservePlaybackState, true);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
this.loadNewSongList(midiBinaries, options?.autoPlay || true);
|
|
150
163
|
|
|
151
164
|
window.addEventListener("beforeunload", this.resetMIDIOut.bind(this));
|
|
152
165
|
}
|
|
@@ -170,6 +183,27 @@ export class Sequencer
|
|
|
170
183
|
this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, this._skipToFirstNoteOn);
|
|
171
184
|
}
|
|
172
185
|
|
|
186
|
+
/**
|
|
187
|
+
* if true,
|
|
188
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/
|
|
191
|
+
get preservePlaybackState()
|
|
192
|
+
{
|
|
193
|
+
return this._preservePlaybackState;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* if true,
|
|
198
|
+
* the sequencer will stay paused when seeking or changing the playback rate
|
|
199
|
+
* @param val {boolean}
|
|
200
|
+
*/
|
|
201
|
+
set preservePlaybackState(val)
|
|
202
|
+
{
|
|
203
|
+
this._preservePlaybackState = val;
|
|
204
|
+
this._sendMessage(WorkletSequencerMessageType.setPreservePlaybackState, val);
|
|
205
|
+
}
|
|
206
|
+
|
|
173
207
|
/**
|
|
174
208
|
* @returns {number} Current playback time, in seconds
|
|
175
209
|
*/
|
|
@@ -186,7 +220,10 @@ export class Sequencer
|
|
|
186
220
|
|
|
187
221
|
set currentTime(time)
|
|
188
222
|
{
|
|
189
|
-
this.
|
|
223
|
+
if (!this._preservePlaybackState)
|
|
224
|
+
{
|
|
225
|
+
this.unpause();
|
|
226
|
+
}
|
|
190
227
|
this._sendMessage(WorkletSequencerMessageType.setTime, time);
|
|
191
228
|
}
|
|
192
229
|
|
|
@@ -395,8 +432,15 @@ export class Sequencer
|
|
|
395
432
|
// message data is absolute time
|
|
396
433
|
const time = this.synth.currentTime - messageData;
|
|
397
434
|
Object.entries(this.onTimeChange).forEach((callback) => callback[1](time));
|
|
398
|
-
this.unpause();
|
|
399
435
|
this._recalculateStartTime(time);
|
|
436
|
+
if (this.paused && this._preservePlaybackState)
|
|
437
|
+
{
|
|
438
|
+
this.pausedTime = time;
|
|
439
|
+
}
|
|
440
|
+
else
|
|
441
|
+
{
|
|
442
|
+
this.unpause();
|
|
443
|
+
}
|
|
400
444
|
break;
|
|
401
445
|
|
|
402
446
|
case WorkletSequencerReturnMessageType.pause:
|
|
@@ -65,6 +65,9 @@ export function processMessage(messageType, messageData)
|
|
|
65
65
|
case WorkletSequencerMessageType.setSkipToFirstNote:
|
|
66
66
|
this._skipToFirstNoteOn = messageData;
|
|
67
67
|
break;
|
|
68
|
+
|
|
69
|
+
case WorkletSequencerMessageType.setPreservePlaybackState:
|
|
70
|
+
this.preservePlaybackState = messageData;
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
|
|
@@ -254,12 +254,14 @@ export function play(resetTime = false)
|
|
|
254
254
|
// reset the time if necesarry
|
|
255
255
|
if (resetTime)
|
|
256
256
|
{
|
|
257
|
+
this.pausedTime = undefined;
|
|
257
258
|
this.currentTime = 0;
|
|
258
259
|
return;
|
|
259
260
|
}
|
|
260
261
|
|
|
261
262
|
if (this.currentTime >= this.duration)
|
|
262
263
|
{
|
|
264
|
+
this.pausedTime = undefined;
|
|
263
265
|
this.currentTime = 0;
|
|
264
266
|
return;
|
|
265
267
|
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* @property {number} changeSong - 8 -> goForwards<boolean> if true, next song, if false, previous
|
|
12
12
|
* @property {number} getMIDI - 9 -> (no data)
|
|
13
13
|
* @property {number} setSkipToFirstNote -10 -> skipToFirstNoteOn<boolean>
|
|
14
|
+
* @property {number} setPreservePlaybackState -11 -> preservePlaybackState<boolean>
|
|
14
15
|
*/
|
|
15
16
|
export const WorkletSequencerMessageType = {
|
|
16
17
|
loadNewSongList: 0,
|
|
@@ -23,7 +24,8 @@ export const WorkletSequencerMessageType = {
|
|
|
23
24
|
setLoop: 7,
|
|
24
25
|
changeSong: 8,
|
|
25
26
|
getMIDI: 9,
|
|
26
|
-
setSkipToFirstNote: 10
|
|
27
|
+
setSkipToFirstNote: 10,
|
|
28
|
+
setPreservePlaybackState: 11
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
/**
|
|
@@ -104,6 +104,12 @@ class WorkletSequencer
|
|
|
104
104
|
* @private
|
|
105
105
|
*/
|
|
106
106
|
this._skipToFirstNoteOn = true;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* If true, seq will stay paused when seeking or changing the playback rate
|
|
110
|
+
* @type {boolean}
|
|
111
|
+
*/
|
|
112
|
+
this.preservePlaybackState = false;
|
|
107
113
|
}
|
|
108
114
|
|
|
109
115
|
/**
|
|
@@ -152,15 +158,19 @@ class WorkletSequencer
|
|
|
152
158
|
}
|
|
153
159
|
this.stop();
|
|
154
160
|
this.playingNotes = [];
|
|
161
|
+
const wasPaused = this.paused && this.preservePlaybackState;
|
|
155
162
|
this.pausedTime = undefined;
|
|
156
163
|
this.post(WorkletSequencerReturnMessageType.timeChange, currentTime - time);
|
|
157
|
-
|
|
164
|
+
this._playTo(time);
|
|
158
165
|
this._recalculateStartTime(time);
|
|
159
|
-
if (
|
|
166
|
+
if (wasPaused)
|
|
160
167
|
{
|
|
161
|
-
|
|
168
|
+
this.pause();
|
|
169
|
+
}
|
|
170
|
+
else
|
|
171
|
+
{
|
|
172
|
+
this.play();
|
|
162
173
|
}
|
|
163
|
-
this.play();
|
|
164
174
|
}
|
|
165
175
|
|
|
166
176
|
/**
|