spessasynth_core 4.0.16 → 4.0.18

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/dist/index.d.ts CHANGED
@@ -3822,6 +3822,11 @@ declare class SpessaSynthSequencer {
3822
3822
  * This is used by spessasynth_lib to pass them over to Web MIDI API.
3823
3823
  */
3824
3824
  externalMIDIPlayback: boolean;
3825
+ /**
3826
+ * If the notes that were playing when the sequencer was paused should be re-triggered.
3827
+ * Defaults to true.
3828
+ */
3829
+ retriggerPausedNotes: boolean;
3825
3830
  /**
3826
3831
  * The loop count of the sequencer.
3827
3832
  * If infinite, it will loop forever.
@@ -4001,18 +4006,10 @@ declare class SpessaSynthSequencer {
4001
4006
  */
4002
4007
  protected addNewMIDIPort(): void;
4003
4008
  protected sendMIDIMessage(message: number[]): void;
4009
+ protected sendMIDIAllOff(): void;
4004
4010
  protected sendMIDIReset(): void;
4005
4011
  protected loadCurrentSong(): void;
4006
4012
  protected shuffleSongIndexes(): void;
4007
- protected sendMIDICC(channel: number, type: number, value: number): void;
4008
- protected sendMIDIProgramChange(channel: number, program: number): void;
4009
- /**
4010
- * Sets the pitch of the given channel
4011
- * @param channel usually 0-15: the channel to change pitch
4012
- * @param MSB SECOND byte of the MIDI pitchWheel message
4013
- * @param LSB FIRST byte of the MIDI pitchWheel message
4014
- */
4015
- protected sendMIDIPitchWheel(channel: number, MSB: number, LSB: number): void;
4016
4013
  /**
4017
4014
  * Sets the time in MIDI ticks.
4018
4015
  * @param ticks the MIDI ticks to set the time to.
@@ -4023,6 +4020,16 @@ declare class SpessaSynthSequencer {
4023
4020
  * @param time the time in seconds to recalculate the start time for.
4024
4021
  */
4025
4022
  protected recalculateStartTime(time: number): void;
4023
+ protected sendMIDINoteOn(channel: number, midiNote: number, velocity: number): void;
4024
+ protected sendMIDINoteOff(channel: number, midiNote: number): void;
4025
+ protected sendMIDICC(channel: number, type: MIDIController, value: number): void;
4026
+ protected sendMIDIProgramChange(channel: number, program: number): void;
4027
+ /**
4028
+ * Sets the pitch of the given channel
4029
+ * @param channel usually 0-15: the channel to change pitch
4030
+ * @param pitch the 14-bit pitch value
4031
+ */
4032
+ protected sendMIDIPitchWheel(channel: number, pitch: number): void;
4026
4033
  }
4027
4034
 
4028
4035
  declare const DEFAULT_MASTER_PARAMETERS: MasterParameterType;
package/dist/index.js CHANGED
@@ -4734,12 +4734,7 @@ function setTimeToInternal(time, ticks = void 0) {
4734
4734
  return false;
4735
4735
  }
4736
4736
  this.oneTickToSeconds = 60 / (120 * this._midiData.timeDivision);
4737
- if (this.externalMIDIPlayback) {
4738
- this.sendMIDIReset();
4739
- } else {
4740
- this.synth.resetAllControllers();
4741
- this.synth.stopAllChannels(false);
4742
- }
4737
+ this.sendMIDIReset();
4743
4738
  this.playedTime = 0;
4744
4739
  this.eventIndexes = Array(this._midiData.tracks.length).fill(0);
4745
4740
  const channelsToSave = this.synth.midiChannels.length;
@@ -4823,15 +4818,7 @@ function setTimeToInternal(time, ticks = void 0) {
4823
4818
  } else if (controllerNumber === midiControllers.resetAllControllers) {
4824
4819
  resetAllControllers(channel);
4825
4820
  }
4826
- if (this.externalMIDIPlayback) {
4827
- this.sendMIDICC(channel, controllerNumber, ccV);
4828
- } else {
4829
- this.synth.controllerChange(
4830
- channel,
4831
- controllerNumber,
4832
- ccV
4833
- );
4834
- }
4821
+ this.sendMIDICC(channel, controllerNumber, ccV);
4835
4822
  } else {
4836
4823
  savedControllers[channel] ??= Array.from(
4837
4824
  defaultControllerArray
@@ -4859,70 +4846,28 @@ function setTimeToInternal(time, ticks = void 0) {
4859
4846
  }
4860
4847
  this.playedTime += this.oneTickToSeconds * (nextEvent.ticks - event.ticks);
4861
4848
  }
4862
- if (this.externalMIDIPlayback) {
4863
- for (let channelNumber = 0; channelNumber < channelsToSave; channelNumber++) {
4864
- if (pitchWheels[channelNumber] !== void 0) {
4865
- this.sendMIDIPitchWheel(
4866
- channelNumber,
4867
- pitchWheels[channelNumber] >> 7,
4868
- pitchWheels[channelNumber] & 127
4869
- );
4870
- }
4871
- if (savedControllers[channelNumber] !== void 0) {
4872
- savedControllers[channelNumber].forEach((value, index) => {
4873
- if (value !== defaultControllerArray[index] && !isCCNonSkippable(index)) {
4874
- this.sendMIDICC(channelNumber, index, value);
4875
- }
4876
- });
4877
- }
4878
- if (programs[channelNumber].program >= 0 && programs[channelNumber].actualBank >= 0) {
4879
- const bank = programs[channelNumber].actualBank;
4849
+ for (let channel = 0; channel < channelsToSave; channel++) {
4850
+ if (pitchWheels[channel] !== void 0) {
4851
+ this.sendMIDIPitchWheel(channel, pitchWheels[channel]);
4852
+ }
4853
+ if (savedControllers[channel] !== void 0) {
4854
+ savedControllers[channel].forEach((value, index) => {
4855
+ if (value !== defaultControllerArray[index] && !isCCNonSkippable(index)) {
4856
+ this.sendMIDICC(channel, index, value);
4857
+ }
4858
+ });
4859
+ }
4860
+ if (programs[channel].actualBank >= 0) {
4861
+ const p = programs[channel];
4862
+ if (p.program !== -1) {
4880
4863
  this.sendMIDICC(
4881
- channelNumber,
4864
+ channel,
4882
4865
  midiControllers.bankSelect,
4883
- bank
4866
+ p.actualBank
4884
4867
  );
4885
- this.sendMIDIProgramChange(
4886
- channelNumber,
4887
- programs[channelNumber].program
4888
- );
4889
- }
4890
- }
4891
- } else {
4892
- for (let channelNumber = 0; channelNumber < channelsToSave; channelNumber++) {
4893
- if (pitchWheels[channelNumber] !== void 0) {
4894
- this.synth.pitchWheel(
4895
- channelNumber,
4896
- pitchWheels[channelNumber]
4897
- );
4898
- }
4899
- if (savedControllers[channelNumber] !== void 0) {
4900
- savedControllers[channelNumber].forEach((value, index) => {
4901
- if (value !== defaultControllerArray[index] && !isCCNonSkippable(index)) {
4902
- this.synth.controllerChange(
4903
- channelNumber,
4904
- index,
4905
- value
4906
- );
4907
- }
4908
- });
4909
- }
4910
- if (programs[channelNumber].actualBank >= 0) {
4911
- const p = programs[channelNumber];
4912
- if (p.program !== -1) {
4913
- this.synth.controllerChange(
4914
- channelNumber,
4915
- midiControllers.bankSelect,
4916
- p.actualBank
4917
- );
4918
- this.synth.programChange(channelNumber, p.program);
4919
- } else {
4920
- this.synth.controllerChange(
4921
- channelNumber,
4922
- midiControllers.bankSelect,
4923
- p.bank
4924
- );
4925
- }
4868
+ this.sendMIDIProgramChange(channel, p.program);
4869
+ } else {
4870
+ this.sendMIDICC(channel, midiControllers.bankSelect, p.bank);
4926
4871
  }
4927
4872
  }
4928
4873
  }
@@ -4958,6 +4903,11 @@ var SpessaSynthSequencer = class {
4958
4903
  * This is used by spessasynth_lib to pass them over to Web MIDI API.
4959
4904
  */
4960
4905
  externalMIDIPlayback = false;
4906
+ /**
4907
+ * If the notes that were playing when the sequencer was paused should be re-triggered.
4908
+ * Defaults to true.
4909
+ */
4910
+ retriggerPausedNotes = false;
4961
4911
  /**
4962
4912
  * The loop count of the sequencer.
4963
4913
  * If infinite, it will loop forever.
@@ -4977,7 +4927,7 @@ var SpessaSynthSequencer = class {
4977
4927
  * Indicates if the synthesizer should preload the voices for the newly loaded sequence.
4978
4928
  * Recommended.
4979
4929
  */
4980
- preload = false;
4930
+ preload = true;
4981
4931
  /**
4982
4932
  * Called when the sequencer calls an event.
4983
4933
  * @param event The event
@@ -5189,9 +5139,9 @@ var SpessaSynthSequencer = class {
5189
5139
  if (this.paused) {
5190
5140
  this.recalculateStartTime(this.pausedTime ?? 0);
5191
5141
  }
5192
- if (!this.externalMIDIPlayback) {
5142
+ if (this.retriggerPausedNotes) {
5193
5143
  this.playingNotes.forEach((n) => {
5194
- this.synth.noteOn(n.channel, n.midiNote, n.velocity);
5144
+ this.sendMIDINoteOn(n.channel, n.midiNote, n.velocity);
5195
5145
  });
5196
5146
  }
5197
5147
  this.pausedTime = void 0;
@@ -5248,21 +5198,7 @@ var SpessaSynthSequencer = class {
5248
5198
  */
5249
5199
  stop() {
5250
5200
  this.pausedTime = this.currentTime;
5251
- for (let i = 0; i < 16; i++) {
5252
- this.synth.controllerChange(i, midiControllers.sustainPedal, 0);
5253
- }
5254
- this.synth.stopAllChannels();
5255
- if (this.externalMIDIPlayback) {
5256
- for (const note of this.playingNotes) {
5257
- this.sendMIDIMessage([
5258
- midiMessageTypes.noteOff | note.channel % 16,
5259
- note.midiNote
5260
- ]);
5261
- }
5262
- for (let c = 0; c < MIDI_CHANNEL_COUNT; c++) {
5263
- this.sendMIDICC(c, midiControllers.allNotesOff, 0);
5264
- }
5265
- }
5201
+ this.sendMIDIAllOff();
5266
5202
  }
5267
5203
  /**
5268
5204
  * @returns the index of the first to the current played time
@@ -5292,24 +5228,36 @@ var SpessaSynthSequencer = class {
5292
5228
  }
5293
5229
  sendMIDIMessage(message) {
5294
5230
  if (!this.externalMIDIPlayback) {
5231
+ SpessaSynthWarn(
5232
+ `Attempting to send ${arrayToHexString(message)} to the synthesizer via sendMIDIMessage. This shouldn't happen!`
5233
+ );
5295
5234
  return;
5296
5235
  }
5297
5236
  this.callEvent("midiMessage", { message });
5298
5237
  }
5238
+ sendMIDIAllOff() {
5239
+ for (let i = 0; i < 16; i++) {
5240
+ this.sendMIDICC(i, midiControllers.sustainPedal, 0);
5241
+ }
5242
+ if (!this.externalMIDIPlayback) {
5243
+ this.synth.stopAllChannels();
5244
+ return;
5245
+ }
5246
+ this.playingNotes.forEach((note) => {
5247
+ this.sendMIDINoteOff(note.channel, note.midiNote);
5248
+ });
5249
+ for (let c = 0; c < MIDI_CHANNEL_COUNT; c++) {
5250
+ this.sendMIDICC(c, midiControllers.allNotesOff, 0);
5251
+ this.sendMIDICC(c, midiControllers.allSoundOff, 0);
5252
+ }
5253
+ }
5299
5254
  sendMIDIReset() {
5300
- this.sendMIDIMessage([midiMessageTypes.reset]);
5301
- for (let ch = 0; ch < MIDI_CHANNEL_COUNT; ch++) {
5302
- this.sendMIDIMessage([
5303
- midiMessageTypes.controllerChange | ch,
5304
- midiControllers.allSoundOff,
5305
- 0
5306
- ]);
5307
- this.sendMIDIMessage([
5308
- midiMessageTypes.controllerChange | ch,
5309
- midiControllers.resetAllControllers,
5310
- 0
5311
- ]);
5255
+ this.sendMIDIAllOff();
5256
+ if (!this.externalMIDIPlayback) {
5257
+ this.synth.resetAllControllers();
5258
+ return;
5312
5259
  }
5260
+ this.sendMIDIMessage([midiMessageTypes.reset]);
5313
5261
  }
5314
5262
  loadCurrentSong() {
5315
5263
  let index = this._songIndex;
@@ -5327,11 +5275,65 @@ var SpessaSynthSequencer = class {
5327
5275
  indexes.splice(indexes.indexOf(index), 1);
5328
5276
  }
5329
5277
  }
5330
- sendMIDICC(channel, type, value) {
5278
+ /**
5279
+ * Sets the time in MIDI ticks.
5280
+ * @param ticks the MIDI ticks to set the time to.
5281
+ */
5282
+ setTimeTicks(ticks) {
5283
+ if (!this._midiData) {
5284
+ return;
5285
+ }
5286
+ this.playingNotes = [];
5287
+ const seconds = this._midiData.midiTicksToSeconds(ticks);
5288
+ this.callEvent("timeChange", { newTime: seconds });
5289
+ const isNotFinished = this.setTimeTo(0, ticks);
5290
+ this.recalculateStartTime(this.playedTime);
5291
+ if (!isNotFinished) {
5292
+ return;
5293
+ }
5294
+ }
5295
+ /**
5296
+ * Recalculates the absolute start time of the sequencer.
5297
+ * @param time the time in seconds to recalculate the start time for.
5298
+ */
5299
+ recalculateStartTime(time) {
5300
+ this.absoluteStartTime = this.synth.currentSynthTime - time / this._playbackRate;
5301
+ }
5302
+ /*
5303
+ SEND MIDI METHOD ABSTRACTIONS
5304
+ These abstract the difference between spessasynth and external MIDI
5305
+ */
5306
+ sendMIDINoteOn(channel, midiNote, velocity) {
5307
+ if (!this.externalMIDIPlayback) {
5308
+ this.synth.noteOn(channel, midiNote, velocity);
5309
+ return;
5310
+ }
5331
5311
  channel %= 16;
5312
+ this.sendMIDIMessage([
5313
+ midiMessageTypes.noteOn | channel,
5314
+ midiNote,
5315
+ velocity
5316
+ ]);
5317
+ }
5318
+ sendMIDINoteOff(channel, midiNote) {
5332
5319
  if (!this.externalMIDIPlayback) {
5320
+ this.synth.noteOff(channel, midiNote);
5333
5321
  return;
5334
5322
  }
5323
+ channel %= 16;
5324
+ this.sendMIDIMessage([
5325
+ midiMessageTypes.noteOff | channel,
5326
+ midiNote,
5327
+ 64
5328
+ // Make sure to send velocity as well
5329
+ ]);
5330
+ }
5331
+ sendMIDICC(channel, type, value) {
5332
+ if (!this.externalMIDIPlayback) {
5333
+ this.synth.controllerChange(channel, type, value);
5334
+ return;
5335
+ }
5336
+ channel %= 16;
5335
5337
  this.sendMIDIMessage([
5336
5338
  midiMessageTypes.controllerChange | channel,
5337
5339
  type,
@@ -5339,10 +5341,11 @@ var SpessaSynthSequencer = class {
5339
5341
  ]);
5340
5342
  }
5341
5343
  sendMIDIProgramChange(channel, program) {
5342
- channel %= 16;
5343
5344
  if (!this.externalMIDIPlayback) {
5345
+ this.synth.programChange(channel, program);
5344
5346
  return;
5345
5347
  }
5348
+ channel %= 16;
5346
5349
  this.sendMIDIMessage([
5347
5350
  midiMessageTypes.programChange | channel,
5348
5351
  program
@@ -5351,39 +5354,19 @@ var SpessaSynthSequencer = class {
5351
5354
  /**
5352
5355
  * Sets the pitch of the given channel
5353
5356
  * @param channel usually 0-15: the channel to change pitch
5354
- * @param MSB SECOND byte of the MIDI pitchWheel message
5355
- * @param LSB FIRST byte of the MIDI pitchWheel message
5357
+ * @param pitch the 14-bit pitch value
5356
5358
  */
5357
- sendMIDIPitchWheel(channel, MSB, LSB) {
5358
- channel %= 16;
5359
+ sendMIDIPitchWheel(channel, pitch) {
5359
5360
  if (!this.externalMIDIPlayback) {
5361
+ this.synth.pitchWheel(channel, pitch);
5360
5362
  return;
5361
5363
  }
5362
- this.sendMIDIMessage([midiMessageTypes.pitchWheel | channel, LSB, MSB]);
5363
- }
5364
- /**
5365
- * Sets the time in MIDI ticks.
5366
- * @param ticks the MIDI ticks to set the time to.
5367
- */
5368
- setTimeTicks(ticks) {
5369
- if (!this._midiData) {
5370
- return;
5371
- }
5372
- this.playingNotes = [];
5373
- const seconds = this._midiData.midiTicksToSeconds(ticks);
5374
- this.callEvent("timeChange", { newTime: seconds });
5375
- const isNotFinished = this.setTimeTo(0, ticks);
5376
- this.recalculateStartTime(this.playedTime);
5377
- if (!isNotFinished) {
5378
- return;
5379
- }
5380
- }
5381
- /**
5382
- * Recalculates the absolute start time of the sequencer.
5383
- * @param time the time in seconds to recalculate the start time for.
5384
- */
5385
- recalculateStartTime(time) {
5386
- this.absoluteStartTime = this.synth.currentSynthTime - time / this._playbackRate;
5364
+ channel %= 16;
5365
+ this.sendMIDIMessage([
5366
+ midiMessageTypes.pitchWheel | channel,
5367
+ pitch & 127,
5368
+ pitch >> 7
5369
+ ]);
5387
5370
  }
5388
5371
  };
5389
5372