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.
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.21.9",
3
+ "version": "3.21.11",
4
4
  "description": "MIDI and SoundFont2/DLS library with no compromises",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",
@@ -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 ?? true;
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.loadNewSongList(midiBinaries, options?.autoPlay ?? false);
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.unpause();
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
- const isNotFinished = this._playTo(time);
164
+ this._playTo(time);
158
165
  this._recalculateStartTime(time);
159
- if (!isNotFinished)
166
+ if (wasPaused)
160
167
  {
161
- return;
168
+ this.pause();
169
+ }
170
+ else
171
+ {
172
+ this.play();
162
173
  }
163
- this.play();
164
174
  }
165
175
 
166
176
  /**