spessasynth_core 3.27.8 → 4.0.1
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 +17178 -0
- package/dist/index.js.map +1 -0
- package/package.json +24 -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,154 +0,0 @@
|
|
|
1
|
-
import { findRIFFListType, readRIFFChunk } from "../basic_soundfont/riff_chunk.js";
|
|
2
|
-
import { readBytesAsString } from "../../utils/byte_functions/string.js";
|
|
3
|
-
import {
|
|
4
|
-
SpessaSynthGroupCollapsed,
|
|
5
|
-
SpessaSynthGroupEnd,
|
|
6
|
-
SpessaSynthInfo,
|
|
7
|
-
SpessaSynthWarn
|
|
8
|
-
} from "../../utils/loggin.js";
|
|
9
|
-
import { consoleColors } from "../../utils/other.js";
|
|
10
|
-
import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
|
|
11
|
-
import { DLSSample } from "./dls_sample.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @this {DLSSoundFont}
|
|
16
|
-
* @param waveListChunk {RiffChunk}
|
|
17
|
-
*/
|
|
18
|
-
export function readDLSSamples(waveListChunk)
|
|
19
|
-
{
|
|
20
|
-
SpessaSynthGroupCollapsed(
|
|
21
|
-
"%cLoading Wave samples...",
|
|
22
|
-
consoleColors.recognized
|
|
23
|
-
);
|
|
24
|
-
let sampleID = 0;
|
|
25
|
-
while (waveListChunk.chunkData.currentIndex < waveListChunk.chunkData.length)
|
|
26
|
-
{
|
|
27
|
-
const waveChunk = readRIFFChunk(waveListChunk.chunkData);
|
|
28
|
-
this.verifyHeader(waveChunk, "LIST");
|
|
29
|
-
this.verifyText(readBytesAsString(waveChunk.chunkData, 4), "wave");
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @type {RiffChunk[]}
|
|
33
|
-
*/
|
|
34
|
-
const waveChunks = [];
|
|
35
|
-
while (waveChunk.chunkData.currentIndex < waveChunk.chunkData.length)
|
|
36
|
-
{
|
|
37
|
-
waveChunks.push(readRIFFChunk(waveChunk.chunkData));
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const fmtChunk = waveChunks.find(c => c.header === "fmt ");
|
|
41
|
-
if (!fmtChunk)
|
|
42
|
-
{
|
|
43
|
-
throw new Error("No fmt chunk in the wave file!");
|
|
44
|
-
}
|
|
45
|
-
// https://github.com/tpn/winsdk-10/blob/9b69fd26ac0c7d0b83d378dba01080e93349c2ed/Include/10.0.14393.0/shared/mmreg.h#L2108
|
|
46
|
-
const wFormatTag = readLittleEndian(fmtChunk.chunkData, 2);
|
|
47
|
-
const channelsAmount = readLittleEndian(fmtChunk.chunkData, 2);
|
|
48
|
-
if (channelsAmount !== 1)
|
|
49
|
-
{
|
|
50
|
-
throw new Error(`Only mono samples are supported. Fmt reports ${channelsAmount} channels`);
|
|
51
|
-
}
|
|
52
|
-
const sampleRate = readLittleEndian(fmtChunk.chunkData, 4);
|
|
53
|
-
// skip avg bytes
|
|
54
|
-
readLittleEndian(fmtChunk.chunkData, 4);
|
|
55
|
-
// blockAlign
|
|
56
|
-
readLittleEndian(fmtChunk.chunkData, 2);
|
|
57
|
-
// it's bits per sample because one channel
|
|
58
|
-
const wBitsPerSample = readLittleEndian(fmtChunk.chunkData, 2);
|
|
59
|
-
const bytesPerSample = wBitsPerSample / 8;
|
|
60
|
-
|
|
61
|
-
const dataChunk = waveChunks.find(c => c.header === "data");
|
|
62
|
-
if (!dataChunk)
|
|
63
|
-
{
|
|
64
|
-
this.parsingError("No data chunk in the WAVE chunk!");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// read sample name
|
|
68
|
-
const waveInfo = findRIFFListType(waveChunks, "INFO");
|
|
69
|
-
let sampleName = `Unnamed ${sampleID}`;
|
|
70
|
-
if (waveInfo)
|
|
71
|
-
{
|
|
72
|
-
let infoChunk = readRIFFChunk(waveInfo.chunkData);
|
|
73
|
-
while (infoChunk.header !== "INAM" && waveInfo.chunkData.currentIndex < waveInfo.chunkData.length)
|
|
74
|
-
{
|
|
75
|
-
infoChunk = readRIFFChunk(waveInfo.chunkData);
|
|
76
|
-
}
|
|
77
|
-
if (infoChunk.header === "INAM")
|
|
78
|
-
{
|
|
79
|
-
sampleName = readBytesAsString(infoChunk.chunkData, infoChunk.size).trim();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// correct defaults
|
|
84
|
-
let sampleKey = 60;
|
|
85
|
-
let samplePitch = 0;
|
|
86
|
-
let sampleLoopStart = 0;
|
|
87
|
-
const sampleLength = dataChunk.size / bytesPerSample;
|
|
88
|
-
let sampleLoopEnd = sampleLength - 1;
|
|
89
|
-
let sampleDbAttenuation = 0;
|
|
90
|
-
|
|
91
|
-
// read wsmp
|
|
92
|
-
const wsmpChunk = waveChunks.find(c => c.header === "wsmp");
|
|
93
|
-
if (wsmpChunk)
|
|
94
|
-
{
|
|
95
|
-
// skip cbsize
|
|
96
|
-
readLittleEndian(wsmpChunk.chunkData, 4);
|
|
97
|
-
sampleKey = readLittleEndian(wsmpChunk.chunkData, 2);
|
|
98
|
-
// section 1.14.2: Each relative pitch unit represents 1/65536 cents.
|
|
99
|
-
// but that doesn't seem true for this one: it's just cents.
|
|
100
|
-
samplePitch = signedInt16(
|
|
101
|
-
wsmpChunk.chunkData[wsmpChunk.chunkData.currentIndex++],
|
|
102
|
-
wsmpChunk.chunkData[wsmpChunk.chunkData.currentIndex++]
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
// pitch correction: convert hundreds to the root key
|
|
106
|
-
const samplePitchSemitones = Math.trunc(samplePitch / 100);
|
|
107
|
-
sampleKey += samplePitchSemitones;
|
|
108
|
-
samplePitch -= samplePitchSemitones * 100;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// gain is applied it manually here (literally multiplying the samples)
|
|
112
|
-
const gainCorrection = readLittleEndian(wsmpChunk.chunkData, 4);
|
|
113
|
-
// convert to signed and turn into decibels
|
|
114
|
-
sampleDbAttenuation = (gainCorrection | 0) / -655360;
|
|
115
|
-
// no idea about ful options
|
|
116
|
-
readLittleEndian(wsmpChunk.chunkData, 4);
|
|
117
|
-
const loopsAmount = readLittleEndian(wsmpChunk.chunkData, 4);
|
|
118
|
-
if (loopsAmount === 1)
|
|
119
|
-
{
|
|
120
|
-
// skip size and type
|
|
121
|
-
readLittleEndian(wsmpChunk.chunkData, 8);
|
|
122
|
-
sampleLoopStart = readLittleEndian(wsmpChunk.chunkData, 4);
|
|
123
|
-
const loopSize = readLittleEndian(wsmpChunk.chunkData, 4);
|
|
124
|
-
sampleLoopEnd = sampleLoopStart + loopSize;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
else
|
|
128
|
-
{
|
|
129
|
-
SpessaSynthWarn("No wsmp chunk in wave... using sane defaults.");
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
this.samples.push(new DLSSample(
|
|
133
|
-
sampleName,
|
|
134
|
-
sampleRate,
|
|
135
|
-
sampleKey,
|
|
136
|
-
samplePitch,
|
|
137
|
-
sampleLoopStart,
|
|
138
|
-
sampleLoopEnd,
|
|
139
|
-
sampleDbAttenuation,
|
|
140
|
-
dataChunk,
|
|
141
|
-
wFormatTag,
|
|
142
|
-
bytesPerSample
|
|
143
|
-
));
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
sampleID++;
|
|
147
|
-
SpessaSynthInfo(
|
|
148
|
-
`%cLoaded sample %c${sampleName}`,
|
|
149
|
-
consoleColors.info,
|
|
150
|
-
consoleColors.recognized
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
SpessaSynthGroupEnd();
|
|
154
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { IndexedByteArray } from "../utils/indexed_array.js";
|
|
2
|
-
import { readBytesAsString } from "../utils/byte_functions/string.js";
|
|
3
|
-
import { DLSSoundFont } from "./dls/dls_soundfont.js";
|
|
4
|
-
import { SoundFont2 } from "./read_sf2/soundfont.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Loads a soundfont or dls file
|
|
8
|
-
* @param buffer {ArrayBuffer} the binary file to load
|
|
9
|
-
* @returns {BasicSoundBank}
|
|
10
|
-
*/
|
|
11
|
-
export function loadSoundFont(buffer)
|
|
12
|
-
{
|
|
13
|
-
const check = buffer.slice(8, 12);
|
|
14
|
-
const a = new IndexedByteArray(check);
|
|
15
|
-
const id = readBytesAsString(a, 4, false).toLowerCase();
|
|
16
|
-
if (id === "dls ")
|
|
17
|
-
{
|
|
18
|
-
return new DLSSoundFont(buffer);
|
|
19
|
-
}
|
|
20
|
-
return new SoundFont2(buffer, false);
|
|
21
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
2
|
-
import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
3
|
-
import { signedInt16 } from "../../utils/byte_functions/little_endian.js";
|
|
4
|
-
import { Generator } from "../basic_soundfont/generator.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export class ReadGenerator extends Generator
|
|
8
|
-
{
|
|
9
|
-
/**
|
|
10
|
-
* Creates a generator
|
|
11
|
-
* @param dataArray {IndexedByteArray}
|
|
12
|
-
*/
|
|
13
|
-
constructor(dataArray)
|
|
14
|
-
{
|
|
15
|
-
super();
|
|
16
|
-
// 4 bytes:
|
|
17
|
-
// type, type, type, value
|
|
18
|
-
const i = dataArray.currentIndex;
|
|
19
|
-
/**
|
|
20
|
-
* @type {generatorTypes|number}
|
|
21
|
-
*/
|
|
22
|
-
this.generatorType = (dataArray[i + 1] << 8) | dataArray[i];
|
|
23
|
-
this.generatorValue = signedInt16(dataArray[i + 2], dataArray[i + 3]);
|
|
24
|
-
dataArray.currentIndex += 4;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Reads the generator read
|
|
30
|
-
* @param generatorChunk {RiffChunk}
|
|
31
|
-
* @returns {Generator[]}
|
|
32
|
-
*/
|
|
33
|
-
export function readGenerators(generatorChunk)
|
|
34
|
-
{
|
|
35
|
-
let gens = [];
|
|
36
|
-
while (generatorChunk.chunkData.length > generatorChunk.chunkData.currentIndex)
|
|
37
|
-
{
|
|
38
|
-
gens.push(new ReadGenerator(generatorChunk.chunkData));
|
|
39
|
-
}
|
|
40
|
-
// remove terminal
|
|
41
|
-
gens.pop();
|
|
42
|
-
return gens;
|
|
43
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* instrument_zones.js
|
|
3
|
-
* purpose: reads instrument zones from soundfont and gets their respective samples and generators and modulators
|
|
4
|
-
*/
|
|
5
|
-
import { BasicInstrumentZone } from "../basic_soundfont/basic_instrument_zone.js";
|
|
6
|
-
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
7
|
-
|
|
8
|
-
export class InstrumentZone extends BasicInstrumentZone
|
|
9
|
-
{
|
|
10
|
-
/**
|
|
11
|
-
* Creates a zone (instrument)
|
|
12
|
-
* @param inst {Instrument}
|
|
13
|
-
*/
|
|
14
|
-
constructor(inst)
|
|
15
|
-
{
|
|
16
|
-
super(inst);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Loads the zone's sample
|
|
21
|
-
* @param samples {BasicSample[]}
|
|
22
|
-
*/
|
|
23
|
-
getSample(samples)
|
|
24
|
-
{
|
|
25
|
-
let sampleID = this.generators.find(g => g.generatorType === generatorTypes.sampleID);
|
|
26
|
-
if (sampleID)
|
|
27
|
-
{
|
|
28
|
-
this.setSample(samples[sampleID.generatorValue]);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Reads the given instrument zone
|
|
35
|
-
* @param indexes {{mod: number[], gen: number[]}}
|
|
36
|
-
* @param instrumentGenerators {Generator[]}
|
|
37
|
-
* @param instrumentModulators {Modulator[]}
|
|
38
|
-
* @param samples {BasicSample[]}
|
|
39
|
-
* @param instruments {Instrument[]}
|
|
40
|
-
*/
|
|
41
|
-
export function applyInstrumentZones(indexes, instrumentGenerators, instrumentModulators, samples, instruments)
|
|
42
|
-
{
|
|
43
|
-
const genStartIndexes = indexes.gen;
|
|
44
|
-
const modStartIndexes = indexes.mod;
|
|
45
|
-
|
|
46
|
-
let modIndex = 0;
|
|
47
|
-
let genIndex = 0;
|
|
48
|
-
for (const instrument of instruments)
|
|
49
|
-
{
|
|
50
|
-
for (let i = 0; i < instrument.zonesCount; i++)
|
|
51
|
-
{
|
|
52
|
-
const gensStart = genStartIndexes[genIndex++];
|
|
53
|
-
const gensEnd = genStartIndexes[genIndex];
|
|
54
|
-
const gens = instrumentGenerators.slice(gensStart, gensEnd);
|
|
55
|
-
const modsStart = modStartIndexes[modIndex++];
|
|
56
|
-
const modsEnd = modStartIndexes[modIndex];
|
|
57
|
-
const mods = instrumentModulators.slice(modsStart, modsEnd);
|
|
58
|
-
// check for global zone
|
|
59
|
-
if (gens.find(g => g.generatorType === generatorTypes.sampleID))
|
|
60
|
-
{
|
|
61
|
-
// regular zone
|
|
62
|
-
const zone = instrument.createZone();
|
|
63
|
-
zone.addGenerators(...gens);
|
|
64
|
-
zone.addModulators(...mods);
|
|
65
|
-
zone.getSample(samples);
|
|
66
|
-
}
|
|
67
|
-
else
|
|
68
|
-
{
|
|
69
|
-
// global zone
|
|
70
|
-
instrument.globalZone.addGenerators(...gens);
|
|
71
|
-
instrument.globalZone.addModulators(...mods);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
2
|
-
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
3
|
-
import { readBytesAsString } from "../../utils/byte_functions/string.js";
|
|
4
|
-
import { BasicInstrument } from "../basic_soundfont/basic_instrument.js";
|
|
5
|
-
|
|
6
|
-
import { InstrumentZone } from "./instrument_zones.js";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* instrument.js
|
|
10
|
-
* purpose: parses soundfont instrument and stores them as a class
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
export class Instrument extends BasicInstrument
|
|
14
|
-
{
|
|
15
|
-
/**
|
|
16
|
-
* @type {number}
|
|
17
|
-
*/
|
|
18
|
-
zoneStartIndex;
|
|
19
|
-
/**
|
|
20
|
-
* @type {number}
|
|
21
|
-
*/
|
|
22
|
-
zonesCount = 0;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Creates an instrument
|
|
26
|
-
* @param instrumentChunk {RiffChunk}
|
|
27
|
-
*/
|
|
28
|
-
constructor(instrumentChunk)
|
|
29
|
-
{
|
|
30
|
-
super();
|
|
31
|
-
this.instrumentName = readBytesAsString(instrumentChunk.chunkData, 20);
|
|
32
|
-
this.zoneStartIndex = readLittleEndian(instrumentChunk.chunkData, 2);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @returns {InstrumentZone}
|
|
37
|
-
*/
|
|
38
|
-
createZone()
|
|
39
|
-
{
|
|
40
|
-
const z = new InstrumentZone(this);
|
|
41
|
-
this.instrumentZones.push(z);
|
|
42
|
-
return z;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Reads the instruments
|
|
48
|
-
* @param instrumentChunk {RiffChunk}
|
|
49
|
-
* @returns {Instrument[]}
|
|
50
|
-
*/
|
|
51
|
-
export function readInstruments(instrumentChunk)
|
|
52
|
-
{
|
|
53
|
-
/**
|
|
54
|
-
* @type {Instrument[]}
|
|
55
|
-
*/
|
|
56
|
-
let instruments = [];
|
|
57
|
-
while (instrumentChunk.chunkData.length > instrumentChunk.chunkData.currentIndex)
|
|
58
|
-
{
|
|
59
|
-
let instrument = new Instrument(instrumentChunk);
|
|
60
|
-
|
|
61
|
-
if (instruments.length > 0)
|
|
62
|
-
{
|
|
63
|
-
const previous = instruments[instruments.length - 1];
|
|
64
|
-
previous.zonesCount = instrument.zoneStartIndex - previous.zoneStartIndex;
|
|
65
|
-
}
|
|
66
|
-
instruments.push(instrument);
|
|
67
|
-
}
|
|
68
|
-
// remove EOI
|
|
69
|
-
instruments.pop();
|
|
70
|
-
return instruments;
|
|
71
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { readLittleEndian, signedInt16 } from "../../utils/byte_functions/little_endian.js";
|
|
2
|
-
import { DecodedModulator, Modulator } from "../basic_soundfont/modulator.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Reads the modulator read
|
|
6
|
-
* @param modulatorChunk {RiffChunk}
|
|
7
|
-
* @returns {Modulator[]}
|
|
8
|
-
*/
|
|
9
|
-
export function readModulators(modulatorChunk)
|
|
10
|
-
{
|
|
11
|
-
let mods = [];
|
|
12
|
-
while (modulatorChunk.chunkData.length > modulatorChunk.chunkData.currentIndex)
|
|
13
|
-
{
|
|
14
|
-
const dataArray = modulatorChunk.chunkData;
|
|
15
|
-
const sourceEnum = readLittleEndian(dataArray, 2);
|
|
16
|
-
const destination = readLittleEndian(dataArray, 2);
|
|
17
|
-
const amount = signedInt16(dataArray[dataArray.currentIndex++], dataArray[dataArray.currentIndex++]);
|
|
18
|
-
const secondarySourceEnum = readLittleEndian(dataArray, 2);
|
|
19
|
-
const transformType = readLittleEndian(dataArray, 2);
|
|
20
|
-
mods.push(new DecodedModulator(sourceEnum, secondarySourceEnum, destination, amount, transformType));
|
|
21
|
-
}
|
|
22
|
-
// remove terminal
|
|
23
|
-
mods.pop();
|
|
24
|
-
return mods;
|
|
25
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { BasicPresetZone } from "../basic_soundfont/basic_preset_zone.js";
|
|
2
|
-
import { Generator } from "../basic_soundfont/generator.js";
|
|
3
|
-
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
4
|
-
import { generatorTypes } from "../basic_soundfont/generator_types.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* preset_zones.js
|
|
8
|
-
* purpose: reads preset zones from soundfont and gets their respective samples and generators and modulators
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export class PresetZone extends BasicPresetZone
|
|
12
|
-
{
|
|
13
|
-
/**
|
|
14
|
-
* Creates a zone (preset)
|
|
15
|
-
* @param preset {BasicPreset}
|
|
16
|
-
*/
|
|
17
|
-
constructor(preset)
|
|
18
|
-
{
|
|
19
|
-
super(preset);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* grab the instrument
|
|
24
|
-
* @param instruments {BasicInstrument[]}
|
|
25
|
-
*/
|
|
26
|
-
getInstrument(instruments)
|
|
27
|
-
{
|
|
28
|
-
let instrumentID = this.generators.find(g => g.generatorType === generatorTypes.instrument);
|
|
29
|
-
if (instrumentID)
|
|
30
|
-
{
|
|
31
|
-
this.setInstrument(instruments[instrumentID.generatorValue]);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Reads the given preset zone
|
|
39
|
-
* @param indexes {{mod: number[], gen: number[]}}
|
|
40
|
-
* @param presetGens {Generator[]}
|
|
41
|
-
* @param instruments {BasicInstrument[]}
|
|
42
|
-
* @param presetMods {Modulator[]}
|
|
43
|
-
* @param presets {Preset[]}
|
|
44
|
-
*/
|
|
45
|
-
export function applyPresetZones(indexes, presetGens, presetMods, instruments, presets)
|
|
46
|
-
{
|
|
47
|
-
const genStartIndexes = indexes.gen;
|
|
48
|
-
const modStartIndexes = indexes.mod;
|
|
49
|
-
|
|
50
|
-
let modIndex = 0;
|
|
51
|
-
let genIndex = 0;
|
|
52
|
-
for (const preset of presets)
|
|
53
|
-
{
|
|
54
|
-
for (let i = 0; i < preset.zonesCount; i++)
|
|
55
|
-
{
|
|
56
|
-
const gensStart = genStartIndexes[genIndex++];
|
|
57
|
-
const gensEnd = genStartIndexes[genIndex];
|
|
58
|
-
const gens = presetGens.slice(gensStart, gensEnd);
|
|
59
|
-
const modsStart = modStartIndexes[modIndex++];
|
|
60
|
-
const modsEnd = modStartIndexes[modIndex];
|
|
61
|
-
const mods = presetMods.slice(modsStart, modsEnd);
|
|
62
|
-
// check for global zone
|
|
63
|
-
if (gens.find(g => g.generatorType === generatorTypes.instrument) !== undefined)
|
|
64
|
-
{
|
|
65
|
-
// regular zone
|
|
66
|
-
const zone = preset.createZone();
|
|
67
|
-
zone.addGenerators(...gens);
|
|
68
|
-
zone.addModulators(...mods);
|
|
69
|
-
zone.getInstrument(instruments);
|
|
70
|
-
}
|
|
71
|
-
else
|
|
72
|
-
{
|
|
73
|
-
// global zone
|
|
74
|
-
preset.globalZone.addGenerators(...gens);
|
|
75
|
-
preset.globalZone.addModulators(...mods);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
2
|
-
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
3
|
-
import { readBytesAsString } from "../../utils/byte_functions/string.js";
|
|
4
|
-
import { BasicPreset } from "../basic_soundfont/basic_preset.js";
|
|
5
|
-
import { PresetZone } from "./preset_zones.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* parses soundfont presets, also includes function for getting the generators and samples from midi note and velocity
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export class Preset extends BasicPreset
|
|
12
|
-
{
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @type {number}
|
|
16
|
-
*/
|
|
17
|
-
zoneStartIndex;
|
|
18
|
-
/**
|
|
19
|
-
* @type {number}
|
|
20
|
-
*/
|
|
21
|
-
zonesCount = 0;
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Creates a preset
|
|
25
|
-
* @param presetChunk {RiffChunk}
|
|
26
|
-
* @param sf2 {BasicSoundBank}
|
|
27
|
-
*/
|
|
28
|
-
constructor(presetChunk, sf2)
|
|
29
|
-
{
|
|
30
|
-
super(sf2);
|
|
31
|
-
this.presetName = readBytesAsString(presetChunk.chunkData, 20)
|
|
32
|
-
.replace(/\d{3}:\d{3}/, ""); // remove those pesky "000:001"
|
|
33
|
-
|
|
34
|
-
this.program = readLittleEndian(presetChunk.chunkData, 2);
|
|
35
|
-
this.bank = readLittleEndian(presetChunk.chunkData, 2);
|
|
36
|
-
this.zoneStartIndex = readLittleEndian(presetChunk.chunkData, 2);
|
|
37
|
-
|
|
38
|
-
// read the dword
|
|
39
|
-
this.library = readLittleEndian(presetChunk.chunkData, 4);
|
|
40
|
-
this.genre = readLittleEndian(presetChunk.chunkData, 4);
|
|
41
|
-
this.morphology = readLittleEndian(presetChunk.chunkData, 4);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* @returns {PresetZone}
|
|
46
|
-
*/
|
|
47
|
-
createZone()
|
|
48
|
-
{
|
|
49
|
-
const z = new PresetZone(this);
|
|
50
|
-
this.presetZones.push(z);
|
|
51
|
-
return z;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Reads the presets
|
|
57
|
-
* @param presetChunk {RiffChunk}
|
|
58
|
-
* @param parent {BasicSoundBank}
|
|
59
|
-
* @returns {Preset[]}
|
|
60
|
-
*/
|
|
61
|
-
export function readPresets(presetChunk, parent)
|
|
62
|
-
{
|
|
63
|
-
/**
|
|
64
|
-
* @type {Preset[]}
|
|
65
|
-
*/
|
|
66
|
-
let presets = [];
|
|
67
|
-
while (presetChunk.chunkData.length > presetChunk.chunkData.currentIndex)
|
|
68
|
-
{
|
|
69
|
-
let preset = new Preset(presetChunk, parent);
|
|
70
|
-
if (presets.length > 0)
|
|
71
|
-
{
|
|
72
|
-
const previous = presets[presets.length - 1];
|
|
73
|
-
previous.zonesCount = preset.zoneStartIndex - previous.zoneStartIndex;
|
|
74
|
-
}
|
|
75
|
-
presets.push(preset);
|
|
76
|
-
}
|
|
77
|
-
// remove EOP
|
|
78
|
-
presets.pop();
|
|
79
|
-
return presets;
|
|
80
|
-
}
|