spessasynth_core 4.0.10 → 4.0.12

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
@@ -3084,7 +3084,7 @@ declare class BasicMIDI {
3084
3084
  */
3085
3085
  tracks: MIDITrack[];
3086
3086
  /**
3087
- * The time division of the sequence, representing the number of ticks per beat.
3087
+ * The time division of the sequence, representing the number of MIDI ticks per beat.
3088
3088
  */
3089
3089
  timeDivision: number;
3090
3090
  /**
@@ -3093,7 +3093,7 @@ declare class BasicMIDI {
3093
3093
  duration: number;
3094
3094
  /**
3095
3095
  * The tempo changes in the sequence, ordered from the last change to the first.
3096
- * Each change is represented by an object with a tick position and a tempo value in beats per minute.
3096
+ * Each change is represented by an object with a MIDI tick position and a tempo value in beats per minute.
3097
3097
  */
3098
3098
  tempoChanges: TempoChange[];
3099
3099
  /**
@@ -3462,7 +3462,7 @@ interface RMIDInfoData {
3462
3462
  }
3463
3463
  interface TempoChange {
3464
3464
  /**
3465
- * MIDI ticks of the change.
3465
+ * MIDI ticks of the change, absolute value from the start of the MIDI file.
3466
3466
  */
3467
3467
  ticks: number;
3468
3468
  /**
package/dist/index.js CHANGED
@@ -2721,13 +2721,6 @@ function loadMIDIFromArrayBufferInternal(outputMIDI, arrayBuffer, fileName) {
2721
2721
  SpessaSynthInfo(`%cAll tracks parsed correctly!`, consoleColors.recognized);
2722
2722
  outputMIDI.flush(false);
2723
2723
  SpessaSynthGroupEnd();
2724
- SpessaSynthInfo(
2725
- `%cMIDI file parsed. Total tick time: %c${outputMIDI.lastVoiceEventTick}%c, total seconds time: %c${outputMIDI.duration}`,
2726
- consoleColors.info,
2727
- consoleColors.recognized,
2728
- consoleColors.info,
2729
- consoleColors.recognized
2730
- );
2731
2724
  }
2732
2725
 
2733
2726
  // src/utils/load_date.ts
@@ -2839,7 +2832,7 @@ var BasicMIDI2 = class _BasicMIDI {
2839
2832
  */
2840
2833
  tracks = [];
2841
2834
  /**
2842
- * The time division of the sequence, representing the number of ticks per beat.
2835
+ * The time division of the sequence, representing the number of MIDI ticks per beat.
2843
2836
  */
2844
2837
  timeDivision = 0;
2845
2838
  /**
@@ -2848,7 +2841,7 @@ var BasicMIDI2 = class _BasicMIDI {
2848
2841
  duration = 0;
2849
2842
  /**
2850
2843
  * The tempo changes in the sequence, ordered from the last change to the first.
2851
- * Each change is represented by an object with a tick position and a tempo value in beats per minute.
2844
+ * Each change is represented by an object with a MIDI tick position and a tempo value in beats per minute.
2852
2845
  */
2853
2846
  tempoChanges = [{ ticks: 0, tempo: 120 }];
2854
2847
  /**
@@ -2985,15 +2978,24 @@ var BasicMIDI2 = class _BasicMIDI {
2985
2978
  * @returns The time in seconds.
2986
2979
  */
2987
2980
  midiTicksToSeconds(ticks) {
2981
+ ticks = Math.max(ticks, 0);
2982
+ if (this.tempoChanges.length < 1) {
2983
+ throw new Error(
2984
+ "There are no tempo changes in the sequence. At least one is needed."
2985
+ );
2986
+ }
2987
+ if (this.tempoChanges[this.tempoChanges.length - 1].ticks !== 0) {
2988
+ throw new Error(
2989
+ `The last tempo change is not at 0 ticks. Got ${this.tempoChanges[this.tempoChanges.length - 1].ticks} ticks.`
2990
+ );
2991
+ }
2992
+ let tempoIndex = this.tempoChanges.findIndex((v) => v.ticks <= ticks);
2988
2993
  let totalSeconds = 0;
2989
- while (ticks > 0) {
2990
- const tempo = this.tempoChanges.find((v) => v.ticks < ticks);
2991
- if (!tempo) {
2992
- return totalSeconds;
2993
- }
2994
- const timeSinceLastTempo = ticks - tempo.ticks;
2995
- totalSeconds += timeSinceLastTempo * 60 / (tempo.tempo * this.timeDivision);
2996
- ticks -= timeSinceLastTempo;
2994
+ while (tempoIndex < this.tempoChanges.length) {
2995
+ const tempo = this.tempoChanges[tempoIndex++];
2996
+ const ticksSinceLastTempo = ticks - tempo.ticks;
2997
+ totalSeconds += ticksSinceLastTempo * 60 / (tempo.tempo * this.timeDivision);
2998
+ ticks = tempo.ticks;
2997
2999
  }
2998
3000
  return totalSeconds;
2999
3001
  }
@@ -3263,9 +3265,6 @@ var BasicMIDI2 = class _BasicMIDI {
3263
3265
  const e = track.events[i];
3264
3266
  if (e.statusByte >= 128 && e.statusByte < 240) {
3265
3267
  trackHasVoiceMessages = true;
3266
- for (let j = 0; j < e.data.length; j++) {
3267
- e.data[j] = Math.min(127, e.data[j]);
3268
- }
3269
3268
  if (e.ticks > this.lastVoiceEventTick) {
3270
3269
  this.lastVoiceEventTick = e.ticks;
3271
3270
  }
@@ -3525,10 +3524,19 @@ var BasicMIDI2 = class _BasicMIDI {
3525
3524
  );
3526
3525
  }
3527
3526
  this.duration = this.midiTicksToSeconds(this.lastVoiceEventTick);
3527
+ if (this.duration === 0) {
3528
+ throw new Error("The MIDI file no duration.");
3529
+ }
3528
3530
  if (this.binaryName && this.binaryName.length < 1) {
3529
3531
  this.binaryName = void 0;
3530
3532
  }
3531
- SpessaSynthInfo("%cSuccess!", consoleColors.recognized);
3533
+ SpessaSynthInfo(
3534
+ `%cMIDI file parsed. Total tick time: %c${this.lastVoiceEventTick}%c, total seconds time: %c${formatTime(Math.ceil(this.duration)).time}`,
3535
+ consoleColors.info,
3536
+ consoleColors.recognized,
3537
+ consoleColors.info,
3538
+ consoleColors.recognized
3539
+ );
3532
3540
  SpessaSynthGroupEnd();
3533
3541
  }
3534
3542
  };
@@ -4727,6 +4735,8 @@ function setTimeToInternal(time, ticks = void 0) {
4727
4735
  Array.from(defaultControllerArray)
4728
4736
  );
4729
4737
  }
4738
+ let savedTempo = void 0;
4739
+ let savedTempoTrack = 0;
4730
4740
  function resetAllControllers(chan) {
4731
4741
  pitchWheels[chan] = 8192;
4732
4742
  if (savedControllers?.[chan] === void 0) {
@@ -4806,6 +4816,12 @@ function setTimeToInternal(time, ticks = void 0) {
4806
4816
  }
4807
4817
  break;
4808
4818
  }
4819
+ case midiMessageTypes.setTempo:
4820
+ const tempoBPM = 6e7 / readBigEndian(event.data, 3);
4821
+ this.oneTickToSeconds = 60 / (tempoBPM * this._midiData.timeDivision);
4822
+ savedTempo = event;
4823
+ savedTempoTrack = trackIndex;
4824
+ break;
4809
4825
  default:
4810
4826
  this.processEvent(event, trackIndex);
4811
4827
  break;
@@ -4886,6 +4902,12 @@ function setTimeToInternal(time, ticks = void 0) {
4886
4902
  }
4887
4903
  }
4888
4904
  }
4905
+ if (savedTempo) {
4906
+ this.callEvent("metaEvent", {
4907
+ event: savedTempo,
4908
+ trackIndex: savedTempoTrack
4909
+ });
4910
+ }
4889
4911
  if (this.paused) {
4890
4912
  this.pausedTime = this.playedTime;
4891
4913
  }
@@ -7984,11 +8006,15 @@ function selectPreset(presets, patch, system) {
7984
8006
  returnReplacement(p);
7985
8007
  return p;
7986
8008
  }
7987
- const bank = Math.max(bankMSB, bankLSB);
7988
- p = matchingPrograms.find((p2) => p2.bankLSB === bank || p2.bankMSB === bank);
7989
- if (p) {
7990
- returnReplacement(p);
7991
- return p;
8009
+ if (bankLSB !== 64 || !isXG) {
8010
+ const bank = Math.max(bankMSB, bankLSB);
8011
+ p = matchingPrograms.find(
8012
+ (p2) => p2.bankLSB === bank || p2.bankMSB === bank
8013
+ );
8014
+ if (p) {
8015
+ returnReplacement(p);
8016
+ return p;
8017
+ }
7992
8018
  }
7993
8019
  returnReplacement(matchingPrograms[0]);
7994
8020
  return matchingPrograms[0];
@@ -8795,6 +8821,12 @@ var Voice = class _Voice {
8795
8821
  }
8796
8822
  };
8797
8823
  function getVoicesForPresetInternal(preset, midiNote, velocity, realKey) {
8824
+ const cached = this.getCachedVoice(preset, midiNote, velocity);
8825
+ if (cached !== void 0) {
8826
+ return cached.map(
8827
+ (v) => Voice.copyFrom(v, this.currentSynthTime, realKey)
8828
+ );
8829
+ }
8798
8830
  const voices = preset.getSynthesisData(midiNote, velocity).reduce((voices2, synthesisData) => {
8799
8831
  if (synthesisData.sample.getAudioData() === void 0) {
8800
8832
  SpessaSynthWarn(
@@ -8836,15 +8868,16 @@ function getVoicesForPresetInternal(preset, midiNote, velocity, realKey) {
8836
8868
  Math.floor(sampleData.length) - 1,
8837
8869
  loopingMode
8838
8870
  );
8871
+ let voiceVelocity = velocity;
8839
8872
  if (generators[generatorTypes.velocity] > -1) {
8840
- velocity = generators[generatorTypes.velocity];
8873
+ voiceVelocity = generators[generatorTypes.velocity];
8841
8874
  }
8842
8875
  voices2.push(
8843
8876
  new Voice(
8844
8877
  this.sampleRate,
8845
8878
  audioSample,
8846
8879
  midiNote,
8847
- velocity,
8880
+ voiceVelocity,
8848
8881
  this.currentSynthTime,
8849
8882
  targetKey,
8850
8883
  realKey,
@@ -8870,19 +8903,8 @@ function getVoicesInternal(channel, midiNote, velocity, realKey) {
8870
8903
  SpessaSynthWarn(`No preset for channel ${channel}!`);
8871
8904
  return [];
8872
8905
  }
8873
- let patch = {
8874
- ...preset
8875
- };
8876
- if (overridePatch) {
8877
- patch = this.keyModifierManager.getPatch(channel, midiNote);
8878
- }
8879
- const cached = this.getCachedVoice(patch, midiNote, velocity);
8880
- if (cached !== void 0) {
8881
- return cached.map(
8882
- (v) => Voice.copyFrom(v, this.currentSynthTime, realKey)
8883
- );
8884
- }
8885
8906
  if (overridePatch) {
8907
+ const patch = this.keyModifierManager.getPatch(channel, midiNote);
8886
8908
  preset = this.soundBankManager.getPreset(
8887
8909
  patch,
8888
8910
  this.privateProps.masterParameters.midiSystem
@@ -11121,7 +11143,7 @@ function getLookup(value) {
11121
11143
  return 0;
11122
11144
  }
11123
11145
  function portamentoTimeToSeconds(time, distance) {
11124
- return getLookup(time) * (distance / 30);
11146
+ return getLookup(time) * (distance / 36);
11125
11147
  }
11126
11148
 
11127
11149
  // src/synthesizer/audio_engine/engine_methods/note_on.ts