spessasynth_lib 3.9.21 → 3.9.22

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.
@@ -0,0 +1,3 @@
1
+ export namespace libvorbis {
2
+ function init(...args: any[]): void;
3
+ }
@@ -1,22 +1,11 @@
1
- /**
2
- * sequencer.js
3
- * purpose: plays back the midi file decoded by midi_loader.js, including support for multi-channel midis (adding channels when more than 1 midi port is detected)
4
- */
5
- /**
6
- * @typedef MidFile {Object}
7
- * @property {ArrayBuffer} binary - the binary data of the file.
8
- * @property {string|undefined} altName - the alternative name for the file
9
- */
10
- /**
11
- * @typedef {MIDI|MidFile} MIDIFile
12
- */
13
1
  export class Sequencer {
14
2
  /**
15
3
  * Creates a new Midi sequencer for playing back MIDI files
16
4
  * @param midiBinaries {MIDIFile[]} List of the buffers of the MIDI files
17
5
  * @param synth {Synthetizer} synth to send events to
6
+ * @param options {SequencerOptions} the sequencer's options
18
7
  */
19
- constructor(midiBinaries: MIDIFile[], synth: Synthetizer);
8
+ constructor(midiBinaries: MIDIFile[], synth: Synthetizer, options?: SequencerOptions);
20
9
  ignoreEvents: boolean;
21
10
  synth: Synthetizer;
22
11
  highResTimeOffset: number;
@@ -47,6 +36,21 @@ export class Sequencer {
47
36
  * @type {number}
48
37
  */
49
38
  duration: number;
39
+ /**
40
+ * @type {boolean}
41
+ * @private
42
+ */
43
+ private _skipToFirstNoteOn;
44
+ /**
45
+ * Indicates if the sequencer should skip to first note on
46
+ * @param val {boolean}
47
+ */
48
+ set skipToFirstNoteOn(val: boolean);
49
+ /**
50
+ * Indicates if the sequencer should skip to first note on
51
+ * @return {boolean}
52
+ */
53
+ get skipToFirstNoteOn(): boolean;
50
54
  resetMIDIOut(): void;
51
55
  set loop(value: boolean);
52
56
  get loop(): boolean;
@@ -186,6 +190,12 @@ export type MidFile = {
186
190
  altName: string | undefined;
187
191
  };
188
192
  export type MIDIFile = MIDI | MidFile;
193
+ export type SequencerOptions = {
194
+ /**
195
+ * - if true, the sequencer will skip to the first note
196
+ */
197
+ skipToFirstNoteOn: boolean;
198
+ };
189
199
  import { Synthetizer } from '../synthetizer/synthetizer.js';
190
200
  import { MidiData } from '../midi_parser/midi_data.js';
191
201
  import { MIDI } from '../midi_parser/midi_loader.js';
@@ -13,6 +13,7 @@ export namespace WorkletSequencerMessageType {
13
13
  let setLoop: number;
14
14
  let changeSong: number;
15
15
  let getMIDI: number;
16
+ let setSkipToFirstNote: number;
16
17
  }
17
18
  export type WorkletSequencerReturnMessageType = number;
18
19
  export namespace WorkletSequencerReturnMessageType {
package/index.js CHANGED
@@ -26,6 +26,7 @@ import { NON_CC_INDEX_OFFSET } from './synthetizer/worklet_system/worklet_utilit
26
26
  import { modulatorSources } from './soundfont/read/modulators.js';
27
27
  import { ALL_CHANNELS_OR_DIFFERENT_ACTION } from './synthetizer/worklet_system/message_protocol/worklet_message.js';
28
28
  import { trimSoundfont } from './soundfont/write/soundfont_trimmer.js';
29
+ import { OggVorbisEncoder } from './externals/libvorbis/OggVorbisEncoder.min.js';
29
30
  import { WORKLET_URL_ABSOLUTE } from './synthetizer/worklet_url.js'
30
31
 
31
32
  // Export modules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.9.21",
3
+ "version": "3.9.22",
4
4
  "description": "No compromise MIDI and SoundFont2 Synthesizer library",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",
@@ -24,14 +24,26 @@ import { DUMMY_MIDI_DATA, MidiData } from '../midi_parser/midi_data.js'
24
24
  * @typedef {MIDI|MidFile} MIDIFile
25
25
  */
26
26
 
27
+ /**
28
+ * @typedef {Object} SequencerOptions
29
+ * @property {boolean} skipToFirstNoteOn - if true, the sequencer will skip to the first note
30
+ */
31
+
32
+ /**
33
+ * @type {SequencerOptions}
34
+ */
35
+ const DEFAULT_OPTIONS = {
36
+ skipToFirstNoteOn: true,
37
+ }
27
38
  export class Sequencer
28
39
  {
29
40
  /**
30
41
  * Creates a new Midi sequencer for playing back MIDI files
31
42
  * @param midiBinaries {MIDIFile[]} List of the buffers of the MIDI files
32
43
  * @param synth {Synthetizer} synth to send events to
44
+ * @param options {SequencerOptions} the sequencer's options
33
45
  */
34
- constructor(midiBinaries, synth)
46
+ constructor(midiBinaries, synth, options = DEFAULT_OPTIONS)
35
47
  {
36
48
  this.ignoreEvents = false;
37
49
  this.synth = synth;
@@ -73,11 +85,42 @@ export class Sequencer
73
85
 
74
86
  this.synth.sequencerCallbackFunction = this._handleMessage.bind(this);
75
87
 
88
+ /**
89
+ * @type {boolean}
90
+ * @private
91
+ */
92
+ this._skipToFirstNoteOn = options?.skipToFirstNoteOn ?? true;
93
+
94
+ if(this._skipToFirstNoteOn === false)
95
+ {
96
+ // setter sends message
97
+ this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, false);
98
+ }
99
+
76
100
  this.loadNewSongList(midiBinaries);
77
101
 
78
102
  window.addEventListener("beforeunload", this.resetMIDIOut.bind(this))
79
103
  }
80
104
 
105
+ /**
106
+ * Indicates if the sequencer should skip to first note on
107
+ * @return {boolean}
108
+ */
109
+ get skipToFirstNoteOn()
110
+ {
111
+ return this._skipToFirstNoteOn;
112
+ }
113
+
114
+ /**
115
+ * Indicates if the sequencer should skip to first note on
116
+ * @param val {boolean}
117
+ */
118
+ set skipToFirstNoteOn(val)
119
+ {
120
+ this._skipToFirstNoteOn = val;
121
+ this._sendMessage(WorkletSequencerMessageType.setSkipToFirstNote, this._skipToFirstNoteOn);
122
+ }
123
+
81
124
  resetMIDIOut()
82
125
  {
83
126
  if(!this.MIDIout)
@@ -58,6 +58,11 @@ export function processMessage(messageType, messageData)
58
58
 
59
59
  case WorkletSequencerMessageType.getMIDI:
60
60
  this.post(WorkletSequencerReturnMessageType.getMIDI, this.midiData);
61
+ break;
62
+
63
+ case WorkletSequencerMessageType.setSkipToFirstNote:
64
+ this._skipToFirstNoteOn = messageData;
65
+ break;
61
66
  }
62
67
  }
63
68
 
@@ -10,6 +10,7 @@
10
10
  * @property {number} setLoop - 7 -> loop<boolean>
11
11
  * @property {number} changeSong - 8 -> goForwards<boolean> if true, next song, if false, previous
12
12
  * @property {number} getMIDI - 9 -> (no data)
13
+ * @property {number} setSkipToFirstNote -10 -> skipToFirstNoteOn<boolean>
13
14
  */
14
15
  export const WorkletSequencerMessageType = {
15
16
  loadNewSongList: 0,
@@ -21,7 +22,8 @@ export const WorkletSequencerMessageType = {
21
22
  setPlaybackRate: 6,
22
23
  setLoop: 7,
23
24
  changeSong: 8,
24
- getMIDI: 9
25
+ getMIDI: 9,
26
+ setSkipToFirstNote: 10
25
27
  }
26
28
 
27
29
  /**
@@ -148,7 +148,6 @@ export function loadNewSongList(midiBuffers)
148
148
  }, []);
149
149
  if(this.songs.length < 1)
150
150
  {
151
- console.log("no valid songs!")
152
151
  return;
153
152
  }
154
153
  this.songIndex = 0;
@@ -88,6 +88,12 @@ class WorkletSequencer
88
88
  * @type {Object<number, number>}
89
89
  */
90
90
  this.midiPortChannelOffsets = {};
91
+
92
+ /**
93
+ * @type {boolean}
94
+ * @private
95
+ */
96
+ this._skipToFirstNoteOn = true;
91
97
  }
92
98
 
93
99
  /**
@@ -113,12 +119,27 @@ class WorkletSequencer
113
119
 
114
120
  set currentTime(time)
115
121
  {
116
- if(time < this.firstNoteTime || time > this.duration)
122
+ if(time > this.duration || time < 0)
117
123
  {
118
124
  // time is 0
119
- this.setTimeTicks(this.midiData.firstNoteOn - 1);
125
+ if(this._skipToFirstNoteOn)
126
+ {
127
+ this.setTimeTicks(this.midiData.firstNoteOn - 1);
128
+ }
129
+ else
130
+ {
131
+ this.setTimeTicks(0);
132
+ }
120
133
  return;
121
134
  }
135
+ if(this._skipToFirstNoteOn)
136
+ {
137
+ if(time < this.firstNoteTime)
138
+ {
139
+ this.setTimeTicks(this.midiData.firstNoteOn - 1);
140
+ return;
141
+ }
142
+ }
122
143
  this.stop();
123
144
  this.playingNotes = [];
124
145
  this.pausedTime = undefined;