sf2-json 1.0.0 → 1.0.2

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 (2) hide show
  1. package/package.json +52 -52
  2. package/src/sf2-json.js +60 -75
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
- {
2
- "name": "sf2-json",
3
- "version": "1.0.0",
4
- "description": "SF2 to JSON Converter for WebAudioFonts",
5
- "keywords": [
6
- "sf2",
7
- "json",
8
- "webaudiofont",
9
- "music",
10
- "sound",
11
- "soundfont",
12
- "midi",
13
- "midiplayer",
14
- "midi-player",
15
- "instruments",
16
- "sound",
17
- "soundbank"
18
- ],
19
- "homepage": "https://github.com/ZmotriN/sf2-json#readme",
20
- "bugs": {
21
- "url": "https://github.com/ZmotriN/sf2-json/issues"
22
- },
23
- "repository": {
24
- "type": "git",
25
- "url": "git+https://github.com/ZmotriN/sf2-json.git"
26
- },
27
- "license": "MIT",
28
- "author": "Maxime Larrivée-Roy",
29
- "type": "module",
30
- "files": [
31
- "src/",
32
- "index.js",
33
- "index.d.ts"
34
- ],
35
- "main": "index.js",
36
- "types": "index.d.ts",
37
- "exports": {
38
- ".": {
39
- "types": "./index.d.ts",
40
- "import": "./index.js"
41
- }
42
- },
43
- "scripts": {
44
- "test": "echo \"Error: no test specified\" && exit 1"
45
- },
46
- "bin": {
47
- "sf2tojson": "./bin/cli.js"
48
- },
49
- "dependencies": {
50
- "@marmooo/soundfont-parser": "^0.1.8",
51
- "ffmpeg-static": "^5.3.0"
52
- }
1
+ {
2
+ "name": "sf2-json",
3
+ "version": "1.0.2",
4
+ "description": "SF2 to JSON Converter for WebAudioFonts",
5
+ "keywords": [
6
+ "sf2",
7
+ "json",
8
+ "webaudiofont",
9
+ "music",
10
+ "sound",
11
+ "soundfont",
12
+ "midi",
13
+ "midiplayer",
14
+ "midi-player",
15
+ "instruments",
16
+ "sound",
17
+ "soundbank"
18
+ ],
19
+ "homepage": "https://github.com/WebAudioFonts/sf2-json#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/WebAudioFonts/sf2-json/issues"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/WebAudioFonts/sf2-json.git"
26
+ },
27
+ "license": "MIT",
28
+ "author": "Maxime Larrivée-Roy",
29
+ "type": "module",
30
+ "files": [
31
+ "src/",
32
+ "index.js",
33
+ "index.d.ts"
34
+ ],
35
+ "main": "index.js",
36
+ "types": "index.d.ts",
37
+ "exports": {
38
+ ".": {
39
+ "types": "./index.d.ts",
40
+ "import": "./index.js"
41
+ }
42
+ },
43
+ "scripts": {
44
+ "test": "echo \"Error: no test specified\" && exit 1"
45
+ },
46
+ "bin": {
47
+ "sf2tojson": "./bin/cli.js"
48
+ },
49
+ "dependencies": {
50
+ "@marmooo/soundfont-parser": "^0.1.8",
51
+ "ffmpeg-static": "^5.3.0"
52
+ }
53
53
  }
package/src/sf2-json.js CHANGED
@@ -69,7 +69,7 @@ function encodeOpus(wavBuffer, bitrate = 128, sampleRate = 32000) {
69
69
  '-i', 'pipe:0',
70
70
  '-ar', String(sampleRate),
71
71
  '-ac', '1',
72
- '-af', "highpass=f=100,lowpass=f=8000,firequalizer=gain='if(lt(f,100),-2,if(lt(f,400),-3,if(lt(f,3000),2,if(lt(f,8000),1,-5))))':gain_entry='entry(0,-10);entry(100,0);entry(400,-2);entry(3000,2);entry(8000,1);entry(20000,-15)'",
72
+ '-af', "highpass=f=100,lowpass=f=8000",
73
73
  '-b:a', `${bitrate}k`,
74
74
  '-c:a', 'libopus',
75
75
  '-id3v2_version', '0',
@@ -147,23 +147,7 @@ function buildWavBuffer(audioData) {
147
147
  else throw new Error(`buildWavBuffer: type '${type}' non supporté (SF3 compressé).`);
148
148
  pcm16 = normalizeBuffer(pcm16);
149
149
 
150
- const loopLen = loopEnd - loopStart;
151
- const MIN_LOOP_SAMPLES = Math.ceil(2 * 1152 * sampleRate / RESAMPLE_RATE);
152
- if (loopLen > 0 && loopLen < MIN_LOOP_SAMPLES) {
153
- const preLoop = pcm16.slice(0, loopStart * 2);
154
- const loopData = pcm16.slice(loopStart * 2, loopEnd * 2);
155
- const postLoop = pcm16.slice(loopEnd * 2);
156
- const repeats = Math.ceil(MIN_LOOP_SAMPLES / loopLen);
157
- const loopRepeated = Buffer.concat(Array(repeats).fill(loopData));
158
- pcm16 = Buffer.concat([preLoop, loopRepeated, postLoop]);
159
- }
160
150
 
161
- const minSamples = Math.ceil(4 * 1152 * sampleRate / RESAMPLE_RATE);
162
- const minBytes = minSamples * 2;
163
- if (pcm16.byteLength < minBytes) {
164
- const pad = Buffer.alloc(minBytes - pcm16.byteLength);
165
- pcm16 = Buffer.concat([pcm16, pad]);
166
- }
167
151
 
168
152
  const numChannels = 1;
169
153
  const bitsPerSample = 16;
@@ -190,67 +174,68 @@ function buildWavBuffer(audioData) {
190
174
  }
191
175
 
192
176
 
193
- function extractZones(soundFont, parsed, presetHeaderIndex) {
194
- const presetGeneratorsList = soundFont.getPresetGenerators(presetHeaderIndex);
195
- const zones = [];
196
- const seenSampleIds = new Set();
197
- let globalPresetGen = null;
198
-
199
- for (const rawGenList of presetGeneratorsList) {
200
- const presetGen = createPresetGeneratorObject(rawGenList);
201
- if (presetGen.instrument === undefined) {
202
- globalPresetGen = presetGen;
203
- continue;
204
- }
205
177
 
206
- const instrId = presetGen.instrument;
207
- const instrGeneratorsList = soundFont.getInstrumentGenerators(instrId);
208
- const defaults = convertToInstrumentGeneratorParams(DefaultInstrumentZone);
209
- let globalInstrGen = null;
210
-
211
- for (const rawInstrGenList of instrGeneratorsList) {
212
- const instrGen = createInstrumentGeneratorObject(rawInstrGenList);
213
- if (instrGen.sampleID === undefined) { globalInstrGen = instrGen; continue; }
214
-
215
- const merged = { ...defaults };
216
- if (globalInstrGen) Object.assign(merged, globalInstrGen);
217
- Object.assign(merged, instrGen);
218
- const applyPresetOffsets = (gen) => {
219
- if (!gen) return;
220
- for (const [key, val] of Object.entries(gen)) {
221
- if (key === 'keyRange' || key === 'velRange' || key === 'instrument') continue;
222
- if (key in merged && typeof val === 'number') merged[key] += val;
223
- }
224
- };
225
- applyPresetOffsets(globalPresetGen);
226
- applyPresetOffsets(presetGen);
227
-
228
- const sampleId = merged.sampleID;
229
- if (seenSampleIds.has(sampleId)) continue;
230
- const sampleHeader = parsed.sampleHeaders[sampleId];
231
- if (!sampleHeader || sampleHeader.isEnd) continue;
232
- seenSampleIds.add(sampleId);
233
- zones.push({ generators: merged, sampleHeader, sample: parsed.samples[sampleId] });
234
- }
235
- }
236
178
 
237
- const byKeyRange = new Map();
238
- for (const zone of zones) {
239
- const lo = zone.generators.keyRange?.lo ?? 0;
240
- const hi = zone.generators.keyRange?.hi ?? 127;
241
- const key = `${lo}-${hi}`;
242
- if (!byKeyRange.has(key)) {
243
- byKeyRange.set(key, zone);
244
- } else {
245
- const center = (lo + hi) / 2;
246
- const existing = byKeyRange.get(key);
247
- const existingDist = Math.abs(existing.sampleHeader.originalPitch - center);
248
- const newDist = Math.abs(zone.sampleHeader.originalPitch - center);
249
- if (newDist < existingDist) byKeyRange.set(key, zone);
250
- }
251
- }
252
179
 
253
- return Array.from(byKeyRange.values());
180
+
181
+
182
+
183
+
184
+
185
+
186
+ function extractZones(soundFont, parsed, presetHeaderIndex) {
187
+ const presetGeneratorsList = soundFont.getPresetGenerators(presetHeaderIndex);
188
+ const zones = [];
189
+ let globalPresetGen = null;
190
+
191
+ for (const rawGenList of presetGeneratorsList) {
192
+ const presetGen = createPresetGeneratorObject(rawGenList);
193
+ if (presetGen.instrument === undefined) {
194
+ globalPresetGen = presetGen;
195
+ continue;
196
+ }
197
+
198
+ const instrId = presetGen.instrument;
199
+ const instrGeneratorsList = soundFont.getInstrumentGenerators(instrId);
200
+ const defaults = convertToInstrumentGeneratorParams(DefaultInstrumentZone);
201
+ let globalInstrGen = null;
202
+
203
+ for (const rawInstrGenList of instrGeneratorsList) {
204
+ const instrGen = createInstrumentGeneratorObject(rawInstrGenList);
205
+
206
+ if (instrGen.sampleID === undefined) {
207
+ globalInstrGen = instrGen;
208
+ continue;
209
+ }
210
+
211
+ const merged = { ...defaults };
212
+ if (globalInstrGen) Object.assign(merged, globalInstrGen);
213
+ Object.assign(merged, instrGen);
214
+
215
+ const applyPresetOffsets = (gen) => {
216
+ if (!gen) return;
217
+ for (const [key, val] of Object.entries(gen)) {
218
+ if (key === 'keyRange' || key === 'velRange' || key === 'instrument' || key === 'sampleID') continue;
219
+ if (key in merged && typeof val === 'number') merged[key] += val;
220
+ }
221
+ };
222
+
223
+ applyPresetOffsets(globalPresetGen);
224
+ applyPresetOffsets(presetGen);
225
+
226
+ const sampleId = merged.sampleID;
227
+ const sampleHeader = parsed.sampleHeaders[sampleId];
228
+
229
+ if (!sampleHeader || sampleHeader.isEnd) continue;
230
+
231
+ zones.push({
232
+ generators: merged,
233
+ sampleHeader,
234
+ sample: parsed.samples[sampleId]
235
+ });
236
+ }
237
+ }
238
+ return zones;
254
239
  }
255
240
 
256
241