spessasynth_core 3.27.8 → 4.0.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.
- package/README.md +85 -51
- package/dist/index.d.ts +4057 -0
- package/dist/index.js +17188 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -6
- package/index.js +0 -132
- package/src/externals/README.md +0 -6
- package/src/externals/fflate/LICENSE +0 -21
- package/src/externals/fflate/fflate.min.js +0 -1
- package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
- package/src/externals/stbvorbis_sync/LICENSE +0 -202
- package/src/externals/stbvorbis_sync/NOTICE +0 -6
- package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
- package/src/midi/README.md +0 -32
- package/src/midi/basic_midi.js +0 -587
- package/src/midi/midi_builder.js +0 -203
- package/src/midi/midi_loader.js +0 -321
- package/src/midi/midi_message.js +0 -254
- package/src/midi/midi_sequence.js +0 -230
- package/src/midi/midi_tools/get_note_times.js +0 -154
- package/src/midi/midi_tools/midi_editor.js +0 -611
- package/src/midi/midi_tools/midi_writer.js +0 -105
- package/src/midi/midi_tools/rmidi_writer.js +0 -566
- package/src/midi/midi_tools/used_keys_loaded.js +0 -256
- package/src/midi/xmf_loader.js +0 -454
- package/src/sequencer/README.md +0 -9
- package/src/sequencer/events.js +0 -81
- package/src/sequencer/play.js +0 -362
- package/src/sequencer/process_event.js +0 -165
- package/src/sequencer/process_tick.js +0 -104
- package/src/sequencer/sequencer_engine.js +0 -372
- package/src/sequencer/song_control.js +0 -196
- package/src/soundfont/README.md +0 -11
- package/src/soundfont/basic_soundfont/basic_global_zone.js +0 -6
- package/src/soundfont/basic_soundfont/basic_instrument.js +0 -115
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +0 -45
- package/src/soundfont/basic_soundfont/basic_preset.js +0 -313
- package/src/soundfont/basic_soundfont/basic_preset_zone.js +0 -39
- package/src/soundfont/basic_soundfont/basic_sample.js +0 -477
- package/src/soundfont/basic_soundfont/basic_soundbank.js +0 -740
- package/src/soundfont/basic_soundfont/basic_zone.js +0 -145
- package/src/soundfont/basic_soundfont/generator.js +0 -76
- package/src/soundfont/basic_soundfont/generator_types.js +0 -151
- package/src/soundfont/basic_soundfont/modulator.js +0 -581
- package/src/soundfont/basic_soundfont/riff_chunk.js +0 -195
- package/src/soundfont/basic_soundfont/write_dls/art2.js +0 -174
- package/src/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -374
- package/src/soundfont/basic_soundfont/write_dls/ins.js +0 -85
- package/src/soundfont/basic_soundfont/write_dls/lins.js +0 -15
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +0 -120
- package/src/soundfont/basic_soundfont/write_dls/wave.js +0 -71
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +0 -124
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +0 -35
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +0 -60
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +0 -91
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +0 -42
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +0 -57
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +0 -92
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +0 -61
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +0 -131
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +0 -77
- package/src/soundfont/basic_soundfont/write_sf2/write.js +0 -287
- package/src/soundfont/dls/articulator_converter.js +0 -402
- package/src/soundfont/dls/dls_destinations.js +0 -38
- package/src/soundfont/dls/dls_instrument.js +0 -20
- package/src/soundfont/dls/dls_preset.js +0 -43
- package/src/soundfont/dls/dls_sample.js +0 -238
- package/src/soundfont/dls/dls_soundfont.js +0 -183
- package/src/soundfont/dls/dls_sources.js +0 -63
- package/src/soundfont/dls/dls_zone.js +0 -89
- package/src/soundfont/dls/read_articulation.js +0 -300
- package/src/soundfont/dls/read_instrument.js +0 -118
- package/src/soundfont/dls/read_instrument_list.js +0 -17
- package/src/soundfont/dls/read_lart.js +0 -35
- package/src/soundfont/dls/read_region.js +0 -157
- package/src/soundfont/dls/read_samples.js +0 -154
- package/src/soundfont/load_soundfont.js +0 -21
- package/src/soundfont/read_sf2/generators.js +0 -43
- package/src/soundfont/read_sf2/instrument_zones.js +0 -75
- package/src/soundfont/read_sf2/instruments.js +0 -71
- package/src/soundfont/read_sf2/modulators.js +0 -25
- package/src/soundfont/read_sf2/preset_zones.js +0 -79
- package/src/soundfont/read_sf2/presets.js +0 -80
- package/src/soundfont/read_sf2/samples.js +0 -317
- package/src/soundfont/read_sf2/soundfont.js +0 -452
- package/src/soundfont/read_sf2/zones.js +0 -28
- package/src/synthetizer/README.md +0 -7
- package/src/synthetizer/audio_engine/README.md +0 -9
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -289
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +0 -90
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +0 -95
- package/src/synthetizer/audio_engine/engine_components/enums.js +0 -18
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -151
- package/src/synthetizer/audio_engine/engine_components/lfo.js +0 -26
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -551
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
- package/src/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -265
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -124
- package/src/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
- package/src/synthetizer/audio_engine/engine_components/voice.js +0 -525
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -402
- package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -274
- package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -159
- package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -53
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +0 -254
- package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +0 -20
- package/src/synthetizer/audio_engine/engine_methods/data_entry/awe32.js +0 -198
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +0 -281
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +0 -109
- package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +0 -17
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +0 -220
- package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +0 -92
- package/src/synthetizer/audio_engine/engine_methods/program_change.js +0 -35
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +0 -214
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +0 -42
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +0 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js +0 -19
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +0 -23
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +0 -56
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +0 -16
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +0 -30
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +0 -63
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +0 -1058
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +0 -23
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +0 -31
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +0 -29
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +0 -15
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +0 -26
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +0 -19
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +0 -27
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +0 -15
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +0 -34
- package/src/synthetizer/audio_engine/main_processor.js +0 -817
- package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +0 -16
- package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +0 -175
- package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +0 -116
- package/src/synthetizer/audio_engine/synth_processor_options.js +0 -18
- package/src/synthetizer/synth_constants.js +0 -26
- package/src/utils/README.md +0 -8
- package/src/utils/buffer_to_wav.js +0 -197
- package/src/utils/byte_functions/big_endian.js +0 -32
- package/src/utils/byte_functions/little_endian.js +0 -77
- package/src/utils/byte_functions/string.js +0 -92
- package/src/utils/byte_functions/variable_length_quantity.js +0 -42
- package/src/utils/fill_with_defaults.js +0 -21
- package/src/utils/indexed_array.js +0 -34
- package/src/utils/loggin.js +0 -71
- package/src/utils/other.js +0 -92
- package/src/utils/sysex_detector.js +0 -58
- package/src/utils/xg_hacks.js +0 -193
|
@@ -1,452 +0,0 @@
|
|
|
1
|
-
import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
2
|
-
import { readSamples } from "./samples.js";
|
|
3
|
-
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
4
|
-
import { readGenerators } from "./generators.js";
|
|
5
|
-
import { applyPresetZones } from "./preset_zones.js";
|
|
6
|
-
import { readPresets } from "./presets.js";
|
|
7
|
-
import { readInstruments } from "./instruments.js";
|
|
8
|
-
import { readModulators } from "./modulators.js";
|
|
9
|
-
import { readRIFFChunk, RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
10
|
-
import { consoleColors } from "../../utils/other.js";
|
|
11
|
-
import { SpessaSynthGroup, SpessaSynthGroupEnd, SpessaSynthInfo } from "../../utils/loggin.js";
|
|
12
|
-
import { readBytesAsString } from "../../utils/byte_functions/string.js";
|
|
13
|
-
import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js";
|
|
14
|
-
import { BasicSoundBank } from "../basic_soundfont/basic_soundbank.js";
|
|
15
|
-
import { Generator } from "../basic_soundfont/generator.js";
|
|
16
|
-
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
17
|
-
import { applyInstrumentZones, InstrumentZone } from "./instrument_zones.js";
|
|
18
|
-
import { readZoneIndexes } from "./zones.js";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* soundfont.js
|
|
22
|
-
* purpose: parses a soundfont2 file
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
export class SoundFont2 extends BasicSoundBank
|
|
26
|
-
{
|
|
27
|
-
/**
|
|
28
|
-
* @type {Instrument[]}
|
|
29
|
-
*/
|
|
30
|
-
instruments = [];
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @type {Preset[]}
|
|
34
|
-
*/
|
|
35
|
-
presets = [];
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Initializes a new SoundFont2 Parser and parses the given data array
|
|
39
|
-
* @param arrayBuffer {ArrayBuffer}
|
|
40
|
-
* @param warnDeprecated {boolean}
|
|
41
|
-
*/
|
|
42
|
-
constructor(arrayBuffer, warnDeprecated = true)
|
|
43
|
-
{
|
|
44
|
-
super();
|
|
45
|
-
if (warnDeprecated)
|
|
46
|
-
{
|
|
47
|
-
console.warn("Using the constructor directly is deprecated. Use loadSoundFont instead.");
|
|
48
|
-
}
|
|
49
|
-
const mainFileArray = new IndexedByteArray(arrayBuffer);
|
|
50
|
-
SpessaSynthGroup("%cParsing SoundFont...", consoleColors.info);
|
|
51
|
-
if (!mainFileArray)
|
|
52
|
-
{
|
|
53
|
-
SpessaSynthGroupEnd();
|
|
54
|
-
this.parsingError("No data provided!");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// read the main chunk
|
|
58
|
-
let firstChunk = readRIFFChunk(mainFileArray, false);
|
|
59
|
-
this.verifyHeader(firstChunk, "riff");
|
|
60
|
-
|
|
61
|
-
const type = readBytesAsString(mainFileArray, 4).toLowerCase();
|
|
62
|
-
if (type !== "sfbk" && type !== "sfpk")
|
|
63
|
-
{
|
|
64
|
-
SpessaSynthGroupEnd();
|
|
65
|
-
throw new SyntaxError(`Invalid soundFont! Expected "sfbk" or "sfpk" got "${type}"`);
|
|
66
|
-
}
|
|
67
|
-
/*
|
|
68
|
-
Some SF2Pack description:
|
|
69
|
-
this is essentially sf2, but the entire smpl chunk is compressed (we only support Ogg Vorbis here)
|
|
70
|
-
and the only other difference is that the main chunk isn't "sfbk" but rather "sfpk"
|
|
71
|
-
*/
|
|
72
|
-
const isSF2Pack = type === "sfpk";
|
|
73
|
-
|
|
74
|
-
// INFO
|
|
75
|
-
let infoChunk = readRIFFChunk(mainFileArray);
|
|
76
|
-
this.verifyHeader(infoChunk, "list");
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
while (infoChunk.chunkData.length > infoChunk.chunkData.currentIndex)
|
|
91
|
-
{
|
|
92
|
-
let chunk = readRIFFChunk(infoChunk.chunkData);
|
|
93
|
-
let text;
|
|
94
|
-
// special cases
|
|
95
|
-
switch (chunk.header.toLowerCase())
|
|
96
|
-
{
|
|
97
|
-
case "ifil":
|
|
98
|
-
case "iver":
|
|
99
|
-
text = `${readLittleEndian(chunk.chunkData, 2)}.${readLittleEndian(chunk.chunkData, 2)}`;
|
|
100
|
-
this.soundFontInfo[chunk.header] = text;
|
|
101
|
-
break;
|
|
102
|
-
|
|
103
|
-
case "icmt":
|
|
104
|
-
text = readBytesAsString(chunk.chunkData, chunk.chunkData.length, false);
|
|
105
|
-
this.soundFontInfo[chunk.header] = text;
|
|
106
|
-
break;
|
|
107
|
-
|
|
108
|
-
// dmod: default modulators
|
|
109
|
-
case "dmod":
|
|
110
|
-
const newModulators = readModulators(chunk);
|
|
111
|
-
text = `Modulators: ${newModulators.length}`;
|
|
112
|
-
|
|
113
|
-
// override default modulators
|
|
114
|
-
this.defaultModulators = newModulators;
|
|
115
|
-
this.customDefaultModulators = true;
|
|
116
|
-
this.soundFontInfo[chunk.header] = text;
|
|
117
|
-
break;
|
|
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
|
-
|
|
129
|
-
default:
|
|
130
|
-
text = readBytesAsString(chunk.chunkData, chunk.chunkData.length);
|
|
131
|
-
this.soundFontInfo[chunk.header] = text;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
SpessaSynthInfo(
|
|
135
|
-
`%c"${chunk.header}": %c"${text}"`,
|
|
136
|
-
consoleColors.info,
|
|
137
|
-
consoleColors.recognized
|
|
138
|
-
);
|
|
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
|
-
}
|
|
169
|
-
|
|
170
|
-
// SDTA
|
|
171
|
-
const sdtaChunk = readRIFFChunk(mainFileArray, false);
|
|
172
|
-
this.verifyHeader(sdtaChunk, "list");
|
|
173
|
-
this.verifyText(readBytesAsString(mainFileArray, 4), "sdta");
|
|
174
|
-
|
|
175
|
-
// smpl
|
|
176
|
-
SpessaSynthInfo("%cVerifying smpl chunk...", consoleColors.warn);
|
|
177
|
-
let sampleDataChunk = readRIFFChunk(mainFileArray, false);
|
|
178
|
-
this.verifyHeader(sampleDataChunk, "smpl");
|
|
179
|
-
/**
|
|
180
|
-
* @type {IndexedByteArray|Float32Array}
|
|
181
|
-
*/
|
|
182
|
-
let sampleData;
|
|
183
|
-
// SF2Pack: the entire data is compressed
|
|
184
|
-
if (isSF2Pack)
|
|
185
|
-
{
|
|
186
|
-
SpessaSynthInfo(
|
|
187
|
-
"%cSF2Pack detected, attempting to decode the smpl chunk...",
|
|
188
|
-
consoleColors.info
|
|
189
|
-
);
|
|
190
|
-
try
|
|
191
|
-
{
|
|
192
|
-
/**
|
|
193
|
-
* @type {Float32Array}
|
|
194
|
-
*/
|
|
195
|
-
sampleData = stbvorbis.decode(mainFileArray.buffer.slice(
|
|
196
|
-
mainFileArray.currentIndex,
|
|
197
|
-
mainFileArray.currentIndex + sdtaChunk.size - 12
|
|
198
|
-
)).data[0];
|
|
199
|
-
}
|
|
200
|
-
catch (e)
|
|
201
|
-
{
|
|
202
|
-
SpessaSynthGroupEnd();
|
|
203
|
-
throw new Error(`SF2Pack Ogg Vorbis decode error: ${e}`);
|
|
204
|
-
}
|
|
205
|
-
SpessaSynthInfo(
|
|
206
|
-
`%cDecoded the smpl chunk! Length: %c${sampleData.length}`,
|
|
207
|
-
consoleColors.info,
|
|
208
|
-
consoleColors.value
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
else
|
|
212
|
-
{
|
|
213
|
-
/**
|
|
214
|
-
* @type {IndexedByteArray}
|
|
215
|
-
*/
|
|
216
|
-
sampleData = mainFileArray;
|
|
217
|
-
this.sampleDataStartIndex = mainFileArray.currentIndex;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
SpessaSynthInfo(
|
|
221
|
-
`%cSkipping sample chunk, length: %c${sdtaChunk.size - 12}`,
|
|
222
|
-
consoleColors.info,
|
|
223
|
-
consoleColors.value
|
|
224
|
-
);
|
|
225
|
-
mainFileArray.currentIndex += sdtaChunk.size - 12;
|
|
226
|
-
|
|
227
|
-
// PDTA
|
|
228
|
-
SpessaSynthInfo("%cLoading preset data chunk...", consoleColors.warn);
|
|
229
|
-
let presetChunk = readRIFFChunk(mainFileArray);
|
|
230
|
-
this.verifyHeader(presetChunk, "list");
|
|
231
|
-
readBytesAsString(presetChunk.chunkData, 4);
|
|
232
|
-
|
|
233
|
-
// read the hydra chunks
|
|
234
|
-
const phdrChunk = readRIFFChunk(presetChunk.chunkData);
|
|
235
|
-
this.verifyHeader(phdrChunk, "phdr");
|
|
236
|
-
|
|
237
|
-
const pbagChunk = readRIFFChunk(presetChunk.chunkData);
|
|
238
|
-
this.verifyHeader(pbagChunk, "pbag");
|
|
239
|
-
|
|
240
|
-
const pmodChunk = readRIFFChunk(presetChunk.chunkData);
|
|
241
|
-
this.verifyHeader(pmodChunk, "pmod");
|
|
242
|
-
|
|
243
|
-
const pgenChunk = readRIFFChunk(presetChunk.chunkData);
|
|
244
|
-
this.verifyHeader(pgenChunk, "pgen");
|
|
245
|
-
|
|
246
|
-
const instChunk = readRIFFChunk(presetChunk.chunkData);
|
|
247
|
-
this.verifyHeader(instChunk, "inst");
|
|
248
|
-
|
|
249
|
-
const ibagChunk = readRIFFChunk(presetChunk.chunkData);
|
|
250
|
-
this.verifyHeader(ibagChunk, "ibag");
|
|
251
|
-
|
|
252
|
-
const imodChunk = readRIFFChunk(presetChunk.chunkData);
|
|
253
|
-
this.verifyHeader(imodChunk, "imod");
|
|
254
|
-
|
|
255
|
-
const igenChunk = readRIFFChunk(presetChunk.chunkData);
|
|
256
|
-
this.verifyHeader(igenChunk, "igen");
|
|
257
|
-
|
|
258
|
-
const shdrChunk = readRIFFChunk(presetChunk.chunkData);
|
|
259
|
-
this.verifyHeader(shdrChunk, "shdr");
|
|
260
|
-
|
|
261
|
-
/**
|
|
262
|
-
* read all the samples
|
|
263
|
-
* (the current index points to start of the smpl read)
|
|
264
|
-
*/
|
|
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);
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* read all the instrument generators
|
|
288
|
-
* @type {Generator[]}
|
|
289
|
-
*/
|
|
290
|
-
let instrumentGenerators = readGenerators(igenChunk);
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* read all the instrument modulators
|
|
294
|
-
* @type {Modulator[]}
|
|
295
|
-
*/
|
|
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
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* read all the instrument zones (and apply them)
|
|
343
|
-
* @type {InstrumentZone[]}
|
|
344
|
-
*/
|
|
345
|
-
applyInstrumentZones(
|
|
346
|
-
ibagIndexes,
|
|
347
|
-
instrumentGenerators,
|
|
348
|
-
instrumentModulators,
|
|
349
|
-
this.samples,
|
|
350
|
-
this.instruments
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* read all the preset generators
|
|
355
|
-
* @type {Generator[]}
|
|
356
|
-
*/
|
|
357
|
-
let presetGenerators = readGenerators(pgenChunk);
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* Read all the preset modulatorrs
|
|
361
|
-
* @type {Modulator[]}
|
|
362
|
-
*/
|
|
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 < presets.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);
|
|
393
|
-
|
|
394
|
-
const pbagIndexes = readZoneIndexes(pbagChunk);
|
|
395
|
-
|
|
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);
|
|
410
|
-
this.flush();
|
|
411
|
-
SpessaSynthInfo(
|
|
412
|
-
`%cParsing finished! %c"${this.soundFontInfo["INAM"]}"%c has %c${this.presets.length} %cpresets,
|
|
413
|
-
%c${this.instruments.length}%c instruments and %c${this.samples.length}%c samples.`,
|
|
414
|
-
consoleColors.info,
|
|
415
|
-
consoleColors.recognized,
|
|
416
|
-
consoleColors.info,
|
|
417
|
-
consoleColors.recognized,
|
|
418
|
-
consoleColors.info,
|
|
419
|
-
consoleColors.recognized,
|
|
420
|
-
consoleColors.info,
|
|
421
|
-
consoleColors.recognized,
|
|
422
|
-
consoleColors.info
|
|
423
|
-
);
|
|
424
|
-
SpessaSynthGroupEnd();
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* @param chunk {RiffChunk}
|
|
429
|
-
* @param expected {string}
|
|
430
|
-
*/
|
|
431
|
-
verifyHeader(chunk, expected)
|
|
432
|
-
{
|
|
433
|
-
if (chunk.header.toLowerCase() !== expected.toLowerCase())
|
|
434
|
-
{
|
|
435
|
-
SpessaSynthGroupEnd();
|
|
436
|
-
this.parsingError(`Invalid chunk header! Expected "${expected.toLowerCase()}" got "${chunk.header.toLowerCase()}"`);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* @param text {string}
|
|
442
|
-
* @param expected {string}
|
|
443
|
-
*/
|
|
444
|
-
verifyText(text, expected)
|
|
445
|
-
{
|
|
446
|
-
if (text.toLowerCase() !== expected.toLowerCase())
|
|
447
|
-
{
|
|
448
|
-
SpessaSynthGroupEnd();
|
|
449
|
-
this.parsingError(`Invalid FourCC: Expected "${expected.toLowerCase()}" got "${text.toLowerCase()}"\``);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
## This is the synthesizer folder.
|
|
2
|
-
|
|
3
|
-
The code here is responsible for making the actual sound.
|
|
4
|
-
This is the heart of the SpessaSynth library.
|
|
5
|
-
|
|
6
|
-
- `audio_engine` - the core synthesis engine, it theoretically can run on non-browser environments
|
|
7
|
-
- `synth_constants.js` - contains the synthesizer's configuration constants
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
## This is the synthesis engine folder.
|
|
2
|
-
|
|
3
|
-
The code here is responsible for a single midi channel, synthesizing the sound to it.
|
|
4
|
-
|
|
5
|
-
- `engine_methods` contains the methods for the `main_processor.js`
|
|
6
|
-
- `engine_components` contains the various digital signal processing functions such as the wavetable oscillator, low
|
|
7
|
-
pass filter, etc.
|
|
8
|
-
|
|
9
|
-
For those interested, `engine_methods/render_voice.js` file contains the actual DSP synthesis code.
|