spessasynth_core 3.26.29 → 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.
- package/README.md +0 -1
- package/package.json +1 -1
- package/src/midi/midi_tools/rmidi_writer.js +34 -35
- package/src/soundfont/basic_soundfont/basic_preset.js +1 -4
- package/src/soundfont/basic_soundfont/basic_sample.js +13 -3
- package/src/soundfont/basic_soundfont/basic_soundbank.js +9 -1
- package/src/soundfont/basic_soundfont/riff_chunk.js +78 -42
- package/src/soundfont/basic_soundfont/write_dls/art2.js +4 -4
- package/src/soundfont/basic_soundfont/write_dls/ins.js +14 -18
- package/src/soundfont/basic_soundfont/write_dls/lins.js +3 -6
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +8 -9
- package/src/soundfont/basic_soundfont/write_dls/wave.js +12 -35
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +18 -29
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +2 -2
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +3 -5
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +3 -12
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +4 -11
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +56 -26
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +3 -11
- package/src/soundfont/basic_soundfont/write_sf2/write.js +23 -52
- package/src/soundfont/dls/dls_soundfont.js +1 -1
- package/src/soundfont/read_sf2/samples.js +20 -5
- package/src/soundfont/read_sf2/soundfont.js +1 -1
- package/src/utils/buffer_to_wav.js +12 -15
- package/src/utils/byte_functions/string.js +7 -2
- package/src/utils/indexed_array.js +0 -18
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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(
|
|
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(
|
|
143
|
-
type,
|
|
144
|
-
dmoddata.length,
|
|
145
|
-
dmoddata
|
|
146
|
-
)));
|
|
138
|
+
infoArrays.push(writeRIFFChunkRaw(type, dmoddata));
|
|
147
139
|
}
|
|
148
140
|
else
|
|
149
141
|
{
|
|
150
|
-
|
|
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
|
-
|
|
156
|
-
|
|
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
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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 >
|
|
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
|
|
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 =
|
|
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
|
|
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
|
-
|
|
288
|
-
|
|
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"] = "
|
|
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
|
-
import { BasicSample } from "../basic_soundfont/basic_sample.js";
|
|
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
|
|
|
@@ -136,7 +137,17 @@ export class SoundFontSample extends BasicSample
|
|
|
136
137
|
{
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
|
-
|
|
140
|
+
const linkedSample = samplesArray[this.linkedSampleIndex];
|
|
141
|
+
if (!linkedSample)
|
|
142
|
+
{
|
|
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);
|
|
145
|
+
this.setSampleType(sampleTypes.monoSample);
|
|
146
|
+
}
|
|
147
|
+
else
|
|
148
|
+
{
|
|
149
|
+
this.setLinkedSample(samplesArray[this.linkedSampleIndex], this.sampleType);
|
|
150
|
+
}
|
|
140
151
|
}
|
|
141
152
|
|
|
142
153
|
/**
|
|
@@ -250,9 +261,13 @@ export class SoundFontSample extends BasicSample
|
|
|
250
261
|
}
|
|
251
262
|
else
|
|
252
263
|
{
|
|
253
|
-
if (this.compressedData
|
|
264
|
+
if (this.compressedData)
|
|
254
265
|
{
|
|
255
|
-
|
|
266
|
+
if (allowVorbis)
|
|
267
|
+
{
|
|
268
|
+
return this.compressedData;
|
|
269
|
+
}
|
|
270
|
+
return this.encodeS16LE();
|
|
256
271
|
}
|
|
257
272
|
return this.sf2FileArrayHandle.slice(this.s16leStart, this.s16leEnd);
|
|
258
273
|
}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
* @property {string|undefined} genre - the song's genre
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
43
|
+
writeRIFFChunkRaw("IART", encoder.encode(metadata.artist), true)
|
|
45
44
|
);
|
|
46
45
|
}
|
|
47
46
|
if (metadata.album)
|
|
48
47
|
{
|
|
49
48
|
infoChunks.push(
|
|
50
|
-
|
|
49
|
+
writeRIFFChunkRaw("IPRD", encoder.encode(metadata.album), true)
|
|
51
50
|
);
|
|
52
51
|
}
|
|
53
52
|
if (metadata.genre)
|
|
54
53
|
{
|
|
55
54
|
infoChunks.push(
|
|
56
|
-
|
|
55
|
+
writeRIFFChunkRaw("IGNR", encoder.encode(metadata.genre), true)
|
|
57
56
|
);
|
|
58
57
|
}
|
|
59
58
|
if (metadata.title)
|
|
60
59
|
{
|
|
61
60
|
infoChunks.push(
|
|
62
|
-
|
|
61
|
+
writeRIFFChunkRaw("INAM", encoder.encode(metadata.title), true)
|
|
63
62
|
);
|
|
64
63
|
}
|
|
65
|
-
infoChunk =
|
|
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
|
-
|
|
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
|
|
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
|
}
|