spessasynth_core 3.26.0 → 3.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -5
- package/package.json +1 -1
- package/src/midi/midi_tools/used_keys_loaded.js +1 -1
- package/src/sequencer/process_event.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/key_modifier_manager.js +1 -0
- package/src/synthetizer/audio_engine/engine_components/lowpass_filter.js +9 -9
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +2 -2
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +4 -4
- package/src/synthetizer/audio_engine/engine_components/voice.js +11 -12
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +2 -2
- package/src/synthetizer/audio_engine/engine_methods/tuning_control/set_master_tuning.js +1 -1
- package/src/synthetizer/audio_engine/main_processor.js +8 -14
- package/src/synthetizer/audio_engine/snapshot/channel_snapshot.js +6 -6
- package/src/synthetizer/audio_engine/snapshot/synthesizer_snapshot.js +21 -21
package/README.md
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
<!--suppress HtmlDeprecatedAttribute, HtmlRequiredAltAttribute, HtmlExtraClosingTag -->
|
|
2
|
+
<p align='center'>
|
|
3
|
+
<img src='https://raw.githubusercontent.com/spessasus/SpessaSynth/refs/heads/master/src/website/spessasynth_logo_rounded.png' width='300' alt='SpessaSynth logo'>
|
|
4
|
+
</p>
|
|
2
5
|
|
|
3
6
|
**A powerful SF2/DLS/MIDI JavaScript library. It works with any modern JS environment that supports WebAssembly.**
|
|
4
7
|
|
|
@@ -11,12 +14,12 @@ npm install --save spessasynth_core
|
|
|
11
14
|
|
|
12
15
|
### [Project site (consider giving it a star!)](https://github.com/spessasus/SpessaSynth)
|
|
13
16
|
|
|
14
|
-
### [Demo (using the spessasynth_lib wrapper)](https://spessasus.github.io/
|
|
17
|
+
### [Demo (using the spessasynth_lib wrapper)](https://spessasus.github.io/SpessaSynth)
|
|
15
18
|
|
|
16
19
|
### [Documentation (in progress!)](https://github.com/spessasus/spessasynth_core/wiki/Home)
|
|
17
20
|
|
|
18
21
|
|
|
19
|
-
> Note: This is the new heart of the
|
|
22
|
+
> Note: This is the new heart of the SpessaSynth library, after the repository has been split.
|
|
20
23
|
|
|
21
24
|
###
|
|
22
25
|
```js
|
|
@@ -84,9 +87,9 @@ process.exit();
|
|
|
84
87
|
|
|
85
88
|
### Easy Integration
|
|
86
89
|
- **Modular design:** *Easy integration into other projects (load what you need)*
|
|
87
|
-
- **[Detailed documentation:](https://github.com/spessasus/spessasynth_core/wiki/Home)** *With [examples!](https://github.com/spessasus/spessasynth_core/wiki/
|
|
90
|
+
- **[Detailed documentation:](https://github.com/spessasus/spessasynth_core/wiki/Home)** *With [examples!](https://github.com/spessasus/spessasynth_core/wiki/Getting-Started#examples)*
|
|
88
91
|
- **Flexible:** *It's not just a MIDI player!*
|
|
89
|
-
- **Easy to Use:** *Basic setup is just [two lines of code!](https://github.com/spessasus/spessasynth_core/wiki/
|
|
92
|
+
- **Easy to Use:** *Basic setup is just [two lines of code!](https://github.com/spessasus/spessasynth_core/wiki/Getting-Started#minimal-setup)*
|
|
90
93
|
- **No dependencies:** *Batteries included!*
|
|
91
94
|
|
|
92
95
|
### Powerful MIDI Synthesizer
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ import { isGSDrumsOn, isXGOn } from "../../utils/sysex_detector.js";
|
|
|
8
8
|
/**
|
|
9
9
|
* Gets the used programs and keys for this MIDI file with a given sound bank
|
|
10
10
|
* @this {BasicMIDI}
|
|
11
|
-
* @param soundfont {BasicSoundBank|
|
|
11
|
+
* @param soundfont {BasicSoundBank|SoundFontManager} - the sound bank
|
|
12
12
|
* @returns {Object<string, Set<string>>} Object<bank:program, Set<key-velocity>>
|
|
13
13
|
*/
|
|
14
14
|
export function getUsedProgramsAndKeys(soundfont)
|
|
@@ -22,7 +22,7 @@ export const FILTER_SMOOTHING_FACTOR = 0.1;
|
|
|
22
22
|
* @property {number} a4 - Filter coefficient 5
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
export class
|
|
25
|
+
export class LowpassFilter
|
|
26
26
|
{
|
|
27
27
|
/**
|
|
28
28
|
* Cached coefficient calculations
|
|
@@ -175,7 +175,7 @@ export class WorkletLowpassFilter
|
|
|
175
175
|
{
|
|
176
176
|
filter.lastTargetCutoff = targetCutoff;
|
|
177
177
|
filter.resonanceCb = modulatedResonance;
|
|
178
|
-
|
|
178
|
+
LowpassFilter.calculateCoefficients(filter, targetCutoff);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// filter the input
|
|
@@ -200,7 +200,7 @@ export class WorkletLowpassFilter
|
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
/**
|
|
203
|
-
* @param filter {
|
|
203
|
+
* @param filter {LowpassFilter}
|
|
204
204
|
* @param cutoffCents {number}
|
|
205
205
|
*/
|
|
206
206
|
static calculateCoefficients(filter, cutoffCents)
|
|
@@ -208,7 +208,7 @@ export class WorkletLowpassFilter
|
|
|
208
208
|
cutoffCents = ~~cutoffCents; // Math.floor
|
|
209
209
|
const qCb = filter.resonanceCb;
|
|
210
210
|
// check if these coefficients were already cached
|
|
211
|
-
const cached =
|
|
211
|
+
const cached = LowpassFilter.cachedCoefficients?.[qCb]?.[cutoffCents];
|
|
212
212
|
if (cached !== undefined)
|
|
213
213
|
{
|
|
214
214
|
filter.a0 = cached.a0;
|
|
@@ -263,20 +263,20 @@ export class WorkletLowpassFilter
|
|
|
263
263
|
filter.a3 = toCache.a3;
|
|
264
264
|
filter.a4 = toCache.a4;
|
|
265
265
|
|
|
266
|
-
if (
|
|
266
|
+
if (LowpassFilter.cachedCoefficients[qCb] === undefined)
|
|
267
267
|
{
|
|
268
|
-
|
|
268
|
+
LowpassFilter.cachedCoefficients[qCb] = [];
|
|
269
269
|
}
|
|
270
|
-
|
|
270
|
+
LowpassFilter.cachedCoefficients[qCb][cutoffCents] = toCache;
|
|
271
271
|
}
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
// precompute all the cutoffs for 0q (most common)
|
|
275
|
-
const dummy = new
|
|
275
|
+
const dummy = new LowpassFilter(44100);
|
|
276
276
|
dummy.resonanceCb = 0;
|
|
277
277
|
// sfspec section 8.1.3: initialFilterFc ranges from 1500 to 13,500 cents
|
|
278
278
|
for (let i = 1500; i < 13500; i++)
|
|
279
279
|
{
|
|
280
280
|
dummy.currentInitialFc = i;
|
|
281
|
-
|
|
281
|
+
LowpassFilter.calculateCoefficients(dummy, i);
|
|
282
282
|
}
|
|
@@ -9,10 +9,10 @@ import { isXGDrums } from "../../../utils/xg_hacks.js";
|
|
|
9
9
|
* @property {number} bankOffset - the soundfont's bank offset
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
export class
|
|
12
|
+
export class SoundFontManager
|
|
13
13
|
{
|
|
14
14
|
/**
|
|
15
|
-
* Creates a new instance of
|
|
15
|
+
* Creates a new instance of soundfont manager
|
|
16
16
|
* @param initialSoundFontBuffer {ArrayBuffer} Array buffer of the soundfont. This soudfont always has the id "main"
|
|
17
17
|
*/
|
|
18
18
|
constructor(initialSoundFontBuffer)
|
|
@@ -7,8 +7,8 @@ import { generatorTypes } from "../../../soundfont/basic_soundfont/generator.js"
|
|
|
7
7
|
|
|
8
8
|
export const PAN_SMOOTHING_FACTOR = 0.05;
|
|
9
9
|
|
|
10
|
-
export const
|
|
11
|
-
export const
|
|
10
|
+
export const REVERB_DIVIDER = 4600;
|
|
11
|
+
export const CHORUS_DIVIDER = 2000;
|
|
12
12
|
const HALF_PI = Math.PI / 2;
|
|
13
13
|
|
|
14
14
|
const MIN_PAN = -500;
|
|
@@ -78,7 +78,7 @@ export function panVoice(voice,
|
|
|
78
78
|
if (reverbSend > 0)
|
|
79
79
|
{
|
|
80
80
|
// reverb is mono so we need to multiply by gain
|
|
81
|
-
const reverbGain = this.synth.reverbGain * gain * (reverbSend /
|
|
81
|
+
const reverbGain = this.synth.reverbGain * gain * (reverbSend / REVERB_DIVIDER);
|
|
82
82
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
83
83
|
{
|
|
84
84
|
reverbLeft[i] += reverbGain * inputBuffer[i];
|
|
@@ -91,7 +91,7 @@ export function panVoice(voice,
|
|
|
91
91
|
if (chorusSend > 0)
|
|
92
92
|
{
|
|
93
93
|
// chorus is stereo so we do not need to
|
|
94
|
-
const chorusGain = this.synth.chorusGain * chorusSend /
|
|
94
|
+
const chorusGain = this.synth.chorusGain * chorusSend / CHORUS_DIVIDER;
|
|
95
95
|
const chorusLeftGain = gainLeft * chorusGain;
|
|
96
96
|
const chorusRightGain = gainRight * chorusGain;
|
|
97
97
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* voice.js
|
|
3
|
-
* purpose: prepares Voices from sample and generator data
|
|
4
|
-
* note: sample dumping means sending it over to the AudioWorkletGlobalScope
|
|
3
|
+
* purpose: prepares Voices from sample and generator data
|
|
5
4
|
*/
|
|
6
5
|
import { MIN_EXCLUSIVE_LENGTH, MIN_NOTE_LENGTH } from "../main_processor.js";
|
|
7
6
|
import { SpessaSynthWarn } from "../../../utils/loggin.js";
|
|
8
|
-
import {
|
|
7
|
+
import { LowpassFilter } from "./lowpass_filter.js";
|
|
9
8
|
import { VolumeEnvelope } from "./volume_envelope.js";
|
|
10
9
|
import { ModulationEnvelope } from "./modulation_envelope.js";
|
|
11
10
|
import { addAndClampGenerator, generatorTypes } from "../../../soundfont/basic_soundfont/generator.js";
|
|
@@ -122,7 +121,7 @@ class Voice
|
|
|
122
121
|
|
|
123
122
|
/**
|
|
124
123
|
* Lowpass filter applied to the voice.
|
|
125
|
-
* @type {
|
|
124
|
+
* @type {LowpassFilter}
|
|
126
125
|
*/
|
|
127
126
|
filter;
|
|
128
127
|
|
|
@@ -270,7 +269,7 @@ class Voice
|
|
|
270
269
|
/**
|
|
271
270
|
* Creates a Voice
|
|
272
271
|
* @param sampleRate {number}
|
|
273
|
-
* @param
|
|
272
|
+
* @param audioSample {AudioSample}
|
|
274
273
|
* @param midiNote {number}
|
|
275
274
|
* @param velocity {number}
|
|
276
275
|
* @param channel {number}
|
|
@@ -282,7 +281,7 @@ class Voice
|
|
|
282
281
|
*/
|
|
283
282
|
constructor(
|
|
284
283
|
sampleRate,
|
|
285
|
-
|
|
284
|
+
audioSample,
|
|
286
285
|
midiNote,
|
|
287
286
|
velocity,
|
|
288
287
|
channel,
|
|
@@ -293,12 +292,12 @@ class Voice
|
|
|
293
292
|
modulators
|
|
294
293
|
)
|
|
295
294
|
{
|
|
296
|
-
this.sample =
|
|
295
|
+
this.sample = audioSample;
|
|
297
296
|
this.generators = generators;
|
|
298
297
|
this.exclusiveClass = this.generators[generatorTypes.exclusiveClass];
|
|
299
298
|
this.modulatedGenerators = new Int16Array(generators);
|
|
300
299
|
this.modulators = modulators;
|
|
301
|
-
this.filter = new
|
|
300
|
+
this.filter = new LowpassFilter(sampleRate);
|
|
302
301
|
|
|
303
302
|
this.velocity = velocity;
|
|
304
303
|
this.midiNote = midiNote;
|
|
@@ -461,11 +460,11 @@ export function getVoices(channel,
|
|
|
461
460
|
let loopEnd = sampleAndGenerators.sample.sampleLoopEndIndex;
|
|
462
461
|
let loopingMode = generators[generatorTypes.sampleModes];
|
|
463
462
|
/**
|
|
464
|
-
* create the
|
|
463
|
+
* create the sample
|
|
465
464
|
* offsets are calculated at note on time (to allow for modulation of them)
|
|
466
465
|
* @type {AudioSample}
|
|
467
466
|
*/
|
|
468
|
-
const
|
|
467
|
+
const audioSample = new AudioSample(
|
|
469
468
|
sampleAndGenerators.sample.sampleData,
|
|
470
469
|
(sampleAndGenerators.sample.sampleRate / this.sampleRate) * Math.pow(
|
|
471
470
|
2,
|
|
@@ -492,14 +491,14 @@ export function getVoices(channel,
|
|
|
492
491
|
// Velocity: velocity,
|
|
493
492
|
// TargetKey: targetKey,
|
|
494
493
|
// MidiNote: midiNote,
|
|
495
|
-
// AudioSample:
|
|
494
|
+
// AudioSample: audioSample
|
|
496
495
|
// }]);
|
|
497
496
|
|
|
498
497
|
|
|
499
498
|
voices.push(
|
|
500
499
|
new Voice(
|
|
501
500
|
this.sampleRate,
|
|
502
|
-
|
|
501
|
+
audioSample,
|
|
503
502
|
midiNote,
|
|
504
503
|
velocity,
|
|
505
504
|
channel,
|
|
@@ -5,7 +5,7 @@ import { customControllers } from "../engine_components/controller_tables.js";
|
|
|
5
5
|
import { absCentsToHz, timecentsToSeconds } from "../engine_components/unit_converter.js";
|
|
6
6
|
import { getLFOValue } from "../engine_components/lfo.js";
|
|
7
7
|
import { WavetableOscillator } from "../engine_components/wavetable_oscillator.js";
|
|
8
|
-
import {
|
|
8
|
+
import { LowpassFilter } from "../engine_components/lowpass_filter.js";
|
|
9
9
|
import { interpolationTypes } from "../engine_components/enums.js";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -181,7 +181,7 @@ export function renderVoice(
|
|
|
181
181
|
}
|
|
182
182
|
|
|
183
183
|
// low pass filter
|
|
184
|
-
|
|
184
|
+
LowpassFilter.apply(voice, bufferOut, lowpassExcursion, this.synth.filterSmoothingFactor);
|
|
185
185
|
|
|
186
186
|
// vol env
|
|
187
187
|
VolumeEnvelope.apply(voice, bufferOut, modLfoCentibels, this.synth.volumeEnvelopeSmoothingFactor);
|
|
@@ -12,7 +12,7 @@ import { VOLUME_ENVELOPE_SMOOTHING_FACTOR } from "./engine_components/volume_env
|
|
|
12
12
|
import { systemExclusive } from "./engine_methods/system_exclusive.js";
|
|
13
13
|
import { masterParameterType, setMasterParameter } from "./engine_methods/controller_control/master_parameters.js";
|
|
14
14
|
import { resetAllControllers } from "./engine_methods/controller_control/reset_controllers.js";
|
|
15
|
-
import {
|
|
15
|
+
import { SoundFontManager } from "./engine_components/soundfont_manager.js";
|
|
16
16
|
import { KeyModifierManager } from "./engine_components/key_modifier_manager.js";
|
|
17
17
|
import { getVoices } from "./engine_components/voice.js";
|
|
18
18
|
import { PAN_SMOOTHING_FACTOR } from "./engine_components/stereo_panner.js";
|
|
@@ -314,7 +314,7 @@ class SpessaSynthProcessor
|
|
|
314
314
|
defaultDrumsUsesOverride = false;
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
|
-
* Controls if the
|
|
317
|
+
* Controls if the processor is fully initialized
|
|
318
318
|
* @type {Promise<boolean>}
|
|
319
319
|
*/
|
|
320
320
|
processorInitialized = stbvorbis.isInitialized;
|
|
@@ -340,7 +340,7 @@ class SpessaSynthProcessor
|
|
|
340
340
|
*/
|
|
341
341
|
|
|
342
342
|
/**
|
|
343
|
-
* Creates a new
|
|
343
|
+
* Creates a new synthesizer engine.
|
|
344
344
|
* @param midiChannels {number}
|
|
345
345
|
* @param soundfont {ArrayBuffer}
|
|
346
346
|
* @param enableEventSystem {boolean}
|
|
@@ -380,12 +380,6 @@ class SpessaSynthProcessor
|
|
|
380
380
|
this.currentSynthTime = initialTime;
|
|
381
381
|
this.sampleRate = sampleRate;
|
|
382
382
|
|
|
383
|
-
this.isFullyReady = false;
|
|
384
|
-
this.processorInitialized.then(() =>
|
|
385
|
-
{
|
|
386
|
-
this.isFullyReady = true;
|
|
387
|
-
});
|
|
388
|
-
|
|
389
383
|
/**
|
|
390
384
|
* Sample time in seconds
|
|
391
385
|
* @type {number}
|
|
@@ -401,9 +395,9 @@ class SpessaSynthProcessor
|
|
|
401
395
|
}
|
|
402
396
|
|
|
403
397
|
/**
|
|
404
|
-
* @type {
|
|
398
|
+
* @type {SoundFontManager}
|
|
405
399
|
*/
|
|
406
|
-
this.soundfontManager = new
|
|
400
|
+
this.soundfontManager = new SoundFontManager(
|
|
407
401
|
soundfont
|
|
408
402
|
);
|
|
409
403
|
this.sendPresetList();
|
|
@@ -412,7 +406,7 @@ class SpessaSynthProcessor
|
|
|
412
406
|
|
|
413
407
|
for (let i = 0; i < initialChannelCount; i++)
|
|
414
408
|
{
|
|
415
|
-
this.
|
|
409
|
+
this.createMidiChannel(false);
|
|
416
410
|
}
|
|
417
411
|
|
|
418
412
|
this.midiAudioChannels[DEFAULT_PERCUSSION].preset = this.drumPreset;
|
|
@@ -764,7 +758,7 @@ class SpessaSynthProcessor
|
|
|
764
758
|
}
|
|
765
759
|
|
|
766
760
|
/**
|
|
767
|
-
* Calls synth event
|
|
761
|
+
* Calls synth event
|
|
768
762
|
* @param eventName {EventTypes} the event name
|
|
769
763
|
* @param eventData {EventCallbackData}
|
|
770
764
|
* @this {SpessaSynthProcessor}
|
|
@@ -785,7 +779,7 @@ SpessaSynthProcessor.prototype.systemExclusive = systemExclusive;
|
|
|
785
779
|
|
|
786
780
|
// channel related
|
|
787
781
|
SpessaSynthProcessor.prototype.stopAllChannels = stopAllChannels;
|
|
788
|
-
SpessaSynthProcessor.prototype.
|
|
782
|
+
SpessaSynthProcessor.prototype.createMidiChannel = createMidiChannel;
|
|
789
783
|
SpessaSynthProcessor.prototype.resetAllControllers = resetAllControllers;
|
|
790
784
|
|
|
791
785
|
// master parameter related
|
|
@@ -104,13 +104,13 @@ export class ChannelSnapshot
|
|
|
104
104
|
|
|
105
105
|
/**
|
|
106
106
|
* Creates a snapshot of a single channel's state in the synthesizer.
|
|
107
|
-
* @param
|
|
107
|
+
* @param spessaSynthProcessor {SpessaSynthProcessor}
|
|
108
108
|
* @param channelNumber {number}
|
|
109
109
|
* @returns {ChannelSnapshot}
|
|
110
110
|
*/
|
|
111
|
-
static getChannelSnapshot(
|
|
111
|
+
static getChannelSnapshot(spessaSynthProcessor, channelNumber)
|
|
112
112
|
{
|
|
113
|
-
const channelObject =
|
|
113
|
+
const channelObject = spessaSynthProcessor.midiAudioChannels[channelNumber];
|
|
114
114
|
const channelSnapshot = new ChannelSnapshot();
|
|
115
115
|
// program data
|
|
116
116
|
channelSnapshot.program = channelObject.preset.program;
|
|
@@ -142,13 +142,13 @@ export class ChannelSnapshot
|
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
144
|
* Applies the snapshot to the specified channel.
|
|
145
|
-
* @param
|
|
145
|
+
* @param spessaSynthProcessor {SpessaSynthProcessor}
|
|
146
146
|
* @param channelNumber {number}
|
|
147
147
|
* @param channelSnapshot {ChannelSnapshot}
|
|
148
148
|
*/
|
|
149
|
-
static applyChannelSnapshot(
|
|
149
|
+
static applyChannelSnapshot(spessaSynthProcessor, channelNumber, channelSnapshot)
|
|
150
150
|
{
|
|
151
|
-
const channelObject =
|
|
151
|
+
const channelObject = spessaSynthProcessor.midiAudioChannels[channelNumber];
|
|
152
152
|
channelObject.muteChannel(channelSnapshot.isMuted);
|
|
153
153
|
channelObject.setDrums(channelSnapshot.drumChannel);
|
|
154
154
|
|
|
@@ -53,27 +53,27 @@ export class SynthesizerSnapshot
|
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Creates a snapshot of the synthesizer's state.
|
|
56
|
-
* @param
|
|
56
|
+
* @param spessaSynthProcessor {SpessaSynthProcessor}
|
|
57
57
|
* @returns {SynthesizerSnapshot}
|
|
58
58
|
*/
|
|
59
|
-
static createSynthesizerSnapshot(
|
|
59
|
+
static createSynthesizerSnapshot(spessaSynthProcessor)
|
|
60
60
|
{
|
|
61
61
|
const snapshot = new SynthesizerSnapshot();
|
|
62
62
|
// channel snapshots
|
|
63
63
|
snapshot.channelSnapshots =
|
|
64
|
-
|
|
65
|
-
ChannelSnapshot.getChannelSnapshot(
|
|
64
|
+
spessaSynthProcessor.midiAudioChannels.map((_, i) =>
|
|
65
|
+
ChannelSnapshot.getChannelSnapshot(spessaSynthProcessor, i));
|
|
66
66
|
|
|
67
67
|
// key mappings
|
|
68
|
-
snapshot.keyMappings =
|
|
68
|
+
snapshot.keyMappings = spessaSynthProcessor.keyModifierManager.getMappings();
|
|
69
69
|
// pan and volume
|
|
70
|
-
snapshot.mainVolume =
|
|
71
|
-
snapshot.pan =
|
|
70
|
+
snapshot.mainVolume = spessaSynthProcessor.midiVolume;
|
|
71
|
+
snapshot.pan = spessaSynthProcessor.pan;
|
|
72
72
|
|
|
73
73
|
// others
|
|
74
|
-
snapshot.system =
|
|
75
|
-
snapshot.interpolation =
|
|
76
|
-
snapshot.transposition =
|
|
74
|
+
snapshot.system = spessaSynthProcessor.system;
|
|
75
|
+
snapshot.interpolation = spessaSynthProcessor.interpolationType;
|
|
76
|
+
snapshot.transposition = spessaSynthProcessor.transposition;
|
|
77
77
|
|
|
78
78
|
// effect config is stored on the main thread, leave it empty
|
|
79
79
|
snapshot.effectsConfig = {};
|
|
@@ -83,31 +83,31 @@ export class SynthesizerSnapshot
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Applies the snapshot to the synthesizer.
|
|
86
|
-
* @param
|
|
86
|
+
* @param spessaSynthProcessor {SpessaSynthProcessor}
|
|
87
87
|
* @param snapshot {SynthesizerSnapshot}
|
|
88
88
|
*/
|
|
89
|
-
static applySnapshot(
|
|
89
|
+
static applySnapshot(spessaSynthProcessor, snapshot)
|
|
90
90
|
{
|
|
91
91
|
// restore system
|
|
92
|
-
|
|
92
|
+
spessaSynthProcessor.setSystem(snapshot.system);
|
|
93
93
|
|
|
94
94
|
// restore pan and volume
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
spessaSynthProcessor.setMasterParameter(masterParameterType.mainVolume, snapshot.mainVolume);
|
|
96
|
+
spessaSynthProcessor.setMasterParameter(masterParameterType.masterPan, snapshot.pan);
|
|
97
|
+
spessaSynthProcessor.transposeAllChannels(snapshot.transposition);
|
|
98
|
+
spessaSynthProcessor.interpolationType = snapshot.interpolation;
|
|
99
|
+
spessaSynthProcessor.keyModifierManager.setMappings(snapshot.keyMappings);
|
|
100
100
|
|
|
101
101
|
// add channels if more needed
|
|
102
|
-
while (
|
|
102
|
+
while (spessaSynthProcessor.midiAudioChannels.length < snapshot.channelSnapshots.length)
|
|
103
103
|
{
|
|
104
|
-
|
|
104
|
+
spessaSynthProcessor.createMidiChannel();
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// restore channels
|
|
108
108
|
snapshot.channelSnapshots.forEach((channelSnapshot, index) =>
|
|
109
109
|
{
|
|
110
|
-
ChannelSnapshot.applyChannelSnapshot(
|
|
110
|
+
ChannelSnapshot.applyChannelSnapshot(spessaSynthProcessor, index, channelSnapshot);
|
|
111
111
|
});
|
|
112
112
|
|
|
113
113
|
SpessaSynthInfo("%cFinished restoring controllers!", consoleColors.info);
|