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.
Files changed (26) hide show
  1. package/package.json +1 -1
  2. package/src/soundfont/basic_soundfont/basic_instrument.js +21 -2
  3. package/src/soundfont/basic_soundfont/basic_instrument_zone.js +1 -1
  4. package/src/soundfont/basic_soundfont/basic_sample.js +48 -17
  5. package/src/soundfont/basic_soundfont/basic_soundbank.js +18 -15
  6. package/src/soundfont/basic_soundfont/riff_chunk.js +4 -1
  7. package/src/soundfont/basic_soundfont/write_dls/wave.js +1 -1
  8. package/src/soundfont/basic_soundfont/write_sf2/ibag.js +28 -10
  9. package/src/soundfont/basic_soundfont/write_sf2/igen.js +26 -11
  10. package/src/soundfont/basic_soundfont/write_sf2/imod.js +28 -14
  11. package/src/soundfont/basic_soundfont/write_sf2/inst.js +28 -10
  12. package/src/soundfont/basic_soundfont/write_sf2/pbag.js +26 -11
  13. package/src/soundfont/basic_soundfont/write_sf2/pgen.js +25 -11
  14. package/src/soundfont/basic_soundfont/write_sf2/phdr.js +45 -20
  15. package/src/soundfont/basic_soundfont/write_sf2/pmod.js +28 -14
  16. package/src/soundfont/basic_soundfont/write_sf2/shdr.js +28 -5
  17. package/src/soundfont/basic_soundfont/write_sf2/write.js +53 -14
  18. package/src/soundfont/dls/dls_sample.js +179 -18
  19. package/src/soundfont/dls/read_samples.js +7 -123
  20. package/src/soundfont/read_sf2/instrument_zones.js +4 -17
  21. package/src/soundfont/read_sf2/instruments.js +1 -1
  22. package/src/soundfont/read_sf2/preset_zones.js +6 -19
  23. package/src/soundfont/read_sf2/presets.js +0 -1
  24. package/src/soundfont/read_sf2/samples.js +115 -106
  25. package/src/soundfont/read_sf2/soundfont.js +198 -56
  26. package/src/soundfont/read_sf2/zones.js +28 -0
@@ -10,101 +10,6 @@ import { consoleColors } from "../../utils/other.js";
10
10
  import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
11
11
  import { DLSSample } from "./dls_sample.js";
12
12
 
13
- const W_FORMAT_TAG = {
14
- PCM: 0x01,
15
- ALAW: 0x6
16
- };
17
-
18
- /**
19
- * @param dataChunk {RiffChunk}
20
- * @param bytesPerSample {number}
21
- * @returns {Float32Array}
22
- */
23
- function readPCM(dataChunk, bytesPerSample)
24
- {
25
- const maxSampleValue = Math.pow(2, bytesPerSample * 8 - 1); // Max value for the sample
26
- const maxUnsigned = Math.pow(2, bytesPerSample * 8);
27
-
28
- let normalizationFactor;
29
- let isUnsigned = false;
30
-
31
- if (bytesPerSample === 1)
32
- {
33
- normalizationFactor = 255; // For 8-bit normalize from 0-255
34
- isUnsigned = true;
35
- }
36
- else
37
- {
38
- normalizationFactor = maxSampleValue; // For 16-bit normalize from -32,768 to 32,767
39
- }
40
- const sampleLength = dataChunk.size / bytesPerSample;
41
- const sampleData = new Float32Array(sampleLength);
42
- for (let i = 0; i < sampleData.length; i++)
43
- {
44
- // read
45
- let sample = readLittleEndian(dataChunk.chunkData, bytesPerSample);
46
- // turn into signed
47
- if (isUnsigned)
48
- {
49
- // normalize unsigned 8-bit sample
50
- sampleData[i] = (sample / normalizationFactor) - 0.5;
51
- }
52
- else
53
- {
54
- // normalize signed 16-bit sample
55
- if (sample >= maxSampleValue)
56
- {
57
- sample -= maxUnsigned;
58
- }
59
- sampleData[i] = sample / normalizationFactor;
60
- }
61
- }
62
- return sampleData;
63
- }
64
-
65
- /**
66
- * @param dataChunk {RiffChunk}
67
- * @param bytesPerSample {number}
68
- * @returns {Float32Array}
69
- */
70
- function readALAW(dataChunk, bytesPerSample)
71
- {
72
- const sampleLength = dataChunk.size / bytesPerSample;
73
- const sampleData = new Float32Array(sampleLength);
74
- for (let i = 0; i < sampleData.length; i++)
75
- {
76
- // read
77
- const input = readLittleEndian(dataChunk.chunkData, bytesPerSample);
78
-
79
- // https://en.wikipedia.org/wiki/G.711#A-law
80
- // re-toggle toggled bits
81
- let sample = input ^ 0x55;
82
-
83
- // remove sign bit
84
- sample &= 0x7F;
85
-
86
- // extract exponent
87
- let exponent = sample >> 4;
88
- // extract mantissa
89
- let mantissa = sample & 0xF;
90
- if (exponent > 0)
91
- {
92
- mantissa += 16; // add leading '1', if exponent > 0
93
- }
94
-
95
- mantissa = (mantissa << 4) + 0x8;
96
- if (exponent > 1)
97
- {
98
- mantissa = mantissa << (exponent - 1);
99
- }
100
-
101
- const s16sample = input > 127 ? mantissa : -mantissa;
102
-
103
- // convert to float
104
- sampleData[i] = s16sample / 32678;
105
- }
106
- return sampleData;
107
- }
108
13
 
109
14
  /**
110
15
  * @this {DLSSoundFont}
@@ -138,7 +43,7 @@ export function readDLSSamples(waveListChunk)
138
43
  throw new Error("No fmt chunk in the wave file!");
139
44
  }
140
45
  // https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.14393.0/shared/mmreg.h#L2108
141
- const waveFormat = readLittleEndian(fmtChunk.chunkData, 2);
46
+ const wFormatTag = readLittleEndian(fmtChunk.chunkData, 2);
142
47
  const channelsAmount = readLittleEndian(fmtChunk.chunkData, 2);
143
48
  if (channelsAmount !== 1)
144
49
  {
@@ -153,30 +58,11 @@ export function readDLSSamples(waveListChunk)
153
58
  const wBitsPerSample = readLittleEndian(fmtChunk.chunkData, 2);
154
59
  const bytesPerSample = wBitsPerSample / 8;
155
60
 
156
- // read the data
157
- let failed = false;
158
61
  const dataChunk = waveChunks.find(c => c.header === "data");
159
62
  if (!dataChunk)
160
63
  {
161
64
  this.parsingError("No data chunk in the WAVE chunk!");
162
65
  }
163
- let sampleData;
164
- switch (waveFormat)
165
- {
166
- default:
167
- failed = true;
168
- sampleData = new Float32Array(dataChunk.size / bytesPerSample);
169
- break;
170
-
171
- case W_FORMAT_TAG.PCM:
172
- sampleData = readPCM(dataChunk, bytesPerSample);
173
- break;
174
-
175
- case W_FORMAT_TAG.ALAW:
176
- sampleData = readALAW(dataChunk, bytesPerSample);
177
- break;
178
-
179
- }
180
66
 
181
67
  // read sample name
182
68
  const waveInfo = findRIFFListType(waveChunks, "INFO");
@@ -198,7 +84,8 @@ export function readDLSSamples(waveListChunk)
198
84
  let sampleKey = 60;
199
85
  let samplePitch = 0;
200
86
  let sampleLoopStart = 0;
201
- let sampleLoopEnd = sampleData.length - 1;
87
+ const sampleLength = dataChunk.size / bytesPerSample;
88
+ let sampleLoopEnd = sampleLength - 1;
202
89
  let sampleDbAttenuation = 0;
203
90
 
204
91
  // read wsmp
@@ -242,11 +129,6 @@ export function readDLSSamples(waveListChunk)
242
129
  SpessaSynthWarn("No wsmp chunk in wave... using sane defaults.");
243
130
  }
244
131
 
245
- if (failed)
246
- {
247
- console.error(`Failed to load '${sampleName}': Unsupported format: (${waveFormat})`);
248
- }
249
-
250
132
  this.samples.push(new DLSSample(
251
133
  sampleName,
252
134
  sampleRate,
@@ -254,8 +136,10 @@ export function readDLSSamples(waveListChunk)
254
136
  samplePitch,
255
137
  sampleLoopStart,
256
138
  sampleLoopEnd,
257
- sampleData,
258
- sampleDbAttenuation
139
+ sampleDbAttenuation,
140
+ dataChunk,
141
+ wFormatTag,
142
+ bytesPerSample
259
143
  ));
260
144
 
261
145
 
@@ -4,7 +4,6 @@
4
4
  */
5
5
  import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
6
6
  import { generatorTypes } from "../basic_soundfont/generator_types.js";
7
- import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
8
7
 
9
8
  export class InstrumentZone extends BasicInstrumentZone
10
9
  {
@@ -33,28 +32,16 @@ export class InstrumentZone extends BasicInstrumentZone
33
32
 
34
33
  /**
35
34
  * Reads the given instrument zone
36
- * @param zonesChunk {RiffChunk}
35
+ * @param indexes {{mod: number[], gen: number[]}}
37
36
  * @param instrumentGenerators {Generator[]}
38
37
  * @param instrumentModulators {Modulator[]}
39
38
  * @param samples {BasicSample[]}
40
39
  * @param instruments {Instrument[]}
41
40
  */
42
- export function readInstrumentZones(zonesChunk, instrumentGenerators, instrumentModulators, samples, instruments)
41
+ export function applyInstrumentZones(indexes, instrumentGenerators, instrumentModulators, samples, instruments)
43
42
  {
44
- /**
45
- * @type {number[]}
46
- */
47
- const modStartIndexes = [];
48
- /**
49
- * @type {number[]}
50
- */
51
- const genStartIndexes = [];
52
-
53
- while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
54
- {
55
- genStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
56
- modStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
57
- }
43
+ const genStartIndexes = indexes.gen;
44
+ const modStartIndexes = indexes.mod;
58
45
 
59
46
  let modIndex = 0;
60
47
  let genIndex = 0;
@@ -28,7 +28,7 @@ export class Instrument extends BasicInstrument
28
28
  constructor(instrumentChunk)
29
29
  {
30
30
  super();
31
- this.instrumentName = readBytesAsString(instrumentChunk.chunkData, 20).trim();
31
+ this.instrumentName = readBytesAsString(instrumentChunk.chunkData, 20);
32
32
  this.zoneStartIndex = readLittleEndian(instrumentChunk.chunkData, 2);
33
33
  }
34
34
 
@@ -1,5 +1,3 @@
1
- import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
2
- import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
3
1
  import { BasicPresetZone } from "../basic_soundfont/basic_preset_zone.js";
4
2
  import { Generator } from "../basic_soundfont/generator.js";
5
3
  import { Modulator } from "../basic_soundfont/modulator.js";
@@ -35,30 +33,19 @@ export class PresetZone extends BasicPresetZone
35
33
  }
36
34
  }
37
35
 
36
+
38
37
  /**
39
- * Reads the given preset zone read
40
- * @param zonesChunk {RiffChunk}
38
+ * Reads the given preset zone
39
+ * @param indexes {{mod: number[], gen: number[]}}
41
40
  * @param presetGens {Generator[]}
42
41
  * @param instruments {BasicInstrument[]}
43
42
  * @param presetMods {Modulator[]}
44
43
  * @param presets {Preset[]}
45
44
  */
46
- export function readPresetZones(zonesChunk, presetGens, presetMods, instruments, presets)
45
+ export function applyPresetZones(indexes, presetGens, presetMods, instruments, presets)
47
46
  {
48
- /**
49
- * @type {number[]}
50
- */
51
- const modStartIndexes = [];
52
- /**
53
- * @type {number[]}
54
- */
55
- const genStartIndexes = [];
56
-
57
- while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
58
- {
59
- genStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
60
- modStartIndexes.push(readLittleEndian(zonesChunk.chunkData, 2));
61
- }
47
+ const genStartIndexes = indexes.gen;
48
+ const modStartIndexes = indexes.mod;
62
49
 
63
50
  let modIndex = 0;
64
51
  let genIndex = 0;
@@ -29,7 +29,6 @@ export class Preset extends BasicPreset
29
29
  {
30
30
  super(sf2);
31
31
  this.presetName = readBytesAsString(presetChunk.chunkData, 20)
32
- .trim()
33
32
  .replace(/\d{3}:\d{3}/, ""); // remove those pesky "000:001"
34
33
 
35
34
  this.program = readLittleEndian(presetChunk.chunkData, 2);
@@ -16,6 +16,23 @@ export class SoundFontSample extends BasicSample
16
16
  */
17
17
  linkedSampleIndex;
18
18
 
19
+ /**
20
+ * The handle to the core sf2 file for dynamic sample reading
21
+ * @type {Uint8Array}
22
+ */
23
+ sf2FileArrayHandle;
24
+
25
+ /**
26
+ * Start index of the sample in the file byte array
27
+ * @type {number}
28
+ */
29
+ s16leStart = 0;
30
+ /**
31
+ * End index of the sample in the file byte array
32
+ * @type {number}
33
+ */
34
+ s16leEnd = 0;
35
+
19
36
  /**
20
37
  * Creates a sample
21
38
  * @param sampleName {string}
@@ -28,9 +45,8 @@ export class SoundFontSample extends BasicSample
28
45
  * @param samplePitchCorrection {number}
29
46
  * @param linkedSampleIndex {number}
30
47
  * @param sampleType {number}
31
- * @param smplArr {IndexedByteArray|Float32Array}
48
+ * @param sampleDataArray {IndexedByteArray|Float32Array}
32
49
  * @param sampleIndex {number} initial sample index when loading the sfont
33
- * @param isDataRaw {boolean} if false, the data is decoded as float32.
34
50
  * Used for SF2Pack support
35
51
  */
36
52
  constructor(
@@ -44,9 +60,8 @@ export class SoundFontSample extends BasicSample
44
60
  samplePitchCorrection,
45
61
  linkedSampleIndex,
46
62
  sampleType,
47
- smplArr,
48
- sampleIndex,
49
- isDataRaw
63
+ sampleDataArray,
64
+ sampleIndex
50
65
  )
51
66
  {
52
67
  // read sf3
@@ -68,20 +83,47 @@ export class SoundFontSample extends BasicSample
68
83
  // in bytes
69
84
  this.sampleStartIndex = sampleStartIndex;
70
85
  this.sampleEndIndex = sampleEndIndex;
71
- this.isSampleLoaded = false;
72
86
  this.sampleID = sampleIndex;
73
87
  // in bytes
74
88
  this.sampleLength = this.sampleEndIndex - this.sampleStartIndex;
75
- this.sampleDataArray = smplArr;
76
- this.sampleData = new Float32Array(0);
89
+ const smplStart = sampleDataArray.currentIndex;
90
+
91
+ // three data types in:
92
+ // SF2 (s16le)
93
+ // SF3 (vorbis)
94
+ // SF2Pack (
77
95
  if (this.isCompressed)
78
96
  {
79
97
  // correct loop points
80
98
  this.sampleLoopStartIndex += this.sampleStartIndex / 2;
81
99
  this.sampleLoopEndIndex += this.sampleStartIndex / 2;
82
100
  this.sampleLength = 99999999; // set to 999,999 before we decode it
101
+
102
+ // copy the compressed data, it can be preserved during writing
103
+ this.compressedData = sampleDataArray.slice(
104
+ this.sampleStartIndex / 2 + smplStart,
105
+ this.sampleEndIndex / 2 + smplStart
106
+ );
107
+ }
108
+ else
109
+ {
110
+ if (sampleDataArray instanceof Float32Array)
111
+ {
112
+ // float32 array from SF2pack, copy directly
113
+ this.sampleData = sampleDataArray.slice(
114
+ this.sampleStartIndex / 2,
115
+ this.sampleEndIndex / 2
116
+ );
117
+ }
118
+ else
119
+ {
120
+ // regular sf2 s16le
121
+ this.s16leStart = smplStart + this.sampleStartIndex;
122
+ this.s16leEnd = smplStart + this.sampleEndIndex;
123
+ this.sf2FileArrayHandle = sampleDataArray;
124
+ }
125
+
83
126
  }
84
- this.isDataRaw = isDataRaw;
85
127
  this.linkedSampleIndex = linkedSampleIndex;
86
128
  }
87
129
 
@@ -98,66 +140,49 @@ export class SoundFontSample extends BasicSample
98
140
  }
99
141
 
100
142
  /**
101
- * Get raw data, whether it's compressed or not as we simply write it to the file
102
- * @return {Uint8Array} either s16 or vorbis data
103
- */
104
- getRawData()
105
- {
106
- const smplArr = this.sampleDataArray;
107
- if (this.isCompressed)
108
- {
109
- if (this.compressedData)
110
- {
111
- return this.compressedData;
112
- }
113
- const smplStart = smplArr.currentIndex;
114
- return smplArr.slice(this.sampleStartIndex / 2 + smplStart, this.sampleEndIndex / 2 + smplStart);
115
- }
116
- else
117
- {
118
- if (!this.isDataRaw)
119
- {
120
- // encode the f32 into s16 manually
121
- super.getRawData();
122
- }
123
- const dataStartIndex = smplArr.currentIndex;
124
- return smplArr.slice(dataStartIndex + this.sampleStartIndex, dataStartIndex + this.sampleEndIndex);
125
- }
126
- }
127
-
128
- /**
143
+ * @private
129
144
  * Decode binary vorbis into a float32 pcm
145
+ * @returns {Float32Array}
130
146
  */
131
147
  decodeVorbis()
132
148
  {
149
+ if (this.sampleData)
150
+ {
151
+ return this.sampleData;
152
+ }
133
153
  if (this.sampleLength < 1)
134
154
  {
135
155
  // eos, do not do anything
136
- return;
156
+ return new Float32Array(0);
137
157
  }
138
158
  // get the compressed byte stream
139
- const smplArr = this.sampleDataArray;
140
- const smplStart = smplArr.currentIndex;
141
- const buff = smplArr.slice(this.sampleStartIndex / 2 + smplStart, this.sampleEndIndex / 2 + smplStart);
142
159
  // reset array and being decoding
143
- this.sampleData = new Float32Array(0);
144
160
  try
145
161
  {
146
162
  /**
147
163
  * @type {{data: Float32Array[], error: (string|null), sampleRate: number, eof: boolean}}
148
164
  */
149
- const vorbis = stbvorbis.decode(buff.buffer);
150
- this.sampleData = vorbis.data[0];
151
- if (this.sampleData === undefined)
165
+ const vorbis = stbvorbis.decode(this.compressedData);
166
+ const decoded = vorbis.data[0];
167
+ if (decoded === undefined)
152
168
  {
153
169
  SpessaSynthWarn(`Error decoding sample ${this.sampleName}: Vorbis decode returned undefined.`);
170
+ return new Float32Array(0);
154
171
  }
172
+ // clip
173
+ // because vorbis can go above 1 sometimes
174
+ for (let i = 0; i < decoded.length; i++)
175
+ {
176
+ // magic number is 32,767 / 32,768
177
+ decoded[i] = Math.max(-1, Math.min(decoded[i], 0.999969482421875));
178
+ }
179
+ return decoded;
155
180
  }
156
181
  catch (e)
157
182
  {
158
183
  // do not error out, fill with silence
159
184
  SpessaSynthWarn(`Error decoding sample ${this.sampleName}: ${e}`);
160
- this.sampleData = new Float32Array(this.sampleLoopEndIndex + 1);
185
+ return new Float32Array(this.sampleLoopEndIndex + 1);
161
186
  }
162
187
  }
163
188
 
@@ -167,8 +192,6 @@ export class SoundFontSample extends BasicSample
167
192
  setAudioData(audioData)
168
193
  {
169
194
  super.setAudioData(audioData);
170
- this.isSampleLoaded = true;
171
- this.isDataRaw = false;
172
195
  }
173
196
 
174
197
  /**
@@ -177,48 +200,31 @@ export class SoundFontSample extends BasicSample
177
200
  */
178
201
  getAudioData()
179
202
  {
180
- if (!this.isSampleLoaded)
203
+ if (this.sampleData)
181
204
  {
182
- // start loading data if it is not loaded
183
- if (this.sampleLength < 1)
184
- {
185
- SpessaSynthWarn(`Invalid sample ${this.sampleName}! Invalid length: ${this.sampleLength}`);
186
- return new Float32Array(1);
187
- }
188
-
189
- if (this.isCompressed)
190
- {
191
- // if compressed, decode
192
- this.decodeVorbis();
193
- this.isSampleLoaded = true;
194
- return this.sampleData;
195
- }
196
- else if (!this.isDataRaw)
197
- {
198
- return this.getUncompressedReadyData();
199
- }
200
- return this.loadUncompressedData();
205
+ return this.sampleData;
201
206
  }
202
- return this.sampleData;
203
- }
204
-
205
- /**
206
- * @returns {Float32Array}
207
- */
208
- loadUncompressedData()
209
- {
210
- if (this.isCompressed)
207
+ // SF2Pack is decoded during load time
208
+
209
+ // start loading data if it is not loaded
210
+ if (this.sampleLength < 1)
211
211
  {
212
- SpessaSynthWarn("Trying to load a compressed sample via loadUncompressedData()... aborting!");
213
- return new Float32Array(0);
212
+ SpessaSynthWarn(`Invalid sample ${this.sampleName}! Invalid length: ${this.sampleLength}`);
213
+ return new Float32Array(1);
214
214
  }
215
215
 
216
+ if (this.isCompressed)
217
+ {
218
+ // SF3
219
+ // if compressed, decode
220
+ this.sampleData = this.decodeVorbis();
221
+ return this.sampleData;
222
+ }
223
+ // SF2
216
224
  // read the sample data
217
225
  let audioData = new Float32Array(this.sampleLength / 2);
218
- const dataStartIndex = this.sampleDataArray.currentIndex;
219
226
  let convertedSigned16 = new Int16Array(
220
- this.sampleDataArray.slice(dataStartIndex + this.sampleStartIndex, dataStartIndex + this.sampleEndIndex)
221
- .buffer
227
+ this.sf2FileArrayHandle.buffer.slice(this.s16leStart, this.s16leEnd)
222
228
  );
223
229
 
224
230
  // convert to float
@@ -228,26 +234,28 @@ export class SoundFontSample extends BasicSample
228
234
  }
229
235
 
230
236
  this.sampleData = audioData;
231
- this.isSampleLoaded = true;
232
237
  return audioData;
238
+
233
239
  }
234
240
 
235
241
  /**
236
- * @returns {Float32Array}
242
+ * @param allowVorbis
243
+ * @returns {Uint8Array}
237
244
  */
238
- getUncompressedReadyData()
245
+ getRawData(allowVorbis = true)
239
246
  {
240
- /**
241
- * read the sample data
242
- * @type {Float32Array}
243
- */
244
- let audioData = /**@type {Float32Array}*/ this.sampleDataArray.slice(
245
- this.sampleStartIndex / 2,
246
- this.sampleEndIndex / 2
247
- );
248
- this.sampleData = audioData;
249
- this.isSampleLoaded = true;
250
- return audioData;
247
+ if (this.dataOverriden)
248
+ {
249
+ return this.encodeS16LE();
250
+ }
251
+ else
252
+ {
253
+ if (this.compressedData && allowVorbis)
254
+ {
255
+ return this.compressedData;
256
+ }
257
+ return this.sf2FileArrayHandle.slice(this.s16leStart, this.s16leEnd);
258
+ }
251
259
  }
252
260
  }
253
261
 
@@ -255,10 +263,10 @@ export class SoundFontSample extends BasicSample
255
263
  * Reads the generatorTranslator from the shdr read
256
264
  * @param sampleHeadersChunk {RiffChunk}
257
265
  * @param smplChunkData {IndexedByteArray|Float32Array}
258
- * @param isSmplDataRaw {boolean}
266
+ * @param linkSamples {boolean}
259
267
  * @returns {SoundFontSample[]}
260
268
  */
261
- export function readSamples(sampleHeadersChunk, smplChunkData, isSmplDataRaw = true)
269
+ export function readSamples(sampleHeadersChunk, smplChunkData, linkSamples = true)
262
270
  {
263
271
  /**
264
272
  * @type {SoundFontSample[]}
@@ -267,7 +275,7 @@ export function readSamples(sampleHeadersChunk, smplChunkData, isSmplDataRaw = t
267
275
  let index = 0;
268
276
  while (sampleHeadersChunk.chunkData.length > sampleHeadersChunk.chunkData.currentIndex)
269
277
  {
270
- const sample = readSample(index, sampleHeadersChunk.chunkData, smplChunkData, isSmplDataRaw);
278
+ const sample = readSample(index, sampleHeadersChunk.chunkData, smplChunkData);
271
279
  samples.push(sample);
272
280
  index++;
273
281
  }
@@ -275,7 +283,10 @@ export function readSamples(sampleHeadersChunk, smplChunkData, isSmplDataRaw = t
275
283
  samples.pop();
276
284
 
277
285
  // link samples
278
- samples.forEach(s => s.getLinkedSample(samples));
286
+ if (linkSamples)
287
+ {
288
+ samples.forEach(s => s.getLinkedSample(samples));
289
+ }
279
290
 
280
291
  return samples;
281
292
  }
@@ -285,10 +296,9 @@ export function readSamples(sampleHeadersChunk, smplChunkData, isSmplDataRaw = t
285
296
  * @param index {number}
286
297
  * @param sampleHeaderData {IndexedByteArray}
287
298
  * @param smplArrayData {IndexedByteArray|Float32Array}
288
- * @param isDataRaw {boolean} true means binary 16-bit data, false means float32
289
299
  * @returns {SoundFontSample}
290
300
  */
291
- function readSample(index, sampleHeaderData, smplArrayData, isDataRaw)
301
+ function readSample(index, sampleHeaderData, smplArrayData)
292
302
  {
293
303
 
294
304
  // read the sample name
@@ -311,9 +321,9 @@ function readSample(index, sampleHeaderData, smplArrayData, isDataRaw)
311
321
 
312
322
  // read the original sample pitch
313
323
  let samplePitch = sampleHeaderData[sampleHeaderData.currentIndex++];
314
- if (samplePitch === 255)
324
+ if (samplePitch > 127)
315
325
  {
316
- // if it's 255, then default to 60
326
+ // if it's out of range, then default to 60
317
327
  samplePitch = 60;
318
328
  }
319
329
 
@@ -338,7 +348,6 @@ function readSample(index, sampleHeaderData, smplArrayData, isDataRaw)
338
348
  sampleLink,
339
349
  sampleType,
340
350
  smplArrayData,
341
- index,
342
- isDataRaw
351
+ index
343
352
  );
344
353
  }