spessasynth_core 3.26.17 → 3.26.19
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/index.js +5 -3
- package/package.json +1 -1
- package/src/externals/README.md +6 -0
- package/src/sequencer/README.md +5 -1
- package/src/soundfont/README.md +6 -8
- package/src/soundfont/basic_soundfont/basic_global_zone.js +16 -0
- package/src/soundfont/basic_soundfont/basic_instrument.js +26 -22
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +35 -0
- package/src/soundfont/basic_soundfont/basic_preset.js +53 -42
- package/src/soundfont/basic_soundfont/basic_preset_zone.js +30 -0
- package/src/soundfont/basic_soundfont/{basic_soundfont.js → basic_soundbank.js} +96 -55
- package/src/soundfont/basic_soundfont/basic_zone.js +73 -5
- package/src/soundfont/basic_soundfont/generator.js +4 -163
- package/src/soundfont/basic_soundfont/generator_types.js +151 -0
- package/src/soundfont/basic_soundfont/modulator.js +217 -65
- package/src/soundfont/basic_soundfont/write_dls/art2.js +3 -2
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +28 -45
- package/src/soundfont/basic_soundfont/write_dls/ins.js +11 -27
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +2 -2
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +2 -2
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +22 -19
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +33 -29
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +26 -16
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +4 -5
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +21 -18
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +32 -29
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +4 -2
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +26 -16
- package/src/soundfont/basic_soundfont/write_sf2/write.js +14 -8
- package/src/soundfont/dls/articulator_converter.js +9 -3
- package/src/soundfont/dls/dls_preset.js +2 -3
- package/src/soundfont/dls/dls_soundfont.js +2 -3
- package/src/soundfont/dls/dls_sources.js +7 -6
- package/src/soundfont/dls/dls_zone.js +13 -16
- package/src/soundfont/dls/read_articulation.js +2 -1
- package/src/soundfont/dls/read_instrument.js +7 -10
- package/src/soundfont/dls/read_lart.js +5 -5
- package/src/soundfont/dls/read_region.js +3 -3
- package/src/soundfont/read_sf2/instruments.js +10 -1
- package/src/soundfont/read_sf2/modulators.js +10 -23
- package/src/soundfont/read_sf2/presets.js +10 -1
- package/src/soundfont/read_sf2/soundfont.js +3 -5
- package/src/soundfont/read_sf2/zones.js +30 -70
- package/src/synthetizer/README.md +3 -3
- package/src/synthetizer/audio_engine/README.md +1 -1
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +20 -19
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +11 -3
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/voice.js +7 -10
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +2 -1
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -4
- package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +7 -0
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +1 -1
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +2 -1
- package/src/utils/README.md +5 -2
- package/src/soundfont/basic_soundfont/basic_zones.js +0 -43
package/index.js
CHANGED
|
@@ -18,12 +18,12 @@ import {
|
|
|
18
18
|
import { SynthesizerSnapshot } from "./src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js";
|
|
19
19
|
import { ChannelSnapshot } from "./src/synthetizer/audio_engine/snapshot/channel_snapshot.js";
|
|
20
20
|
|
|
21
|
-
import { BasicSoundBank } from "./src/soundfont/basic_soundfont/
|
|
21
|
+
import { BasicSoundBank } from "./src/soundfont/basic_soundfont/basic_soundbank.js";
|
|
22
22
|
import { BasicSample } from "./src/soundfont/basic_soundfont/basic_sample.js";
|
|
23
|
-
import {
|
|
23
|
+
import { BasicPresetZone } from "./src/soundfont/basic_soundfont/basic_preset_zone.js";
|
|
24
24
|
import { BasicInstrument } from "./src/soundfont/basic_soundfont/basic_instrument.js";
|
|
25
25
|
import { BasicPreset } from "./src/soundfont/basic_soundfont/basic_preset.js";
|
|
26
|
-
import { Generator
|
|
26
|
+
import { Generator } from "./src/soundfont/basic_soundfont/generator.js";
|
|
27
27
|
import { Modulator, modulatorCurveTypes, modulatorSources } from "./src/soundfont/basic_soundfont/modulator.js";
|
|
28
28
|
import { loadSoundFont } from "./src/soundfont/load_soundfont.js";
|
|
29
29
|
|
|
@@ -51,6 +51,8 @@ import { consoleColors } from "./src/utils/other.js";
|
|
|
51
51
|
import { inflateSync } from "./src/externals/fflate/fflate.min.js";
|
|
52
52
|
import { DLSDestinations } from "./src/soundfont/dls/dls_destinations.js";
|
|
53
53
|
import { DLSSources } from "./src/soundfont/dls/dls_sources.js";
|
|
54
|
+
import { generatorTypes } from "./src/soundfont/basic_soundfont/generator_types.js";
|
|
55
|
+
import { BasicInstrumentZone } from "./src/soundfont/basic_soundfont/basic_instrument_zone.js";
|
|
54
56
|
// you shouldn't use these...
|
|
55
57
|
const SpessaSynthCoreUtils = {
|
|
56
58
|
consoleColors,
|
package/package.json
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## This is the external dependencies' folder.
|
|
2
|
+
|
|
3
|
+
The code here contains third-party libraries used by SpessaSynth.
|
|
4
|
+
|
|
5
|
+
- `stbvorbis_sync` - Vorbis audio decoder for SF3 soundfonts
|
|
6
|
+
- `fflate` - Used for decompressing XMF files. It is also used to compress the reverb buffer in spessasynth_lib
|
package/src/sequencer/README.md
CHANGED
|
@@ -2,4 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The code here is responsible for playing back the parsed MIDI sequence with the synthesizer.
|
|
4
4
|
|
|
5
|
-
- `sequencer_engine` - the core sequencer engine
|
|
5
|
+
- `sequencer_engine.js` - the core sequencer engine
|
|
6
|
+
- `play.js` - handles playback control and timing
|
|
7
|
+
- `song_control.js` - manages song state and control
|
|
8
|
+
- `process_event.js` - processes MIDI events during playback
|
|
9
|
+
- `process_tick.js` - processes a single MIDI tick (think of it like a rendering quantum of the sequencer)
|
package/src/soundfont/README.md
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
## This is the
|
|
1
|
+
## This is the SoundFont and DLS parsing library.
|
|
2
2
|
|
|
3
|
-
The code here is responsible for parsing the SoundFont2 file and
|
|
3
|
+
The code here is responsible for parsing the SoundFont2/DLS file and
|
|
4
4
|
providing an easy way to get the data out.
|
|
5
|
-
Default modulators are also stored here (in `modulators.js`)
|
|
6
5
|
|
|
7
|
-
`basic_soundfont` folder contains the classes that represent
|
|
6
|
+
- `basic_soundfont` folder contains the classes that represent a sound bank file.
|
|
7
|
+
It also contains the code for writing the files.
|
|
8
8
|
|
|
9
|
-
`read_sf2` folder contains the code for reading
|
|
9
|
+
- `read_sf2` folder contains the code for reading a `.sf2` file.
|
|
10
10
|
|
|
11
|
-
`
|
|
12
|
-
|
|
13
|
-
`dls` folder contains the code for reading a `.dls` file (and converting in into a soundfont representation).
|
|
11
|
+
- `dls` folder contains the code for reading a `.dls` file (and converting in into a soundfont representation).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BasicZone } from "./basic_zone.js";
|
|
2
|
+
|
|
3
|
+
export class BasicGlobalZone extends BasicZone
|
|
4
|
+
{
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param zone {BasicZone}
|
|
8
|
+
*/
|
|
9
|
+
copyFrom(zone)
|
|
10
|
+
{
|
|
11
|
+
this.keyRange = { ...zone.keyRange };
|
|
12
|
+
this.velRange = { ...zone.velRange };
|
|
13
|
+
this.generators = [...zone.generators];
|
|
14
|
+
this.modulators = [...zone.modulators];
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { BasicGlobalZone } from "./basic_global_zone.js";
|
|
2
|
+
|
|
1
3
|
export class BasicInstrument
|
|
2
4
|
{
|
|
3
5
|
/**
|
|
@@ -9,9 +11,16 @@ export class BasicInstrument
|
|
|
9
11
|
/**
|
|
10
12
|
* The instrument's zones
|
|
11
13
|
* @type {BasicInstrumentZone[]}
|
|
14
|
+
* @readonly
|
|
12
15
|
*/
|
|
13
16
|
instrumentZones = [];
|
|
14
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Instrument's global zone
|
|
20
|
+
* @type {BasicGlobalZone}
|
|
21
|
+
*/
|
|
22
|
+
globalZone = new BasicGlobalZone();
|
|
23
|
+
|
|
15
24
|
/**
|
|
16
25
|
* Instrument's use count, used for trimming
|
|
17
26
|
* @type {number}
|
|
@@ -27,6 +36,15 @@ export class BasicInstrument
|
|
|
27
36
|
return this._useCount;
|
|
28
37
|
}
|
|
29
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @param zones {BasicInstrumentZone}
|
|
41
|
+
*/
|
|
42
|
+
addZones(...zones)
|
|
43
|
+
{
|
|
44
|
+
zones.forEach(z => z.useCount++);
|
|
45
|
+
this.instrumentZones.push(...zones);
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
addUseCount()
|
|
31
49
|
{
|
|
32
50
|
this._useCount++;
|
|
@@ -36,16 +54,10 @@ export class BasicInstrument
|
|
|
36
54
|
removeUseCount()
|
|
37
55
|
{
|
|
38
56
|
this._useCount--;
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
if (this.safeDeleteZone(i))
|
|
42
|
-
{
|
|
43
|
-
i--;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
57
|
+
this.instrumentZones.forEach(z => z.useCount--);
|
|
46
58
|
}
|
|
47
59
|
|
|
48
|
-
|
|
60
|
+
deleteZones()
|
|
49
61
|
{
|
|
50
62
|
this.instrumentZones.forEach(z => z.deleteZone());
|
|
51
63
|
this.instrumentZones.length = 0;
|
|
@@ -53,25 +65,17 @@ export class BasicInstrument
|
|
|
53
65
|
|
|
54
66
|
/**
|
|
55
67
|
* @param index {number}
|
|
56
|
-
* @returns {boolean}
|
|
68
|
+
* @returns {boolean} if deleted
|
|
57
69
|
*/
|
|
58
|
-
|
|
70
|
+
deleteZone(index)
|
|
59
71
|
{
|
|
60
|
-
this.instrumentZones[index]
|
|
61
|
-
if (
|
|
72
|
+
const zone = this.instrumentZones[index];
|
|
73
|
+
if (zone.useCount < 1)
|
|
62
74
|
{
|
|
63
|
-
|
|
75
|
+
zone.deleteZone();
|
|
76
|
+
this.instrumentZones.splice(index, 1);
|
|
64
77
|
return true;
|
|
65
78
|
}
|
|
66
79
|
return false;
|
|
67
80
|
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* @param index {number}
|
|
71
|
-
*/
|
|
72
|
-
deleteZone(index)
|
|
73
|
-
{
|
|
74
|
-
this.instrumentZones[index].deleteZone();
|
|
75
|
-
this.instrumentZones.splice(index, 1);
|
|
76
|
-
}
|
|
77
81
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BasicZone } from "./basic_zone.js";
|
|
2
|
+
|
|
3
|
+
export class BasicInstrumentZone extends BasicZone
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* Zone's sample.
|
|
7
|
+
* @type {BasicSample}
|
|
8
|
+
*/
|
|
9
|
+
sample;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* For tracking on the individual zone level, since multiple presets can refer to the same instrument
|
|
13
|
+
* @type {number}
|
|
14
|
+
*/
|
|
15
|
+
useCount = 0;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param sample {BasicSample}
|
|
19
|
+
*/
|
|
20
|
+
setSample(sample)
|
|
21
|
+
{
|
|
22
|
+
this.sample = sample;
|
|
23
|
+
this.sample.useCount++;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
deleteZone()
|
|
27
|
+
{
|
|
28
|
+
this.sample.useCount--;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hasSample()
|
|
32
|
+
{
|
|
33
|
+
return !!this.sample;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* presetGenerators: Generator[],
|
|
5
5
|
* modulators: Modulator[],
|
|
6
6
|
* sample: BasicSample,
|
|
7
|
-
* sampleID: number,
|
|
8
7
|
* }} SampleAndGenerators
|
|
9
8
|
*/
|
|
10
|
-
import { generatorTypes } from "./generator.js";
|
|
11
9
|
import { Modulator } from "./modulator.js";
|
|
12
10
|
import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
13
11
|
|
|
12
|
+
import { BasicGlobalZone } from "./basic_global_zone.js";
|
|
13
|
+
|
|
14
14
|
export class BasicPreset
|
|
15
15
|
{
|
|
16
16
|
/**
|
|
@@ -44,6 +44,12 @@ export class BasicPreset
|
|
|
44
44
|
*/
|
|
45
45
|
presetZones = [];
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Preset's global zone
|
|
49
|
+
* @type {BasicGlobalZone}
|
|
50
|
+
*/
|
|
51
|
+
globalZone = new BasicGlobalZone();
|
|
52
|
+
|
|
47
53
|
/**
|
|
48
54
|
* unused metadata
|
|
49
55
|
* @type {number}
|
|
@@ -69,6 +75,14 @@ export class BasicPreset
|
|
|
69
75
|
this.parentSoundBank = parentSoundBank;
|
|
70
76
|
}
|
|
71
77
|
|
|
78
|
+
/**
|
|
79
|
+
* @param zones {BasicPresetZone}
|
|
80
|
+
*/
|
|
81
|
+
addZones(...zones)
|
|
82
|
+
{
|
|
83
|
+
this.presetZones.push(...zones);
|
|
84
|
+
}
|
|
85
|
+
|
|
72
86
|
/**
|
|
73
87
|
* @param allowXG {boolean}
|
|
74
88
|
* @param allowSFX {boolean}
|
|
@@ -171,62 +185,60 @@ export class BasicPreset
|
|
|
171
185
|
* global zone is always first, so it or nothing
|
|
172
186
|
* @type {Generator[]}
|
|
173
187
|
*/
|
|
174
|
-
let globalPresetGenerators =
|
|
188
|
+
let globalPresetGenerators = [...this.globalZone.generators];
|
|
175
189
|
|
|
176
190
|
/**
|
|
177
191
|
* @type {Modulator[]}
|
|
178
192
|
*/
|
|
179
|
-
let globalPresetModulators =
|
|
180
|
-
const globalKeyRange = this.
|
|
181
|
-
const globalVelRange = this.
|
|
193
|
+
let globalPresetModulators = [...this.globalZone.modulators];
|
|
194
|
+
const globalKeyRange = this.globalZone.keyRange;
|
|
195
|
+
const globalVelRange = this.globalZone.velRange;
|
|
182
196
|
|
|
183
197
|
// find the preset zones in range
|
|
184
198
|
let presetZonesInRange = this.presetZones.filter(currentZone =>
|
|
185
|
-
(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
) && !currentZone.isGlobal);
|
|
199
|
+
isInRange(
|
|
200
|
+
currentZone.hasKeyRange ? currentZone.keyRange : globalKeyRange,
|
|
201
|
+
midiNote
|
|
202
|
+
)
|
|
203
|
+
&&
|
|
204
|
+
isInRange(
|
|
205
|
+
currentZone.hasVelRange ? currentZone.velRange : globalVelRange,
|
|
206
|
+
velocity
|
|
207
|
+
)
|
|
208
|
+
);
|
|
196
209
|
|
|
197
|
-
presetZonesInRange.forEach(
|
|
210
|
+
presetZonesInRange.forEach(presetZone =>
|
|
198
211
|
{
|
|
212
|
+
const instrument = presetZone.instrument;
|
|
199
213
|
// the global zone is already taken into account earlier
|
|
200
|
-
if (
|
|
214
|
+
if (instrument.instrumentZones.length < 1)
|
|
201
215
|
{
|
|
202
216
|
return;
|
|
203
217
|
}
|
|
204
|
-
let presetGenerators =
|
|
205
|
-
let presetModulators =
|
|
206
|
-
const firstZone = zone.instrument.instrumentZones[0];
|
|
218
|
+
let presetGenerators = presetZone.generators;
|
|
219
|
+
let presetModulators = presetZone.modulators;
|
|
207
220
|
/**
|
|
208
221
|
* global zone is always first, so it or nothing
|
|
209
222
|
* @type {Generator[]}
|
|
210
223
|
*/
|
|
211
|
-
let globalInstrumentGenerators =
|
|
212
|
-
let globalInstrumentModulators =
|
|
213
|
-
const globalKeyRange =
|
|
214
|
-
const globalVelRange =
|
|
224
|
+
let globalInstrumentGenerators = [...instrument.globalZone.generators];
|
|
225
|
+
let globalInstrumentModulators = [...instrument.globalZone.modulators];
|
|
226
|
+
const globalKeyRange = instrument.globalZone.keyRange;
|
|
227
|
+
const globalVelRange = instrument.globalZone.velRange;
|
|
215
228
|
|
|
216
229
|
|
|
217
|
-
let instrumentZonesInRange =
|
|
230
|
+
let instrumentZonesInRange = instrument.instrumentZones
|
|
218
231
|
.filter(currentZone =>
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
) && !currentZone.isGlobal
|
|
232
|
+
|
|
233
|
+
isInRange(
|
|
234
|
+
currentZone.hasKeyRange ? currentZone.keyRange : globalKeyRange,
|
|
235
|
+
midiNote
|
|
236
|
+
)
|
|
237
|
+
&&
|
|
238
|
+
isInRange(
|
|
239
|
+
currentZone.hasVelRange ? currentZone.velRange : globalVelRange,
|
|
240
|
+
velocity
|
|
241
|
+
)
|
|
230
242
|
);
|
|
231
243
|
|
|
232
244
|
instrumentZonesInRange.forEach(instrumentZone =>
|
|
@@ -275,7 +287,8 @@ export class BasicPreset
|
|
|
275
287
|
if (identicalInstrumentModulator !== -1)
|
|
276
288
|
{
|
|
277
289
|
// sum the amounts
|
|
278
|
-
//
|
|
290
|
+
// this makes a new modulator
|
|
291
|
+
// because otherwise it would overwrite the one in the soundfont!
|
|
279
292
|
finalModulatorList[identicalInstrumentModulator] = finalModulatorList[identicalInstrumentModulator].sumTransform(
|
|
280
293
|
mod);
|
|
281
294
|
}
|
|
@@ -291,9 +304,7 @@ export class BasicPreset
|
|
|
291
304
|
instrumentGenerators: instrumentGenerators,
|
|
292
305
|
presetGenerators: presetGenerators,
|
|
293
306
|
modulators: finalModulatorList,
|
|
294
|
-
sample: instrumentZone.sample
|
|
295
|
-
sampleID: instrumentZone.generators.find(
|
|
296
|
-
g => g.generatorType === generatorTypes.sampleID).generatorValue
|
|
307
|
+
sample: instrumentZone.sample
|
|
297
308
|
});
|
|
298
309
|
});
|
|
299
310
|
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { BasicZone } from "./basic_zone.js";
|
|
2
|
+
|
|
3
|
+
export class BasicPresetZone extends BasicZone
|
|
4
|
+
{
|
|
5
|
+
/**
|
|
6
|
+
* Zone's instrument
|
|
7
|
+
* @type {BasicInstrument}
|
|
8
|
+
*/
|
|
9
|
+
instrument;
|
|
10
|
+
|
|
11
|
+
deleteZone()
|
|
12
|
+
{
|
|
13
|
+
this.instrument.removeUseCount();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param instrument {BasicInstrument}
|
|
18
|
+
*/
|
|
19
|
+
setInstrument(instrument)
|
|
20
|
+
{
|
|
21
|
+
this.instrument = instrument;
|
|
22
|
+
this.instrument.addUseCount();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
hasInstrument()
|
|
27
|
+
{
|
|
28
|
+
return !!this.instrument;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -10,15 +10,20 @@ import { write } from "./write_sf2/write.js";
|
|
|
10
10
|
import { defaultModulators, Modulator } from "./modulator.js";
|
|
11
11
|
import { writeDLS } from "./write_dls/write_dls.js";
|
|
12
12
|
import { BasicSample } from "./basic_sample.js";
|
|
13
|
-
import {
|
|
14
|
-
import { Generator
|
|
13
|
+
import { BasicPresetZone } from "./basic_preset_zone.js";
|
|
14
|
+
import { Generator } from "./generator.js";
|
|
15
15
|
import { BasicInstrument } from "./basic_instrument.js";
|
|
16
16
|
import { BasicPreset } from "./basic_preset.js";
|
|
17
17
|
import { isXGDrums } from "../../utils/xg_hacks.js";
|
|
18
|
+
import { generatorTypes } from "./generator_types.js";
|
|
19
|
+
import { BasicInstrumentZone } from "./basic_instrument_zone.js";
|
|
20
|
+
import { BasicGlobalZone } from "./basic_global_zone.js";
|
|
18
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Represents a single sound bank, be it DLS or SF2.
|
|
24
|
+
*/
|
|
19
25
|
class BasicSoundBank
|
|
20
26
|
{
|
|
21
|
-
|
|
22
27
|
/**
|
|
23
28
|
* Soundfont's info stored as name: value. ifil and iver are stored as string representation of float (e.g., 2.1)
|
|
24
29
|
* @type {Object<string, string|IndexedByteArray>}
|
|
@@ -62,15 +67,47 @@ class BasicSoundBank
|
|
|
62
67
|
isXGBank = false;
|
|
63
68
|
|
|
64
69
|
/**
|
|
65
|
-
* Creates a new basic soundfont template
|
|
70
|
+
* Creates a new basic soundfont template (or copies)
|
|
66
71
|
* @param data {undefined|{presets: BasicPreset[], info: Object<string, string>}}
|
|
67
72
|
*/
|
|
68
73
|
constructor(data = undefined)
|
|
69
74
|
{
|
|
70
75
|
if (data?.presets)
|
|
71
76
|
{
|
|
72
|
-
this.presets.push(...data.presets);
|
|
73
77
|
this.soundFontInfo = data.info;
|
|
78
|
+
this.addPresets(...data.presets);
|
|
79
|
+
/**
|
|
80
|
+
* @type {BasicInstrument[]}
|
|
81
|
+
*/
|
|
82
|
+
const instrumentList = [];
|
|
83
|
+
for (const preset of data.presets)
|
|
84
|
+
{
|
|
85
|
+
for (const zone of preset.presetZones)
|
|
86
|
+
{
|
|
87
|
+
if (!instrumentList.includes(zone.instrument))
|
|
88
|
+
{
|
|
89
|
+
instrumentList.push(zone.instrument);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
this.addInstruments(...instrumentList);
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @type {BasicSample[]}
|
|
97
|
+
*/
|
|
98
|
+
const sampleList = [];
|
|
99
|
+
|
|
100
|
+
for (const instrument of instrumentList)
|
|
101
|
+
{
|
|
102
|
+
for (const zone of instrument.instrumentZones)
|
|
103
|
+
{
|
|
104
|
+
if (!sampleList.includes(zone.sample))
|
|
105
|
+
{
|
|
106
|
+
sampleList.push(zone.sample);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.addSamples(...sampleList);
|
|
74
111
|
}
|
|
75
112
|
}
|
|
76
113
|
|
|
@@ -122,44 +159,74 @@ class BasicSoundBank
|
|
|
122
159
|
{
|
|
123
160
|
sample.sampleData[i] = (i / 128) * 2 - 1;
|
|
124
161
|
}
|
|
125
|
-
font.
|
|
162
|
+
font.addSamples(sample);
|
|
126
163
|
|
|
127
|
-
const gZone = new
|
|
128
|
-
gZone.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
164
|
+
const gZone = new BasicGlobalZone();
|
|
165
|
+
gZone.addGenerators(
|
|
166
|
+
new Generator(generatorTypes.initialAttenuation, 375),
|
|
167
|
+
new Generator(generatorTypes.releaseVolEnv, -1000),
|
|
168
|
+
new Generator(generatorTypes.sampleModes, 1)
|
|
169
|
+
);
|
|
132
170
|
|
|
133
171
|
const zone1 = new BasicInstrumentZone();
|
|
134
|
-
zone1.sample
|
|
172
|
+
zone1.setSample(sample);
|
|
135
173
|
|
|
136
174
|
const zone2 = new BasicInstrumentZone();
|
|
137
|
-
zone2.sample
|
|
138
|
-
zone2.
|
|
175
|
+
zone2.setSample(sample);
|
|
176
|
+
zone2.addGenerators(new Generator(generatorTypes.fineTune, -9));
|
|
139
177
|
|
|
140
178
|
|
|
141
179
|
const inst = new BasicInstrument();
|
|
142
180
|
inst.instrumentName = "Saw Wave";
|
|
143
|
-
inst.
|
|
144
|
-
inst.
|
|
145
|
-
|
|
146
|
-
font.instruments.push(inst);
|
|
181
|
+
inst.globalZone = gZone;
|
|
182
|
+
inst.addZones(zone1, zone2);
|
|
183
|
+
font.addInstruments(inst);
|
|
147
184
|
|
|
148
185
|
const pZone = new BasicPresetZone();
|
|
149
|
-
pZone.
|
|
186
|
+
pZone.setInstrument(inst);
|
|
150
187
|
|
|
151
188
|
const preset = new BasicPreset(font);
|
|
152
189
|
preset.presetName = "Saw Wave";
|
|
153
|
-
preset.
|
|
154
|
-
font.
|
|
190
|
+
preset.addZones(pZone);
|
|
191
|
+
font.addPresets(preset);
|
|
155
192
|
|
|
156
193
|
font.soundFontInfo["ifil"] = "2.1";
|
|
157
194
|
font.soundFontInfo["isng"] = "EMU8000";
|
|
158
195
|
font.soundFontInfo["INAM"] = "Dummy";
|
|
159
|
-
font.
|
|
196
|
+
font.flush();
|
|
160
197
|
return font.write().buffer;
|
|
161
198
|
}
|
|
162
199
|
|
|
200
|
+
/**
|
|
201
|
+
* @param preset {BasicPreset}
|
|
202
|
+
*/
|
|
203
|
+
addPresets(...preset)
|
|
204
|
+
{
|
|
205
|
+
this.presets.push(...preset);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
flush()
|
|
209
|
+
{
|
|
210
|
+
this.presets.sort((a, b) => (a.program - b.program) + (a.bank - b.bank));
|
|
211
|
+
this._parseInternal();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* @param instrument {BasicInstrument}
|
|
216
|
+
*/
|
|
217
|
+
addInstruments(...instrument)
|
|
218
|
+
{
|
|
219
|
+
this.instruments.push(...instrument);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* @param sample {BasicSample}
|
|
224
|
+
*/
|
|
225
|
+
addSamples(...sample)
|
|
226
|
+
{
|
|
227
|
+
this.samples.push(...sample);
|
|
228
|
+
}
|
|
229
|
+
|
|
163
230
|
/**
|
|
164
231
|
* parses the bank after loading is done
|
|
165
232
|
* @protected
|
|
@@ -209,7 +276,7 @@ class BasicSoundBank
|
|
|
209
276
|
const soundfont = this;
|
|
210
277
|
|
|
211
278
|
/**
|
|
212
|
-
* @param instrument {
|
|
279
|
+
* @param instrument {BasicInstrument}
|
|
213
280
|
* @param combos {{key: number, velocity: number}[]}
|
|
214
281
|
* @returns {number}
|
|
215
282
|
*/
|
|
@@ -219,10 +286,6 @@ class BasicSoundBank
|
|
|
219
286
|
for (let iZoneIndex = 0; iZoneIndex < instrument.instrumentZones.length; iZoneIndex++)
|
|
220
287
|
{
|
|
221
288
|
const iZone = instrument.instrumentZones[iZoneIndex];
|
|
222
|
-
if (iZone.isGlobal)
|
|
223
|
-
{
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
289
|
const iKeyRange = iZone.keyRange;
|
|
227
290
|
const iVelRange = iZone.velRange;
|
|
228
291
|
let isIZoneUsed = false;
|
|
@@ -240,14 +303,13 @@ class BasicSoundBank
|
|
|
240
303
|
if (!isIZoneUsed)
|
|
241
304
|
{
|
|
242
305
|
SpessaSynthInfo(
|
|
243
|
-
`%c${iZone.sample.sampleName} %cremoved from %c${instrument.instrumentName}%c
|
|
306
|
+
`%c${iZone.sample.sampleName} %cremoved from %c${instrument.instrumentName}%c.`,
|
|
244
307
|
consoleColors.recognized,
|
|
245
308
|
consoleColors.info,
|
|
246
309
|
consoleColors.recognized,
|
|
247
|
-
consoleColors.info
|
|
248
|
-
consoleColors.recognized
|
|
310
|
+
consoleColors.info
|
|
249
311
|
);
|
|
250
|
-
if (instrument.
|
|
312
|
+
if (instrument.deleteZone(iZoneIndex))
|
|
251
313
|
{
|
|
252
314
|
trimmedIZones++;
|
|
253
315
|
iZoneIndex--;
|
|
@@ -293,6 +355,7 @@ class BasicSoundBank
|
|
|
293
355
|
consoleColors.info
|
|
294
356
|
);
|
|
295
357
|
soundfont.deletePreset(p);
|
|
358
|
+
soundfont.removeUnusedElements();
|
|
296
359
|
presetIndex--;
|
|
297
360
|
}
|
|
298
361
|
else
|
|
@@ -316,10 +379,6 @@ class BasicSoundBank
|
|
|
316
379
|
for (let zoneIndex = 0; zoneIndex < p.presetZones.length; zoneIndex++)
|
|
317
380
|
{
|
|
318
381
|
const zone = p.presetZones[zoneIndex];
|
|
319
|
-
if (zone.isGlobal)
|
|
320
|
-
{
|
|
321
|
-
continue;
|
|
322
|
-
}
|
|
323
382
|
const keyRange = zone.keyRange;
|
|
324
383
|
const velRange = zone.velRange;
|
|
325
384
|
// check if any of the combos matches the zone
|
|
@@ -384,13 +443,7 @@ class BasicSoundBank
|
|
|
384
443
|
{
|
|
385
444
|
if (i.useCount < 1)
|
|
386
445
|
{
|
|
387
|
-
i.
|
|
388
|
-
{
|
|
389
|
-
if (!z.isGlobal)
|
|
390
|
-
{
|
|
391
|
-
z.sample.useCount--;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
446
|
+
i.deleteZones();
|
|
394
447
|
}
|
|
395
448
|
});
|
|
396
449
|
this.instruments = this.instruments.filter(i => i.useCount > 0);
|
|
@@ -407,8 +460,7 @@ class BasicSoundBank
|
|
|
407
460
|
throw new Error(`Cannot delete an instrument that has ${instrument.useCount} usages.`);
|
|
408
461
|
}
|
|
409
462
|
this.instruments.splice(this.instruments.indexOf(instrument), 1);
|
|
410
|
-
instrument.
|
|
411
|
-
this.removeUnusedElements();
|
|
463
|
+
instrument.deleteZones();
|
|
412
464
|
}
|
|
413
465
|
|
|
414
466
|
/**
|
|
@@ -418,7 +470,6 @@ class BasicSoundBank
|
|
|
418
470
|
{
|
|
419
471
|
preset.deletePreset();
|
|
420
472
|
this.presets.splice(this.presets.indexOf(preset), 1);
|
|
421
|
-
this.removeUnusedElements();
|
|
422
473
|
}
|
|
423
474
|
|
|
424
475
|
/**
|
|
@@ -431,7 +482,6 @@ class BasicSoundBank
|
|
|
431
482
|
throw new Error(`Cannot delete sample that has ${sample.useCount} usages.`);
|
|
432
483
|
}
|
|
433
484
|
this.samples.splice(this.samples.indexOf(sample), 1);
|
|
434
|
-
this.removeUnusedElements();
|
|
435
485
|
}
|
|
436
486
|
|
|
437
487
|
/**
|
|
@@ -563,15 +613,6 @@ class BasicSoundBank
|
|
|
563
613
|
delete this.instruments;
|
|
564
614
|
delete this.samples;
|
|
565
615
|
}
|
|
566
|
-
|
|
567
|
-
// noinspection JSUnusedGlobalSymbols
|
|
568
|
-
/**
|
|
569
|
-
* Clears the cache for all the presets
|
|
570
|
-
*/
|
|
571
|
-
clearCache()
|
|
572
|
-
{
|
|
573
|
-
this.presets.forEach(p => p.clearCache());
|
|
574
|
-
}
|
|
575
616
|
}
|
|
576
617
|
|
|
577
618
|
BasicSoundBank.prototype.write = write;
|