spessasynth_lib 3.23.11 → 3.23.13

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.
Files changed (35) hide show
  1. package/@types/index.d.ts +8 -1
  2. package/@types/midi_parser/basic_midi.d.ts +7 -116
  3. package/@types/midi_parser/midi_builder.d.ts +3 -0
  4. package/@types/midi_parser/midi_data.d.ts +27 -118
  5. package/@types/midi_parser/midi_editor.d.ts +71 -27
  6. package/@types/midi_parser/midi_loader.d.ts +4 -0
  7. package/@types/midi_parser/midi_sequence.d.ts +124 -0
  8. package/@types/midi_parser/midi_writer.d.ts +1 -1
  9. package/@types/midi_parser/rmidi_writer.d.ts +1 -0
  10. package/@types/sequencer/sequencer.d.ts +3 -1
  11. package/@types/soundfont/basic_soundfont/basic_sample.d.ts +9 -8
  12. package/@types/soundfont/read_sf2/samples.d.ts +1 -1
  13. package/index.js +17 -3
  14. package/midi_parser/basic_midi.js +7 -124
  15. package/midi_parser/midi_builder.js +3 -0
  16. package/midi_parser/midi_data.js +11 -127
  17. package/midi_parser/midi_editor.js +32 -18
  18. package/midi_parser/midi_loader.js +5 -0
  19. package/midi_parser/midi_sequence.js +133 -0
  20. package/midi_parser/midi_writer.js +5 -1
  21. package/midi_parser/rmidi_writer.js +6 -1
  22. package/package.json +1 -1
  23. package/sequencer/sequencer.js +3 -6
  24. package/sequencer/worklet_sequencer/process_event.js +12 -1
  25. package/sequencer/worklet_sequencer/sequencer_message.js +1 -1
  26. package/sequencer/worklet_sequencer/worklet_sequencer.js +0 -1
  27. package/soundfont/basic_soundfont/basic_sample.js +38 -10
  28. package/soundfont/basic_soundfont/write_sf2/sdta.js +5 -2
  29. package/soundfont/read_sf2/samples.js +6 -3
  30. package/synthetizer/worklet_processor.min.js +11 -11
  31. package/synthetizer/worklet_system/main_processor.js +1 -1
  32. package/synthetizer/worklet_system/snapshot/snapshot.js +311 -0
  33. package/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -14
  34. package/synthetizer/worklet_system/worklet_methods/note_off.js +1 -1
  35. package/synthetizer/worklet_system/worklet_methods/snapshot.js +0 -145
@@ -35,7 +35,7 @@ export const WorkletSequencerMessageType = {
35
35
  export const WorkletSequencerReturnMessageType = {
36
36
  midiEvent: 0, // [...midiEventBytes<number>]
37
37
  songChange: 1, // [midiData<MidiData>, songIndex<number>, isAutoPlayed<boolean>]
38
- textEvent: 2, // [messageData<number[]>, statusByte<number]
38
+ textEvent: 2, // [messageData<number[]>, statusByte<number>, lyricsIndex<number>]
39
39
  timeChange: 3, // newAbsoluteTime<number>
40
40
  pause: 4, // no data
41
41
  getMIDI: 5, // midiData<MIDI>
@@ -219,7 +219,6 @@ class WorkletSequencer
219
219
  for (let c = 0; c < MIDI_CHANNEL_COUNT; c++)
220
220
  {
221
221
  this.sendMIDICC(c, midiControllers.allNotesOff, 0);
222
- this.sendMIDICC(c, midiControllers.allSoundOff, 0);
223
222
  }
224
223
  }
225
224
  }
@@ -5,18 +5,21 @@
5
5
  */
6
6
  import { SpessaSynthWarn } from "../../utils/loggin.js";
7
7
 
8
+ // should be reasonable for most cases
9
+ const RESAMPLE_RATE = 48000;
10
+
8
11
  export class BasicSample
9
12
  {
10
13
  /**
11
14
  * The basic representation of a soundfont sample
12
- * @param sampleName {string}
13
- * @param sampleRate {number}
14
- * @param samplePitch {number}
15
- * @param samplePitchCorrection {number}
16
- * @param sampleLink {number}
17
- * @param sampleType {number}
18
- * @param loopStart {number} relative to sample start
19
- * @param loopEnd {number} relative to sample start
15
+ * @param sampleName {string} The sample's name
16
+ * @param sampleRate {number} The sample's rate in Hz
17
+ * @param samplePitch {number} The sample's pitch as a MIDI note number
18
+ * @param samplePitchCorrection {number} The sample's pitch correction in cents
19
+ * @param sampleLink {number} The sample's link, currently unused
20
+ * @param sampleType {number} The sample's type, an enum
21
+ * @param loopStart {number} The sample's loop start relative to the sample start in sample points
22
+ * @param loopEnd {number} The sample's loop end relative to the sample start in sample points
20
23
  */
21
24
  constructor(
22
25
  sampleName,
@@ -110,6 +113,23 @@ export class BasicSample
110
113
  return uint8;
111
114
  }
112
115
 
116
+ resampleData(newSampleRate)
117
+ {
118
+ let audioData = this.getAudioData();
119
+ const ratio = newSampleRate / this.sampleRate;
120
+ const resampled = new Float32Array(Math.floor(audioData.length * ratio));
121
+ for (let i = 0; i < resampled.length; i++)
122
+ {
123
+ resampled[i] = audioData[Math.floor(i * (1 / ratio))];
124
+ }
125
+ audioData = resampled;
126
+ this.sampleRate = newSampleRate;
127
+ // adjust loop points
128
+ this.sampleLoopStartIndex = Math.floor(this.sampleLoopStartIndex * ratio);
129
+ this.sampleLoopEndIndex = Math.floor(this.sampleLoopEndIndex * ratio);
130
+ this.sampleData = audioData;
131
+ }
132
+
113
133
  /**
114
134
  * @param quality {number}
115
135
  * @param encodeVorbis {EncodeVorbisFunction}
@@ -124,7 +144,14 @@ export class BasicSample
124
144
  // compress, always mono!
125
145
  try
126
146
  {
127
- this.compressedData = encodeVorbis([this.getAudioData()], 1, this.sampleRate, quality);
147
+ // if the sample rate is too low or too high, resample
148
+ let audioData = this.getAudioData();
149
+ if (this.sampleRate < 8000 || this.sampleRate > 96000)
150
+ {
151
+ this.resampleData(RESAMPLE_RATE);
152
+ audioData = this.getAudioData();
153
+ }
154
+ this.compressedData = encodeVorbis([audioData], 1, this.sampleRate, quality);
128
155
  // flag as compressed
129
156
  this.sampleType |= 0x10;
130
157
  this.isCompressed = true;
@@ -134,7 +161,8 @@ export class BasicSample
134
161
  SpessaSynthWarn(`Failed to compress ${this.sampleName}. Leaving as uncompressed!`);
135
162
  this.isCompressed = false;
136
163
  this.compressedData = undefined;
137
- this.sampleType &= -17;
164
+ // flag as uncompressed
165
+ this.sampleType &= 0xEF;
138
166
  }
139
167
 
140
168
  }
@@ -24,11 +24,14 @@ export function getSDTA(smplStartOffsets, smplEndOffsets, compress, quality, vor
24
24
  }
25
25
  const r = s.getRawData();
26
26
  SpessaSynthInfo(
27
- `%cEncoded sample %c${i}. ${s.sampleName}%c of %c${this.samples.length}`,
27
+ `%cEncoded sample %c${i}. ${s.sampleName}%c of %c${this.samples.length}%c. Compressed: %c${s.isCompressed}%c.`,
28
28
  consoleColors.info,
29
29
  consoleColors.recognized,
30
30
  consoleColors.info,
31
- consoleColors.recognized
31
+ consoleColors.recognized,
32
+ consoleColors.info,
33
+ s.isCompressed ? consoleColors.recognized : consoleColors.unrecognized,
34
+ consoleColors.info
32
35
  );
33
36
  return r;
34
37
  });
@@ -72,7 +72,7 @@ export class LoadedSample extends BasicSample
72
72
 
73
73
  /**
74
74
  * Get raw data, whether it's compressed or not as we simply write it to the file
75
- * @return {Uint8Array}
75
+ * @return {Uint8Array} either s16 or vorbis data
76
76
  */
77
77
  getRawData()
78
78
  {
@@ -90,7 +90,8 @@ export class LoadedSample extends BasicSample
90
90
  {
91
91
  if (!this.isDataRaw)
92
92
  {
93
- throw new Error("Writing SF2Pack samples is not supported.");
93
+ // encode the f32 into s16 manually
94
+ super.getRawData();
94
95
  }
95
96
  const dataStartIndex = smplArr.currentIndex;
96
97
  return smplArr.slice(dataStartIndex + this.sampleStartIndex, dataStartIndex + this.sampleEndIndex);
@@ -123,7 +124,9 @@ export class LoadedSample extends BasicSample
123
124
  }
124
125
  catch (e)
125
126
  {
126
- throw new Error(`Ogg Vorbis decode error: ${e}`);
127
+ // do not error out, fill with silence
128
+ SpessaSynthWarn(`Error decoding sample ${this.sampleName}: ${e}`);
129
+ this.sampleData = new Float32Array(this.sampleLoopEndIndex + 1);
127
130
  }
128
131
  }
129
132