spessasynth_lib 3.17.0 → 3.20.0

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 (43) hide show
  1. package/@types/soundfont/basic_soundfont/basic_sample.d.ts +2 -2
  2. package/@types/soundfont/basic_soundfont/basic_zone.d.ts +12 -12
  3. package/@types/soundfont/basic_soundfont/basic_zones.d.ts +4 -0
  4. package/@types/soundfont/basic_soundfont/riff_chunk.d.ts +6 -0
  5. package/@types/soundfont/dls/articulator_converter.d.ts +10 -0
  6. package/@types/soundfont/dls/dls_destinations.d.ts +29 -0
  7. package/@types/soundfont/dls/dls_preset.d.ts +7 -5
  8. package/@types/soundfont/dls/dls_sample.d.ts +18 -0
  9. package/@types/soundfont/dls/dls_soundfont.d.ts +9 -2
  10. package/@types/soundfont/dls/dls_sources.d.ts +22 -0
  11. package/@types/soundfont/dls/dls_zone.d.ts +22 -0
  12. package/@types/soundfont/dls/read_articulation.d.ts +12 -0
  13. package/@types/soundfont/dls/read_instrument_list.d.ts +2 -2
  14. package/@types/soundfont/dls/read_lart.d.ts +7 -0
  15. package/@types/soundfont/dls/read_region.d.ts +7 -0
  16. package/@types/soundfont/dls/read_samples.d.ts +5 -0
  17. package/@types/soundfont/read_sf2/generators.d.ts +18 -5
  18. package/@types/soundfont/read_sf2/modulators.d.ts +1 -0
  19. package/README.md +10 -0
  20. package/midi_parser/midi_loader.js +30 -3
  21. package/package.json +1 -1
  22. package/soundfont/README.md +6 -2
  23. package/soundfont/basic_soundfont/basic_sample.js +3 -3
  24. package/soundfont/basic_soundfont/basic_zone.js +28 -28
  25. package/soundfont/basic_soundfont/basic_zones.js +15 -19
  26. package/soundfont/basic_soundfont/riff_chunk.js +18 -2
  27. package/soundfont/dls/articulator_converter.js +311 -0
  28. package/soundfont/dls/dls_destinations.js +38 -0
  29. package/soundfont/dls/dls_preset.js +15 -8
  30. package/soundfont/dls/dls_sample.js +58 -0
  31. package/soundfont/dls/dls_soundfont.js +68 -11
  32. package/soundfont/dls/dls_sources.js +26 -0
  33. package/soundfont/dls/dls_zone.js +75 -0
  34. package/soundfont/dls/read_articulation.js +327 -0
  35. package/soundfont/dls/read_instrument.js +82 -4
  36. package/soundfont/dls/read_instrument_list.js +6 -6
  37. package/soundfont/dls/read_lart.js +35 -0
  38. package/soundfont/dls/read_region.js +129 -0
  39. package/soundfont/dls/read_samples.js +174 -0
  40. package/soundfont/read_sf2/generators.js +41 -6
  41. package/soundfont/read_sf2/modulators.js +3 -3
  42. package/synthetizer/worklet_processor.min.js +10 -8
  43. package/utils/buffer_to_wav.js +5 -26
@@ -0,0 +1,311 @@
1
+ import { DLSSources } from './dls_sources.js'
2
+ import { getModSourceEnum, Modulator, modulatorCurveTypes, modulatorSources } from '../read_sf2/modulators.js'
3
+ import { midiControllers } from '../../midi_parser/midi_message.js'
4
+ import { DLSDestinations } from './dls_destinations.js'
5
+ import { generatorTypes } from '../read_sf2/generators.js'
6
+
7
+ /**
8
+ * @param source {number}
9
+ * @returns {{enum: number, isCC: boolean}|undefined}
10
+ */
11
+ function getSF2SourceFromDLS(source)
12
+ {
13
+ let sourceEnum = undefined;
14
+ let isCC = false;
15
+ switch(source)
16
+ {
17
+ default:
18
+ case DLSSources.modLfo:
19
+ case DLSSources.vibratoLfo:
20
+ case DLSSources.coarseTune:
21
+ case DLSSources.fineTune:
22
+ case DLSSources.modEnv:
23
+ return undefined; // cannot be this in sf2
24
+
25
+ case DLSSources.keyNum:
26
+ sourceEnum = modulatorSources.noteOnKeyNum;
27
+ break;
28
+ case DLSSources.none:
29
+ sourceEnum = modulatorSources.noController;
30
+ break;
31
+ case DLSSources.modulationWheel:
32
+ sourceEnum = midiControllers.modulationWheel;
33
+ isCC = true;
34
+ break;
35
+ case DLSSources.pan:
36
+ sourceEnum = midiControllers.pan;
37
+ isCC = true;
38
+ break;
39
+ case DLSSources.reverb:
40
+ sourceEnum = midiControllers.effects1Depth;
41
+ isCC = true;
42
+ break;
43
+ case DLSSources.chorus:
44
+ sourceEnum = midiControllers.effects3Depth;
45
+ isCC = true;
46
+ break;
47
+ case DLSSources.expression:
48
+ sourceEnum = midiControllers.expressionController;
49
+ isCC = true;
50
+ break;
51
+ case DLSSources.volume:
52
+ sourceEnum = midiControllers.mainVolume;
53
+ isCC = true;
54
+ break;
55
+ case DLSSources.velocity:
56
+ sourceEnum = modulatorSources.noteOnVelocity;
57
+ break;
58
+ case DLSSources.polyPressure:
59
+ sourceEnum = modulatorSources.polyPressure;
60
+ break;
61
+ case DLSSources.channelPressure:
62
+ sourceEnum = modulatorSources.channelPressure;
63
+ break;
64
+ case DLSSources.pitchWheel:
65
+ sourceEnum = modulatorSources.pitchWheel;
66
+ break;
67
+ case DLSSources.pitchWheelRange:
68
+ sourceEnum = modulatorSources.pitchWheelRange;
69
+ break;
70
+ }
71
+ if(sourceEnum === undefined)
72
+ {
73
+ throw `not known?? ${source}`
74
+ }
75
+ return {enum: sourceEnum, isCC: isCC};
76
+ }
77
+
78
+ /**
79
+ * @param destination {number}
80
+ * @param amount {number}
81
+ * @returns {generatorTypes|{gen: generatorTypes, newAmount: number}} // transform amount to sf2 units
82
+ */
83
+ function getSF2GeneratorFromDLS(destination, amount)
84
+ {
85
+ switch (destination)
86
+ {
87
+ default:
88
+ case DLSDestinations.none:
89
+ return undefined;
90
+ case DLSDestinations.pan:
91
+ return generatorTypes.pan;
92
+ case DLSDestinations.gain:
93
+ return {gen: generatorTypes.initialAttenuation, newAmount: amount * -1};
94
+ case DLSDestinations.pitch:
95
+ return generatorTypes.fineTune;
96
+ case DLSDestinations.keyNum:
97
+ return generatorTypes.overridingRootKey;
98
+
99
+ // vol env
100
+ case DLSDestinations.volEnvDelay:
101
+ return generatorTypes.delayVolEnv;
102
+ case DLSDestinations.volEnvAttack:
103
+ return generatorTypes.attackVolEnv;
104
+ case DLSDestinations.volEnvHold:
105
+ return generatorTypes.holdVolEnv;
106
+ case DLSDestinations.volEnvDecay:
107
+ return generatorTypes.decayVolEnv;
108
+ case DLSDestinations.volEnvSustain:
109
+ return {gen: generatorTypes.sustainVolEnv, newAmount: 1000 - amount};
110
+ case DLSDestinations.volEnvRelease:
111
+ return generatorTypes.releaseVolEnv;
112
+
113
+ // mod env
114
+ case DLSDestinations.modEnvDelay:
115
+ return generatorTypes.delayModEnv;
116
+ case DLSDestinations.modEnvAttack:
117
+ return generatorTypes.attackModEnv;
118
+ case DLSDestinations.modEnvHold:
119
+ return generatorTypes.holdModEnv;
120
+ case DLSDestinations.modEnvDecay:
121
+ return generatorTypes.decayModEnv;
122
+ case DLSDestinations.modEnvSustain:
123
+ return {gen: generatorTypes.sustainModEnv, newAmount: (1000 - amount) / 10};
124
+ case DLSDestinations.modEnvRelease:
125
+ return generatorTypes.releaseModEnv;
126
+
127
+ case DLSDestinations.filterCutoff:
128
+ return generatorTypes.initialFilterFc;
129
+ case DLSDestinations.filterQ:
130
+ return generatorTypes.initialFilterQ;
131
+ case DLSDestinations.chorusSend:
132
+ return generatorTypes.chorusEffectsSend;
133
+ case DLSDestinations.reverbSend:
134
+ return generatorTypes.reverbEffectsSend;
135
+ }
136
+ }
137
+
138
+ /**
139
+ * checks for combos such as mod lfo as source and pitch as destination which results in modLfoToPitch
140
+ * @param source {number}
141
+ * @param destination {number}
142
+ * @returns {generatorTypes} real destination
143
+ */
144
+ function checkForSpecialDLSCombo(source, destination)
145
+ {
146
+ if(source === DLSSources.vibratoLfo && destination === DLSDestinations.pitch)
147
+ {
148
+ return generatorTypes.vibLfoToPitch;
149
+ }
150
+ else
151
+ if(source === DLSSources.modLfo && destination === DLSDestinations.pitch)
152
+ {
153
+ return generatorTypes.modLfoToPitch;
154
+ }
155
+ else
156
+ if(source === DLSSources.modLfo && destination === DLSDestinations.filterCutoff)
157
+ {
158
+ return generatorTypes.modLfoToFilterFc;
159
+ }
160
+ else
161
+ if(source === DLSSources.modLfo && destination === DLSDestinations.gain)
162
+ {
163
+ return generatorTypes.modLfoToVolume;
164
+ }
165
+ else
166
+ if(source === DLSSources.modEnv && destination === DLSDestinations.filterCutoff)
167
+ {
168
+ return generatorTypes.modEnvToFilterFc;
169
+ }
170
+ else
171
+ if(source === DLSSources.modEnv && destination === DLSDestinations.pitch)
172
+ {
173
+ return generatorTypes.modEnvToPitch;
174
+ }
175
+ else
176
+ {
177
+ return undefined;
178
+ }
179
+ }
180
+
181
+ /**
182
+ * @param source {number}
183
+ * @param control {number}
184
+ * @param destination {number}
185
+ * @param transform {number}
186
+ * @param value {number}
187
+ * @returns {Modulator|undefined}
188
+ */
189
+ export function getSF2ModulatorFromArticulator(
190
+ source,
191
+ control,
192
+ destination,
193
+ transform,
194
+ value
195
+ )
196
+ {
197
+ // check for special combinations
198
+ const specialDestination = checkForSpecialDLSCombo(source, destination);
199
+ /**
200
+ * @type {generatorTypes}
201
+ */
202
+ let destinationGenerator;
203
+ /**
204
+ * @type {{enum: number, isCC: boolean}}
205
+ */
206
+ let sf2Source
207
+ let swapSources = false;
208
+ let isSourceNoController = false;
209
+ if(specialDestination === undefined)
210
+ {
211
+ // determine destination
212
+ const sf2GenDestination = getSF2GeneratorFromDLS(destination, value);
213
+ if(sf2GenDestination === undefined)
214
+ {
215
+ // cannot be a valid modulator
216
+ return undefined;
217
+ }
218
+ /**
219
+ * @type {generatorTypes}
220
+ */
221
+ destinationGenerator = sf2GenDestination;
222
+ if(sf2GenDestination.newAmount !== undefined)
223
+ {
224
+ value = sf2GenDestination.newAmount;
225
+ destinationGenerator = sf2GenDestination.gen;
226
+ }
227
+ sf2Source = getSF2SourceFromDLS(source);
228
+ if(sf2Source === undefined)
229
+ {
230
+ // cannot be a valid modulator
231
+ return undefined;
232
+ }
233
+ }
234
+ else
235
+ {
236
+ destinationGenerator = specialDestination;
237
+ swapSources = true;
238
+ sf2Source = {enum: modulatorSources.noController, isCC: false};
239
+ isSourceNoController = true;
240
+ }
241
+ let sf2SecondSource = getSF2SourceFromDLS(control);
242
+ if(sf2SecondSource === undefined)
243
+ {
244
+ // cannot be a valid modulator
245
+ return undefined;
246
+ }
247
+
248
+ // get transforms and final enums
249
+ let sourceEnumFinal;
250
+ if(isSourceNoController)
251
+ {
252
+ // we force it into this state because before it was some strange value,
253
+ // like vibrato lfo bipolar for example
254
+ // since we turn it into NoController -> vibLfoToPitch the result is the same and bipolar concontroller is technically 0
255
+ sourceEnumFinal = 0x0;
256
+ }
257
+ else
258
+ {
259
+ // output transform is ignored as it's not a thing in sfont format
260
+ // unless the curve type of source is linear, then output is copied
261
+ const outputTransform = transform & 0b1111;
262
+ // source curve type maps to desfont curve type in section 2.10, table 9
263
+ let sourceTransform = (transform >> 10) & 0b1111;
264
+ if(sourceTransform === modulatorCurveTypes.linear && outputTransform !== modulatorCurveTypes.linear)
265
+ {
266
+ sourceTransform = outputTransform;
267
+ }
268
+ const sourceIsBipolar = (transform >> 14) & 1;
269
+ let sourceIsNegative = (transform >> 15) & 1;
270
+ // special case: for attenuation, invert source
271
+ if(destinationGenerator === generatorTypes.initialAttenuation)
272
+ {
273
+ sourceIsNegative = !sourceIsNegative;
274
+ }
275
+ sourceEnumFinal = getModSourceEnum(
276
+ sourceTransform,
277
+ sourceIsBipolar,
278
+ sourceIsNegative,
279
+ sf2Source.isCC,
280
+ sf2Source.enum
281
+ );
282
+ }
283
+
284
+ const secSourceTransform = (transform >> 4) & 0b1111;
285
+ const secSourceIsBipolar = (transform >> 8) & 1;
286
+ const secSourceIsNegative = transform >> 9 & 1;
287
+ let secSourceEnumFinal = getModSourceEnum(
288
+ secSourceTransform,
289
+ secSourceIsBipolar,
290
+ secSourceIsNegative,
291
+ sf2SecondSource.isCC,
292
+ sf2SecondSource.enum
293
+ );
294
+
295
+ if(swapSources)
296
+ {
297
+ const temp = secSourceEnumFinal;
298
+ secSourceEnumFinal = sourceEnumFinal;
299
+ sourceEnumFinal = temp;
300
+ }
301
+
302
+ // return the modulator!
303
+ return new Modulator({
304
+ srcEnum: sourceEnumFinal,
305
+ secSrcEnum: secSourceEnumFinal,
306
+ dest: destinationGenerator,
307
+ transform: 0x0,
308
+ amt: value
309
+ });
310
+
311
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ *
3
+ * @enum {number}
4
+ */
5
+ export const DLSDestinations = {
6
+ none: 0x0,
7
+ gain: 0x1,
8
+ reserved: 0x2,
9
+ pitch: 0x3,
10
+ pan: 0x4,
11
+ keyNum: 0x5,
12
+ // nuh uh, the channel controllers are not supported!!!!
13
+ chorusSend: 0x80,
14
+ reverbSend: 0x81,
15
+
16
+ modLfoFreq: 0x104,
17
+ modLfoDelay: 0x105,
18
+
19
+ vibLfoFreq: 0x114,
20
+ vibLfoDelay: 0x115,
21
+
22
+ volEnvAttack: 0x206,
23
+ volEnvDecay: 0x207,
24
+ volEnvRelease: 0x209,
25
+ volEnvSustain: 0x20a,
26
+ volEnvDelay: 0x20b,
27
+ volEnvHold: 0x20c,
28
+
29
+ modEnvAttack: 0x30a,
30
+ modEnvDecay: 0x30b,
31
+ modEnvRelease: 0x30d,
32
+ modEnvSustain: 0x30e,
33
+ modEnvDelay: 0x30f,
34
+ modEnvHold: 0x310,
35
+
36
+ filterCutoff: 0x500,
37
+ filterQ: 0x501
38
+ }
@@ -1,25 +1,32 @@
1
1
  import { BasicPreset } from '../basic_soundfont/basic_preset.js'
2
+ import { BasicPresetZone } from '../basic_soundfont/basic_zones.js'
3
+ import { BasicInstrument } from '../basic_soundfont/basic_instrument.js'
2
4
 
3
5
  export class DLSPreset extends BasicPreset
4
6
  {
5
7
  /**
6
8
  * Creates a new DLS preset
7
- * @param ulBank {number} the ULONG value
8
- * @param ulInstrument {number} the ULONG value
9
- * @param regionsAmount {number}
9
+ * @param ulBank {number}
10
+ * @param ulInstrument {number}
10
11
  */
11
- constructor(ulBank, ulInstrument, regionsAmount)
12
+ constructor(ulBank, ulInstrument)
12
13
  {
13
14
  super();
14
- this.regionsAmount = regionsAmount;
15
15
  this.program = ulInstrument & 127;
16
16
  this.bank = (ulBank >> 8) & 127;
17
- const isDrums = ulInstrument & (1 << 31);
17
+ const isDrums = ulBank >> 31;
18
18
  if(isDrums)
19
19
  {
20
- console.log("DEUMS")
20
+ // soundfont bank is 128 so we change it here
21
+ this.bank = 128;
21
22
  }
22
- console.log(this.bank, this.program)
23
23
 
24
+ this.DLSInstrument = new BasicInstrument();
25
+ this.DLSInstrument.addUseCount();
26
+
27
+ const zone = new BasicPresetZone();
28
+ zone.instrument = this.DLSInstrument;
29
+
30
+ this.presetZones = [zone];
24
31
  }
25
32
  }
@@ -0,0 +1,58 @@
1
+ import { BasicSample } from '../basic_soundfont/basic_sample.js'
2
+
3
+ export class DLSSample extends BasicSample
4
+ {
5
+ /**
6
+ * @param name {string}
7
+ * @param rate {number}
8
+ * @param pitch {number}
9
+ * @param pitchCorrection {number}
10
+ * @param loopStart {number} sample data points
11
+ * @param loopEnd {number} sample data points
12
+ * @param data {Float32Array}
13
+ */
14
+ constructor(
15
+ name,
16
+ rate,
17
+ pitch,
18
+ pitchCorrection,
19
+ loopStart,
20
+ loopEnd,
21
+ data
22
+ )
23
+ {
24
+ super(
25
+ name,
26
+ rate,
27
+ pitch,
28
+ pitchCorrection,
29
+ 0,
30
+ 1,
31
+ loopStart * 2,
32
+ (loopEnd - 1) * 2 // -1 sample because soundfont end is last sample and dls end is next sample
33
+ );
34
+ this.sampleData = data;
35
+ }
36
+
37
+ getAudioData()
38
+ {
39
+ return this.sampleData;
40
+ }
41
+
42
+ /**
43
+ * @type {Float32Array}
44
+ */
45
+ sampleData;
46
+
47
+ getRawData()
48
+ {
49
+ const uint8 = new Uint8Array(this.sampleData.length * 2);
50
+ for (let i = 0; i < this.sampleData.length; i++)
51
+ {
52
+ const sample = Math.floor(this.sampleData[i] * 32767);
53
+ uint8[i * 2] = sample & 0xFF; // lower byte
54
+ uint8[i * 2 + 1] = (sample >> 8) & 0xFF; // upper byte
55
+ }
56
+ return uint8;
57
+ }
58
+ }
@@ -2,11 +2,14 @@ import { BasicSoundFont } from '../basic_soundfont/basic_soundfont.js'
2
2
  import { IndexedByteArray } from '../../utils/indexed_array.js'
3
3
  import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from '../../utils/loggin.js'
4
4
  import { consoleColors } from '../../utils/other.js'
5
- import { readRIFFChunk } from '../basic_soundfont/riff_chunk.js'
5
+ import { findRIFFListType, readRIFFChunk } from '../basic_soundfont/riff_chunk.js'
6
6
  import { readBytesAsString } from '../../utils/byte_functions/string.js'
7
7
  import { readLittleEndian } from '../../utils/byte_functions/little_endian.js'
8
8
  import { readDLSInstrumentList } from './read_instrument_list.js'
9
9
  import { readDLSInstrument } from './read_instrument.js'
10
+ import { readLart } from './read_lart.js'
11
+ import { readRegion } from './read_region.js'
12
+ import { readDLSSamples } from './read_samples.js'
10
13
 
11
14
  class DLSSoundFont extends BasicSoundFont
12
15
  {
@@ -25,28 +28,80 @@ class DLSSoundFont extends BasicSoundFont
25
28
  throw new TypeError("No data!");
26
29
  }
27
30
 
28
- this.soundFontInfo["ifil"] = "2.1"; // always for dls
29
-
30
31
  // read the main chunk
31
32
  let firstChunk = readRIFFChunk(this.dataArray, false);
32
33
  this.verifyHeader(firstChunk, "riff");
33
34
  this.verifyText(readBytesAsString(this.dataArray,4).toLowerCase(), "dls ");
34
35
 
35
- // read until we reach "colh"
36
- let colhChunk = readRIFFChunk(this.dataArray);
37
- while(colhChunk.header !== "colh")
36
+ /**
37
+ * Read list
38
+ * @type {RiffChunk[]}
39
+ */
40
+ const chunks = [];
41
+ while(this.dataArray.currentIndex < this.dataArray.length)
38
42
  {
39
- colhChunk = readRIFFChunk(this.dataArray);
43
+ chunks.push(readRIFFChunk(this.dataArray));
44
+ }
45
+
46
+ // mandatory
47
+ this.soundFontInfo["ifil"] = "2.1"; // always for dls
48
+ this.soundFontInfo["isng"] = "EMU8000";
49
+
50
+ // set some defaults
51
+ this.soundFontInfo["IPRD"] = "SpessaSynth DLS";
52
+ this.soundFontInfo["ICRD"] = new Date().toDateString();
53
+
54
+ // read info
55
+ const infoChunk = findRIFFListType(chunks, "INFO");
56
+ if(infoChunk)
57
+ {
58
+ while(infoChunk.chunkData.currentIndex < infoChunk.chunkData.length)
59
+ {
60
+ const infoPart = readRIFFChunk(infoChunk.chunkData);
61
+ this.soundFontInfo[infoPart.header] = readBytesAsString(infoPart.chunkData, infoPart.size);
62
+ }
63
+ }
64
+ this.soundFontInfo["ICMT"] = (this.soundFontInfo["ICMT"] || "") + "\nConverted from DLS to SF2 with SpessaSynth";
65
+ if(this.soundFontInfo["ISBJ"])
66
+ {
67
+ // merge it
68
+ this.soundFontInfo["ICMT"] += "\n" + this.soundFontInfo["ISBJ"];
69
+ delete this.soundFontInfo["ISBJ"];
70
+ }
71
+
72
+ for(const [info, value] of Object.entries(this.soundFontInfo))
73
+ {
74
+ SpessaSynthInfo(`%c"${info}": %c"${value}"`,
75
+ consoleColors.info,
76
+ consoleColors.recognized);
77
+ }
78
+
79
+ // read "colh"
80
+ let colhChunk = chunks.find(c => c.header === "colh");
81
+ if(!colhChunk)
82
+ {
83
+ SpessaSynthGroupEnd();
84
+ throw new Error("No colh chunk!");
40
85
  }
41
86
  this.instrumentAmount = readLittleEndian(colhChunk.chunkData, 4);
42
87
  SpessaSynthInfo(`%cInstruments amount: %c${this.instrumentAmount}`,
43
88
  consoleColors.info,
44
89
  consoleColors.recognized);
45
90
 
46
- // instrument list
47
- this.readDLSInstrumentList(this.dataArray);
91
+ // read wave list
92
+ let waveListChunk = findRIFFListType(chunks , "wvpl");
93
+ this.readDLSSamples(waveListChunk);
94
+
95
+ // read instrument list
96
+ let instrumentListChunk = findRIFFListType(chunks, "lins");
97
+ if(!instrumentListChunk)
98
+ {
99
+ SpessaSynthGroupEnd();
100
+ throw new Error("No lins chunk!");
101
+ }
102
+ this.readDLSInstrumentList(instrumentListChunk);
48
103
 
49
- SpessaSynthInfo(`%cParsing finished! %c"desfont"%c has %c${this.presets.length} %cpresets,
104
+ SpessaSynthInfo(`%cParsing finished! %c"${this.soundFontInfo["INAM"] || "UNNAMED"}"%c has %c${this.presets.length} %cpresets,
50
105
  %c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
51
106
  consoleColors.info,
52
107
  consoleColors.recognized,
@@ -58,7 +113,6 @@ class DLSSoundFont extends BasicSoundFont
58
113
  consoleColors.recognized,
59
114
  consoleColors.info);
60
115
  SpessaSynthGroupEnd();
61
- throw new Error("Not implemented yet...")
62
116
  }
63
117
 
64
118
  /**
@@ -89,5 +143,8 @@ class DLSSoundFont extends BasicSoundFont
89
143
  }
90
144
  DLSSoundFont.prototype.readDLSInstrumentList = readDLSInstrumentList;
91
145
  DLSSoundFont.prototype.readDLSInstrument = readDLSInstrument;
146
+ DLSSoundFont.prototype.readRegion = readRegion;
147
+ DLSSoundFont.prototype.readLart = readLart;
148
+ DLSSoundFont.prototype.readDLSSamples = readDLSSamples;
92
149
 
93
150
  export {DLSSoundFont}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @enum {number}
3
+ */
4
+ export const DLSSources = {
5
+ none: 0x0,
6
+ modLfo: 0x1,
7
+ velocity: 0x2,
8
+ keyNum: 0x3,
9
+ volEnv: 0x4,
10
+ modEnv: 0x5,
11
+ pitchWheel: 0x6,
12
+ polyPressure: 0x7,
13
+ channelPressure: 0x8,
14
+ vibratoLfo: 0x9,
15
+
16
+ modulationWheel: 0x81,
17
+ volume: 0x87,
18
+ pan: 0x8a,
19
+ expression: 0x8b,
20
+ chorus: 0xdb,
21
+ reverb: 0xdd,
22
+
23
+ pitchWheelRange: 0x100,
24
+ fineTune: 0x101,
25
+ coarseTune: 0x102
26
+ }
@@ -0,0 +1,75 @@
1
+ import { BasicInstrumentZone } from '../basic_soundfont/basic_zones.js'
2
+ import { Generator, generatorTypes } from '../read_sf2/generators.js'
3
+
4
+ export class DLSZone extends BasicInstrumentZone
5
+ {
6
+ /**
7
+ * @param keyRange {SoundFontRange}
8
+ * @param velRange {SoundFontRange}
9
+ */
10
+ constructor(keyRange, velRange)
11
+ {
12
+ super();
13
+ this.keyRange = keyRange;
14
+ this.velRange = velRange;
15
+ this.isGlobal = true;
16
+ }
17
+
18
+ /**
19
+ * @param attenuationCb {number} with EMU correction
20
+ * @param loopingMode {number} the sfont one
21
+ * @param loop {{start: number, end: number}}
22
+ * @param sampleKey {number}
23
+ * @param sample {BasicSample}
24
+ * @param sampleID {number}
25
+ */
26
+ setWavesample(
27
+ attenuationCb,
28
+ loopingMode,
29
+ loop,
30
+ sampleKey,
31
+ sample,
32
+ sampleID,
33
+ )
34
+ {
35
+ if(loopingMode !== 0)
36
+ {
37
+ this.generators.push(new Generator(generatorTypes.sampleModes, loopingMode));
38
+ }
39
+ this.generators.push(new Generator(generatorTypes.initialAttenuation, attenuationCb));
40
+ this.isGlobal = false;
41
+
42
+ // correct loop if needed
43
+ const diffStart = loop.start - (sample.sampleLoopStartIndex / 2);
44
+ const diffEnd = loop.end - (sample.sampleLoopEndIndex / 2);
45
+ if(diffStart !== 0)
46
+ {
47
+ const fine = diffStart % 32768;
48
+ this.generators.push(new Generator(generatorTypes.startloopAddrsOffset, fine));
49
+ const coarse = Math.round(diffStart / 32768);
50
+ if(coarse !== 0)
51
+ {
52
+ this.generators.push(new Generator(generatorTypes.startloopAddrsCoarseOffset, fine));
53
+ }
54
+ }
55
+ if(diffEnd !== 0)
56
+ {
57
+ const fine = diffEnd % 32768;
58
+ this.generators.push(new Generator(generatorTypes.endloopAddrsOffset, fine));
59
+ const coarse = Math.round(diffEnd / 32768);
60
+ if(coarse !== 0)
61
+ {
62
+ this.generators.push(new Generator(generatorTypes.endloopAddrsCoarseOffset, fine));
63
+ }
64
+ }
65
+ // correct key if needed
66
+ if(sampleKey !== sample.samplePitch)
67
+ {
68
+ this.generators.push(new Generator(generatorTypes.overridingRootKey, sampleKey));
69
+ }
70
+ // add sample ID
71
+ this.generators.push(new Generator(generatorTypes.sampleID, sampleID));
72
+ this.sample = sample;
73
+ sample.useCount++;
74
+ }
75
+ }