spessasynth_core 1.1.3 → 1.1.5
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 +74 -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,272 +0,0 @@
|
|
|
1
|
-
import { decibelAttenuationToGain, timecentsToSeconds } from './unit_converter.js'
|
|
2
|
-
import { generatorTypes } from '../../../soundfont/chunk/generators.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* volume_envelope.js
|
|
6
|
-
* purpose: applies a volume envelope for a given voice
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {Object} WorkletVolumeEnvelope
|
|
11
|
-
* @property {number} currentAttenuationDb - current voice attenuation in dB (current sample)
|
|
12
|
-
* @property {0|1|2|3|4} state - state of the volume envelope. 0 is delay, 1 is attack, 2 is hold, 3 is decay, 4 is sustain
|
|
13
|
-
* @property {number} releaseStartDb - the dB attenuation of the voice when it was released
|
|
14
|
-
* @property {number} currentReleaseGain - the current linear gain of the release phase
|
|
15
|
-
*
|
|
16
|
-
* @property {number} attackDuration - the duration of the attack phase, in seconds
|
|
17
|
-
* @property {number} decayDuration - the duration of the decay phase, in seconds
|
|
18
|
-
*
|
|
19
|
-
* @property {number} attenuation - the absolute attenuation in dB
|
|
20
|
-
* @property {number} releaseDuration - the duration of the release phase in seconds
|
|
21
|
-
* @property {number} sustainDb - the sustain amount in dB
|
|
22
|
-
*
|
|
23
|
-
* @property {number} delayEnd - the time when delay ends, in absolute seconds
|
|
24
|
-
* @property {number} attackEnd - the time when the attack phase ends, in absolute seconds
|
|
25
|
-
* @property {number} holdEnd - the time when the hold phase ends, in absolute seconds
|
|
26
|
-
* @property {number} decayEnd - the time when the decay phase ends, in absolute seconds
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @type {WorkletVolumeEnvelope}
|
|
31
|
-
*/
|
|
32
|
-
export const DEFAULT_WORKLET_VOLUME_ENVELOPE = {
|
|
33
|
-
attenuation: 100,
|
|
34
|
-
currentAttenuationDb: 100,
|
|
35
|
-
state: 0,
|
|
36
|
-
releaseStartDb: 100,
|
|
37
|
-
attackDuration: 0,
|
|
38
|
-
decayDuration: 0,
|
|
39
|
-
releaseDuration: 0,
|
|
40
|
-
sustainDb: 0,
|
|
41
|
-
delayEnd: 0,
|
|
42
|
-
attackEnd: 0,
|
|
43
|
-
holdEnd: 0,
|
|
44
|
-
decayEnd: 0,
|
|
45
|
-
currentReleaseGain: 1,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export const VOLUME_ENVELOPE_SMOOTHING_FACTOR = 0.001;
|
|
49
|
-
|
|
50
|
-
const DB_SILENCE = 100;
|
|
51
|
-
const GAIN_SILENCE = 0.005;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* VOL ENV STATES:
|
|
55
|
-
* 0 - delay
|
|
56
|
-
* 1 - attack
|
|
57
|
-
* 2 - hold/peak
|
|
58
|
-
* 3 - decay
|
|
59
|
-
* 4 - sustain
|
|
60
|
-
* release is indicated by isInRelease property
|
|
61
|
-
*/
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Recalculates the times of the volume envelope
|
|
65
|
-
* @param voice {WorkletVoice} the voice we're working on
|
|
66
|
-
*/
|
|
67
|
-
export function recalculateVolumeEnvelope(voice)
|
|
68
|
-
{
|
|
69
|
-
const env = voice.volumeEnvelope;
|
|
70
|
-
// calculate durations
|
|
71
|
-
env.attackDuration = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.attackVolEnv]);
|
|
72
|
-
env.decayDuration = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.decayVolEnv]
|
|
73
|
-
+ ((60 - voice.midiNote) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvDecay]));
|
|
74
|
-
env.releaseDuration = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.releaseVolEnv]);
|
|
75
|
-
|
|
76
|
-
// calculate absolute times (they can change, so we have to recalculate every time
|
|
77
|
-
env.attenuation = voice.modulatedGenerators[generatorTypes.initialAttenuation] / 10; // divide by ten to get decibelts
|
|
78
|
-
env.sustainDb = voice.volumeEnvelope.attenuation + voice.modulatedGenerators[generatorTypes.sustainVolEnv] / 10;
|
|
79
|
-
|
|
80
|
-
// calculate absolute end time
|
|
81
|
-
env.delayEnd = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayVolEnv]) + voice.startTime;
|
|
82
|
-
env.attackEnd = env.attackDuration + env.delayEnd;
|
|
83
|
-
|
|
84
|
-
// make sure to take keyNumToVolEnvHold into account!!!
|
|
85
|
-
env.holdEnd = timecentsToSeconds(voice.modulatedGenerators[generatorTypes.holdVolEnv]
|
|
86
|
-
+ ((60 - voice.midiNote) * voice.modulatedGenerators[generatorTypes.keyNumToVolEnvHold]))
|
|
87
|
-
+ env.attackEnd;
|
|
88
|
-
|
|
89
|
-
env.decayEnd = env.decayDuration + env.holdEnd;
|
|
90
|
-
// check if voice is in release
|
|
91
|
-
if(voice.isInRelease)
|
|
92
|
-
{
|
|
93
|
-
// calculate the db attenuation at the time of release (not a constant because it can change (ex, volume set to 0, the sound should cut off)
|
|
94
|
-
switch (env.state) {
|
|
95
|
-
case 0:
|
|
96
|
-
env.releaseStartDb = 0;
|
|
97
|
-
break;
|
|
98
|
-
|
|
99
|
-
case 1:
|
|
100
|
-
// attack phase
|
|
101
|
-
// attack is linear (in gain) so we need to do get db from that
|
|
102
|
-
let elapsed = 1 - ((env.attackEnd - voice.releaseStartTime) / env.attackDuration);
|
|
103
|
-
// calculate the gain that the attack would have
|
|
104
|
-
let attackGain = elapsed * decibelAttenuationToGain(env.attenuation);
|
|
105
|
-
|
|
106
|
-
// turn that into db
|
|
107
|
-
env.releaseStartDb = 20 * Math.log10(attackGain) * -1;
|
|
108
|
-
break;
|
|
109
|
-
|
|
110
|
-
case 2:
|
|
111
|
-
env.releaseStartDb = env.attenuation;
|
|
112
|
-
break;
|
|
113
|
-
|
|
114
|
-
case 3:
|
|
115
|
-
env.releaseStartDb = (1 - (env.decayEnd - voice.releaseStartTime) / env.decayDuration) * (env.sustainDb - env.attenuation) + env.attenuation;
|
|
116
|
-
break;
|
|
117
|
-
|
|
118
|
-
case 4:
|
|
119
|
-
env.releaseStartDb = env.sustainDb;
|
|
120
|
-
break;
|
|
121
|
-
|
|
122
|
-
default:
|
|
123
|
-
env.releaseStartDb = env.currentAttenuationDb;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Applies volume envelope gain to the given output buffer
|
|
130
|
-
* @param voice {WorkletVoice} the voice we're working on
|
|
131
|
-
* @param audioBuffer {Float32Array} the audio buffer to modify
|
|
132
|
-
* @param currentTime {number} the current audio time
|
|
133
|
-
* @param centibelOffset {number} the centibel offset of volume, for modLFOtoVolume
|
|
134
|
-
* @param sampleTime {number} single sample time in seconds, usually 1 / 44100 of a second
|
|
135
|
-
* @param smoothingFactor {number} the adjusted smoothing factor for the envelope
|
|
136
|
-
*/
|
|
137
|
-
|
|
138
|
-
export function applyVolumeEnvelope(voice, audioBuffer, currentTime, centibelOffset, sampleTime, smoothingFactor)
|
|
139
|
-
{
|
|
140
|
-
let decibelOffset = centibelOffset / 10;
|
|
141
|
-
const env = voice.volumeEnvelope;
|
|
142
|
-
|
|
143
|
-
// RELEASE PHASE
|
|
144
|
-
if(voice.isInRelease)
|
|
145
|
-
{
|
|
146
|
-
// release needs a more aggressive smoothing factor as the instant notes don't end instantly when they should
|
|
147
|
-
const releaseSmoothingFactor = smoothingFactor * 10;
|
|
148
|
-
const releaseStartDb = env.releaseStartDb + decibelOffset;
|
|
149
|
-
let elapsedRelease = currentTime - voice.releaseStartTime;
|
|
150
|
-
let dbDifference = DB_SILENCE - releaseStartDb;
|
|
151
|
-
let gain = env.currentReleaseGain;
|
|
152
|
-
for (let i = 0; i < audioBuffer.length; i++)
|
|
153
|
-
{
|
|
154
|
-
let db = (elapsedRelease / env.releaseDuration) * dbDifference + releaseStartDb;
|
|
155
|
-
gain = decibelAttenuationToGain(db + decibelOffset);
|
|
156
|
-
env.currentReleaseGain += (gain - env.currentReleaseGain) * releaseSmoothingFactor;
|
|
157
|
-
audioBuffer[i] *= env.currentReleaseGain;
|
|
158
|
-
elapsedRelease += sampleTime;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if(env.currentReleaseGain <= GAIN_SILENCE)
|
|
162
|
-
{
|
|
163
|
-
voice.finished = true;
|
|
164
|
-
}
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if(!voice.hasStarted)
|
|
169
|
-
{
|
|
170
|
-
voice.startTime = currentTime;
|
|
171
|
-
recalculateVolumeEnvelope(voice);
|
|
172
|
-
voice.hasStarted = true;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let currentFrameTime = currentTime;
|
|
176
|
-
let filledBuffer = 0;
|
|
177
|
-
switch(env.state)
|
|
178
|
-
{
|
|
179
|
-
case 0:
|
|
180
|
-
// delay phase, no sound is produced
|
|
181
|
-
while(currentFrameTime < env.delayEnd)
|
|
182
|
-
{
|
|
183
|
-
env.currentAttenuationDb = DB_SILENCE;
|
|
184
|
-
audioBuffer[filledBuffer] = 0;
|
|
185
|
-
|
|
186
|
-
currentFrameTime += sampleTime;
|
|
187
|
-
if(++filledBuffer >= audioBuffer.length)
|
|
188
|
-
{
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
env.state++;
|
|
193
|
-
// fallthrough
|
|
194
|
-
|
|
195
|
-
case 1:
|
|
196
|
-
// attack phase: ramp from 0 to attenuation
|
|
197
|
-
while(currentFrameTime < env.attackEnd)
|
|
198
|
-
{
|
|
199
|
-
// Special case: linear gain ramp instead of linear db ramp
|
|
200
|
-
let linearAttenuation = 1 - (env.attackEnd - currentFrameTime) / env.attackDuration; // 0 to 1
|
|
201
|
-
const gain = linearAttenuation * decibelAttenuationToGain(env.attenuation + decibelOffset)
|
|
202
|
-
audioBuffer[filledBuffer] *= gain;
|
|
203
|
-
|
|
204
|
-
// set current attenuation to peak as its invalid during this phase
|
|
205
|
-
env.currentAttenuationDb = env.attenuation;
|
|
206
|
-
|
|
207
|
-
currentFrameTime += sampleTime;
|
|
208
|
-
if(++filledBuffer >= audioBuffer.length)
|
|
209
|
-
{
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
env.state++;
|
|
214
|
-
// fallthrough
|
|
215
|
-
|
|
216
|
-
case 2:
|
|
217
|
-
// hold/peak phase: stay at attenuation
|
|
218
|
-
while(currentFrameTime < env.holdEnd)
|
|
219
|
-
{
|
|
220
|
-
const newAttenuation = env.attenuation
|
|
221
|
-
+ decibelOffset;
|
|
222
|
-
|
|
223
|
-
// interpolate attenuation to prevent clicking
|
|
224
|
-
env.currentAttenuationDb += (newAttenuation - env.currentAttenuationDb) * smoothingFactor;
|
|
225
|
-
audioBuffer[filledBuffer] *= decibelAttenuationToGain(env.currentAttenuationDb);
|
|
226
|
-
|
|
227
|
-
currentFrameTime += sampleTime;
|
|
228
|
-
if(++filledBuffer >= audioBuffer.length)
|
|
229
|
-
{
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
env.state++;
|
|
234
|
-
// fallthrough
|
|
235
|
-
|
|
236
|
-
case 3:
|
|
237
|
-
// decay phase: linear ramp from attenuation to sustain
|
|
238
|
-
while(currentFrameTime < env.decayEnd)
|
|
239
|
-
{
|
|
240
|
-
const newAttenuation = (1 - (env.decayEnd - currentFrameTime) / env.decayDuration) * (env.sustainDb - env.attenuation) + env.attenuation
|
|
241
|
-
+ decibelOffset;
|
|
242
|
-
|
|
243
|
-
// interpolate attenuation to prevent clicking
|
|
244
|
-
env.currentAttenuationDb += (newAttenuation - env.currentAttenuationDb) * smoothingFactor;
|
|
245
|
-
audioBuffer[filledBuffer] *= decibelAttenuationToGain(env.currentAttenuationDb);
|
|
246
|
-
|
|
247
|
-
currentFrameTime += sampleTime;
|
|
248
|
-
if(++filledBuffer >= audioBuffer.length)
|
|
249
|
-
{
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
env.state++;
|
|
254
|
-
// fallthrough
|
|
255
|
-
|
|
256
|
-
case 4:
|
|
257
|
-
// sustain phase: stay at sustain
|
|
258
|
-
while(true)
|
|
259
|
-
{
|
|
260
|
-
// interpolate attenuation to prevent clicking
|
|
261
|
-
const newAttenuation = env.sustainDb
|
|
262
|
-
+ decibelOffset;
|
|
263
|
-
env.currentAttenuationDb += (newAttenuation - env.currentAttenuationDb) * smoothingFactor;
|
|
264
|
-
audioBuffer[filledBuffer] *= decibelAttenuationToGain(env.currentAttenuationDb);
|
|
265
|
-
if(++filledBuffer >= audioBuffer.length)
|
|
266
|
-
{
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
}
|
package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/wavetable_oscillator.js
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* wavetable_oscillator.js
|
|
3
|
-
* purpose: plays back raw audio data at an arbitrary playback rate
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Fills the output buffer with raw sample data
|
|
9
|
-
* @param voice {WorkletVoice} the voice we're working on
|
|
10
|
-
* @param sampleData {Float32Array} the sample data to write with
|
|
11
|
-
* @param outputBuffer {Float32Array} the output buffer to write to
|
|
12
|
-
*/
|
|
13
|
-
export function getOscillatorData(voice, sampleData, outputBuffer)
|
|
14
|
-
{
|
|
15
|
-
let cur = voice.sample.cursor;
|
|
16
|
-
const loop = (voice.sample.loopingMode === 1) || (voice.sample.loopingMode === 3 && !voice.isInRelease);
|
|
17
|
-
const loopLength = voice.sample.loopEnd - voice.sample.loopStart;
|
|
18
|
-
|
|
19
|
-
if(loop)
|
|
20
|
-
{
|
|
21
|
-
for (let i = 0; i < outputBuffer.length; i++) {
|
|
22
|
-
// check for loop
|
|
23
|
-
while(cur >= voice.sample.loopEnd) {
|
|
24
|
-
cur -= loopLength;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// grab the 2 nearest points
|
|
28
|
-
const floor = ~~cur;
|
|
29
|
-
let ceil = floor + 1;
|
|
30
|
-
|
|
31
|
-
while(ceil >= voice.sample.loopEnd) {
|
|
32
|
-
ceil -= loopLength;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const fraction = cur - floor;
|
|
36
|
-
|
|
37
|
-
// grab the samples and interpolate
|
|
38
|
-
const upper = sampleData[ceil];
|
|
39
|
-
const lower = sampleData[floor];
|
|
40
|
-
outputBuffer[i] = (lower + (upper - lower) * fraction);
|
|
41
|
-
|
|
42
|
-
// commented code because it's probably gonna come handy... (it did like 6 times already :/)
|
|
43
|
-
// if(isNaN(outputBuffer[i]))
|
|
44
|
-
// {
|
|
45
|
-
// console.error(voice, upper, lower, floor, ceil, cur)
|
|
46
|
-
// throw "NAN ALERT";
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
cur += voice.sample.playbackStep * voice.currentTuningCalculated;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else
|
|
53
|
-
{
|
|
54
|
-
// check and correct end errors
|
|
55
|
-
if(voice.sample.end >= sampleData.length)
|
|
56
|
-
{
|
|
57
|
-
voice.sample.end = sampleData.length - 1;
|
|
58
|
-
}
|
|
59
|
-
for (let i = 0; i < outputBuffer.length; i++) {
|
|
60
|
-
|
|
61
|
-
// linear interpolation
|
|
62
|
-
const floor = ~~cur;
|
|
63
|
-
const ceil = floor + 1;
|
|
64
|
-
|
|
65
|
-
// flag the voice as finished if needed
|
|
66
|
-
if(ceil >= voice.sample.end)
|
|
67
|
-
{
|
|
68
|
-
voice.finished = true;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const fraction = cur - floor;
|
|
73
|
-
|
|
74
|
-
// grab the samples and interpolate
|
|
75
|
-
const upper = sampleData[ceil];
|
|
76
|
-
const lower = sampleData[floor];
|
|
77
|
-
outputBuffer[i] = (lower + (upper - lower) * fraction);
|
|
78
|
-
|
|
79
|
-
cur += voice.sample.playbackStep * voice.currentTuningCalculated;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
voice.sample.cursor = cur;
|
|
83
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { modulatorSources } from '../../../soundfont/chunk/modulators.js'
|
|
2
|
-
import { getModulatorCurveValue, MOD_PRECOMPUTED_LENGTH } from './modulator_curves.js'
|
|
3
|
-
import { NON_CC_INDEX_OFFSET } from './worklet_processor_channel.js'
|
|
4
|
-
import {recalculateVolumeEnvelope} from "./volume_envelope.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* worklet_modulator.js
|
|
8
|
-
* purpose: precomputes all curve types and computes modulators
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Computes a given modulator
|
|
13
|
-
* @param controllerTable {Int16Array} all midi controllers as 14bit values + the non controller indexes, starting at 128
|
|
14
|
-
* @param modulator {Modulator} the modulator to compute
|
|
15
|
-
* @param midiNote {number} the midiNote of the voice belonging to the modulator
|
|
16
|
-
* @param velocity {number} the velocity of the voice belonging to the modulator
|
|
17
|
-
* @returns {number} the computed value
|
|
18
|
-
*/
|
|
19
|
-
export function computeWorkletModulator(controllerTable, modulator, midiNote, velocity)
|
|
20
|
-
{
|
|
21
|
-
if(modulator.transformAmount === 0)
|
|
22
|
-
{
|
|
23
|
-
return 0;
|
|
24
|
-
}
|
|
25
|
-
// mapped to 0-16384
|
|
26
|
-
let rawSourceValue = 0;
|
|
27
|
-
if(modulator.sourceUsesCC)
|
|
28
|
-
{
|
|
29
|
-
rawSourceValue = controllerTable[modulator.sourceIndex];
|
|
30
|
-
}
|
|
31
|
-
else
|
|
32
|
-
{
|
|
33
|
-
const index = modulator.sourceIndex + NON_CC_INDEX_OFFSET;
|
|
34
|
-
switch (modulator.sourceIndex)
|
|
35
|
-
{
|
|
36
|
-
case modulatorSources.noController:
|
|
37
|
-
return 0;// fluid_mod.c line 374 (0 times secondary times amount is still zero)
|
|
38
|
-
|
|
39
|
-
case modulatorSources.noteOnKeyNum:
|
|
40
|
-
rawSourceValue = midiNote << 7;
|
|
41
|
-
break;
|
|
42
|
-
|
|
43
|
-
case modulatorSources.noteOnVelocity:
|
|
44
|
-
case modulatorSources.polyPressure:
|
|
45
|
-
rawSourceValue = velocity << 7;
|
|
46
|
-
break;
|
|
47
|
-
|
|
48
|
-
default:
|
|
49
|
-
rawSourceValue = controllerTable[index]; // use the 7 bit value
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const sourceValue = transforms[modulator.sourceCurveType][modulator.sourcePolarity][modulator.sourceDirection][rawSourceValue];
|
|
56
|
-
|
|
57
|
-
// mapped to 0-127
|
|
58
|
-
let rawSecondSrcValue;
|
|
59
|
-
if(modulator.secSrcUsesCC)
|
|
60
|
-
{
|
|
61
|
-
rawSecondSrcValue = controllerTable[modulator.secSrcIndex];
|
|
62
|
-
}
|
|
63
|
-
else
|
|
64
|
-
{
|
|
65
|
-
const index = modulator.secSrcIndex + NON_CC_INDEX_OFFSET;
|
|
66
|
-
switch (modulator.secSrcIndex)
|
|
67
|
-
{
|
|
68
|
-
case modulatorSources.noController:
|
|
69
|
-
rawSecondSrcValue = 16383;// fluid_mod.c line 376
|
|
70
|
-
break;
|
|
71
|
-
|
|
72
|
-
case modulatorSources.noteOnKeyNum:
|
|
73
|
-
rawSecondSrcValue = midiNote << 7;
|
|
74
|
-
break;
|
|
75
|
-
|
|
76
|
-
case modulatorSources.noteOnVelocity:
|
|
77
|
-
case modulatorSources.polyPressure:
|
|
78
|
-
rawSecondSrcValue = velocity << 7;
|
|
79
|
-
break;
|
|
80
|
-
|
|
81
|
-
default:
|
|
82
|
-
rawSecondSrcValue = controllerTable[index];
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
const secondSrcValue = transforms[modulator.secSrcCurveType][modulator.secSrcPolarity][modulator.secSrcDirection][rawSecondSrcValue];
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
// compute the modulator
|
|
90
|
-
const computedValue = sourceValue * secondSrcValue * modulator.transformAmount;
|
|
91
|
-
|
|
92
|
-
if(modulator.transformType === 2)
|
|
93
|
-
{
|
|
94
|
-
// abs value
|
|
95
|
-
return Math.abs(computedValue);
|
|
96
|
-
}
|
|
97
|
-
return computedValue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Computes all modulators of a given voice
|
|
102
|
-
* @param voice {WorkletVoice} the voice to compute modulators for
|
|
103
|
-
* @param controllerTable {Int16Array} all midi controllers as 14bit values + the non controller indexes, starting at 128
|
|
104
|
-
*/
|
|
105
|
-
export function computeModulators(voice, controllerTable)
|
|
106
|
-
{
|
|
107
|
-
voice.modulatedGenerators.set(voice.generators);
|
|
108
|
-
voice.modulators.forEach(mod => {
|
|
109
|
-
voice.modulatedGenerators[mod.modulatorDestination] += computeWorkletModulator(controllerTable, mod, voice.midiNote, voice.velocity);
|
|
110
|
-
});
|
|
111
|
-
recalculateVolumeEnvelope(voice);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* as follows: transforms[curveType][polarity][direction] is an array
|
|
116
|
-
* @type {Float32Array[][][]}
|
|
117
|
-
*/
|
|
118
|
-
const transforms = [];
|
|
119
|
-
|
|
120
|
-
for(let curve = 0; curve < 4; curve++)
|
|
121
|
-
{
|
|
122
|
-
transforms[curve] =
|
|
123
|
-
[
|
|
124
|
-
[
|
|
125
|
-
new Float32Array(MOD_PRECOMPUTED_LENGTH),
|
|
126
|
-
new Float32Array(MOD_PRECOMPUTED_LENGTH)
|
|
127
|
-
],
|
|
128
|
-
[
|
|
129
|
-
new Float32Array(MOD_PRECOMPUTED_LENGTH),
|
|
130
|
-
new Float32Array(MOD_PRECOMPUTED_LENGTH)
|
|
131
|
-
]
|
|
132
|
-
];
|
|
133
|
-
for (let i = 0; i < MOD_PRECOMPUTED_LENGTH; i++) {
|
|
134
|
-
|
|
135
|
-
// polarity 0 dir 0
|
|
136
|
-
transforms[curve][0][0][i] = getModulatorCurveValue(
|
|
137
|
-
0,
|
|
138
|
-
curve,
|
|
139
|
-
i / MOD_PRECOMPUTED_LENGTH,
|
|
140
|
-
0);
|
|
141
|
-
if (isNaN(transforms[curve][0][0][i])) {
|
|
142
|
-
transforms[curve][0][0][i] = 1;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// polarity 1 dir 0
|
|
146
|
-
transforms[curve][1][0][i] = getModulatorCurveValue(
|
|
147
|
-
0,
|
|
148
|
-
curve,
|
|
149
|
-
i / MOD_PRECOMPUTED_LENGTH,
|
|
150
|
-
1);
|
|
151
|
-
if (isNaN(transforms[curve][1][0][i])) {
|
|
152
|
-
transforms[curve][1][0][i] = 1;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// polarity 0 dir 1
|
|
156
|
-
transforms[curve][0][1][i] = getModulatorCurveValue(
|
|
157
|
-
1,
|
|
158
|
-
curve,
|
|
159
|
-
i / MOD_PRECOMPUTED_LENGTH,
|
|
160
|
-
0);
|
|
161
|
-
if (isNaN(transforms[curve][0][1][i])) {
|
|
162
|
-
transforms[curve][0][1][i] = 1;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// polarity 1 dir 1
|
|
166
|
-
transforms[curve][1][1][i] = getModulatorCurveValue(
|
|
167
|
-
1,
|
|
168
|
-
curve,
|
|
169
|
-
i / MOD_PRECOMPUTED_LENGTH,
|
|
170
|
-
1);
|
|
171
|
-
if (isNaN(transforms[curve][1][1][i])) {
|
|
172
|
-
transforms[curve][1][1][i] = 1;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
package/spessasynth_core/synthetizer/worklet_system/worklet_utilities/worklet_processor_channel.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { midiControllers } from '../../../midi_parser/midi_message.js'
|
|
2
|
-
import { modulatorSources } from '../../../soundfont/chunk/modulators.js'
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {Object} WorkletProcessorChannel
|
|
5
|
-
* @property {Int16Array} midiControllers - array of MIDI controller values
|
|
6
|
-
* @property {boolean[]} lockedControllers - array indicating if a controller is locked
|
|
7
|
-
* @property {Float32Array} customControllers - array of custom (not sf2) control values such as RPN pitch tuning, transpose, modulation depth, etc.
|
|
8
|
-
* @property {boolean} holdPedal - indicates whether the hold pedal is active
|
|
9
|
-
* @property {boolean} drumChannel - indicates whether the channel is a drum channel
|
|
10
|
-
* @property {dataEntryStates} dataEntryState - the current state of the data entry
|
|
11
|
-
* @property {number} NRPCoarse - the current coarse value of the Non-Registered Parameter
|
|
12
|
-
* @property {number} NRPFine - the current fine value of the Non-Registered Parameter
|
|
13
|
-
* @property {number} RPValue - the current value of the Registered Parameter
|
|
14
|
-
*
|
|
15
|
-
* @property {Preset} preset - the channel's preset
|
|
16
|
-
* @property {boolean} lockPreset - indicates whether the program on the channel is locked
|
|
17
|
-
*
|
|
18
|
-
* @property {boolean} lockVibrato - indicates whether the custom vibrato is locked
|
|
19
|
-
* @property {Object} channelVibrato - vibrato settings for the channel
|
|
20
|
-
* @property {number} channelVibrato.depth - depth of the vibrato effect (cents)
|
|
21
|
-
* @property {number} channelVibrato.delay - delay before the vibrato effect starts (seconds)
|
|
22
|
-
* @property {number} channelVibrato.rate - rate of the vibrato oscillation (Hz)
|
|
23
|
-
|
|
24
|
-
* @property {boolean} isMuted - indicates whether the channel is muted
|
|
25
|
-
* @property {WorkletVoice[]} voices - array of voices currently active on the channel
|
|
26
|
-
* @property {WorkletVoice[]} sustainedVoices - array of voices that are sustained on the channel
|
|
27
|
-
* @property {WorkletVoice[][][]} cachedVoices - first is midi note, second is velocity. output is an array of WorkletVoices
|
|
28
|
-
*/
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Adds a new channel
|
|
32
|
-
* @this {Synthesizer}
|
|
33
|
-
*/
|
|
34
|
-
export function addNewChannel()
|
|
35
|
-
{
|
|
36
|
-
/**
|
|
37
|
-
* @type {WorkletProcessorChannel}
|
|
38
|
-
*/
|
|
39
|
-
const channel = {
|
|
40
|
-
midiControllers: new Int16Array(CONTROLLER_TABLE_SIZE),
|
|
41
|
-
lockedControllers: Array(CONTROLLER_TABLE_SIZE).fill(false),
|
|
42
|
-
customControllers: new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE),
|
|
43
|
-
|
|
44
|
-
NRPCoarse: 0,
|
|
45
|
-
NRPFine: 0,
|
|
46
|
-
RPValue: 0,
|
|
47
|
-
dataEntryState: dataEntryStates.Idle,
|
|
48
|
-
|
|
49
|
-
voices: [],
|
|
50
|
-
sustainedVoices: [],
|
|
51
|
-
cachedVoices: [],
|
|
52
|
-
preset: this.defaultPreset,
|
|
53
|
-
|
|
54
|
-
channelVibrato: {delay: 0, depth: 0, rate: 0},
|
|
55
|
-
lockVibrato: false,
|
|
56
|
-
holdPedal: false,
|
|
57
|
-
isMuted: false,
|
|
58
|
-
drumChannel: false,
|
|
59
|
-
lockPreset: false,
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
for (let i = 0; i < 128; i++) {
|
|
63
|
-
channel.cachedVoices.push([]);
|
|
64
|
-
}
|
|
65
|
-
this.workletProcessorChannels.push(channel);
|
|
66
|
-
this.resetControllers(this.workletProcessorChannels.length - 1);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export const NON_CC_INDEX_OFFSET = 128;
|
|
70
|
-
export const CONTROLLER_TABLE_SIZE = 147;
|
|
71
|
-
// an array with preset default values so we can quickly use set() to reset the controllers
|
|
72
|
-
export const resetArray = new Int16Array(CONTROLLER_TABLE_SIZE);
|
|
73
|
-
// default values (the array is 14 bit so shift the 7 bit values by 7 bits)
|
|
74
|
-
resetArray[midiControllers.mainVolume] = 100 << 7;
|
|
75
|
-
resetArray[midiControllers.expressionController] = 127 << 7;
|
|
76
|
-
resetArray[midiControllers.pan] = 64 << 7;
|
|
77
|
-
resetArray[midiControllers.releaseTime] = 64 << 7;
|
|
78
|
-
resetArray[midiControllers.brightness] = 64 << 7;
|
|
79
|
-
resetArray[midiControllers.effects1Depth] = 40 << 7;
|
|
80
|
-
resetArray[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheel] = 8192;
|
|
81
|
-
resetArray[NON_CC_INDEX_OFFSET + modulatorSources.pitchWheelRange] = 2 << 7;
|
|
82
|
-
resetArray[NON_CC_INDEX_OFFSET + modulatorSources.channelPressure] = 127 << 7;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* @enum {number}
|
|
86
|
-
*/
|
|
87
|
-
export const dataEntryStates = {
|
|
88
|
-
Idle: 0,
|
|
89
|
-
RPCoarse: 1,
|
|
90
|
-
RPFine: 2,
|
|
91
|
-
NRPCoarse: 3,
|
|
92
|
-
NRPFine: 4,
|
|
93
|
-
DataCoarse: 5,
|
|
94
|
-
DataFine: 6
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
export const customControllers = {
|
|
99
|
-
channelTuning: 0, // cents
|
|
100
|
-
channelTranspose: 1, // cents
|
|
101
|
-
modulationMultiplier: 2, // cents
|
|
102
|
-
masterTuning: 3, // cents
|
|
103
|
-
}
|
|
104
|
-
export const CUSTOM_CONTROLLER_TABLE_SIZE = Object.keys(customControllers).length;
|
|
105
|
-
export const customResetArray = new Float32Array(CUSTOM_CONTROLLER_TABLE_SIZE);
|
|
106
|
-
customResetArray[customControllers.modulationMultiplier] = 1;
|