spessasynth_core 4.0.20 → 4.0.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.
package/dist/index.js CHANGED
@@ -2873,7 +2873,7 @@ var BasicMIDI2 = class _BasicMIDI {
2873
2873
  /**
2874
2874
  * The loop points (in ticks) of the sequence, including both start and end points.
2875
2875
  */
2876
- loop = { start: 0, end: 0 };
2876
+ loop = { start: 0, end: 0, type: "hard" };
2877
2877
  /**
2878
2878
  * The file name of the MIDI sequence, if provided during parsing.
2879
2879
  */
@@ -3257,7 +3257,7 @@ var BasicMIDI2 = class _BasicMIDI {
3257
3257
  this.keyRange = { max: 0, min: 127 };
3258
3258
  this.lastVoiceEventTick = 0;
3259
3259
  this.portChannelOffsetMap = [0];
3260
- this.loop = { start: 0, end: 0 };
3260
+ this.loop = { start: 0, end: 0, type: "hard" };
3261
3261
  this.isKaraokeFile = false;
3262
3262
  this.isMultiPort = false;
3263
3263
  let nameDetected = false;
@@ -3266,6 +3266,7 @@ var BasicMIDI2 = class _BasicMIDI {
3266
3266
  }
3267
3267
  let loopStart = null;
3268
3268
  let loopEnd = null;
3269
+ let loopType = "hard";
3269
3270
  for (const track of this.tracks) {
3270
3271
  const usedChannels = /* @__PURE__ */ new Set();
3271
3272
  let trackHasVoiceMessages = false;
@@ -3293,6 +3294,7 @@ var BasicMIDI2 = class _BasicMIDI {
3293
3294
  // EMIDI/XMI
3294
3295
  case 117:
3295
3296
  if (loopEnd === null) {
3297
+ loopType = "soft";
3296
3298
  loopEnd = e.ticks;
3297
3299
  } else {
3298
3300
  loopEnd = 0;
@@ -3435,7 +3437,7 @@ var BasicMIDI2 = class _BasicMIDI {
3435
3437
  if (loopEnd === null || loopEnd === 0) {
3436
3438
  loopEnd = this.lastVoiceEventTick;
3437
3439
  }
3438
- this.loop = { start: loopStart, end: loopEnd };
3440
+ this.loop = { start: loopStart, end: loopEnd, type: loopType };
3439
3441
  SpessaSynthInfo(
3440
3442
  `%cLoop points: start: %c${this.loop.start}%c end: %c${this.loop.end}`,
3441
3443
  consoleColors.info,
@@ -3629,13 +3631,7 @@ var MIDIBuilder = class extends BasicMIDI2 {
3629
3631
  `Track ${track} does not exist. Add it via addTrack method.`
3630
3632
  );
3631
3633
  }
3632
- if (event < midiMessageTypes.noteOff) {
3633
- if (track > 0) {
3634
- throw new Error(
3635
- `Meta events must be added to the first track, not track ${track}.`
3636
- );
3637
- }
3638
- } else {
3634
+ if (event >= midiMessageTypes.noteOff) {
3639
3635
  if (this.format === 1 && track === 0) {
3640
3636
  throw new Error(
3641
3637
  "Can't add voice messages to the conductor track (0) in format 1. Consider using format 0 using a different track."
@@ -3904,7 +3900,11 @@ function processTick() {
3904
3900
  newCount: this.loopCount
3905
3901
  });
3906
3902
  }
3907
- this.setTimeTicks(this._midiData.loop.start);
3903
+ if (this._midiData.loop.type === "soft") {
3904
+ this.jumpToTick(this._midiData.loop.start);
3905
+ } else {
3906
+ this.setTimeTicks(this._midiData.loop.start);
3907
+ }
3908
3908
  return;
3909
3909
  }
3910
3910
  if (nextTrack.events.length <= this.eventIndexes[nextTrackIndex] || // https://github.com/spessasus/spessasynth_core/issues/21
@@ -4911,8 +4911,8 @@ var SpessaSynthSequencer = class {
4911
4911
  retriggerPausedNotes = true;
4912
4912
  /**
4913
4913
  * The loop count of the sequencer.
4914
- * If infinite, it will loop forever.
4915
- * If zero, the loop is disabled.
4914
+ * If set to Infinity, it will loop forever.
4915
+ * If set to zero, the loop is disabled.
4916
4916
  */
4917
4917
  loopCount = 0;
4918
4918
  /**
@@ -5300,6 +5300,29 @@ var SpessaSynthSequencer = class {
5300
5300
  recalculateStartTime(time) {
5301
5301
  this.absoluteStartTime = this.synth.currentSynthTime - time / this._playbackRate;
5302
5302
  }
5303
+ /**
5304
+ * Jumps to a MIDI tick without any further processing.
5305
+ * @param tick The MIDI tick to jump to.
5306
+ * @protected
5307
+ */
5308
+ jumpToTick(tick) {
5309
+ if (!this._midiData) {
5310
+ return;
5311
+ }
5312
+ const seconds = this._midiData.midiTicksToSeconds(tick);
5313
+ this.callEvent("timeChange", { newTime: seconds });
5314
+ this.recalculateStartTime(seconds);
5315
+ this.playedTime = seconds;
5316
+ this.eventIndexes.length = 0;
5317
+ for (const track of this._midiData.tracks) {
5318
+ this.eventIndexes.push(
5319
+ Math.max(
5320
+ 0,
5321
+ track.events.findIndex((e) => e.ticks >= tick)
5322
+ )
5323
+ );
5324
+ }
5325
+ }
5303
5326
  /*
5304
5327
  SEND MIDI METHOD ABSTRACTIONS
5305
5328
  These abstract the difference between spessasynth and external MIDI
@@ -10505,15 +10528,15 @@ function renderVoice(voice, timeNow, outputLeft, outputRight, reverbOutputLeft,
10505
10528
  volumeExcursionCentibels += -modLfoValue * modVolDepth;
10506
10529
  lowpassExcursion += modLfoValue * modFilterDepth;
10507
10530
  }
10508
- if (this.channelVibrato.depth > 0) {
10509
- const channelVibrato = getLFOValue(
10531
+ if (
10532
+ // Only enabled when modulation wheel is disabled (to prevent overlap)
10533
+ this.midiControllers[midiControllers.modulationWheel] == 0 && this.channelVibrato.depth > 0
10534
+ ) {
10535
+ cents += getLFOValue(
10510
10536
  voice.startTime + this.channelVibrato.delay,
10511
10537
  this.channelVibrato.rate,
10512
10538
  timeNow
10513
- );
10514
- if (channelVibrato) {
10515
- cents += channelVibrato * this.channelVibrato.depth;
10516
- }
10539
+ ) * this.channelVibrato.depth;
10517
10540
  }
10518
10541
  const modEnvPitchDepth = voice.modulatedGenerators[generatorTypes.modEnvToPitch];
10519
10542
  const modEnvFilterDepth = voice.modulatedGenerators[generatorTypes.modEnvToFilterFc];