spessasynth_core 3.26.27 → 3.26.29
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/package.json +1 -1
- package/src/soundfont/basic_soundfont/basic_instrument.js +21 -2
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +1 -1
- package/src/soundfont/basic_soundfont/basic_sample.js +48 -17
- package/src/soundfont/basic_soundfont/basic_soundbank.js +18 -15
- package/src/soundfont/basic_soundfont/riff_chunk.js +4 -1
- package/src/soundfont/basic_soundfont/write_dls/wave.js +1 -1
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +28 -10
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +26 -11
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +28 -14
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +28 -10
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +26 -11
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +25 -11
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +45 -20
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +28 -14
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +28 -5
- package/src/soundfont/basic_soundfont/write_sf2/write.js +53 -14
- package/src/soundfont/dls/dls_sample.js +179 -18
- package/src/soundfont/dls/read_samples.js +7 -123
- package/src/soundfont/read_sf2/instrument_zones.js +4 -17
- package/src/soundfont/read_sf2/instruments.js +1 -1
- package/src/soundfont/read_sf2/preset_zones.js +6 -19
- package/src/soundfont/read_sf2/presets.js +0 -1
- package/src/soundfont/read_sf2/samples.js +115 -106
- package/src/soundfont/read_sf2/soundfont.js +198 -56
- package/src/soundfont/read_sf2/zones.js +28 -0
|
@@ -2,7 +2,7 @@ import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
|
2
2
|
import { readSamples } from "./samples.js";
|
|
3
3
|
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
4
4
|
import { readGenerators } from "./generators.js";
|
|
5
|
-
import {
|
|
5
|
+
import { applyPresetZones } from "./preset_zones.js";
|
|
6
6
|
import { readPresets } from "./presets.js";
|
|
7
7
|
import { readInstruments } from "./instruments.js";
|
|
8
8
|
import { readModulators } from "./modulators.js";
|
|
@@ -14,7 +14,8 @@ import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js"
|
|
|
14
14
|
import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
|
|
15
15
|
import { Generator } from "../basic_soundfont/generator.js";
|
|
16
16
|
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
17
|
-
import {
|
|
17
|
+
import { applyInstrumentZones, InstrumentZone } from "./instrument_zones.js";
|
|
18
|
+
import { readZoneIndexes } from "./zones.js";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* soundfont.js
|
|
@@ -45,19 +46,19 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
45
46
|
{
|
|
46
47
|
console.warn("Using the constructor directly is deprecated. Use loadSoundFont instead.");
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
const mainFileArray = new IndexedByteArray(arrayBuffer);
|
|
49
50
|
SpessaSynthGroup("%cParsing SoundFont...", consoleColors.info);
|
|
50
|
-
if (!
|
|
51
|
+
if (!mainFileArray)
|
|
51
52
|
{
|
|
52
53
|
SpessaSynthGroupEnd();
|
|
53
54
|
this.parsingError("No data provided!");
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
// read the main read
|
|
57
|
-
let firstChunk = readRIFFChunk(
|
|
58
|
+
let firstChunk = readRIFFChunk(mainFileArray, false);
|
|
58
59
|
this.verifyHeader(firstChunk, "riff");
|
|
59
60
|
|
|
60
|
-
const type = readBytesAsString(
|
|
61
|
+
const type = readBytesAsString(mainFileArray, 4).toLowerCase();
|
|
61
62
|
if (type !== "sfbk" && type !== "sfpk")
|
|
62
63
|
{
|
|
63
64
|
SpessaSynthGroupEnd();
|
|
@@ -71,9 +72,20 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
71
72
|
const isSF2Pack = type === "sfpk";
|
|
72
73
|
|
|
73
74
|
// INFO
|
|
74
|
-
let infoChunk = readRIFFChunk(
|
|
75
|
+
let infoChunk = readRIFFChunk(mainFileArray);
|
|
75
76
|
this.verifyHeader(infoChunk, "list");
|
|
76
|
-
readBytesAsString(infoChunk.chunkData, 4);
|
|
77
|
+
const infoString = readBytesAsString(infoChunk.chunkData, 4);
|
|
78
|
+
if (infoString !== "INFO")
|
|
79
|
+
{
|
|
80
|
+
SpessaSynthGroupEnd();
|
|
81
|
+
throw new SyntaxError(`Invalid soundFont! Expected "INFO" or "${infoString}"`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @type {RiffChunk|undefined}
|
|
86
|
+
*/
|
|
87
|
+
let xdtaChunk = undefined;
|
|
88
|
+
|
|
77
89
|
|
|
78
90
|
while (infoChunk.chunkData.length > infoChunk.chunkData.currentIndex)
|
|
79
91
|
{
|
|
@@ -104,6 +116,16 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
104
116
|
this.soundFontInfo[chunk.header] = text;
|
|
105
117
|
break;
|
|
106
118
|
|
|
119
|
+
case "list":
|
|
120
|
+
// possible xdta
|
|
121
|
+
const listType = readBytesAsString(chunk.chunkData, 4);
|
|
122
|
+
if (listType === "xdta")
|
|
123
|
+
{
|
|
124
|
+
SpessaSynthInfo("%cExtended SF2 found!", consoleColors.recognized);
|
|
125
|
+
xdtaChunk = chunk;
|
|
126
|
+
}
|
|
127
|
+
break;
|
|
128
|
+
|
|
107
129
|
default:
|
|
108
130
|
text = readBytesAsString(chunk.chunkData, chunk.chunkData.length);
|
|
109
131
|
this.soundFontInfo[chunk.header] = text;
|
|
@@ -115,15 +137,44 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
115
137
|
consoleColors.recognized
|
|
116
138
|
);
|
|
117
139
|
}
|
|
140
|
+
// https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md
|
|
141
|
+
const isExtended = xdtaChunk !== undefined;
|
|
142
|
+
/**
|
|
143
|
+
* @type {{
|
|
144
|
+
* phdr: RiffChunk,
|
|
145
|
+
* pbag: RiffChunk,
|
|
146
|
+
* pmod: RiffChunk,
|
|
147
|
+
* pgen: RiffChunk,
|
|
148
|
+
* inst: RiffChunk,
|
|
149
|
+
* ibag: RiffChunk,
|
|
150
|
+
* imod: RiffChunk,
|
|
151
|
+
* igen: RiffChunk,
|
|
152
|
+
* shdr: RiffChunk,
|
|
153
|
+
* }}
|
|
154
|
+
*/
|
|
155
|
+
let xChunks = {};
|
|
156
|
+
if (isExtended)
|
|
157
|
+
{
|
|
158
|
+
// read the hydra chunks
|
|
159
|
+
xChunks.phdr = readRIFFChunk(xdtaChunk.chunkData);
|
|
160
|
+
xChunks.pbag = readRIFFChunk(xdtaChunk.chunkData);
|
|
161
|
+
xChunks.pmod = readRIFFChunk(xdtaChunk.chunkData);
|
|
162
|
+
xChunks.pgen = readRIFFChunk(xdtaChunk.chunkData);
|
|
163
|
+
xChunks.inst = readRIFFChunk(xdtaChunk.chunkData);
|
|
164
|
+
xChunks.ibag = readRIFFChunk(xdtaChunk.chunkData);
|
|
165
|
+
xChunks.imod = readRIFFChunk(xdtaChunk.chunkData);
|
|
166
|
+
xChunks.igen = readRIFFChunk(xdtaChunk.chunkData);
|
|
167
|
+
xChunks.shdr = readRIFFChunk(xdtaChunk.chunkData);
|
|
168
|
+
}
|
|
118
169
|
|
|
119
170
|
// SDTA
|
|
120
|
-
const sdtaChunk = readRIFFChunk(
|
|
171
|
+
const sdtaChunk = readRIFFChunk(mainFileArray, false);
|
|
121
172
|
this.verifyHeader(sdtaChunk, "list");
|
|
122
|
-
this.verifyText(readBytesAsString(
|
|
173
|
+
this.verifyText(readBytesAsString(mainFileArray, 4), "sdta");
|
|
123
174
|
|
|
124
175
|
// smpl
|
|
125
176
|
SpessaSynthInfo("%cVerifying smpl chunk...", consoleColors.warn);
|
|
126
|
-
let sampleDataChunk = readRIFFChunk(
|
|
177
|
+
let sampleDataChunk = readRIFFChunk(mainFileArray, false);
|
|
127
178
|
this.verifyHeader(sampleDataChunk, "smpl");
|
|
128
179
|
/**
|
|
129
180
|
* @type {IndexedByteArray|Float32Array}
|
|
@@ -141,9 +192,9 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
141
192
|
/**
|
|
142
193
|
* @type {Float32Array}
|
|
143
194
|
*/
|
|
144
|
-
sampleData = stbvorbis.decode(
|
|
145
|
-
|
|
146
|
-
|
|
195
|
+
sampleData = stbvorbis.decode(mainFileArray.buffer.slice(
|
|
196
|
+
mainFileArray.currentIndex,
|
|
197
|
+
mainFileArray.currentIndex + sdtaChunk.size - 12
|
|
147
198
|
)).data[0];
|
|
148
199
|
}
|
|
149
200
|
catch (e)
|
|
@@ -162,8 +213,8 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
162
213
|
/**
|
|
163
214
|
* @type {IndexedByteArray}
|
|
164
215
|
*/
|
|
165
|
-
sampleData =
|
|
166
|
-
this.sampleDataStartIndex =
|
|
216
|
+
sampleData = mainFileArray;
|
|
217
|
+
this.sampleDataStartIndex = mainFileArray.currentIndex;
|
|
167
218
|
}
|
|
168
219
|
|
|
169
220
|
SpessaSynthInfo(
|
|
@@ -171,68 +222,128 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
171
222
|
consoleColors.info,
|
|
172
223
|
consoleColors.value
|
|
173
224
|
);
|
|
174
|
-
|
|
225
|
+
mainFileArray.currentIndex += sdtaChunk.size - 12;
|
|
175
226
|
|
|
176
227
|
// PDTA
|
|
177
228
|
SpessaSynthInfo("%cLoading preset data chunk...", consoleColors.warn);
|
|
178
|
-
let presetChunk = readRIFFChunk(
|
|
229
|
+
let presetChunk = readRIFFChunk(mainFileArray);
|
|
179
230
|
this.verifyHeader(presetChunk, "list");
|
|
180
231
|
readBytesAsString(presetChunk.chunkData, 4);
|
|
181
232
|
|
|
182
233
|
// read the hydra chunks
|
|
183
|
-
const
|
|
184
|
-
this.verifyHeader(
|
|
234
|
+
const phdrChunk = readRIFFChunk(presetChunk.chunkData);
|
|
235
|
+
this.verifyHeader(phdrChunk, "phdr");
|
|
185
236
|
|
|
186
|
-
const
|
|
187
|
-
this.verifyHeader(
|
|
237
|
+
const pbagChunk = readRIFFChunk(presetChunk.chunkData);
|
|
238
|
+
this.verifyHeader(pbagChunk, "pbag");
|
|
188
239
|
|
|
189
|
-
const
|
|
190
|
-
this.verifyHeader(
|
|
240
|
+
const pmodChunk = readRIFFChunk(presetChunk.chunkData);
|
|
241
|
+
this.verifyHeader(pmodChunk, "pmod");
|
|
191
242
|
|
|
192
|
-
const
|
|
193
|
-
this.verifyHeader(
|
|
243
|
+
const pgenChunk = readRIFFChunk(presetChunk.chunkData);
|
|
244
|
+
this.verifyHeader(pgenChunk, "pgen");
|
|
194
245
|
|
|
195
246
|
const instChunk = readRIFFChunk(presetChunk.chunkData);
|
|
196
247
|
this.verifyHeader(instChunk, "inst");
|
|
197
248
|
|
|
198
|
-
const
|
|
199
|
-
this.verifyHeader(
|
|
249
|
+
const ibagChunk = readRIFFChunk(presetChunk.chunkData);
|
|
250
|
+
this.verifyHeader(ibagChunk, "ibag");
|
|
200
251
|
|
|
201
|
-
const
|
|
202
|
-
this.verifyHeader(
|
|
252
|
+
const imodChunk = readRIFFChunk(presetChunk.chunkData);
|
|
253
|
+
this.verifyHeader(imodChunk, "imod");
|
|
203
254
|
|
|
204
|
-
const
|
|
205
|
-
this.verifyHeader(
|
|
255
|
+
const igenChunk = readRIFFChunk(presetChunk.chunkData);
|
|
256
|
+
this.verifyHeader(igenChunk, "igen");
|
|
206
257
|
|
|
207
|
-
const
|
|
208
|
-
this.verifyHeader(
|
|
258
|
+
const shdrChunk = readRIFFChunk(presetChunk.chunkData);
|
|
259
|
+
this.verifyHeader(shdrChunk, "shdr");
|
|
209
260
|
|
|
210
261
|
/**
|
|
211
262
|
* read all the samples
|
|
212
263
|
* (the current index points to start of the smpl read)
|
|
213
264
|
*/
|
|
214
|
-
|
|
215
|
-
|
|
265
|
+
mainFileArray.currentIndex = this.sampleDataStartIndex;
|
|
266
|
+
const samples = readSamples(shdrChunk, sampleData, !isExtended);
|
|
267
|
+
|
|
268
|
+
if (isExtended)
|
|
269
|
+
{
|
|
270
|
+
// apply extensions to samples
|
|
271
|
+
const xSamples = readSamples(xChunks.shdr, new Float32Array(1), false);
|
|
272
|
+
if (xSamples.length === samples.length)
|
|
273
|
+
{
|
|
274
|
+
samples.forEach((s, i) =>
|
|
275
|
+
{
|
|
276
|
+
s.sampleName += xSamples[i].sampleName;
|
|
277
|
+
s.linkedSampleIndex |= xSamples[i].linkedSampleIndex << 16;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
// trim names
|
|
283
|
+
samples.forEach(s => s.sampleName = s.sampleName.trim());
|
|
284
|
+
this.samples.push(...samples);
|
|
216
285
|
|
|
217
286
|
/**
|
|
218
287
|
* read all the instrument generators
|
|
219
288
|
* @type {Generator[]}
|
|
220
289
|
*/
|
|
221
|
-
let instrumentGenerators = readGenerators(
|
|
290
|
+
let instrumentGenerators = readGenerators(igenChunk);
|
|
222
291
|
|
|
223
292
|
/**
|
|
224
293
|
* read all the instrument modulators
|
|
225
294
|
* @type {Modulator[]}
|
|
226
295
|
*/
|
|
227
|
-
let instrumentModulators = readModulators(
|
|
296
|
+
let instrumentModulators = readModulators(imodChunk);
|
|
297
|
+
|
|
298
|
+
const instruments = readInstruments(instChunk);
|
|
299
|
+
|
|
300
|
+
if (isExtended)
|
|
301
|
+
{
|
|
302
|
+
// apply extensions to instruments
|
|
303
|
+
const xInst = readInstruments(xChunks.inst);
|
|
304
|
+
if (xInst.length === instruments.length)
|
|
305
|
+
{
|
|
306
|
+
instruments.forEach((inst, i) =>
|
|
307
|
+
{
|
|
308
|
+
inst.instrumentName += xInst[i].instrumentName;
|
|
309
|
+
inst.zoneStartIndex |= xInst[i].zoneStartIndex;
|
|
310
|
+
});
|
|
311
|
+
// adjust zone counts
|
|
312
|
+
instruments.forEach((inst, i) =>
|
|
313
|
+
{
|
|
314
|
+
if (i < instruments.length - 1)
|
|
315
|
+
{
|
|
316
|
+
inst.zonesCount = instruments[i + 1].zoneStartIndex - inst.zoneStartIndex;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
}
|
|
322
|
+
// trim names
|
|
323
|
+
instruments.forEach(i => i.instrumentName = i.instrumentName.trim());
|
|
324
|
+
this.instruments.push(...instruments);
|
|
325
|
+
|
|
326
|
+
const ibagIndexes = readZoneIndexes(ibagChunk);
|
|
327
|
+
|
|
328
|
+
if (isExtended)
|
|
329
|
+
{
|
|
330
|
+
const extraIndexes = readZoneIndexes(xChunks.ibag);
|
|
331
|
+
for (let i = 0; i < ibagIndexes.mod.length; i++)
|
|
332
|
+
{
|
|
333
|
+
ibagIndexes.mod[i] |= extraIndexes.mod[i] << 16;
|
|
334
|
+
}
|
|
335
|
+
for (let i = 0; i < ibagIndexes.gen.length; i++)
|
|
336
|
+
{
|
|
337
|
+
ibagIndexes.gen[i] |= extraIndexes.gen[i] << 16;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
228
340
|
|
|
229
|
-
this.instruments = readInstruments(instChunk);
|
|
230
341
|
/**
|
|
231
342
|
* read all the instrument zones (and apply them)
|
|
232
343
|
* @type {InstrumentZone[]}
|
|
233
344
|
*/
|
|
234
|
-
|
|
235
|
-
|
|
345
|
+
applyInstrumentZones(
|
|
346
|
+
ibagIndexes,
|
|
236
347
|
instrumentGenerators,
|
|
237
348
|
instrumentModulators,
|
|
238
349
|
this.samples,
|
|
@@ -243,17 +354,59 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
243
354
|
* read all the preset generators
|
|
244
355
|
* @type {Generator[]}
|
|
245
356
|
*/
|
|
246
|
-
let presetGenerators = readGenerators(
|
|
357
|
+
let presetGenerators = readGenerators(pgenChunk);
|
|
247
358
|
|
|
248
359
|
/**
|
|
249
360
|
* Read all the preset modulatorrs
|
|
250
361
|
* @type {Modulator[]}
|
|
251
362
|
*/
|
|
252
|
-
let presetModulators = readModulators(
|
|
363
|
+
let presetModulators = readModulators(pmodChunk);
|
|
364
|
+
|
|
365
|
+
const presets = readPresets(phdrChunk, this);
|
|
366
|
+
|
|
367
|
+
if (isExtended)
|
|
368
|
+
{
|
|
369
|
+
// apply extensions to presets
|
|
370
|
+
const xPreset = readPresets(xChunks.phdr, this);
|
|
371
|
+
if (xPreset.length === presets.length)
|
|
372
|
+
{
|
|
373
|
+
presets.forEach((pres, i) =>
|
|
374
|
+
{
|
|
375
|
+
pres.presetName += xPreset[i].presetName;
|
|
376
|
+
pres.zoneStartIndex |= xPreset[i].zoneStartIndex;
|
|
377
|
+
});
|
|
378
|
+
// adjust zone counts
|
|
379
|
+
presets.forEach((preset, i) =>
|
|
380
|
+
{
|
|
381
|
+
if (i < instruments.length - 1)
|
|
382
|
+
{
|
|
383
|
+
preset.zonesCount = presets[i + 1].zoneStartIndex - preset.zoneStartIndex;
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// trim names
|
|
391
|
+
presets.forEach(p => p.presetName === p.presetName.trim());
|
|
392
|
+
this.addPresets(...presets);
|
|
253
393
|
|
|
254
|
-
|
|
394
|
+
const pbagIndexes = readZoneIndexes(pbagChunk);
|
|
255
395
|
|
|
256
|
-
|
|
396
|
+
if (isExtended)
|
|
397
|
+
{
|
|
398
|
+
const extraIndexes = readZoneIndexes(xChunks.pbag);
|
|
399
|
+
for (let i = 0; i < pbagIndexes.mod.length; i++)
|
|
400
|
+
{
|
|
401
|
+
pbagIndexes.mod[i] |= extraIndexes.mod[i] << 16;
|
|
402
|
+
}
|
|
403
|
+
for (let i = 0; i < pbagIndexes.gen.length; i++)
|
|
404
|
+
{
|
|
405
|
+
pbagIndexes.gen[i] |= extraIndexes.gen[i] << 16;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
applyPresetZones(pbagIndexes, presetGenerators, presetModulators, this.instruments, this.presets);
|
|
257
410
|
this.flush();
|
|
258
411
|
SpessaSynthInfo(
|
|
259
412
|
`%cParsing finished! %c"${this.soundFontInfo["INAM"]}"%c has %c${this.presets.length} %cpresets,
|
|
@@ -269,11 +422,6 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
269
422
|
consoleColors.info
|
|
270
423
|
);
|
|
271
424
|
SpessaSynthGroupEnd();
|
|
272
|
-
|
|
273
|
-
if (isSF2Pack)
|
|
274
|
-
{
|
|
275
|
-
delete this.dataArray;
|
|
276
|
-
}
|
|
277
425
|
}
|
|
278
426
|
|
|
279
427
|
/**
|
|
@@ -301,10 +449,4 @@ export class SoundFont2 extends BasicSoundBank
|
|
|
301
449
|
this.parsingError(`Invalid FourCC: Expected "${expected.toLowerCase()}" got "${text.toLowerCase()}"\``);
|
|
302
450
|
}
|
|
303
451
|
}
|
|
304
|
-
|
|
305
|
-
destroySoundBank()
|
|
306
|
-
{
|
|
307
|
-
super.destroySoundBank();
|
|
308
|
-
delete this.dataArray;
|
|
309
|
-
}
|
|
310
452
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param zonesChunk {RiffChunk} both pbag and ibag work
|
|
6
|
+
* @returns {{mod: number[], gen: number[]}}
|
|
7
|
+
*/
|
|
8
|
+
export function readZoneIndexes(zonesChunk)
|
|
9
|
+
{
|
|
10
|
+
/**
|
|
11
|
+
* @type {number[]}
|
|
12
|
+
*/
|
|
13
|
+
const modStartIndexes = [];
|
|
14
|
+
/**
|
|
15
|
+
* @type {number[]}
|
|
16
|
+
*/
|
|
17
|
+
const genStartIndexes = [];
|
|
18
|
+
|
|
19
|
+
while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
|
|
20
|
+
{
|
|
21
|
+
genStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
|
|
22
|
+
modStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
mod: modStartIndexes,
|
|
26
|
+
gen: genStartIndexes
|
|
27
|
+
};
|
|
28
|
+
}
|