spessasynth_core 1.1.3 → 1.1.4
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/LICENSE +3 -26
- package/README.md +156 -474
- package/index.js +73 -8
- package/package.json +21 -8
- package/src/externals/fflate/LICENSE +21 -0
- package/src/externals/fflate/fflate.min.js +1 -0
- package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +12 -0
- package/src/externals/stbvorbis_sync/LICENSE +202 -0
- package/src/externals/stbvorbis_sync/NOTICE +6 -0
- package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +1 -0
- package/src/midi/README.md +32 -0
- package/src/midi/basic_midi.js +567 -0
- package/src/midi/midi_builder.js +202 -0
- package/src/midi/midi_loader.js +324 -0
- package/{spessasynth_core/midi_parser → src/midi}/midi_message.js +58 -35
- package/src/midi/midi_sequence.js +224 -0
- package/src/midi/midi_tools/get_note_times.js +154 -0
- package/src/midi/midi_tools/midi_editor.js +611 -0
- package/src/midi/midi_tools/midi_writer.js +99 -0
- package/src/midi/midi_tools/rmidi_writer.js +567 -0
- package/src/midi/midi_tools/used_keys_loaded.js +238 -0
- package/src/midi/xmf_loader.js +454 -0
- package/src/sequencer/README.md +5 -0
- package/src/sequencer/events.js +81 -0
- package/src/sequencer/play.js +349 -0
- package/src/sequencer/process_event.js +165 -0
- package/{spessasynth_core/sequencer/worklet_sequencer → src/sequencer}/process_tick.js +103 -84
- package/src/sequencer/sequencer_engine.js +367 -0
- package/src/sequencer/song_control.js +201 -0
- package/src/soundfont/README.md +13 -0
- package/src/soundfont/basic_soundfont/basic_instrument.js +77 -0
- package/src/soundfont/basic_soundfont/basic_preset.js +336 -0
- package/src/soundfont/basic_soundfont/basic_sample.js +206 -0
- package/src/soundfont/basic_soundfont/basic_soundfont.js +565 -0
- package/src/soundfont/basic_soundfont/basic_zone.js +64 -0
- package/src/soundfont/basic_soundfont/basic_zones.js +43 -0
- package/src/soundfont/basic_soundfont/generator.js +220 -0
- package/src/soundfont/basic_soundfont/modulator.js +378 -0
- package/src/soundfont/basic_soundfont/riff_chunk.js +149 -0
- package/src/soundfont/basic_soundfont/write_dls/art2.js +173 -0
- package/src/soundfont/basic_soundfont/write_dls/articulator.js +49 -0
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +400 -0
- package/src/soundfont/basic_soundfont/write_dls/ins.js +103 -0
- package/src/soundfont/basic_soundfont/write_dls/lins.js +18 -0
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +330 -0
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +121 -0
- package/src/soundfont/basic_soundfont/write_dls/wave.js +94 -0
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +119 -0
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +78 -0
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +32 -0
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +39 -0
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +80 -0
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +46 -0
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +34 -0
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +39 -0
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +82 -0
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +42 -0
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +46 -0
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +80 -0
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +55 -0
- package/src/soundfont/basic_soundfont/write_sf2/write.js +222 -0
- package/src/soundfont/dls/articulator_converter.js +396 -0
- package/src/soundfont/dls/dls_destinations.js +38 -0
- package/src/soundfont/dls/dls_preset.js +44 -0
- package/src/soundfont/dls/dls_sample.js +75 -0
- package/src/soundfont/dls/dls_soundfont.js +186 -0
- package/src/soundfont/dls/dls_sources.js +62 -0
- package/src/soundfont/dls/dls_zone.js +95 -0
- package/src/soundfont/dls/read_articulation.js +299 -0
- package/src/soundfont/dls/read_instrument.js +121 -0
- package/src/soundfont/dls/read_instrument_list.js +17 -0
- package/src/soundfont/dls/read_lart.js +35 -0
- package/src/soundfont/dls/read_region.js +152 -0
- package/src/soundfont/dls/read_samples.js +270 -0
- package/src/soundfont/load_soundfont.js +21 -0
- package/src/soundfont/read_sf2/generators.js +46 -0
- package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/instruments.js +20 -14
- package/src/soundfont/read_sf2/modulators.js +36 -0
- package/src/soundfont/read_sf2/presets.js +80 -0
- package/src/soundfont/read_sf2/samples.js +304 -0
- package/src/soundfont/read_sf2/soundfont.js +305 -0
- package/{spessasynth_core/soundfont/chunk → src/soundfont/read_sf2}/zones.js +68 -69
- package/src/synthetizer/README.md +7 -0
- package/src/synthetizer/audio_engine/README.md +9 -0
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +266 -0
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +88 -0
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +150 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/lfo.js +9 -6
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +282 -0
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +467 -0
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +181 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/modulator_curves.js +33 -30
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +221 -0
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +120 -0
- package/{spessasynth_core/synthetizer/worklet_system/worklet_utilities → src/synthetizer/audio_engine/engine_components}/unit_converter.js +11 -4
- package/src/synthetizer/audio_engine/engine_components/voice.js +519 -0
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +401 -0
- package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +263 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +132 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +48 -0
- package/src/synthetizer/audio_engine/engine_methods/controller_control/reset_controllers.js +241 -0
- package/src/synthetizer/audio_engine/engine_methods/create_midi_channel.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_coarse.js +253 -0
- package/src/synthetizer/audio_engine/engine_methods/data_entry/data_entry_fine.js +66 -0
- package/src/synthetizer/audio_engine/engine_methods/mute_channel.js +17 -0
- package/src/synthetizer/audio_engine/engine_methods/note_on.js +175 -0
- package/src/synthetizer/audio_engine/engine_methods/portamento_time.js +92 -0
- package/src/synthetizer/audio_engine/engine_methods/program_change.js +61 -0
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +196 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/clear_sound_font.js +30 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/get_preset.js +22 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/reload_sound_font.js +28 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/send_preset_list.js +31 -0
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/set_embedded_sound_font.js +21 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/kill_note.js +20 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/note_off.js +55 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_channels.js +16 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/stop_all_notes.js +30 -0
- package/src/synthetizer/audio_engine/engine_methods/stopping_notes/voice_killing.js +63 -0
- package/src/synthetizer/audio_engine/engine_methods/system_exclusive.js +776 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/channel_pressure.js +24 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/pitch_wheel.js +33 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/poly_pressure.js +31 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +15 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_modulation_depth.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_octave_tuning.js +19 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_tuning.js +27 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_all_channels.js +15 -0
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/transpose_channel.js +34 -0
- package/src/synthetizer/audio_engine/main_processor.js +804 -0
- package/src/synthetizer/audio_engine/snapshot/apply_synthesizer_snapshot.js +15 -0
- package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +175 -0
- package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +116 -0
- package/src/synthetizer/synth_constants.js +22 -0
- package/{spessasynth_core → src}/utils/README.md +1 -0
- package/src/utils/buffer_to_wav.js +185 -0
- package/src/utils/byte_functions/big_endian.js +32 -0
- package/src/utils/byte_functions/little_endian.js +77 -0
- package/src/utils/byte_functions/string.js +107 -0
- package/src/utils/byte_functions/variable_length_quantity.js +42 -0
- package/src/utils/fill_with_defaults.js +21 -0
- package/src/utils/indexed_array.js +52 -0
- package/{spessasynth_core → src}/utils/loggin.js +70 -78
- package/src/utils/other.js +92 -0
- package/src/utils/sysex_detector.js +58 -0
- package/src/utils/xg_hacks.js +193 -0
- package/.idea/inspectionProfiles/Project_Default.xml +0 -10
- package/.idea/jsLibraryMappings.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/spessasynth_core.iml +0 -12
- package/.idea/vcs.xml +0 -6
- package/spessasynth_core/midi_parser/README.md +0 -3
- package/spessasynth_core/midi_parser/midi_loader.js +0 -386
- package/spessasynth_core/sequencer/sequencer.js +0 -202
- package/spessasynth_core/sequencer/worklet_sequencer/play.js +0 -209
- package/spessasynth_core/sequencer/worklet_sequencer/process_event.js +0 -120
- package/spessasynth_core/sequencer/worklet_sequencer/song_control.js +0 -112
- package/spessasynth_core/soundfont/README.md +0 -4
- package/spessasynth_core/soundfont/chunk/generators.js +0 -205
- package/spessasynth_core/soundfont/chunk/modulators.js +0 -232
- package/spessasynth_core/soundfont/chunk/presets.js +0 -264
- package/spessasynth_core/soundfont/chunk/riff_chunk.js +0 -46
- package/spessasynth_core/soundfont/chunk/samples.js +0 -250
- package/spessasynth_core/soundfont/soundfont_parser.js +0 -301
- package/spessasynth_core/synthetizer/README.md +0 -6
- package/spessasynth_core/synthetizer/synthesizer.js +0 -313
- package/spessasynth_core/synthetizer/worklet_system/README.md +0 -3
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/controller_control.js +0 -290
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/data_entry.js +0 -280
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_off.js +0 -102
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/note_on.js +0 -77
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/program_control.js +0 -140
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/system_exclusive.js +0 -266
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/tuning_control.js +0 -104
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/vibrato_control.js +0 -29
- package/spessasynth_core/synthetizer/worklet_system/worklet_methods/voice_control.js +0 -223
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/lowpass_filter.js +0 -133
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/modulation_envelope.js +0 -73
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/stereo_panner.js +0 -76
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/volume_envelope.js +0 -272
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js +0 -83
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_modulator.js +0 -175
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js +0 -106
- package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_voice.js +0 -285
- package/spessasynth_core/utils/buffer_to_wav.js +0 -70
- package/spessasynth_core/utils/byte_functions.js +0 -141
- package/spessasynth_core/utils/other.js +0 -49
- package/spessasynth_core/utils/shiftable_array.js +0 -26
- package/spessasynth_core/utils/stbvorbis_sync.js +0 -1877
|
@@ -1,102 +1,96 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {RiffChunk} from "
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {Modulator} from "./modulators.js";
|
|
1
|
+
import { readLittleEndian } from "../../utils/byte_functions/little_endian.js";
|
|
2
|
+
import { IndexedByteArray } from "../../utils/indexed_array.js";
|
|
3
|
+
import { RiffChunk } from "../basic_soundfont/riff_chunk.js";
|
|
4
|
+
import { BasicInstrumentZone, BasicPresetZone } from "../basic_soundfont/basic_zones.js";
|
|
5
|
+
import { Generator, generatorTypes } from "../basic_soundfont/generator.js";
|
|
6
|
+
import { Modulator } from "../basic_soundfont/modulator.js";
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* zones.js
|
|
11
10
|
* purpose: reads instrumend and preset zones from soundfont and gets their respective samples and generators and modulators
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
|
-
export class InstrumentZone
|
|
13
|
+
export class InstrumentZone extends BasicInstrumentZone
|
|
14
|
+
{
|
|
15
15
|
/**
|
|
16
16
|
* Creates a zone (instrument)
|
|
17
|
-
* @param dataArray {
|
|
17
|
+
* @param dataArray {IndexedByteArray}
|
|
18
18
|
*/
|
|
19
|
-
constructor(dataArray)
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
constructor(dataArray)
|
|
20
|
+
{
|
|
21
|
+
super();
|
|
22
|
+
this.generatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
23
|
+
this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
22
24
|
this.modulatorZoneSize = 0;
|
|
23
25
|
this.generatorZoneSize = 0;
|
|
24
|
-
this.keyRange = {min: 0, max: 127};
|
|
25
|
-
this.velRange = {min: 0, max: 127}
|
|
26
26
|
this.isGlobal = true;
|
|
27
|
-
/**
|
|
28
|
-
* @type {Generator[]}
|
|
29
|
-
*/
|
|
30
|
-
this.generators = [];
|
|
31
|
-
/**
|
|
32
|
-
* @type {Modulator[]}
|
|
33
|
-
*/
|
|
34
|
-
this.modulators = [];
|
|
35
27
|
}
|
|
36
|
-
|
|
28
|
+
|
|
37
29
|
setZoneSize(modulatorZoneSize, generatorZoneSize)
|
|
38
30
|
{
|
|
39
31
|
this.modulatorZoneSize = modulatorZoneSize;
|
|
40
32
|
this.generatorZoneSize = generatorZoneSize;
|
|
41
33
|
}
|
|
42
|
-
|
|
34
|
+
|
|
43
35
|
/**
|
|
44
36
|
* grab the generators
|
|
45
37
|
* @param generators {Generator[]}
|
|
46
38
|
*/
|
|
47
39
|
getGenerators(generators)
|
|
48
40
|
{
|
|
49
|
-
for(let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
41
|
+
for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
50
42
|
{
|
|
51
43
|
this.generators.push(generators[i]);
|
|
52
44
|
}
|
|
53
45
|
}
|
|
54
|
-
|
|
46
|
+
|
|
55
47
|
/**
|
|
56
48
|
* grab the modulators
|
|
57
49
|
* @param modulators {Modulator[]}
|
|
58
50
|
*/
|
|
59
51
|
getModulators(modulators)
|
|
60
52
|
{
|
|
61
|
-
for(let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
53
|
+
for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
62
54
|
{
|
|
63
55
|
this.modulators.push(modulators[i]);
|
|
64
56
|
}
|
|
65
57
|
}
|
|
66
|
-
|
|
58
|
+
|
|
67
59
|
/**
|
|
68
60
|
* Loads the zone's sample
|
|
69
|
-
* @param samples {
|
|
61
|
+
* @param samples {BasicSample[]}
|
|
70
62
|
*/
|
|
71
|
-
getSample(samples)
|
|
63
|
+
getSample(samples)
|
|
64
|
+
{
|
|
72
65
|
let sampleID = this.generators.find(g => g.generatorType === generatorTypes.sampleID);
|
|
73
66
|
if (sampleID)
|
|
74
67
|
{
|
|
75
68
|
this.sample = samples[sampleID.generatorValue];
|
|
76
69
|
this.isGlobal = false;
|
|
70
|
+
this.sample.useCount++;
|
|
77
71
|
}
|
|
78
72
|
}
|
|
79
|
-
|
|
73
|
+
|
|
80
74
|
/**
|
|
81
75
|
* Reads the keyRange of the zone
|
|
82
76
|
*/
|
|
83
77
|
getKeyRange()
|
|
84
78
|
{
|
|
85
79
|
let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
|
|
86
|
-
if(range)
|
|
80
|
+
if (range)
|
|
87
81
|
{
|
|
88
82
|
this.keyRange.min = range.generatorValue & 0x7F;
|
|
89
83
|
this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
90
84
|
}
|
|
91
85
|
}
|
|
92
|
-
|
|
86
|
+
|
|
93
87
|
/**
|
|
94
88
|
* reads the velolicty range of the zone
|
|
95
89
|
*/
|
|
96
90
|
getVelRange()
|
|
97
91
|
{
|
|
98
92
|
let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
|
|
99
|
-
if(range)
|
|
93
|
+
if (range)
|
|
100
94
|
{
|
|
101
95
|
this.velRange.min = range.generatorValue & 0x7F;
|
|
102
96
|
this.velRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
@@ -105,11 +99,11 @@ export class InstrumentZone {
|
|
|
105
99
|
}
|
|
106
100
|
|
|
107
101
|
/**
|
|
108
|
-
* Reads the given instrument zone
|
|
102
|
+
* Reads the given instrument zone read
|
|
109
103
|
* @param zonesChunk {RiffChunk}
|
|
110
104
|
* @param instrumentGenerators {Generator[]}
|
|
111
105
|
* @param instrumentModulators {Modulator[]}
|
|
112
|
-
* @param instrumentSamples {
|
|
106
|
+
* @param instrumentSamples {BasicSample[]}
|
|
113
107
|
* @returns {InstrumentZone[]}
|
|
114
108
|
*/
|
|
115
109
|
export function readInstrumentZones(zonesChunk, instrumentGenerators, instrumentModulators, instrumentSamples)
|
|
@@ -118,10 +112,10 @@ export function readInstrumentZones(zonesChunk, instrumentGenerators, instrument
|
|
|
118
112
|
* @type {InstrumentZone[]}
|
|
119
113
|
*/
|
|
120
114
|
let zones = [];
|
|
121
|
-
while(zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
|
|
115
|
+
while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
|
|
122
116
|
{
|
|
123
117
|
let zone = new InstrumentZone(zonesChunk.chunkData);
|
|
124
|
-
if(zones.length > 0)
|
|
118
|
+
if (zones.length > 0)
|
|
125
119
|
{
|
|
126
120
|
let modulatorZoneSize = zone.modulatorZoneStartIndex - zones[zones.length - 1].modulatorZoneStartIndex;
|
|
127
121
|
let generatorZoneSize = zone.generatorZoneStartIndex - zones[zones.length - 1].generatorZoneStartIndex;
|
|
@@ -134,95 +128,95 @@ export function readInstrumentZones(zonesChunk, instrumentGenerators, instrument
|
|
|
134
128
|
}
|
|
135
129
|
zones.push(zone);
|
|
136
130
|
}
|
|
131
|
+
if (zones.length > 1)
|
|
132
|
+
{
|
|
133
|
+
// remove terminal
|
|
134
|
+
zones.pop();
|
|
135
|
+
}
|
|
137
136
|
return zones;
|
|
138
137
|
}
|
|
139
138
|
|
|
140
|
-
export class PresetZone
|
|
139
|
+
export class PresetZone extends BasicPresetZone
|
|
140
|
+
{
|
|
141
141
|
/**
|
|
142
142
|
* Creates a zone (preset)
|
|
143
|
-
* @param dataArray {
|
|
143
|
+
* @param dataArray {IndexedByteArray}
|
|
144
144
|
*/
|
|
145
|
-
constructor(dataArray)
|
|
146
|
-
|
|
147
|
-
|
|
145
|
+
constructor(dataArray)
|
|
146
|
+
{
|
|
147
|
+
super();
|
|
148
|
+
this.generatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
149
|
+
this.modulatorZoneStartIndex = readLittleEndian(dataArray, 2);
|
|
148
150
|
this.modulatorZoneSize = 0;
|
|
149
151
|
this.generatorZoneSize = 0;
|
|
150
|
-
this.keyRange = {min: 0, max: 127};
|
|
151
|
-
this.velRange = {min: 0, max: 127}
|
|
152
152
|
this.isGlobal = true;
|
|
153
|
-
/**
|
|
154
|
-
* @type {Generator[]}
|
|
155
|
-
*/
|
|
156
|
-
this.generators = [];
|
|
157
|
-
/**
|
|
158
|
-
* @type {Modulator[]}
|
|
159
|
-
*/
|
|
160
|
-
this.modulators = [];
|
|
161
153
|
}
|
|
162
|
-
|
|
154
|
+
|
|
163
155
|
setZoneSize(modulatorZoneSize, generatorZoneSize)
|
|
164
156
|
{
|
|
165
157
|
this.modulatorZoneSize = modulatorZoneSize;
|
|
166
158
|
this.generatorZoneSize = generatorZoneSize;
|
|
167
159
|
}
|
|
168
|
-
|
|
160
|
+
|
|
169
161
|
/**
|
|
170
162
|
* grab the generators
|
|
171
163
|
* @param generators {Generator[]}
|
|
172
164
|
*/
|
|
173
165
|
getGenerators(generators)
|
|
174
166
|
{
|
|
175
|
-
for(let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
167
|
+
for (let i = this.generatorZoneStartIndex; i < this.generatorZoneStartIndex + this.generatorZoneSize; i++)
|
|
176
168
|
{
|
|
177
169
|
this.generators.push(generators[i]);
|
|
178
170
|
}
|
|
179
171
|
}
|
|
180
|
-
|
|
172
|
+
|
|
181
173
|
/**
|
|
182
174
|
* grab the modulators
|
|
183
175
|
* @param modulators {Modulator[]}
|
|
184
176
|
*/
|
|
185
177
|
getModulators(modulators)
|
|
186
178
|
{
|
|
187
|
-
for(let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
179
|
+
for (let i = this.modulatorZoneStartIndex; i < this.modulatorZoneStartIndex + this.modulatorZoneSize; i++)
|
|
188
180
|
{
|
|
189
181
|
this.modulators.push(modulators[i]);
|
|
190
182
|
}
|
|
191
183
|
}
|
|
192
|
-
|
|
184
|
+
|
|
193
185
|
/**
|
|
194
186
|
* grab the instrument
|
|
195
|
-
* @param instruments {
|
|
187
|
+
* @param instruments {BasicInstrument[]}
|
|
196
188
|
*/
|
|
197
189
|
getInstrument(instruments)
|
|
198
190
|
{
|
|
199
191
|
let instrumentID = this.generators.find(g => g.generatorType === generatorTypes.instrument);
|
|
200
|
-
if(instrumentID)
|
|
192
|
+
if (instrumentID)
|
|
193
|
+
{
|
|
201
194
|
this.instrument = instruments[instrumentID.generatorValue];
|
|
195
|
+
this.instrument.addUseCount();
|
|
202
196
|
this.isGlobal = false;
|
|
203
197
|
}
|
|
204
198
|
}
|
|
205
|
-
|
|
199
|
+
|
|
206
200
|
/**
|
|
207
201
|
* Reads the keyRange of the zone
|
|
208
202
|
*/
|
|
209
203
|
getKeyRange()
|
|
210
204
|
{
|
|
211
205
|
let range = this.generators.find(g => g.generatorType === generatorTypes.keyRange);
|
|
212
|
-
if(range)
|
|
206
|
+
if (range)
|
|
213
207
|
{
|
|
214
208
|
this.keyRange.min = range.generatorValue & 0x7F;
|
|
215
209
|
this.keyRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
216
210
|
}
|
|
217
211
|
}
|
|
218
|
-
|
|
212
|
+
|
|
219
213
|
/**
|
|
220
214
|
* reads the velolicty range of the zone
|
|
221
215
|
*/
|
|
222
216
|
getVelRange()
|
|
223
217
|
{
|
|
224
218
|
let range = this.generators.find(g => g.generatorType === generatorTypes.velRange);
|
|
225
|
-
if(range)
|
|
219
|
+
if (range)
|
|
226
220
|
{
|
|
227
221
|
this.velRange.min = range.generatorValue & 0x7F;
|
|
228
222
|
this.velRange.max = (range.generatorValue >> 8) & 0x7F;
|
|
@@ -231,10 +225,10 @@ export class PresetZone {
|
|
|
231
225
|
}
|
|
232
226
|
|
|
233
227
|
/**
|
|
234
|
-
* Reads the given preset zone
|
|
228
|
+
* Reads the given preset zone read
|
|
235
229
|
* @param zonesChunk {RiffChunk}
|
|
236
230
|
* @param presetGenerators {Generator[]}
|
|
237
|
-
* @param instruments {
|
|
231
|
+
* @param instruments {BasicInstrument[]}
|
|
238
232
|
* @param presetModulators {Modulator[]}
|
|
239
233
|
* @returns {PresetZone[]}
|
|
240
234
|
*/
|
|
@@ -244,10 +238,10 @@ export function readPresetZones(zonesChunk, presetGenerators, presetModulators,
|
|
|
244
238
|
* @type {PresetZone[]}
|
|
245
239
|
*/
|
|
246
240
|
let zones = [];
|
|
247
|
-
while(zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
|
|
241
|
+
while (zonesChunk.chunkData.length > zonesChunk.chunkData.currentIndex)
|
|
248
242
|
{
|
|
249
243
|
let zone = new PresetZone(zonesChunk.chunkData);
|
|
250
|
-
if(zones.length > 0)
|
|
244
|
+
if (zones.length > 0)
|
|
251
245
|
{
|
|
252
246
|
let modulatorZoneSize = zone.modulatorZoneStartIndex - zones[zones.length - 1].modulatorZoneStartIndex;
|
|
253
247
|
let generatorZoneSize = zone.generatorZoneStartIndex - zones[zones.length - 1].generatorZoneStartIndex;
|
|
@@ -260,5 +254,10 @@ export function readPresetZones(zonesChunk, presetGenerators, presetModulators,
|
|
|
260
254
|
}
|
|
261
255
|
zones.push(zone);
|
|
262
256
|
}
|
|
257
|
+
if (zones.length > 1)
|
|
258
|
+
{
|
|
259
|
+
// remove terminal
|
|
260
|
+
zones.pop();
|
|
261
|
+
}
|
|
263
262
|
return zones;
|
|
264
263
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
## This is the main 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
|
+
- `audio_effects` - the WebAudioAPI audio effects.
|
|
@@ -0,0 +1,9 @@
|
|
|
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, `render_voice.js` file contains the actual DSP synthesis code.
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { getModulatorCurveValue, MOD_PRECOMPUTED_LENGTH } from "./modulator_curves.js";
|
|
2
|
+
import { VolumeEnvelope } from "./volume_envelope.js";
|
|
3
|
+
import { ModulationEnvelope } from "./modulation_envelope.js";
|
|
4
|
+
import { generatorLimits, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
|
|
5
|
+
import { Modulator, modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
6
|
+
import { NON_CC_INDEX_OFFSET } from "./controller_tables.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* compute_modulator.js
|
|
10
|
+
* purpose: precomputes all curve types and computes modulators
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const EFFECT_MODULATOR_TRANSFORM_MULTIPLIER = 1000 / 200;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Computes a given modulator
|
|
17
|
+
* @param controllerTable {Int16Array} all midi controllers as 14bit values + the non-controller indexes, starting at 128
|
|
18
|
+
* @param modulator {Modulator} the modulator to compute
|
|
19
|
+
* @param voice {Voice} the voice belonging to the modulator
|
|
20
|
+
* @returns {number} the computed value
|
|
21
|
+
*/
|
|
22
|
+
export function computeModulator(controllerTable, modulator, voice)
|
|
23
|
+
{
|
|
24
|
+
if (modulator.transformAmount === 0)
|
|
25
|
+
{
|
|
26
|
+
modulator.currentValue = 0;
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
// mapped to 0-16384
|
|
30
|
+
let rawSourceValue;
|
|
31
|
+
if (modulator.sourceUsesCC)
|
|
32
|
+
{
|
|
33
|
+
rawSourceValue = controllerTable[modulator.sourceIndex];
|
|
34
|
+
}
|
|
35
|
+
else
|
|
36
|
+
{
|
|
37
|
+
const index = modulator.sourceIndex + NON_CC_INDEX_OFFSET;
|
|
38
|
+
switch (modulator.sourceIndex)
|
|
39
|
+
{
|
|
40
|
+
case modulatorSources.noController:
|
|
41
|
+
rawSourceValue = 16383; // equals to 1
|
|
42
|
+
break;
|
|
43
|
+
|
|
44
|
+
case modulatorSources.noteOnKeyNum:
|
|
45
|
+
rawSourceValue = voice.midiNote << 7;
|
|
46
|
+
break;
|
|
47
|
+
|
|
48
|
+
case modulatorSources.noteOnVelocity:
|
|
49
|
+
rawSourceValue = voice.velocity << 7;
|
|
50
|
+
break;
|
|
51
|
+
|
|
52
|
+
case modulatorSources.polyPressure:
|
|
53
|
+
rawSourceValue = voice.pressure << 7;
|
|
54
|
+
break;
|
|
55
|
+
|
|
56
|
+
default:
|
|
57
|
+
rawSourceValue = controllerTable[index]; // pitch bend and range are stored in the cc table
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const sourceValue = transforms[modulator.sourceCurveType][modulator.sourcePolarity][modulator.sourceDirection][rawSourceValue];
|
|
64
|
+
|
|
65
|
+
// mapped to 0-127
|
|
66
|
+
let rawSecondSrcValue;
|
|
67
|
+
if (modulator.secSrcUsesCC)
|
|
68
|
+
{
|
|
69
|
+
rawSecondSrcValue = controllerTable[modulator.secSrcIndex];
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
{
|
|
73
|
+
const index = modulator.secSrcIndex + NON_CC_INDEX_OFFSET;
|
|
74
|
+
switch (modulator.secSrcIndex)
|
|
75
|
+
{
|
|
76
|
+
case modulatorSources.noController:
|
|
77
|
+
rawSecondSrcValue = 16383; // equals to 1
|
|
78
|
+
break;
|
|
79
|
+
|
|
80
|
+
case modulatorSources.noteOnKeyNum:
|
|
81
|
+
rawSecondSrcValue = voice.midiNote << 7;
|
|
82
|
+
break;
|
|
83
|
+
|
|
84
|
+
case modulatorSources.noteOnVelocity:
|
|
85
|
+
rawSecondSrcValue = voice.velocity << 7;
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case modulatorSources.polyPressure:
|
|
89
|
+
rawSecondSrcValue = voice.pressure << 7;
|
|
90
|
+
break;
|
|
91
|
+
|
|
92
|
+
default:
|
|
93
|
+
rawSecondSrcValue = controllerTable[index]; // pitch bend and range are stored in the cc table
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
|
97
|
+
const secondSrcValue = transforms[modulator.secSrcCurveType][modulator.secSrcPolarity][modulator.secSrcDirection][rawSecondSrcValue];
|
|
98
|
+
|
|
99
|
+
// see the comment for isEffectModulator (modulator.js in basic_soundfont) for explanation
|
|
100
|
+
let transformAmount = modulator.transformAmount;
|
|
101
|
+
if (modulator.isEffectModulator && transformAmount <= 1000)
|
|
102
|
+
{
|
|
103
|
+
transformAmount *= EFFECT_MODULATOR_TRANSFORM_MULTIPLIER;
|
|
104
|
+
transformAmount = Math.min(transformAmount, 1000);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// compute the modulator
|
|
108
|
+
let computedValue = sourceValue * secondSrcValue * transformAmount;
|
|
109
|
+
|
|
110
|
+
if (modulator.transformType === 2)
|
|
111
|
+
{
|
|
112
|
+
// abs value
|
|
113
|
+
computedValue = Math.abs(computedValue);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
modulator.currentValue = computedValue;
|
|
117
|
+
return computedValue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Computes modulators of a given voice. Source and index indicate what modulators shall be computed
|
|
122
|
+
* @param voice {Voice} the voice to compute modulators for
|
|
123
|
+
* @param controllerTable {Int16Array} all midi controllers as 14bit values + the non-controller indexes, starting at 128
|
|
124
|
+
* @param sourceUsesCC {number} what modulators should be computed, -1 means all, 0 means modulator source enum 1 means midi controller
|
|
125
|
+
* @param sourceIndex {number} enum for the source
|
|
126
|
+
*/
|
|
127
|
+
export function computeModulators(voice, controllerTable, sourceUsesCC = -1, sourceIndex = 0)
|
|
128
|
+
{
|
|
129
|
+
const modulators = voice.modulators;
|
|
130
|
+
const generators = voice.generators;
|
|
131
|
+
const modulatedGenerators = voice.modulatedGenerators;
|
|
132
|
+
|
|
133
|
+
if (sourceUsesCC === -1)
|
|
134
|
+
{
|
|
135
|
+
// All modulators mode: compute all modulators
|
|
136
|
+
modulatedGenerators.set(generators);
|
|
137
|
+
modulators.forEach(mod =>
|
|
138
|
+
{
|
|
139
|
+
const limits = generatorLimits[mod.modulatorDestination];
|
|
140
|
+
const newValue = modulatedGenerators[mod.modulatorDestination] + computeModulator(
|
|
141
|
+
controllerTable,
|
|
142
|
+
mod,
|
|
143
|
+
voice
|
|
144
|
+
);
|
|
145
|
+
modulatedGenerators[mod.modulatorDestination] = Math.max(
|
|
146
|
+
limits.min,
|
|
147
|
+
Math.min(newValue, limits.max)
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
VolumeEnvelope.recalculate(voice);
|
|
151
|
+
ModulationEnvelope.recalculate(voice);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Optimized mode: calculate only modulators that use the given source
|
|
156
|
+
const volenvNeedsRecalculation = new Set([
|
|
157
|
+
generatorTypes.initialAttenuation,
|
|
158
|
+
generatorTypes.delayVolEnv,
|
|
159
|
+
generatorTypes.attackVolEnv,
|
|
160
|
+
generatorTypes.holdVolEnv,
|
|
161
|
+
generatorTypes.decayVolEnv,
|
|
162
|
+
generatorTypes.sustainVolEnv,
|
|
163
|
+
generatorTypes.releaseVolEnv,
|
|
164
|
+
generatorTypes.keyNumToVolEnvHold,
|
|
165
|
+
generatorTypes.keyNumToVolEnvDecay
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
const computedDestinations = new Set();
|
|
169
|
+
|
|
170
|
+
modulators.forEach(mod =>
|
|
171
|
+
{
|
|
172
|
+
if (
|
|
173
|
+
(mod.sourceUsesCC === sourceUsesCC && mod.sourceIndex === sourceIndex) ||
|
|
174
|
+
(mod.secSrcUsesCC === sourceUsesCC && mod.secSrcIndex === sourceIndex)
|
|
175
|
+
)
|
|
176
|
+
{
|
|
177
|
+
const destination = mod.modulatorDestination;
|
|
178
|
+
if (!computedDestinations.has(destination))
|
|
179
|
+
{
|
|
180
|
+
// Reset this destination
|
|
181
|
+
modulatedGenerators[destination] = generators[destination];
|
|
182
|
+
// compute our modulator
|
|
183
|
+
computeModulator(controllerTable, mod, voice);
|
|
184
|
+
// sum the values of all modulators for this destination
|
|
185
|
+
modulators.forEach(m =>
|
|
186
|
+
{
|
|
187
|
+
if (m.modulatorDestination === destination)
|
|
188
|
+
{
|
|
189
|
+
const limits = generatorLimits[mod.modulatorDestination];
|
|
190
|
+
const newValue = modulatedGenerators[mod.modulatorDestination] + m.currentValue;
|
|
191
|
+
modulatedGenerators[mod.modulatorDestination] = Math.max(
|
|
192
|
+
limits.min,
|
|
193
|
+
Math.min(newValue, limits.max)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
computedDestinations.add(destination);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Recalculate volume envelope if necessary
|
|
203
|
+
if ([...computedDestinations].some(dest => volenvNeedsRecalculation.has(dest)))
|
|
204
|
+
{
|
|
205
|
+
VolumeEnvelope.recalculate(voice);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
ModulationEnvelope.recalculate(voice);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* as follows: transforms[curveType][polarity][direction] is an array
|
|
214
|
+
* @type {Float32Array[][][]}
|
|
215
|
+
*/
|
|
216
|
+
const transforms = [];
|
|
217
|
+
|
|
218
|
+
for (let curve = 0; curve < 4; curve++)
|
|
219
|
+
{
|
|
220
|
+
transforms[curve] =
|
|
221
|
+
[
|
|
222
|
+
[
|
|
223
|
+
new Float32Array(MOD_PRECOMPUTED_LENGTH),
|
|
224
|
+
new Float32Array(MOD_PRECOMPUTED_LENGTH)
|
|
225
|
+
],
|
|
226
|
+
[
|
|
227
|
+
new Float32Array(MOD_PRECOMPUTED_LENGTH),
|
|
228
|
+
new Float32Array(MOD_PRECOMPUTED_LENGTH)
|
|
229
|
+
]
|
|
230
|
+
];
|
|
231
|
+
for (let i = 0; i < MOD_PRECOMPUTED_LENGTH; i++)
|
|
232
|
+
{
|
|
233
|
+
|
|
234
|
+
// polarity 0 dir 0
|
|
235
|
+
transforms[curve][0][0][i] = getModulatorCurveValue(
|
|
236
|
+
0,
|
|
237
|
+
curve,
|
|
238
|
+
i / MOD_PRECOMPUTED_LENGTH,
|
|
239
|
+
0
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// polarity 1 dir 0
|
|
243
|
+
transforms[curve][1][0][i] = getModulatorCurveValue(
|
|
244
|
+
0,
|
|
245
|
+
curve,
|
|
246
|
+
i / MOD_PRECOMPUTED_LENGTH,
|
|
247
|
+
1
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// polarity 0 dir 1
|
|
251
|
+
transforms[curve][0][1][i] = getModulatorCurveValue(
|
|
252
|
+
1,
|
|
253
|
+
curve,
|
|
254
|
+
i / MOD_PRECOMPUTED_LENGTH,
|
|
255
|
+
0
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
// polarity 1 dir 1
|
|
259
|
+
transforms[curve][1][1][i] = getModulatorCurveValue(
|
|
260
|
+
1,
|
|
261
|
+
curve,
|
|
262
|
+
i / MOD_PRECOMPUTED_LENGTH,
|
|
263
|
+
1
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { midiControllers } from "../../../midi/midi_message.js";
|
|
2
|
+
import { modulatorSources } from "../../../soundfont/basic_soundfont/modulator.js";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* A bit of explanation:
|
|
6
|
+
* The controller table is stored as an int16 array, it stores 14-bit values.
|
|
7
|
+
* This controller table is then extended with the modulatorSources section,
|
|
8
|
+
* for example, pitch range and pitch range depth.
|
|
9
|
+
* This allows us for precise control range and supports full pitch-wheel resolution.
|
|
10
|
+
*/
|
|
11
|
+
export const NON_CC_INDEX_OFFSET = 128;
|
|
12
|
+
export const CONTROLLER_TABLE_SIZE = 147;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// an array with preset default values, so we can quickly use set() to reset the controllers
|
|
16
|
+
export const resetArray = new Int16Array(CONTROLLER_TABLE_SIZE).fill(0);
|
|
17
|
+
export const setResetValue = (i, v) => resetArray[i] = v << 7;
|
|
18
|
+
|
|
19
|
+
// values come from Falcosoft MidiPlayer 6
|
|
20
|
+
setResetValue(midiControllers.mainVolume, 100);
|
|
21
|
+
setResetValue(midiControllers.balance, 64);
|
|
22
|
+
setResetValue(midiControllers.expressionController, 127);
|
|
23
|
+
setResetValue(midiControllers.pan, 64);
|
|
24
|
+
|
|
25
|
+
setResetValue(midiControllers.portamentoOnOff, 127);
|
|
26
|
+
|
|
27
|
+
setResetValue(midiControllers.filterResonance, 64);
|
|
28
|
+
setResetValue(midiControllers.releaseTime, 64);
|
|
29
|
+
setResetValue(midiControllers.attackTime, 64);
|
|
30
|
+
setResetValue(midiControllers.brightness, 64);
|
|
31
|
+
|
|
32
|
+
setResetValue(midiControllers.decayTime, 64);
|
|
33
|
+
setResetValue(midiControllers.vibratoRate, 64);
|
|
34
|
+
setResetValue(midiControllers.vibratoDepth, 64);
|
|
35
|
+
setResetValue(midiControllers.vibratoDelay, 64);
|
|
36
|
+
setResetValue(midiControllers.generalPurposeController6, 64);
|
|
37
|
+
setResetValue(midiControllers.generalPurposeController8, 64);
|
|
38
|
+
|
|
39
|
+
setResetValue(midiControllers.RPNLsb, 127);
|
|
40
|
+
setResetValue(midiControllers.RPNMsb, 127);
|
|
41
|
+
setResetValue(midiControllers.NRPNLsb, 127);
|
|
42
|
+
setResetValue(midiControllers.NRPNMsb, 127);
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export const PORTAMENTO_CONTROL_UNSET = 1;
|
|
46
|
+
// special case: portamento control
|
|
47
|
+
// since it is only 7-bit, only the values at multiple of 128 are allowed.
|
|
48
|
+
// a value of just 1 indicates no key set, hence no portamento.
|
|
49
|
+
// this is the "initial unset portamento key" flag.
|
|
50
|
+
resetArray[midiControllers.portamentoControl] = PORTAMENTO_CONTROL_UNSET;
|
|
51
|
+
|
|
52
|
+
// pitch wheel
|
|
53
|
+
setResetValue(NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel, 64);
|
|
54
|
+
setResetValue(NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange, 2);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @enum {number}
|
|
58
|
+
*/
|
|
59
|
+
export const customControllers = {
|
|
60
|
+
channelTuning: 0, // cents, RPN for fine tuning
|
|
61
|
+
channelTransposeFine: 1, // cents, only the decimal tuning, (e.g., transpose is 4.5,
|
|
62
|
+
// then shift by 4 keys + tune by 50 cents)
|
|
63
|
+
modulationMultiplier: 2, // cents, set by modulation depth RPN
|
|
64
|
+
masterTuning: 3, // cents, set by system exclusive
|
|
65
|
+
channelTuningSemitones: 4 // semitones, for RPN coarse tuning
|
|
66
|
+
};
|
|
67
|
+
export const CUSTOM_CONTROLLER_TABLE_SIZE = Object.keys(customControllers).length;
|
|
68
|
+
export const customResetArray = new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE);
|
|
69
|
+
customResetArray[customControllers.modulationMultiplier] = 1;
|
|
70
|
+
/**
|
|
71
|
+
* @enum {number}
|
|
72
|
+
*/
|
|
73
|
+
export const dataEntryStates = {
|
|
74
|
+
Idle: 0,
|
|
75
|
+
RPCoarse: 1,
|
|
76
|
+
RPFine: 2,
|
|
77
|
+
NRPCoarse: 3,
|
|
78
|
+
NRPFine: 4,
|
|
79
|
+
DataCoarse: 5,
|
|
80
|
+
DataFine: 6
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* This is a channel configuration enum, it is internally sent from Synthetizer via controller change
|
|
84
|
+
* @enum {number}
|
|
85
|
+
*/
|
|
86
|
+
export const channelConfiguration = {
|
|
87
|
+
velocityOverride: 128 // overrides velocity for the given channel
|
|
88
|
+
};
|