spessasynth_core 3.27.7 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +188 -116
- package/dist/index.d.ts +4057 -0
- package/dist/index.js +17188 -0
- package/dist/index.js.map +1 -0
- package/package.json +23 -6
- package/index.js +0 -132
- package/src/externals/README.md +0 -6
- package/src/externals/fflate/LICENSE +0 -21
- package/src/externals/fflate/fflate.min.js +0 -1
- package/src/externals/stbvorbis_sync/@types/stbvorbis_sync.d.ts +0 -12
- package/src/externals/stbvorbis_sync/LICENSE +0 -202
- package/src/externals/stbvorbis_sync/NOTICE +0 -6
- package/src/externals/stbvorbis_sync/stbvorbis_sync.min.js +0 -1
- package/src/midi/README.md +0 -32
- package/src/midi/basic_midi.js +0 -587
- package/src/midi/midi_builder.js +0 -203
- package/src/midi/midi_loader.js +0 -321
- package/src/midi/midi_message.js +0 -254
- package/src/midi/midi_sequence.js +0 -230
- package/src/midi/midi_tools/get_note_times.js +0 -154
- package/src/midi/midi_tools/midi_editor.js +0 -611
- package/src/midi/midi_tools/midi_writer.js +0 -105
- package/src/midi/midi_tools/rmidi_writer.js +0 -566
- package/src/midi/midi_tools/used_keys_loaded.js +0 -256
- package/src/midi/xmf_loader.js +0 -454
- package/src/sequencer/README.md +0 -9
- package/src/sequencer/events.js +0 -81
- package/src/sequencer/play.js +0 -362
- package/src/sequencer/process_event.js +0 -165
- package/src/sequencer/process_tick.js +0 -104
- package/src/sequencer/sequencer_engine.js +0 -372
- package/src/sequencer/song_control.js +0 -196
- package/src/soundfont/README.md +0 -11
- package/src/soundfont/basic_soundfont/basic_global_zone.js +0 -6
- package/src/soundfont/basic_soundfont/basic_instrument.js +0 -115
- package/src/soundfont/basic_soundfont/basic_instrument_zone.js +0 -45
- package/src/soundfont/basic_soundfont/basic_preset.js +0 -313
- package/src/soundfont/basic_soundfont/basic_preset_zone.js +0 -39
- package/src/soundfont/basic_soundfont/basic_sample.js +0 -477
- package/src/soundfont/basic_soundfont/basic_soundbank.js +0 -740
- package/src/soundfont/basic_soundfont/basic_zone.js +0 -145
- package/src/soundfont/basic_soundfont/generator.js +0 -76
- package/src/soundfont/basic_soundfont/generator_types.js +0 -151
- package/src/soundfont/basic_soundfont/modulator.js +0 -581
- package/src/soundfont/basic_soundfont/riff_chunk.js +0 -195
- package/src/soundfont/basic_soundfont/write_dls/art2.js +0 -174
- package/src/soundfont/basic_soundfont/write_dls/articulator.js +0 -49
- package/src/soundfont/basic_soundfont/write_dls/combine_zones.js +0 -374
- package/src/soundfont/basic_soundfont/write_dls/ins.js +0 -85
- package/src/soundfont/basic_soundfont/write_dls/lins.js +0 -15
- package/src/soundfont/basic_soundfont/write_dls/modulator_converter.js +0 -330
- package/src/soundfont/basic_soundfont/write_dls/rgn2.js +0 -120
- package/src/soundfont/basic_soundfont/write_dls/wave.js +0 -71
- package/src/soundfont/basic_soundfont/write_dls/write_dls.js +0 -124
- package/src/soundfont/basic_soundfont/write_dls/wsmp.js +0 -78
- package/src/soundfont/basic_soundfont/write_dls/wvpl.js +0 -35
- package/src/soundfont/basic_soundfont/write_sf2/ibag.js +0 -60
- package/src/soundfont/basic_soundfont/write_sf2/igen.js +0 -91
- package/src/soundfont/basic_soundfont/write_sf2/imod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/inst.js +0 -42
- package/src/soundfont/basic_soundfont/write_sf2/pbag.js +0 -57
- package/src/soundfont/basic_soundfont/write_sf2/pgen.js +0 -92
- package/src/soundfont/basic_soundfont/write_sf2/phdr.js +0 -61
- package/src/soundfont/basic_soundfont/write_sf2/pmod.js +0 -62
- package/src/soundfont/basic_soundfont/write_sf2/sdta.js +0 -131
- package/src/soundfont/basic_soundfont/write_sf2/shdr.js +0 -77
- package/src/soundfont/basic_soundfont/write_sf2/write.js +0 -287
- package/src/soundfont/dls/articulator_converter.js +0 -402
- package/src/soundfont/dls/dls_destinations.js +0 -38
- package/src/soundfont/dls/dls_instrument.js +0 -20
- package/src/soundfont/dls/dls_preset.js +0 -43
- package/src/soundfont/dls/dls_sample.js +0 -238
- package/src/soundfont/dls/dls_soundfont.js +0 -183
- package/src/soundfont/dls/dls_sources.js +0 -63
- package/src/soundfont/dls/dls_zone.js +0 -89
- package/src/soundfont/dls/read_articulation.js +0 -300
- package/src/soundfont/dls/read_instrument.js +0 -118
- package/src/soundfont/dls/read_instrument_list.js +0 -17
- package/src/soundfont/dls/read_lart.js +0 -35
- package/src/soundfont/dls/read_region.js +0 -157
- package/src/soundfont/dls/read_samples.js +0 -154
- package/src/soundfont/load_soundfont.js +0 -21
- package/src/soundfont/read_sf2/generators.js +0 -43
- package/src/soundfont/read_sf2/instrument_zones.js +0 -75
- package/src/soundfont/read_sf2/instruments.js +0 -71
- package/src/soundfont/read_sf2/modulators.js +0 -25
- package/src/soundfont/read_sf2/preset_zones.js +0 -79
- package/src/soundfont/read_sf2/presets.js +0 -80
- package/src/soundfont/read_sf2/samples.js +0 -317
- package/src/soundfont/read_sf2/soundfont.js +0 -452
- package/src/soundfont/read_sf2/zones.js +0 -28
- package/src/synthetizer/README.md +0 -7
- package/src/synthetizer/audio_engine/README.md +0 -9
- package/src/synthetizer/audio_engine/engine_components/compute_modulator.js +0 -289
- package/src/synthetizer/audio_engine/engine_components/controller_tables.js +0 -90
- package/src/synthetizer/audio_engine/engine_components/dynamic_modulator_system.js +0 -95
- package/src/synthetizer/audio_engine/engine_components/enums.js +0 -18
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +0 -151
- package/src/synthetizer/audio_engine/engine_components/lfo.js +0 -26
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +0 -282
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +0 -551
- package/src/synthetizer/audio_engine/engine_components/modulation_envelope.js +0 -181
- package/src/synthetizer/audio_engine/engine_components/modulator_curves.js +0 -89
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +0 -265
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +0 -124
- package/src/synthetizer/audio_engine/engine_components/unit_converter.js +0 -73
- package/src/synthetizer/audio_engine/engine_components/voice.js +0 -525
- package/src/synthetizer/audio_engine/engine_components/volume_envelope.js +0 -402
- package/src/synthetizer/audio_engine/engine_components/wavetable_oscillator.js +0 -274
- package/src/synthetizer/audio_engine/engine_methods/controller_control/controller_change.js +0 -159
- package/src/synthetizer/audio_engine/engine_methods/controller_control/master_parameters.js +0 -48
- 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 -214
- 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 -27
- 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 -813
- 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,92 +0,0 @@
|
|
|
1
|
-
// Tests were performed by John Novak
|
|
2
|
-
// https://github.com/dosbox-staging/dosbox-staging/pull/2705
|
|
3
|
-
|
|
4
|
-
/*
|
|
5
|
-
CC 5 value Portamento time
|
|
6
|
-
---------- ---------------
|
|
7
|
-
0 0.000 s
|
|
8
|
-
1 0.006 s
|
|
9
|
-
2 0.023 s
|
|
10
|
-
4 0.050 s
|
|
11
|
-
8 0.110 s
|
|
12
|
-
16 0.250 s
|
|
13
|
-
32 0.500 s
|
|
14
|
-
64 2.060 s
|
|
15
|
-
80 4.200 s
|
|
16
|
-
96 8.400 s
|
|
17
|
-
112 19.500 s
|
|
18
|
-
116 26.700 s
|
|
19
|
-
120 40.000 s
|
|
20
|
-
124 80.000 s
|
|
21
|
-
127 480.000 s
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
const portamentoLookup = {
|
|
25
|
-
0: 0.000,
|
|
26
|
-
1: 0.006,
|
|
27
|
-
2: 0.023,
|
|
28
|
-
4: 0.050,
|
|
29
|
-
8: 0.110,
|
|
30
|
-
16: 0.250,
|
|
31
|
-
32: 0.500,
|
|
32
|
-
64: 2.060,
|
|
33
|
-
80: 4.200,
|
|
34
|
-
96: 8.400,
|
|
35
|
-
112: 19.500,
|
|
36
|
-
116: 26.700,
|
|
37
|
-
120: 40.000,
|
|
38
|
-
124: 80.000,
|
|
39
|
-
127: 480.000
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param value {number}
|
|
44
|
-
* @returns {number}
|
|
45
|
-
*/
|
|
46
|
-
function getLookup(value)
|
|
47
|
-
{
|
|
48
|
-
if (portamentoLookup[value] !== undefined)
|
|
49
|
-
{
|
|
50
|
-
return portamentoLookup[value];
|
|
51
|
-
}
|
|
52
|
-
// get the nearest lower and upper points from the lookup table
|
|
53
|
-
let lower = null;
|
|
54
|
-
let upper = null;
|
|
55
|
-
|
|
56
|
-
for (let key of Object.keys(portamentoLookup))
|
|
57
|
-
{
|
|
58
|
-
key = parseInt(key);
|
|
59
|
-
if (key < value && (lower === null || key > lower))
|
|
60
|
-
{
|
|
61
|
-
lower = key;
|
|
62
|
-
}
|
|
63
|
-
if (key > value && (upper === null || key < upper))
|
|
64
|
-
{
|
|
65
|
-
upper = key;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// if we have found both lower and upper points, perform linear interpolation
|
|
70
|
-
if (lower !== null && upper !== null)
|
|
71
|
-
{
|
|
72
|
-
let lowerTime = portamentoLookup[lower];
|
|
73
|
-
let upperTime = portamentoLookup[upper];
|
|
74
|
-
|
|
75
|
-
// linear interpolation
|
|
76
|
-
return lowerTime + ((value - lower) * (upperTime - lowerTime)) / (upper - lower);
|
|
77
|
-
}
|
|
78
|
-
return 0;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Converts portamento time to seconds
|
|
84
|
-
* @param time {number} 0 - 127
|
|
85
|
-
* @param distance {number} distance in keys
|
|
86
|
-
* @returns {number} seconds
|
|
87
|
-
*/
|
|
88
|
-
export function portamentoTimeToSeconds(time, distance)
|
|
89
|
-
{
|
|
90
|
-
// this seems to work fine for the MIDIs I have
|
|
91
|
-
return getLookup(time) * (distance / 30);
|
|
92
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { SpessaSynthWarn } from "../../../utils/loggin.js";
|
|
2
|
-
import { BasicPreset } from "../../../soundfont/basic_soundfont/basic_preset.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* executes a program change
|
|
6
|
-
* @param programNumber {number}
|
|
7
|
-
* @this {MidiAudioChannel}
|
|
8
|
-
*/
|
|
9
|
-
export function programChange(programNumber)
|
|
10
|
-
{
|
|
11
|
-
if (this.lockPreset)
|
|
12
|
-
{
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
// always 128 for percussion
|
|
16
|
-
let bank = this.getBankSelect();
|
|
17
|
-
|
|
18
|
-
const isXG = this.isXGChannel;
|
|
19
|
-
const p = this.synth.soundfontManager.getPreset(bank, programNumber, isXG);
|
|
20
|
-
let preset = p.preset;
|
|
21
|
-
if (!preset)
|
|
22
|
-
{
|
|
23
|
-
SpessaSynthWarn("No presets! Using empty fallback.");
|
|
24
|
-
preset = new BasicPreset(this.synth.soundfontManager.soundfontList[0].soundfont);
|
|
25
|
-
preset.presetName = "SPESSA EMPTY FALLBACK PRESET";
|
|
26
|
-
}
|
|
27
|
-
this.setPreset(preset);
|
|
28
|
-
this.sentBank = Math.min(128, preset.bank + p.bankOffset);
|
|
29
|
-
this.synth.callEvent("programchange", {
|
|
30
|
-
channel: this.channelNumber,
|
|
31
|
-
program: preset.program,
|
|
32
|
-
bank: this.sentBank
|
|
33
|
-
});
|
|
34
|
-
this.sendChannelProperty();
|
|
35
|
-
}
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { VolumeEnvelope } from "../engine_components/volume_envelope.js";
|
|
2
|
-
import { ModulationEnvelope } from "../engine_components/modulation_envelope.js";
|
|
3
|
-
import { customControllers } from "../engine_components/controller_tables.js";
|
|
4
|
-
import { absCentsToHz, timecentsToSeconds } from "../engine_components/unit_converter.js";
|
|
5
|
-
import { getLFOValue } from "../engine_components/lfo.js";
|
|
6
|
-
import { WavetableOscillator } from "../engine_components/wavetable_oscillator.js";
|
|
7
|
-
import { LowpassFilter } from "../engine_components/lowpass_filter.js";
|
|
8
|
-
import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_types.js";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Renders a voice to the stereo output buffer
|
|
12
|
-
* @param voice {Voice} the voice to render
|
|
13
|
-
* @param timeNow {number} current time in seconds
|
|
14
|
-
* @param outputLeft {Float32Array} the left output buffer
|
|
15
|
-
* @param outputRight {Float32Array} the right output buffer
|
|
16
|
-
* @param reverbOutputLeft {Float32Array} left output for reverb
|
|
17
|
-
* @param reverbOutputRight {Float32Array} right output for reverb
|
|
18
|
-
* @param chorusOutputLeft {Float32Array} left output for chorus
|
|
19
|
-
* @param chorusOutputRight {Float32Array} right output for chorus
|
|
20
|
-
* @param startIndex {number}
|
|
21
|
-
* @param sampleCount {number}
|
|
22
|
-
* @this {MidiAudioChannel}
|
|
23
|
-
* @returns {boolean} true if the voice is finished
|
|
24
|
-
*/
|
|
25
|
-
export function renderVoice(
|
|
26
|
-
voice, timeNow,
|
|
27
|
-
outputLeft, outputRight,
|
|
28
|
-
reverbOutputLeft, reverbOutputRight,
|
|
29
|
-
chorusOutputLeft, chorusOutputRight,
|
|
30
|
-
startIndex, sampleCount
|
|
31
|
-
)
|
|
32
|
-
{
|
|
33
|
-
// check if release
|
|
34
|
-
if (!voice.isInRelease)
|
|
35
|
-
{
|
|
36
|
-
// if not in release, check if the release time is
|
|
37
|
-
if (timeNow >= voice.releaseStartTime)
|
|
38
|
-
{
|
|
39
|
-
// release the voice here
|
|
40
|
-
voice.isInRelease = true;
|
|
41
|
-
VolumeEnvelope.startRelease(voice);
|
|
42
|
-
ModulationEnvelope.startRelease(voice);
|
|
43
|
-
if (voice.sample.loopingMode === 3)
|
|
44
|
-
{
|
|
45
|
-
voice.sample.isLooping = false;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// if the initial attenuation is more than 100dB, skip the voice (it's silent anyway)
|
|
52
|
-
if (voice.modulatedGenerators[generatorTypes.initialAttenuation] > 2500)
|
|
53
|
-
{
|
|
54
|
-
if (voice.isInRelease)
|
|
55
|
-
{
|
|
56
|
-
voice.finished = true;
|
|
57
|
-
}
|
|
58
|
-
return voice.finished;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// TUNING
|
|
62
|
-
let targetKey = voice.targetKey;
|
|
63
|
-
|
|
64
|
-
// calculate tuning
|
|
65
|
-
let cents = voice.modulatedGenerators[generatorTypes.fineTune] // soundfont fine tune
|
|
66
|
-
+ this.channelOctaveTuning[voice.midiNote] // MTS octave tuning
|
|
67
|
-
+ this.channelTuningCents; // channel tuning
|
|
68
|
-
let semitones = voice.modulatedGenerators[generatorTypes.coarseTune]; // soundfont coarse tuning
|
|
69
|
-
|
|
70
|
-
// midi tuning standard
|
|
71
|
-
const tuning = this.synth.tunings[this.preset?.program]?.[voice.realKey];
|
|
72
|
-
if (tuning !== undefined && tuning?.midiNote >= 0)
|
|
73
|
-
{
|
|
74
|
-
// override key
|
|
75
|
-
targetKey = tuning.midiNote;
|
|
76
|
-
// add micro-tonal tuning
|
|
77
|
-
cents += tuning.centTuning;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// portamento
|
|
81
|
-
if (voice.portamentoFromKey > -1)
|
|
82
|
-
{
|
|
83
|
-
// 0 to 1
|
|
84
|
-
const elapsed = Math.min((timeNow - voice.startTime) / voice.portamentoDuration, 1);
|
|
85
|
-
const diff = targetKey - voice.portamentoFromKey;
|
|
86
|
-
// zero progress means the pitch being in fromKey, full progress means the normal pitch
|
|
87
|
-
semitones -= diff * (1 - elapsed);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// calculate tuning by key using soundfont's scale tuning
|
|
91
|
-
cents += (targetKey - voice.sample.rootKey) * voice.modulatedGenerators[generatorTypes.scaleTuning];
|
|
92
|
-
|
|
93
|
-
// low pass excursion with LFO and mod envelope
|
|
94
|
-
let lowpassExcursion = 0;
|
|
95
|
-
let volumeExcursionCentibels = 0;
|
|
96
|
-
|
|
97
|
-
// vibrato LFO
|
|
98
|
-
const vibPitchDepth = voice.modulatedGenerators[generatorTypes.vibLfoToPitch];
|
|
99
|
-
const vibVolDepth = voice.modulatedGenerators[generatorTypes.vibLfoToVolume];
|
|
100
|
-
const vibFilterDepth = voice.modulatedGenerators[generatorTypes.vibLfoToFilterFc];
|
|
101
|
-
if (vibPitchDepth !== 0 || vibVolDepth !== 0 || vibFilterDepth !== 0)
|
|
102
|
-
{
|
|
103
|
-
// calculate start time and lfo value
|
|
104
|
-
const vibStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayVibLFO]);
|
|
105
|
-
const vibFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqVibLFO]);
|
|
106
|
-
const vibLfoValue = getLFOValue(vibStart, vibFreqHz, timeNow);
|
|
107
|
-
// use modulation multiplier (RPN modulation depth)
|
|
108
|
-
cents += vibLfoValue * (vibPitchDepth * this.customControllers[customControllers.modulationMultiplier]);
|
|
109
|
-
// vol env volume offset
|
|
110
|
-
// negate the lfo value because audigy starts with increase rather than decrease
|
|
111
|
-
volumeExcursionCentibels += -vibLfoValue * vibVolDepth;
|
|
112
|
-
// low pass frequency
|
|
113
|
-
lowpassExcursion += vibLfoValue * vibFilterDepth;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// mod LFO
|
|
117
|
-
const modPitchDepth = voice.modulatedGenerators[generatorTypes.modLfoToPitch];
|
|
118
|
-
const modVolDepth = voice.modulatedGenerators[generatorTypes.modLfoToVolume];
|
|
119
|
-
const modFilterDepth = voice.modulatedGenerators[generatorTypes.modLfoToFilterFc];
|
|
120
|
-
// don't compute mod lfo unless necessary
|
|
121
|
-
if (modPitchDepth !== 0 || modFilterDepth !== 0 || modVolDepth !== 0)
|
|
122
|
-
{
|
|
123
|
-
// calculate start time and lfo value
|
|
124
|
-
const modStart = voice.startTime + timecentsToSeconds(voice.modulatedGenerators[generatorTypes.delayModLFO]);
|
|
125
|
-
const modFreqHz = absCentsToHz(voice.modulatedGenerators[generatorTypes.freqModLFO]);
|
|
126
|
-
const modLfoValue = getLFOValue(modStart, modFreqHz, timeNow);
|
|
127
|
-
// use modulation multiplier (RPN modulation depth)
|
|
128
|
-
cents += modLfoValue * (modPitchDepth * this.customControllers[customControllers.modulationMultiplier]);
|
|
129
|
-
// vol env volume offset
|
|
130
|
-
// negate the lfo value because audigy starts with increase rather than decrease
|
|
131
|
-
volumeExcursionCentibels += -modLfoValue * modVolDepth;
|
|
132
|
-
// low pass frequency
|
|
133
|
-
lowpassExcursion += modLfoValue * modFilterDepth;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// channel vibrato (GS NRPN)
|
|
137
|
-
if (this.channelVibrato.depth > 0)
|
|
138
|
-
{
|
|
139
|
-
// same as others
|
|
140
|
-
const channelVibrato = getLFOValue(
|
|
141
|
-
voice.startTime + this.channelVibrato.delay,
|
|
142
|
-
this.channelVibrato.rate,
|
|
143
|
-
timeNow
|
|
144
|
-
);
|
|
145
|
-
if (channelVibrato)
|
|
146
|
-
{
|
|
147
|
-
cents += channelVibrato * this.channelVibrato.depth;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// mod env
|
|
152
|
-
const modEnvPitchDepth = voice.modulatedGenerators[generatorTypes.modEnvToPitch];
|
|
153
|
-
const modEnvFilterDepth = voice.modulatedGenerators[generatorTypes.modEnvToFilterFc];
|
|
154
|
-
// don't compute mod env unless necessary
|
|
155
|
-
if (modEnvFilterDepth !== 0 || modEnvPitchDepth !== 0)
|
|
156
|
-
{
|
|
157
|
-
const modEnv = ModulationEnvelope.getValue(voice, timeNow);
|
|
158
|
-
// apply values
|
|
159
|
-
lowpassExcursion += modEnv * modEnvFilterDepth;
|
|
160
|
-
cents += modEnv * modEnvPitchDepth;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// default resonant modulator: it does not affect the filter gain (neither XG nor GS did that)
|
|
164
|
-
volumeExcursionCentibels -= voice.resonanceOffset;
|
|
165
|
-
|
|
166
|
-
// finally, calculate the playback rate
|
|
167
|
-
const centsTotal = ~~(cents + semitones * 100);
|
|
168
|
-
if (centsTotal !== voice.currentTuningCents)
|
|
169
|
-
{
|
|
170
|
-
voice.currentTuningCents = centsTotal;
|
|
171
|
-
voice.currentTuningCalculated = Math.pow(2, centsTotal / 1200);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// SYNTHESIS
|
|
176
|
-
const bufferOut = new Float32Array(sampleCount);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
// looping mode 2: start on release. process only volEnv
|
|
180
|
-
if (voice.sample.loopingMode === 2 && !voice.isInRelease)
|
|
181
|
-
{
|
|
182
|
-
VolumeEnvelope.apply(
|
|
183
|
-
voice,
|
|
184
|
-
bufferOut,
|
|
185
|
-
volumeExcursionCentibels,
|
|
186
|
-
this.synth.volumeEnvelopeSmoothingFactor
|
|
187
|
-
);
|
|
188
|
-
return voice.finished;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// wave table oscillator
|
|
192
|
-
WavetableOscillator.getSample(voice, bufferOut, this.synth.interpolationType);
|
|
193
|
-
|
|
194
|
-
// low pass filter
|
|
195
|
-
LowpassFilter.apply(voice, bufferOut, lowpassExcursion, this.synth.filterSmoothingFactor);
|
|
196
|
-
|
|
197
|
-
// vol env
|
|
198
|
-
VolumeEnvelope.apply(
|
|
199
|
-
voice,
|
|
200
|
-
bufferOut,
|
|
201
|
-
volumeExcursionCentibels,
|
|
202
|
-
this.synth.volumeEnvelopeSmoothingFactor
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
this.panAndMixVoice(
|
|
206
|
-
voice,
|
|
207
|
-
bufferOut,
|
|
208
|
-
outputLeft, outputRight,
|
|
209
|
-
reverbOutputLeft, reverbOutputRight,
|
|
210
|
-
chorusOutputLeft, chorusOutputRight,
|
|
211
|
-
startIndex
|
|
212
|
-
);
|
|
213
|
-
return voice.finished;
|
|
214
|
-
}
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { loadSoundFont } from "../../../../soundfont/load_soundfont.js";
|
|
2
|
-
import { SpessaSynthInfo } from "../../../../utils/loggin.js";
|
|
3
|
-
import { consoleColors } from "../../../../utils/other.js";
|
|
4
|
-
import { EMBEDDED_SOUND_BANK_ID } from "../../../synth_constants.js";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @this {SpessaSynthProcessor}
|
|
8
|
-
*/
|
|
9
|
-
export function clearEmbeddedBank()
|
|
10
|
-
{
|
|
11
|
-
if (this.soundfontManager.soundfontList.some(s => s.id === EMBEDDED_SOUND_BANK_ID))
|
|
12
|
-
{
|
|
13
|
-
this.soundfontManager.deleteSoundFont(EMBEDDED_SOUND_BANK_ID);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Sets the embedded (RMI soundfont)
|
|
19
|
-
* @param font {ArrayBuffer}
|
|
20
|
-
* @param offset {number}
|
|
21
|
-
* @this {SpessaSynthProcessor}
|
|
22
|
-
*/
|
|
23
|
-
export function setEmbeddedSoundFont(font, offset)
|
|
24
|
-
{
|
|
25
|
-
// the embedded bank is set as the first bank in the manager,
|
|
26
|
-
// with a special ID that does not clear when reloadManager is performed.
|
|
27
|
-
const loadedFont = loadSoundFont(font);
|
|
28
|
-
this.soundfontManager.addNewSoundFont(loadedFont, EMBEDDED_SOUND_BANK_ID, offset);
|
|
29
|
-
// rearrange so the embedded is first (most important as it overrides all others)
|
|
30
|
-
const order = this.soundfontManager.getCurrentSoundFontOrder();
|
|
31
|
-
order.pop();
|
|
32
|
-
order.unshift(EMBEDDED_SOUND_BANK_ID);
|
|
33
|
-
this.soundfontManager.rearrangeSoundFonts(order);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// apply snapshot again if applicable
|
|
37
|
-
if (this._snapshot !== undefined)
|
|
38
|
-
{
|
|
39
|
-
this.applySynthesizerSnapshot(this._snapshot);
|
|
40
|
-
}
|
|
41
|
-
SpessaSynthInfo(`%cEmbedded sound bank set at offset %c${offset}`, consoleColors.recognized, consoleColors.value);
|
|
42
|
-
}
|
|
File without changes
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/update_preset_list.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @this {SpessaSynthProcessor}
|
|
3
|
-
*/
|
|
4
|
-
export function updatePresetList()
|
|
5
|
-
{
|
|
6
|
-
/**
|
|
7
|
-
* @type {{bank: number, presetName: string, program: number}[]}
|
|
8
|
-
*/
|
|
9
|
-
const mainFont = this.soundfontManager.getPresetList();
|
|
10
|
-
this.clearCache();
|
|
11
|
-
this.callEvent("presetlistchange", mainFont);
|
|
12
|
-
this.getDefaultPresets();
|
|
13
|
-
// unlock presets
|
|
14
|
-
this.midiAudioChannels.forEach(c =>
|
|
15
|
-
{
|
|
16
|
-
c.setPresetLock(false);
|
|
17
|
-
});
|
|
18
|
-
this.resetAllControllers(false);
|
|
19
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { customControllers } from "../../engine_components/controller_tables.js";
|
|
2
|
-
import { generatorTypes } from "../../../../soundfont/basic_soundfont/generator_types.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Stops a note nearly instantly
|
|
6
|
-
* @param midiNote {number}
|
|
7
|
-
* @param releaseTime {number} ticks
|
|
8
|
-
* @this {MidiAudioChannel}
|
|
9
|
-
*/
|
|
10
|
-
export function killNote(midiNote, releaseTime = -12000)
|
|
11
|
-
{
|
|
12
|
-
midiNote += this.customControllers[customControllers.channelKeyShift];
|
|
13
|
-
|
|
14
|
-
this.voices.forEach(v =>
|
|
15
|
-
{
|
|
16
|
-
if (v.realKey !== midiNote)
|
|
17
|
-
{
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
v.modulatedGenerators[generatorTypes.releaseVolEnv] = releaseTime; // set release to be very short
|
|
21
|
-
v.release(this.synth.currentSynthTime);
|
|
22
|
-
});
|
|
23
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { SpessaSynthWarn } from "../../../../utils/loggin.js";
|
|
2
|
-
import { customControllers } from "../../engine_components/controller_tables.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Release a note
|
|
6
|
-
* @param midiNote {number}
|
|
7
|
-
* @this {MidiAudioChannel}
|
|
8
|
-
*/
|
|
9
|
-
export function noteOff(midiNote)
|
|
10
|
-
{
|
|
11
|
-
if (midiNote > 127 || midiNote < 0)
|
|
12
|
-
{
|
|
13
|
-
SpessaSynthWarn(`Received a noteOn for note`, midiNote, "Ignoring.");
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let realKey = midiNote + this.channelTransposeKeyShift + this.customControllers[customControllers.channelKeyShift];
|
|
18
|
-
|
|
19
|
-
// if high performance mode, kill notes instead of stopping them
|
|
20
|
-
if (this.synth.highPerformanceMode)
|
|
21
|
-
{
|
|
22
|
-
// if the channel is percussion channel, do not kill the notes
|
|
23
|
-
if (!this.drumChannel)
|
|
24
|
-
{
|
|
25
|
-
this.killNote(realKey, -6950);
|
|
26
|
-
this.synth.callEvent("noteoff", {
|
|
27
|
-
midiNote: midiNote,
|
|
28
|
-
channel: this.channelNumber
|
|
29
|
-
});
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const channelVoices = this.voices;
|
|
35
|
-
channelVoices.forEach(v =>
|
|
36
|
-
{
|
|
37
|
-
if (v.realKey !== realKey || v.isInRelease === true)
|
|
38
|
-
{
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
// if hold pedal, move to sustain
|
|
42
|
-
if (this.holdPedal)
|
|
43
|
-
{
|
|
44
|
-
this.sustainedVoices.push(v);
|
|
45
|
-
}
|
|
46
|
-
else
|
|
47
|
-
{
|
|
48
|
-
v.release(this.synth.currentSynthTime);
|
|
49
|
-
}
|
|
50
|
-
});
|
|
51
|
-
this.synth.callEvent("noteoff", {
|
|
52
|
-
midiNote: midiNote,
|
|
53
|
-
channel: this.channelNumber
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { SpessaSynthInfo } from "../../../../utils/loggin.js";
|
|
2
|
-
import { consoleColors } from "../../../../utils/other.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @this {SpessaSynthProcessor}
|
|
6
|
-
* @param force {boolean}
|
|
7
|
-
*/
|
|
8
|
-
export function stopAllChannels(force = false)
|
|
9
|
-
{
|
|
10
|
-
SpessaSynthInfo("%cStop all received!", consoleColors.info);
|
|
11
|
-
for (let i = 0; i < this.midiAudioChannels.length; i++)
|
|
12
|
-
{
|
|
13
|
-
this.midiAudioChannels[i].stopAllNotes(force);
|
|
14
|
-
}
|
|
15
|
-
this.callEvent("stopall", undefined);
|
|
16
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* stops all notes on a given channel
|
|
3
|
-
* @param force {boolean}
|
|
4
|
-
* @this {MidiAudioChannel}
|
|
5
|
-
*/
|
|
6
|
-
export function stopAllNotes(force = false)
|
|
7
|
-
{
|
|
8
|
-
if (force)
|
|
9
|
-
{
|
|
10
|
-
// force stop all
|
|
11
|
-
this.voices.length = 0;
|
|
12
|
-
this.sustainedVoices.length = 0;
|
|
13
|
-
this.sendChannelProperty();
|
|
14
|
-
}
|
|
15
|
-
else
|
|
16
|
-
{
|
|
17
|
-
this.voices.forEach(v =>
|
|
18
|
-
{
|
|
19
|
-
if (v.isInRelease)
|
|
20
|
-
{
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
v.release(this.synth.currentSynthTime);
|
|
24
|
-
});
|
|
25
|
-
this.sustainedVoices.forEach(v =>
|
|
26
|
-
{
|
|
27
|
-
v.release(this.synth.currentSynthTime);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @param channel {MidiAudioChannel}
|
|
3
|
-
* @param voice {Voice}
|
|
4
|
-
* @return {number}
|
|
5
|
-
*/
|
|
6
|
-
function getPriority(channel, voice)
|
|
7
|
-
{
|
|
8
|
-
let priority = 0;
|
|
9
|
-
if (channel.drumChannel)
|
|
10
|
-
{
|
|
11
|
-
// important
|
|
12
|
-
priority += 5;
|
|
13
|
-
}
|
|
14
|
-
if (voice.isInRelease)
|
|
15
|
-
{
|
|
16
|
-
// not important
|
|
17
|
-
priority -= 5;
|
|
18
|
-
}
|
|
19
|
-
// less velocity = less important
|
|
20
|
-
priority += voice.velocity / 25; // map to 0-5
|
|
21
|
-
// the newer, more important
|
|
22
|
-
priority -= voice.volumeEnvelope.state;
|
|
23
|
-
if (voice.isInRelease)
|
|
24
|
-
{
|
|
25
|
-
priority -= 5;
|
|
26
|
-
}
|
|
27
|
-
priority -= voice.volumeEnvelope.currentAttenuationDb / 50;
|
|
28
|
-
return priority;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @this {SpessaSynthProcessor}
|
|
33
|
-
* @param amount {number}
|
|
34
|
-
*/
|
|
35
|
-
export function voiceKilling(amount)
|
|
36
|
-
{
|
|
37
|
-
let allVoices = [];
|
|
38
|
-
for (const channel of this.midiAudioChannels)
|
|
39
|
-
{
|
|
40
|
-
for (const voice of channel.voices)
|
|
41
|
-
{
|
|
42
|
-
if (!voice.finished)
|
|
43
|
-
{
|
|
44
|
-
const priority = getPriority(channel, voice);
|
|
45
|
-
allVoices.push({ channel, voice, priority });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Step 2: Sort voices by priority (ascending order)
|
|
51
|
-
allVoices.sort((a, b) => a.priority - b.priority);
|
|
52
|
-
const voicesToRemove = allVoices.slice(0, amount);
|
|
53
|
-
|
|
54
|
-
for (const { channel, voice } of voicesToRemove)
|
|
55
|
-
{
|
|
56
|
-
const index = channel.voices.indexOf(voice);
|
|
57
|
-
if (index > -1)
|
|
58
|
-
{
|
|
59
|
-
channel.voices.splice(index, 1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|