spessasynth_core 3.26.30 → 3.26.31

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 (32) hide show
  1. package/README.md +0 -1
  2. package/package.json +1 -1
  3. package/src/midi/midi_tools/rmidi_writer.js +34 -35
  4. package/src/soundfont/basic_soundfont/basic_preset.js +1 -4
  5. package/src/soundfont/basic_soundfont/basic_sample.js +13 -3
  6. package/src/soundfont/basic_soundfont/basic_soundbank.js +9 -1
  7. package/src/soundfont/basic_soundfont/riff_chunk.js +78 -42
  8. package/src/soundfont/basic_soundfont/write_dls/art2.js +4 -4
  9. package/src/soundfont/basic_soundfont/write_dls/ins.js +14 -18
  10. package/src/soundfont/basic_soundfont/write_dls/lins.js +3 -6
  11. package/src/soundfont/basic_soundfont/write_dls/rgn2.js +8 -9
  12. package/src/soundfont/basic_soundfont/write_dls/wave.js +12 -35
  13. package/src/soundfont/basic_soundfont/write_dls/write_dls.js +18 -29
  14. package/src/soundfont/basic_soundfont/write_dls/wsmp.js +2 -2
  15. package/src/soundfont/basic_soundfont/write_dls/wvpl.js +3 -5
  16. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +3 -11
  17. package/src/soundfont/basic_soundfont/write_sf2/igen.js +3 -11
  18. package/src/soundfont/basic_soundfont/write_sf2/imod.js +3 -11
  19. package/src/soundfont/basic_soundfont/write_sf2/inst.js +3 -12
  20. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +3 -11
  21. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +4 -11
  22. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +3 -11
  23. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +3 -11
  24. package/src/soundfont/basic_soundfont/write_sf2/sdta.js +56 -26
  25. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +3 -11
  26. package/src/soundfont/basic_soundfont/write_sf2/write.js +23 -52
  27. package/src/soundfont/dls/dls_soundfont.js +1 -1
  28. package/src/soundfont/read_sf2/samples.js +10 -4
  29. package/src/soundfont/read_sf2/soundfont.js +1 -1
  30. package/src/utils/buffer_to_wav.js +12 -15
  31. package/src/utils/byte_functions/string.js +7 -2
  32. package/src/utils/indexed_array.js +0 -18
@@ -1,6 +1,6 @@
1
- import { combineArrays, IndexedByteArray } from "../../../utils/indexed_array.js";
2
- import { RiffChunk, writeRIFFChunk, writeRIFFOddSize } from "../riff_chunk.js";
3
- import { writeStringAsBytes } from "../../../utils/byte_functions/string.js";
1
+ import { IndexedByteArray } from "../../../utils/indexed_array.js";
2
+ import { writeRIFFChunkParts, writeRIFFChunkRaw } from "../riff_chunk.js";
3
+ import { getStringBytes } from "../../../utils/byte_functions/string.js";
4
4
  import { consoleColors } from "../../../utils/other.js";
5
5
  import { getIGEN } from "./igen.js";
6
6
  import { getSDTA } from "./sdta.js";
@@ -109,11 +109,7 @@ export function write(options = DEFAULT_WRITE_OPTIONS)
109
109
  const ckdata = new IndexedByteArray(4);
110
110
  writeWord(ckdata, major);
111
111
  writeWord(ckdata, minor);
112
- infoArrays.push(writeRIFFChunk(new RiffChunk(
113
- type,
114
- 4,
115
- ckdata
116
- )));
112
+ infoArrays.push(writeRIFFChunkRaw(type, ckdata));
117
113
  }
118
114
  else if (type === "DMOD")
119
115
  {
@@ -139,22 +135,14 @@ export function write(options = DEFAULT_WRITE_OPTIONS)
139
135
  // terminal modulator, is zero
140
136
  writeLittleEndian(dmoddata, 0, MOD_BYTE_SIZE);
141
137
 
142
- infoArrays.push(writeRIFFChunk(new RiffChunk(
143
- type,
144
- dmoddata.length,
145
- dmoddata
146
- )));
138
+ infoArrays.push(writeRIFFChunkRaw(type, dmoddata));
147
139
  }
148
140
  else
149
141
  {
150
- // pad with zero
151
- const arr = new IndexedByteArray(data.length + 1);
152
- writeStringAsBytes(arr, data);
153
- infoArrays.push(writeRIFFChunk(new RiffChunk(
142
+ infoArrays.push(writeRIFFChunkRaw(
154
143
  type,
155
- arr.length,
156
- arr
157
- )));
144
+ getStringBytes(data, true, true) // pad with zero and ensure even length
145
+ ));
158
146
  }
159
147
  }
160
148
 
@@ -206,6 +194,10 @@ export function write(options = DEFAULT_WRITE_OPTIONS)
206
194
  consoleColors.info
207
195
  );
208
196
  const instChunk = getINST.call(this);
197
+ SpessaSynthInfo(
198
+ "%cWriting PGEN...",
199
+ consoleColors.info
200
+ );
209
201
  // presets
210
202
  const pgenChunk = getPGEN.call(this);
211
203
  SpessaSynthInfo(
@@ -228,21 +220,17 @@ export function write(options = DEFAULT_WRITE_OPTIONS)
228
220
  */
229
221
  const chunks = [phdrChunk, pbagChunk, pmodChunk, pgenChunk, instChunk, ibagChunk, imodChunk, igenChunk, shdrChunk];
230
222
  // combine in the sfspec order
231
- const pdtaData = combineArrays([
232
- new IndexedByteArray([112, 100, 116, 97]), // "pdta"
233
- ...chunks.map(c => c.pdta)
234
- ]);
235
- const pdtaChunk = writeRIFFChunk(new RiffChunk(
236
- "LIST",
237
- pdtaData.length,
238
- pdtaData
239
- ));
223
+ const pdtaChunk = writeRIFFChunkParts(
224
+ "pdta",
225
+ chunks.map(c => c.pdta),
226
+ true
227
+ );
240
228
  const maxIndex = Math.max(
241
229
  ...chunks.map(c => c.highestIndex)
242
230
  );
243
231
 
244
232
  const writeXdta = options.writeExtendedLimits && (
245
- maxIndex > 0xFFF
233
+ maxIndex > 0xFFFF
246
234
  || this.presets.some(p => p.presetName.length > 20)
247
235
  || this.instruments.some(i => i.instrumentName.length > 20)
248
236
  || this.samples.some(s => s.sampleName.length > 20)
@@ -256,37 +244,20 @@ export function write(options = DEFAULT_WRITE_OPTIONS)
256
244
  consoleColors.value
257
245
  );
258
246
  // https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md
259
- const xpdtaData = combineArrays([
260
- new IndexedByteArray([120, 100, 116, 97]), // "xdta"
261
- ...chunks.map(c => c.xdta)
262
- ]);
263
-
264
- const xpdtaChunk = writeRIFFChunk(new RiffChunk(
265
- "LIST",
266
- xpdtaData.length,
267
- xpdtaData
268
- ));
247
+ const xpdtaChunk = writeRIFFChunkParts("xdta", chunks.map(c => c.xdta), true);
269
248
  infoArrays.push(xpdtaChunk);
270
249
  }
271
250
 
272
- const infoChunk = writeRIFFOddSize("INFO", combineArrays(infoArrays), false, true);
251
+ const infoChunk = writeRIFFChunkParts("INFO", infoArrays, true);
273
252
  SpessaSynthInfo(
274
253
  "%cWriting the output file...",
275
254
  consoleColors.info
276
255
  );
277
256
  // finally, combine everything
278
- const riffdata = combineArrays([
279
- new IndexedByteArray([115, 102, 98, 107]), // "sfbk"
280
- infoChunk,
281
- sdtaChunk,
282
- pdtaChunk
283
- ]);
284
-
285
- const main = writeRIFFChunk(new RiffChunk(
257
+ const main = writeRIFFChunkParts(
286
258
  "RIFF",
287
- riffdata.length,
288
- riffdata
289
- ));
259
+ [getStringBytes("sfbk"), infoChunk, sdtaChunk, pdtaChunk]
260
+ );
290
261
  SpessaSynthInfo(
291
262
  `%cSaved succesfully! Final file size: %c${main.length}`,
292
263
  consoleColors.info,
@@ -45,7 +45,7 @@ class DLSSoundFont extends BasicSoundBank
45
45
 
46
46
  // mandatory
47
47
  this.soundFontInfo["ifil"] = "2.1"; // always for dls
48
- this.soundFontInfo["isng"] = "EMU8000";
48
+ this.soundFontInfo["isng"] = "E-mu 10K2";
49
49
 
50
50
  // set some defaults
51
51
  this.soundFontInfo["INAM"] = "Unnamed DLS";
@@ -2,9 +2,10 @@ import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
2
2
  import { IndexedByteArray } from "../../utils/indexed_array.js";
3
3
  import { readLittleEndian, signedInt8 } from "../../utils/byte_functions/little_endian.js";
4
4
  import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
5
- import { SpessaSynthWarn } from "../../utils/loggin.js";
5
+ import { SpessaSynthInfo, SpessaSynthWarn } from "../../utils/loggin.js";
6
6
  import { readBytesAsString } from "../../utils/byte_functions/string.js";
7
7
  import { BasicSample, sampleTypes } from "../basic_soundfont/basic_sample.js";
8
+ import { consoleColors } from "../../utils/other.js";
8
9
 
9
10
  export const SF3_BIT_FLIT = 0x10;
10
11
 
@@ -139,7 +140,8 @@ export class SoundFontSample extends BasicSample
139
140
  const linkedSample = samplesArray[this.linkedSampleIndex];
140
141
  if (!linkedSample)
141
142
  {
142
- SpessaSynthWarn(`Invalid linked sample for ${this.sampleName}. Setting to mono.`);
143
+ // log as info because it's common and not really dangerous
144
+ SpessaSynthInfo(`%cInvalid linked sample for ${this.sampleName}. Setting to mono.`, consoleColors.warn);
143
145
  this.setSampleType(sampleTypes.monoSample);
144
146
  }
145
147
  else
@@ -259,9 +261,13 @@ export class SoundFontSample extends BasicSample
259
261
  }
260
262
  else
261
263
  {
262
- if (this.compressedData && allowVorbis)
264
+ if (this.compressedData)
263
265
  {
264
- return this.compressedData;
266
+ if (allowVorbis)
267
+ {
268
+ return this.compressedData;
269
+ }
270
+ return this.encodeS16LE();
265
271
  }
266
272
  return this.sf2FileArrayHandle.slice(this.s16leStart, this.s16leEnd);
267
273
  }
@@ -54,7 +54,7 @@ export class SoundFont2 extends BasicSoundBank
54
54
  this.parsingError("No data provided!");
55
55
  }
56
56
 
57
- // read the main read
57
+ // read the main chunk
58
58
  let firstChunk = readRIFFChunk(mainFileArray, false);
59
59
  this.verifyHeader(firstChunk, "riff");
60
60
 
@@ -6,9 +6,9 @@
6
6
  * @property {string|undefined} genre - the song's genre
7
7
  */
8
8
 
9
- import { combineArrays, IndexedByteArray } from "./indexed_array.js";
10
- import { getStringBytes, writeStringAsBytes } from "./byte_functions/string.js";
11
- import { writeRIFFOddSize } from "../soundfont/basic_soundfont/riff_chunk.js";
9
+ import { IndexedByteArray } from "./indexed_array.js";
10
+ import { writeStringAsBytes } from "./byte_functions/string.js";
11
+ import { writeRIFFChunkParts, writeRIFFChunkRaw } from "../soundfont/basic_soundfont/riff_chunk.js";
12
12
  import { writeLittleEndian } from "./byte_functions/little_endian.js";
13
13
 
14
14
  /**
@@ -35,34 +35,33 @@ export function audioToWav(audioData, sampleRate, normalizeAudio = true, metadat
35
35
  {
36
36
  const encoder = new TextEncoder();
37
37
  const infoChunks = [
38
- getStringBytes("INFO"),
39
- writeRIFFOddSize("ICMT", encoder.encode("Created with SpessaSynth"), true)
38
+ writeRIFFChunkRaw("ICMT", encoder.encode("Created with SpessaSynth"), true)
40
39
  ];
41
40
  if (metadata.artist)
42
41
  {
43
42
  infoChunks.push(
44
- writeRIFFOddSize("IART", encoder.encode(metadata.artist), true)
43
+ writeRIFFChunkRaw("IART", encoder.encode(metadata.artist), true)
45
44
  );
46
45
  }
47
46
  if (metadata.album)
48
47
  {
49
48
  infoChunks.push(
50
- writeRIFFOddSize("IPRD", encoder.encode(metadata.album), true)
49
+ writeRIFFChunkRaw("IPRD", encoder.encode(metadata.album), true)
51
50
  );
52
51
  }
53
52
  if (metadata.genre)
54
53
  {
55
54
  infoChunks.push(
56
- writeRIFFOddSize("IGNR", encoder.encode(metadata.genre), true)
55
+ writeRIFFChunkRaw("IGNR", encoder.encode(metadata.genre), true)
57
56
  );
58
57
  }
59
58
  if (metadata.title)
60
59
  {
61
60
  infoChunks.push(
62
- writeRIFFOddSize("INAM", encoder.encode(metadata.title), true)
61
+ writeRIFFChunkRaw("INAM", encoder.encode(metadata.title), true)
63
62
  );
64
63
  }
65
- infoChunk = writeRIFFOddSize("LIST", combineArrays(infoChunks));
64
+ infoChunk = writeRIFFChunkParts("INFO", infoChunks, true);
66
65
  }
67
66
 
68
67
  // prepare CUE chunk
@@ -89,12 +88,10 @@ export function audioToWav(audioData, sampleRate, normalizeAudio = true, metadat
89
88
  writeLittleEndian(cueEnd, 0, 4); // BlockStart, always 0
90
89
  writeLittleEndian(cueEnd, loopEndSamples, 4); // sampleOffset
91
90
 
92
- const out = combineArrays([
93
- new IndexedByteArray([2, 0, 0, 0]), // cue points count,
91
+ cueChunk = writeRIFFChunkParts("cue ", [
92
+ new IndexedByteArray([2, 0, 0, 0]), // cue points count
94
93
  cueStart,
95
- cueEnd
96
- ]);
97
- cueChunk = writeRIFFOddSize("cue ", out);
94
+ cueEnd]);
98
95
  }
99
96
 
100
97
  // Prepare the header
@@ -52,14 +52,19 @@ export function readBytesAsString(dataArray, bytes, encoding = undefined, trimEn
52
52
  /**
53
53
  * @param string {string}
54
54
  * @param addZero {boolean} adds a zero terminator at the end
55
+ * @param ensureEven {boolean} ensures even byte count
55
56
  * @returns {IndexedByteArray}
56
57
  */
57
- export function getStringBytes(string, addZero = false)
58
+ export function getStringBytes(string, addZero = false, ensureEven = false)
58
59
  {
59
60
  let len = string.length;
60
61
  if (addZero)
61
62
  {
62
- len = len + 1;
63
+ len++;
64
+ }
65
+ if (ensureEven && len % 2 !== 0)
66
+ {
67
+ len++;
63
68
  }
64
69
  const arr = new IndexedByteArray(len);
65
70
  writeStringAsBytes(arr, string);
@@ -31,22 +31,4 @@ export class IndexedByteArray extends Uint8Array
31
31
  a.currentIndex = 0;
32
32
  return a;
33
33
  }
34
- }
35
-
36
-
37
- /**
38
- * @param arrs {(IndexedByteArray|Uint8Array)[]}
39
- * @returns {IndexedByteArray|Uint8Array}
40
- */
41
- export function combineArrays(arrs)
42
- {
43
- const length = arrs.reduce((sum, current) => sum + current.length, 0);
44
- const newArr = new IndexedByteArray(length);
45
- let offset = 0;
46
- for (const arr of arrs)
47
- {
48
- newArr.set(arr, offset);
49
- offset += arr.length;
50
- }
51
- return newArr;
52
34
  }