spessasynth_lib 4.2.1 → 4.2.3

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  <img src='https://raw.githubusercontent.com/spessasus/SpessaSynth/refs/heads/master/src/website/spessasynth_logo_rounded.png' width='300' alt='SpessaSynth logo'>
4
4
  </p>
5
5
 
6
- _A powerful SF2/DLS/MIDI TypeScript/JavaScript library for the browsers, based on spessasynth_core.
6
+ _A powerful multipurpose SF2/DLS/MIDI TypeScript/JavaScript library for the browsers, based on spessasynth_core.
7
7
  This is a WebAudioAPI wrapper for the [spessasynth_core](https://github.com/spessasus/spessasynth_core) library._
8
8
 
9
9
  It allows you to:
@@ -91,9 +91,15 @@ document.getElementById("button").onclick = async () => {
91
91
  };
92
92
  ```
93
93
 
94
- # License
94
+ ## License
95
95
 
96
96
  Copyright © 2026 Spessasus
97
97
  Licensed under the Apache-2.0 License.
98
98
 
99
+ #### Legal
100
+
101
+ This project is in no way endorsed or otherwise affiliated with the MIDI Manufacturers Association,
102
+ Roland Corporation, Yamaha Corporation, Creative Technology Ltd. or E-mu Systems, Inc.,
103
+ or any other organization mentioned.
99
104
  SoundFont® is a registered trademark of Creative Technology Ltd.
105
+ All other trademarks are the property of their respective owners.
package/dist/index.d.ts CHANGED
@@ -436,7 +436,6 @@ interface BasicSynthesizerMessageData {
436
436
  midiMessage: {
437
437
  messageData: Uint8Array;
438
438
  channelOffset: number;
439
- force: boolean;
440
439
  options: SynthMethodOptions;
441
440
  };
442
441
  ccReset: null;
@@ -706,12 +705,27 @@ declare abstract class BasicSynthesizer {
706
705
  rate: number;
707
706
  }): void;
708
707
  /**
709
- * Connects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.
708
+ * Connects a given channel output to the given audio node.
709
+ * Note that this output is only meant for visualization and may be silent when Insertion Effect for this channel is enabled.
710
+ * @param targetNode The node to connect to.
711
+ * @param channelNumber The channel number to connect to, will be rolled over if value is greater than 15.
712
+ * @returns The target node.
713
+ */
714
+ connectChannel(targetNode: AudioNode, channelNumber: number): AudioNode;
715
+ /**
716
+ * Disconnects a given channel output to the given audio node.
717
+ * @param targetNode The node to disconnect from.
718
+ * @param channelNumber The channel number to connect to, will be rolled over if value is greater than 15.
719
+ */
720
+ disconnectChannel(targetNode: AudioNode, channelNumber: number): void;
721
+ /**
722
+ * Connects the individual audio outputs to the given audio nodes.
723
+ * Note that these outputs is only meant for visualization and may be silent when Insertion Effect for this channel is enabled.
710
724
  * @param audioNodes Exactly 16 outputs.
711
725
  */
712
726
  connectIndividualOutputs(audioNodes: AudioNode[]): void;
713
727
  /**
714
- * Disconnects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.
728
+ * Disconnects the individual audio outputs from the given audio nodes.
715
729
  * @param audioNodes Exactly 16 outputs.
716
730
  */
717
731
  disconnectIndividualOutputs(audioNodes: AudioNode[]): void;
@@ -739,10 +753,9 @@ declare abstract class BasicSynthesizer {
739
753
  * Stops playing a note.
740
754
  * @param channel Usually 0-15: the channel of the note.
741
755
  * @param midiNote {number} 0-127 the key number of the note.
742
- * @param force Instantly kills the note if true.
743
756
  * @param eventOptions Additional options for this command.
744
757
  */
745
- noteOff(channel: number, midiNote: number, force?: boolean, eventOptions?: SynthMethodOptions): void;
758
+ noteOff(channel: number, midiNote: number, eventOptions?: SynthMethodOptions): void;
746
759
  /**
747
760
  * Stops all notes.
748
761
  * @param force If the notes should immediately be stopped, defaults to false.
@@ -753,10 +766,9 @@ declare abstract class BasicSynthesizer {
753
766
  * @param channel Usually 0-15: the channel to change the controller.
754
767
  * @param controllerNumber 0-127 the MIDI CC number.
755
768
  * @param controllerValue 0-127 the controller value.
756
- * @param force Forces the controller-change message, even if it's locked or gm system is set and the cc is bank select.
757
769
  * @param eventOptions Additional options for this command.
758
770
  */
759
- controllerChange(channel: number, controllerNumber: MIDIController, controllerValue: number, force?: boolean, eventOptions?: SynthMethodOptions): void;
771
+ controllerChange(channel: number, controllerNumber: MIDIController, controllerValue: number, eventOptions?: SynthMethodOptions): void;
760
772
  /**
761
773
  * Resets all controllers (for every channel)
762
774
  */
@@ -796,15 +808,16 @@ declare abstract class BasicSynthesizer {
796
808
  * Sets the channel's pitch wheel range, in semitones.
797
809
  * @param channel Usually 0-15: the channel to change.
798
810
  * @param range The bend range in semitones.
811
+ * @param eventOptions Additional options for this command.
799
812
  */
800
- pitchWheelRange(channel: number, range: number): void;
813
+ pitchWheelRange(channel: number, range: number, eventOptions?: SynthMethodOptions): void;
801
814
  /**
802
815
  * Changes the program for a given channel
803
816
  * @param channel Usually 0-15: the channel to change.
804
817
  * @param programNumber 0-127 the MIDI patch number.
805
- * defaults to false
818
+ * @param eventOptions Additional options for this command.
806
819
  */
807
- programChange(channel: number, programNumber: number): void;
820
+ programChange(channel: number, programNumber: number, eventOptions?: SynthMethodOptions): void;
808
821
  /**
809
822
  * Transposes the channel by given number of semitones.
810
823
  * @param channel The channel number.
@@ -860,7 +873,7 @@ declare abstract class BasicSynthesizer {
860
873
  assignNewSequencer(callback: (m: SequencerReturnMessage) => unknown): number;
861
874
  protected assignProgressTracker<K extends keyof SynthesizerProgress>(type: K, progressFunction: (args: SynthesizerProgress[K]) => unknown): void;
862
875
  protected revokeProgressTracker<K extends keyof SynthesizerProgress>(type: K): void;
863
- protected _sendInternal(message: Iterable<number>, channelOffset: number, force: boolean | undefined, eventOptions: Partial<SynthMethodOptions>): void;
876
+ protected _sendInternal(message: Iterable<number>, channelOffset: number, eventOptions: Partial<SynthMethodOptions>): void;
864
877
  /**
865
878
  * Handles the messages received from the worklet.
866
879
  */
package/dist/index.js CHANGED
@@ -557,7 +557,27 @@ var BasicSynthesizer = class {
557
557
  void value;
558
558
  }
559
559
  /**
560
- * Connects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.
560
+ * Connects a given channel output to the given audio node.
561
+ * Note that this output is only meant for visualization and may be silent when Insertion Effect for this channel is enabled.
562
+ * @param targetNode The node to connect to.
563
+ * @param channelNumber The channel number to connect to, will be rolled over if value is greater than 15.
564
+ * @returns The target node.
565
+ */
566
+ connectChannel(targetNode, channelNumber) {
567
+ this.worklet.connect(targetNode, channelNumber % 16 + 1);
568
+ return targetNode;
569
+ }
570
+ /**
571
+ * Disconnects a given channel output to the given audio node.
572
+ * @param targetNode The node to disconnect from.
573
+ * @param channelNumber The channel number to connect to, will be rolled over if value is greater than 15.
574
+ */
575
+ disconnectChannel(targetNode, channelNumber) {
576
+ this.worklet.disconnect(targetNode, channelNumber % 16 + 1);
577
+ }
578
+ /**
579
+ * Connects the individual audio outputs to the given audio nodes.
580
+ * Note that these outputs is only meant for visualization and may be silent when Insertion Effect for this channel is enabled.
561
581
  * @param audioNodes Exactly 16 outputs.
562
582
  */
563
583
  connectIndividualOutputs(audioNodes) {
@@ -565,12 +585,12 @@ var BasicSynthesizer = class {
565
585
  throw new Error(`input nodes amount differs from the system's outputs amount!
566
586
  Expected ${this._outputsAmount} got ${audioNodes.length}`);
567
587
  }
568
- for (let outputNumber = 0; outputNumber < this._outputsAmount; outputNumber++) {
569
- this.worklet.connect(audioNodes[outputNumber], outputNumber + 1);
588
+ for (let channel = 0; channel < this._outputsAmount; channel++) {
589
+ this.connectChannel(audioNodes[channel], channel);
570
590
  }
571
591
  }
572
592
  /**
573
- * Disconnects the individual audio outputs to the given audio nodes. In the app, it's used by the renderer.
593
+ * Disconnects the individual audio outputs from the given audio nodes.
574
594
  * @param audioNodes Exactly 16 outputs.
575
595
  */
576
596
  disconnectIndividualOutputs(audioNodes) {
@@ -578,8 +598,8 @@ var BasicSynthesizer = class {
578
598
  throw new Error(`input nodes amount differs from the system's outputs amount!
579
599
  Expected ${this._outputsAmount} got ${audioNodes.length}`);
580
600
  }
581
- for (let outputNumber = 0; outputNumber < this._outputsAmount; outputNumber++) {
582
- this.worklet.disconnect(audioNodes[outputNumber], outputNumber + 2);
601
+ for (let channel = 0; channel < this._outputsAmount; channel++) {
602
+ this.disconnectChannel(audioNodes[channel], channel);
583
603
  }
584
604
  }
585
605
  // noinspection JSUnusedGlobalSymbols
@@ -597,7 +617,7 @@ var BasicSynthesizer = class {
597
617
  * @param eventOptions additional options for this command.
598
618
  */
599
619
  sendMessage(message, channelOffset = 0, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
600
- this._sendInternal(message, channelOffset, false, eventOptions);
620
+ this._sendInternal(message, channelOffset, eventOptions);
601
621
  }
602
622
  /**
603
623
  * Starts playing a note
@@ -621,17 +641,15 @@ var BasicSynthesizer = class {
621
641
  * Stops playing a note.
622
642
  * @param channel Usually 0-15: the channel of the note.
623
643
  * @param midiNote {number} 0-127 the key number of the note.
624
- * @param force Instantly kills the note if true.
625
644
  * @param eventOptions Additional options for this command.
626
645
  */
627
- noteOff(channel, midiNote, force = false, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
646
+ noteOff(channel, midiNote, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
628
647
  midiNote %= 128;
629
648
  const ch = channel % 16;
630
649
  const offset = channel - ch;
631
650
  this._sendInternal(
632
651
  [midiMessageTypes.noteOff | ch, midiNote],
633
652
  offset,
634
- force,
635
653
  eventOptions
636
654
  );
637
655
  }
@@ -651,10 +669,9 @@ var BasicSynthesizer = class {
651
669
  * @param channel Usually 0-15: the channel to change the controller.
652
670
  * @param controllerNumber 0-127 the MIDI CC number.
653
671
  * @param controllerValue 0-127 the controller value.
654
- * @param force Forces the controller-change message, even if it's locked or gm system is set and the cc is bank select.
655
672
  * @param eventOptions Additional options for this command.
656
673
  */
657
- controllerChange(channel, controllerNumber, controllerValue, force = false, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
674
+ controllerChange(channel, controllerNumber, controllerValue, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
658
675
  if (controllerNumber > 127 || controllerNumber < 0) {
659
676
  throw new Error(`Invalid controller number: ${controllerNumber}`);
660
677
  }
@@ -669,7 +686,6 @@ var BasicSynthesizer = class {
669
686
  controllerValue
670
687
  ],
671
688
  offset,
672
- force,
673
689
  eventOptions
674
690
  );
675
691
  }
@@ -756,44 +772,55 @@ var BasicSynthesizer = class {
756
772
  * Sets the channel's pitch wheel range, in semitones.
757
773
  * @param channel Usually 0-15: the channel to change.
758
774
  * @param range The bend range in semitones.
775
+ * @param eventOptions Additional options for this command.
759
776
  */
760
- pitchWheelRange(channel, range) {
777
+ pitchWheelRange(channel, range, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
761
778
  this.controllerChange(
762
779
  channel,
763
780
  midiControllers.registeredParameterMSB,
764
- 0
781
+ 0,
782
+ eventOptions
765
783
  );
766
784
  this.controllerChange(
767
785
  channel,
768
786
  midiControllers.registeredParameterLSB,
769
- 0
787
+ 0,
788
+ eventOptions
770
789
  );
771
790
  this.controllerChange(channel, midiControllers.dataEntryMSB, range);
772
791
  this.controllerChange(
773
792
  channel,
774
793
  midiControllers.registeredParameterMSB,
775
- 127
794
+ 127,
795
+ eventOptions
776
796
  );
777
797
  this.controllerChange(
778
798
  channel,
779
799
  midiControllers.registeredParameterLSB,
780
- 127
800
+ 127,
801
+ eventOptions
802
+ );
803
+ this.controllerChange(
804
+ channel,
805
+ midiControllers.dataEntryMSB,
806
+ 0,
807
+ eventOptions
781
808
  );
782
- this.controllerChange(channel, midiControllers.dataEntryMSB, 0);
783
809
  }
784
810
  /**
785
811
  * Changes the program for a given channel
786
812
  * @param channel Usually 0-15: the channel to change.
787
813
  * @param programNumber 0-127 the MIDI patch number.
788
- * defaults to false
814
+ * @param eventOptions Additional options for this command.
789
815
  */
790
- programChange(channel, programNumber) {
816
+ programChange(channel, programNumber, eventOptions = DEFAULT_SYNTH_METHOD_OPTIONS) {
791
817
  const ch = channel % 16;
792
818
  const offset = channel - ch;
793
819
  programNumber %= 128;
794
820
  this.sendMessage(
795
821
  [midiMessageTypes.programChange | ch, programNumber],
796
- offset
822
+ offset,
823
+ eventOptions
797
824
  );
798
825
  }
799
826
  // noinspection JSUnusedGlobalSymbols
@@ -836,7 +863,6 @@ var BasicSynthesizer = class {
836
863
  this._sendInternal(
837
864
  [midiMessageTypes.systemExclusive, ...Array.from(messageData)],
838
865
  channelOffset,
839
- false,
840
866
  eventOptions
841
867
  );
842
868
  }
@@ -943,7 +969,7 @@ var BasicSynthesizer = class {
943
969
  revokeProgressTracker(type) {
944
970
  this.renderingProgressTracker.delete(type);
945
971
  }
946
- _sendInternal(message, channelOffset, force = false, eventOptions) {
972
+ _sendInternal(message, channelOffset, eventOptions) {
947
973
  const options = fillWithDefaults(
948
974
  eventOptions,
949
975
  DEFAULT_SYNTH_METHOD_OPTIONS
@@ -954,10 +980,8 @@ var BasicSynthesizer = class {
954
980
  data: {
955
981
  messageData: new Uint8Array(message),
956
982
  channelOffset,
957
- force,
958
983
  options
959
984
  }
960
- //[new Uint8Array(message), offset, force, opts]
961
985
  });
962
986
  }
963
987
  /**
@@ -1223,8 +1247,6 @@ function renderAudioWorker(sampleRate, options) {
1223
1247
  const rendererSynth = new SpessaSynthProcessor(sampleRate, {
1224
1248
  enableEventSystem: false
1225
1249
  });
1226
- const rendererSeq = new SpessaSynthSequencer(rendererSynth);
1227
- rendererSynth.setMasterParameter("autoAllocateVoices", true);
1228
1250
  for (const entry of this.synthesizer.soundBankManager.soundBankList)
1229
1251
  rendererSynth.soundBankManager.addSoundBank(
1230
1252
  entry.soundBank,
@@ -1244,12 +1266,14 @@ function renderAudioWorker(sampleRate, options) {
1244
1266
  const loopDuration = loopEndAbsolute - loopStartAbsolute;
1245
1267
  const duration = parsedMid.duration / playbackRate + options.extraTime + loopDuration * options.loopCount;
1246
1268
  const sampleDuration = sampleRate * duration;
1269
+ const rendererSeq = new SpessaSynthSequencer(rendererSynth);
1247
1270
  rendererSeq.loopCount = options.loopCount;
1248
1271
  if (options.preserveSynthParams) {
1249
1272
  rendererSeq.playbackRate = seq.playbackRate;
1250
1273
  const snapshot = this.synthesizer.getSnapshot();
1251
1274
  rendererSynth.applySynthesizerSnapshot(snapshot);
1252
1275
  }
1276
+ rendererSynth.setMasterParameter("autoAllocateVoices", true);
1253
1277
  rendererSeq.loadNewSongList([parsedMid]);
1254
1278
  rendererSeq.play();
1255
1279
  const wetL = new Float32Array(sampleDuration);
@@ -1744,7 +1768,6 @@ var BasicSynthesizerCore = class {
1744
1768
  this.synthesizer.processMessage(
1745
1769
  m.data.messageData,
1746
1770
  m.data.channelOffset,
1747
- m.data.force,
1748
1771
  m.data.options
1749
1772
  );
1750
1773
  break;