spessasynth_lib 3.22.7 → 3.22.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spessasynth_lib",
3
- "version": "3.22.7",
3
+ "version": "3.22.8",
4
4
  "description": "MIDI and SoundFont2/DLS library with no compromises",
5
5
  "browser": "index.js",
6
6
  "types": "@types/index.d.ts",
@@ -4,6 +4,7 @@ import { midiControllers } from "../../midi_parser/midi_message.js";
4
4
  import { DLSDestinations } from "./dls_destinations.js";
5
5
 
6
6
  import { generatorTypes } from "../basic_soundfont/generator.js";
7
+ import { consoleColors } from "../../utils/other.js";
7
8
 
8
9
  /**
9
10
  * @param source {number}
@@ -174,6 +175,48 @@ function checkForSpecialDLSCombo(source, destination)
174
175
  }
175
176
  }
176
177
 
178
+ /**
179
+ * @param source {number}
180
+ * @param control {number}
181
+ * @param destination {number}
182
+ * @param value {number}
183
+ * @param transform {number}
184
+ */
185
+ function modulatorConverterDebug(
186
+ source,
187
+ control,
188
+ destination,
189
+ value,
190
+ transform
191
+ )
192
+ {
193
+ const type = Object.keys(DLSDestinations).find(k => DLSDestinations[k] === destination);
194
+ const srcType = Object.keys(DLSSources).find(k => DLSSources[k] === source);
195
+ const ctrlType = Object.keys(DLSSources).find(k => DLSSources[k] === control);
196
+ const typeString = type ? type : destination.toString(16);
197
+ const srcString = srcType ? srcType : source.toString(16);
198
+ const ctrlString = ctrlType ? ctrlType : control.toString(16);
199
+ console.debug(
200
+ `%cAttempting to convert the following DLS Articulator to SF2 Modulator:
201
+ Source: %c${srcString}%c
202
+ Control: %c${ctrlString}%c
203
+ Destination: %c${typeString}%c
204
+ Amount: %c${value}%c
205
+ Transform: %c${transform}%c...`,
206
+ consoleColors.info,
207
+ consoleColors.recognized,
208
+ consoleColors.info,
209
+ consoleColors.recognized,
210
+ consoleColors.info,
211
+ consoleColors.recognized,
212
+ consoleColors.info,
213
+ consoleColors.recognized,
214
+ consoleColors.info,
215
+ consoleColors.recognized,
216
+ consoleColors.info
217
+ );
218
+ }
219
+
177
220
  /**
178
221
  * @param source {number}
179
222
  * @param control {number}
@@ -202,6 +245,7 @@ export function getSF2ModulatorFromArticulator(
202
245
  let sf2Source;
203
246
  let swapSources = false;
204
247
  let isSourceNoController = false;
248
+ let newValue = value;
205
249
  if (specialDestination === undefined)
206
250
  {
207
251
  // determine destination
@@ -217,7 +261,7 @@ export function getSF2ModulatorFromArticulator(
217
261
  destinationGenerator = sf2GenDestination;
218
262
  if (sf2GenDestination.newAmount !== undefined)
219
263
  {
220
- value = sf2GenDestination.newAmount;
264
+ newValue = sf2GenDestination.newAmount;
221
265
  destinationGenerator = sf2GenDestination.gen;
222
266
  }
223
267
  sf2Source = getSF2SourceFromDLS(source);
@@ -263,10 +307,22 @@ export function getSF2ModulatorFromArticulator(
263
307
  }
264
308
  const sourceIsBipolar = (transform >> 14) & 1;
265
309
  let sourceIsNegative = (transform >> 15) & 1;
266
- // special case: for attenuation, invert source
310
+ // special case: for attenuation, invert source (dls gain is the opposite of sf2 attenuation)
267
311
  if (destinationGenerator === generatorTypes.initialAttenuation)
268
312
  {
269
- sourceIsNegative = !sourceIsNegative;
313
+ // modulatorConverterDebug(
314
+ // source,
315
+ // control,
316
+ // destination,
317
+ // value,
318
+ // transform
319
+ // );
320
+ // invert only if the actual transform value is not negative.
321
+ // if it is, it's already inverted
322
+ if (value > 0)
323
+ {
324
+ sourceIsNegative = !sourceIsNegative;
325
+ }
270
326
  }
271
327
  sourceEnumFinal = getModSourceEnum(
272
328
  sourceTransform,
@@ -301,7 +357,7 @@ export function getSF2ModulatorFromArticulator(
301
357
  secSrcEnum: secSourceEnumFinal,
302
358
  dest: destinationGenerator,
303
359
  transform: 0x0,
304
- amt: value
360
+ amt: newValue
305
361
  });
306
362
 
307
363
  }
@@ -7,47 +7,6 @@ import { consoleColors } from "../../utils/other.js";
7
7
  import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
8
8
  import { Modulator } from "../basic_soundfont/modulator.js";
9
9
 
10
- /**
11
- * @param source {number}
12
- * @param control {number}
13
- * @param destination {number}
14
- * @param value {number}
15
- * @param transform {number}
16
- */
17
- function modulatorConverterDebug(
18
- source,
19
- control,
20
- destination,
21
- value,
22
- transform
23
- )
24
- {
25
- const type = Object.keys(DLSDestinations).find(k => DLSDestinations[k] === destination);
26
- const srcType = Object.keys(DLSSources).find(k => DLSSources[k] === source);
27
- const ctrlType = Object.keys(DLSSources).find(k => DLSSources[k] === control);
28
- const typeString = type ? type : destination.toString(16);
29
- const srcString = srcType ? srcType : source.toString(16);
30
- const ctrlString = ctrlType ? ctrlType : control.toString(16);
31
- SpessaSynthInfo(
32
- `%cAttempting to convert the following DLS Articulator to SF2 Modulator:
33
- Source: %c${srcString}%c
34
- Control: %c${ctrlString}%c
35
- Destination: %c${typeString}%c
36
- Amount: %c${value}%c
37
- Transform: %c${transform}%c...`,
38
- consoleColors.info,
39
- consoleColors.recognized,
40
- consoleColors.info,
41
- consoleColors.recognized,
42
- consoleColors.info,
43
- consoleColors.recognized,
44
- consoleColors.info,
45
- consoleColors.recognized,
46
- consoleColors.info,
47
- consoleColors.recognized,
48
- consoleColors.info
49
- );
50
- }
51
10
 
52
11
  /**
53
12
  * Reads the articulator chunk
@@ -80,7 +39,6 @@ export function readArticulation(chunk, disableVibrato)
80
39
  const scale = readLittleEndian(artData, 4) | 0;
81
40
  const value = scale >> 16; // convert it to 16 bit as soundfont uses that
82
41
 
83
- // modulatorConverterDebug(source, control, destination, value, transform);
84
42
  // interpret this somehow...
85
43
  // if source and control are both zero, it's a generator
86
44
  if (source === 0 && control === 0 && transform === 0)
@@ -10,6 +10,102 @@ 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 -32768 to 32767
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
  * @this {DLSSoundFont}
15
111
  * @param waveListChunk {RiffChunk}
@@ -43,10 +139,6 @@ export function readDLSSamples(waveListChunk)
43
139
  }
44
140
  // https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.14393.0/shared/mmreg.h#L2108
45
141
  const waveFormat = readLittleEndian(fmtChunk.chunkData, 2);
46
- if (waveFormat !== 1)
47
- {
48
- throw new Error(`Only PCM format in WAVE is supported. Fmt reports ${waveFormat}`);
49
- }
50
142
  const channelsAmount = readLittleEndian(fmtChunk.chunkData, 2);
51
143
  if (channelsAmount !== 1)
52
144
  {
@@ -61,48 +153,30 @@ export function readDLSSamples(waveListChunk)
61
153
  const wBitsPerSample = readLittleEndian(fmtChunk.chunkData, 2);
62
154
  const bytesPerSample = wBitsPerSample / 8;
63
155
 
64
- const maxSampleValue = Math.pow(2, bytesPerSample * 8 - 1); // Max value for the sample
65
- const maxUnsigned = Math.pow(2, bytesPerSample * 8);
66
-
67
- let normalizationFactor;
68
- let isUnsigned = false;
69
-
70
- if (wBitsPerSample === 8)
71
- {
72
- normalizationFactor = 255; // For 8-bit normalize from 0-255
73
- isUnsigned = true;
74
- }
75
- else
76
- {
77
- normalizationFactor = maxSampleValue; // For 16-bit normalize from -32768 to 32767
78
- }
79
156
  // read the data
157
+ let failed = false;
80
158
  const dataChunk = waveChunks.find(c => c.header === "data");
81
159
  if (!dataChunk)
82
160
  {
83
161
  this.parsingError("No data chunk in the WAVE chunk!");
84
162
  }
85
- const sampleLength = dataChunk.size / bytesPerSample;
86
- const sampleData = new Float32Array(sampleLength);
87
- for (let i = 0; i < sampleData.length; i++)
163
+ let sampleData;
164
+ switch (waveFormat)
88
165
  {
89
- // read
90
- let sample = readLittleEndian(dataChunk.chunkData, bytesPerSample);
91
- // turn into signed
92
- if (isUnsigned)
93
- {
94
- // normalize unsigned 8-bit sample
95
- sampleData[i] = (sample / normalizationFactor) - 0.5;
96
- }
97
- else
98
- {
99
- // normalize signed 16-bit sample
100
- if (sample >= maxSampleValue)
101
- {
102
- sample -= maxUnsigned;
103
- }
104
- sampleData[i] = sample / normalizationFactor;
105
- }
166
+ default:
167
+ failed = true;
168
+ sampleData = new Float32Array(dataChunk.size / bytesPerSample);
169
+ break;
170
+ //throw new Error(`Unsupported WAVE format. Fmt reports ${waveFormat}`);
171
+
172
+ case W_FORMAT_TAG.PCM:
173
+ sampleData = readPCM(dataChunk, bytesPerSample);
174
+ break;
175
+
176
+ case W_FORMAT_TAG.ALAW:
177
+ sampleData = readALAW(dataChunk, bytesPerSample);
178
+ break;
179
+
106
180
  }
107
181
 
108
182
  // sane defaults
@@ -162,13 +236,18 @@ export function readDLSSamples(waveListChunk)
162
236
  }
163
237
  }
164
238
 
239
+ if (failed)
240
+ {
241
+ console.error(`Failed to load '${sampleName}': Unsupported format: (${waveFormat})`);
242
+ }
243
+
165
244
  this.samples.push(new DLSSample(
166
245
  sampleName,
167
246
  sampleRate,
168
247
  sampleKey,
169
248
  samplePitch,
170
249
  sampleLoopStart,
171
- sampleLength,
250
+ sampleData.length,
172
251
  sampleData,
173
252
  sampleDbAttenuation
174
253
  ));