spessasynth_core 3.26.41 → 3.27.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 +12 -9
- package/index.js +2 -1
- package/package.json +1 -1
- package/src/soundfont/basic_soundfont/basic_instrument.js +3 -2
- package/src/soundfont/basic_soundfont/basic_sample.js +39 -2
- package/src/soundfont/basic_soundfont/basic_soundbank.js +2 -2
- package/src/synthetizer/audio_engine/engine_components/midi_audio_channel.js +8 -4
- package/src/synthetizer/audio_engine/engine_components/soundfont_manager.js +1 -1
- package/src/synthetizer/audio_engine/engine_components/stereo_panner.js +15 -12
- package/src/synthetizer/audio_engine/engine_methods/render_voice.js +14 -5
- package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js +0 -1
- package/src/synthetizer/audio_engine/main_processor.js +33 -19
package/README.md
CHANGED
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
**A powerful SF2/DLS/MIDI JavaScript library. It works with any modern JS environment that supports WebAssembly.**
|
|
7
7
|
|
|
8
8
|
It allows you to:
|
|
9
|
-
- Play MIDI files using SF2/SF3/DLS files
|
|
10
|
-
-
|
|
11
|
-
- Write SF2/SF3 files
|
|
12
|
-
- Convert DLS to SF2 (and back!)
|
|
9
|
+
- Play MIDI files using SF2/SF3/DLS files!
|
|
10
|
+
- Read and write MIDI files!
|
|
11
|
+
- Write SF2/SF3 files!
|
|
12
|
+
- Convert DLS to SF2! (and back!)
|
|
13
13
|
- [and more!](https://github.com/spessasus/spessasynth_core?tab=readme-ov-file#current-features)
|
|
14
14
|
> **TIP:**
|
|
15
15
|
> Looking for an easy-to-use WebAudioAPI browser wrapper? Try [spessasynth_lib](https://github.com/spessasus/spessasynth_lib)!
|
|
@@ -18,20 +18,23 @@ It allows you to:
|
|
|
18
18
|
npm install --save spessasynth_core
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
### [Project site (consider giving it a star!)](https://github.com/spessasus/
|
|
21
|
+
### [Project site (consider giving it a star!)](https://github.com/spessasus/spessasynth_core)
|
|
22
22
|
|
|
23
|
-
###
|
|
23
|
+
### Made with spessasynth_core
|
|
24
|
+
- [SpessaSynth Online SF2/DLS MIDI Player](https://spessasus.github.io/SpessaSynth)
|
|
25
|
+
- [SpessaFont Online SoundFont/DLS Editor](https://spessasus.github.io/SpessaFont)
|
|
24
26
|
|
|
25
27
|
### [Documentation (in progress!)](https://github.com/spessasus/spessasynth_core/wiki/Home)
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
> Note: This is the new heart of the SpessaSynth library, after the repository has been split.
|
|
29
31
|
|
|
30
|
-
**Project index**
|
|
32
|
+
**SpessaSynth Project index**
|
|
31
33
|
|
|
32
|
-
- spessasynth_core (you are here) - SF2/DLS/MIDI library
|
|
34
|
+
- [spessasynth_core](https://github.com/spessasus/spessasynth_core) (you are here) - SF2/DLS/MIDI library
|
|
33
35
|
- [spessasynth_lib](https://github.com/spessasus/spessasynth_lib) - spessasynth_core wrapper optimized for browsers and WebAudioAPI
|
|
34
|
-
- [SpessaSynth](https://github.com/spessasus/SpessaSynth) - online/local
|
|
36
|
+
- [SpessaSynth](https://github.com/spessasus/SpessaSynth) - online/local MIDI player/editor application
|
|
37
|
+
- [SpessaFont](https://github.com/spessasus/SpessaFont) - online SF2/DLS editor
|
|
35
38
|
|
|
36
39
|
## Current Features
|
|
37
40
|
|
package/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { SynthesizerSnapshot } from "./src/synthetizer/audio_engine/snapshot/syn
|
|
|
21
21
|
import { ChannelSnapshot } from "./src/synthetizer/audio_engine/snapshot/channel_snapshot.js";
|
|
22
22
|
|
|
23
23
|
import { BasicSoundBank } from "./src/soundfont/basic_soundfont/basic_soundbank.js";
|
|
24
|
-
import { BasicSample, sampleTypes } from "./src/soundfont/basic_soundfont/basic_sample.js";
|
|
24
|
+
import { BasicSample, CreatedSample, sampleTypes } from "./src/soundfont/basic_soundfont/basic_sample.js";
|
|
25
25
|
import { BasicPresetZone } from "./src/soundfont/basic_soundfont/basic_preset_zone.js";
|
|
26
26
|
import { BasicInstrument } from "./src/soundfont/basic_soundfont/basic_instrument.js";
|
|
27
27
|
import { BasicPreset } from "./src/soundfont/basic_soundfont/basic_preset.js";
|
|
@@ -98,6 +98,7 @@ export {
|
|
|
98
98
|
BasicZone,
|
|
99
99
|
BasicGlobalZone,
|
|
100
100
|
BasicSample,
|
|
101
|
+
CreatedSample,
|
|
101
102
|
BasicInstrumentZone,
|
|
102
103
|
BasicInstrument,
|
|
103
104
|
BasicPreset,
|
package/package.json
CHANGED
|
@@ -97,13 +97,14 @@ export class BasicInstrument
|
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
99
|
* @param index {number}
|
|
100
|
+
* @param force {boolean} ignore use count
|
|
100
101
|
* @returns {boolean} if deleted
|
|
101
102
|
*/
|
|
102
|
-
deleteZone(index)
|
|
103
|
+
deleteZone(index, force = false)
|
|
103
104
|
{
|
|
104
105
|
const zone = this.instrumentZones[index];
|
|
105
106
|
zone.useCount -= 1;
|
|
106
|
-
if (zone.useCount < 1)
|
|
107
|
+
if (zone.useCount < 1 || force)
|
|
107
108
|
{
|
|
108
109
|
zone.deleteZone();
|
|
109
110
|
this.instrumentZones.splice(index, 1);
|
|
@@ -6,7 +6,11 @@ import { stbvorbis } from "../../externals/stbvorbis_sync/stbvorbis_sync.min.js"
|
|
|
6
6
|
const RESAMPLE_RATE = 48000;
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
|
-
* @
|
|
9
|
+
* @typedef {1|2|4|8|32769|32770|32772|32776} sampleTypes
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @enum {sampleTypes}
|
|
10
14
|
*/
|
|
11
15
|
export const sampleTypes = {
|
|
12
16
|
monoSample: 1,
|
|
@@ -113,7 +117,7 @@ export class BasicSample
|
|
|
113
117
|
* @param sampleRate {number} The sample's rate in Hz
|
|
114
118
|
* @param samplePitch {number} The sample's pitch as a MIDI note number
|
|
115
119
|
* @param samplePitchCorrection {number} The sample's pitch correction in cents
|
|
116
|
-
* @param sampleType {sampleTypes
|
|
120
|
+
* @param sampleType {sampleTypes} The sample's type, an enum that can indicate SF3
|
|
117
121
|
* @param loopStart {number} The sample's loop start relative to the sample start in sample points
|
|
118
122
|
* @param loopEnd {number} The sample's loop end relative to the sample start in sample points
|
|
119
123
|
*/
|
|
@@ -437,4 +441,37 @@ export class BasicSample
|
|
|
437
441
|
this.isCompressed = true;
|
|
438
442
|
this.dataOverriden = false;
|
|
439
443
|
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
export class CreatedSample extends BasicSample
|
|
448
|
+
{
|
|
449
|
+
/**
|
|
450
|
+
* A simplified class for creating samples
|
|
451
|
+
* @param name
|
|
452
|
+
* @param sampleRate
|
|
453
|
+
* @param sampleData
|
|
454
|
+
*/
|
|
455
|
+
constructor(name, sampleRate, sampleData)
|
|
456
|
+
{
|
|
457
|
+
super(name, sampleRate, 60, 0, sampleTypes.monoSample, 0, sampleData.length - 1);
|
|
458
|
+
this.setAudioData(sampleData);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* @param allowVorbis {boolean}
|
|
463
|
+
* @returns {Uint8Array}
|
|
464
|
+
*/
|
|
465
|
+
getRawData(allowVorbis)
|
|
466
|
+
{
|
|
467
|
+
return super.getRawData(allowVorbis);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @param audioData {Float32Array}
|
|
472
|
+
*/
|
|
473
|
+
setAudioData(audioData)
|
|
474
|
+
{
|
|
475
|
+
super.setAudioData(audioData);
|
|
476
|
+
}
|
|
440
477
|
}
|
|
@@ -9,7 +9,7 @@ import { consoleColors } from "../../utils/other.js";
|
|
|
9
9
|
import { write } from "./write_sf2/write.js";
|
|
10
10
|
import { defaultModulators, Modulator } from "./modulator.js";
|
|
11
11
|
import { writeDLS } from "./write_dls/write_dls.js";
|
|
12
|
-
import { BasicSample } from "./basic_sample.js";
|
|
12
|
+
import { BasicSample, sampleTypes } from "./basic_sample.js";
|
|
13
13
|
import { Generator } from "./generator.js";
|
|
14
14
|
import { BasicInstrument } from "./basic_instrument.js";
|
|
15
15
|
import { BasicPreset } from "./basic_preset.js";
|
|
@@ -158,7 +158,7 @@ class BasicSoundBank
|
|
|
158
158
|
44100,
|
|
159
159
|
65,
|
|
160
160
|
20,
|
|
161
|
-
|
|
161
|
+
sampleTypes.monoSample,
|
|
162
162
|
0,
|
|
163
163
|
127
|
|
164
164
|
);
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
resetParameters
|
|
12
12
|
} from "../engine_methods/controller_control/reset_controllers.js";
|
|
13
13
|
import { renderVoice } from "../engine_methods/render_voice.js";
|
|
14
|
-
import {
|
|
14
|
+
import { panAndMixVoice } from "./stereo_panner.js";
|
|
15
15
|
import { killNote } from "../engine_methods/stopping_notes/kill_note.js";
|
|
16
16
|
import { setTuning } from "../engine_methods/tuning_control/set_tuning.js";
|
|
17
17
|
import { setModulationDepth } from "../engine_methods/tuning_control/set_modulation_depth.js";
|
|
@@ -273,18 +273,22 @@ class MidiAudioChannel
|
|
|
273
273
|
* @param reverbOutputRight {Float32Array} right output for reverb
|
|
274
274
|
* @param chorusOutputLeft {Float32Array} left output for chorus
|
|
275
275
|
* @param chorusOutputRight {Float32Array} right output for chorus
|
|
276
|
+
* @param startIndex {number}
|
|
277
|
+
* @param sampleCount {number}
|
|
276
278
|
*/
|
|
277
279
|
renderAudio(
|
|
278
280
|
outputLeft, outputRight,
|
|
279
281
|
reverbOutputLeft, reverbOutputRight,
|
|
280
|
-
chorusOutputLeft, chorusOutputRight
|
|
282
|
+
chorusOutputLeft, chorusOutputRight,
|
|
283
|
+
startIndex, sampleCount
|
|
281
284
|
)
|
|
282
285
|
{
|
|
283
286
|
this.voices = this.voices.filter(v => !this.renderVoice(
|
|
284
287
|
v, this.synth.currentSynthTime,
|
|
285
288
|
outputLeft, outputRight,
|
|
286
289
|
reverbOutputLeft, reverbOutputRight,
|
|
287
|
-
chorusOutputLeft, chorusOutputRight
|
|
290
|
+
chorusOutputLeft, chorusOutputRight,
|
|
291
|
+
startIndex, sampleCount
|
|
288
292
|
));
|
|
289
293
|
}
|
|
290
294
|
|
|
@@ -516,7 +520,7 @@ class MidiAudioChannel
|
|
|
516
520
|
|
|
517
521
|
// voice
|
|
518
522
|
MidiAudioChannel.prototype.renderVoice = renderVoice;
|
|
519
|
-
MidiAudioChannel.prototype.
|
|
523
|
+
MidiAudioChannel.prototype.panAndMixVoice = panAndMixVoice;
|
|
520
524
|
MidiAudioChannel.prototype.killNote = killNote;
|
|
521
525
|
MidiAudioChannel.prototype.stopAllNotes = stopAllNotes;
|
|
522
526
|
MidiAudioChannel.prototype.muteChannel = muteChannel;
|
|
@@ -125,7 +125,7 @@ export class SoundFontManager
|
|
|
125
125
|
|
|
126
126
|
// noinspection JSUnusedGlobalSymbols
|
|
127
127
|
/**
|
|
128
|
-
* Adds a new soundfont with a given ID
|
|
128
|
+
* Adds a new soundfont with a given ID, or replaces an existing one.
|
|
129
129
|
* @param font {BasicSoundBank}
|
|
130
130
|
* @param id {string}
|
|
131
131
|
* @param bankOffset {number}
|
|
@@ -38,13 +38,15 @@ for (let pan = MIN_PAN; pan <= MAX_PAN; pan++)
|
|
|
38
38
|
* @param reverbRight {Float32Array} right reverb input
|
|
39
39
|
* @param chorusLeft {Float32Array} left chorus buffer
|
|
40
40
|
* @param chorusRight {Float32Array} right chorus buffer
|
|
41
|
+
* @param startIndex {number}
|
|
41
42
|
* @this {MidiAudioChannel}
|
|
42
43
|
*/
|
|
43
|
-
export function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
export function panAndMixVoice(voice,
|
|
45
|
+
inputBuffer,
|
|
46
|
+
outputLeft, outputRight,
|
|
47
|
+
reverbLeft, reverbRight,
|
|
48
|
+
chorusLeft, chorusRight,
|
|
49
|
+
startIndex)
|
|
48
50
|
{
|
|
49
51
|
if (isNaN(inputBuffer[0]))
|
|
50
52
|
{
|
|
@@ -82,10 +84,10 @@ export function panVoice(voice,
|
|
|
82
84
|
const reverbGain = this.synth.reverbGain * this.synth.reverbSend * gain * (reverbSend / REVERB_DIVIDER);
|
|
83
85
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
84
86
|
{
|
|
85
|
-
|
|
87
|
+
const idx = i + startIndex;
|
|
88
|
+
reverbLeft[idx] += reverbGain * inputBuffer[i];
|
|
89
|
+
reverbRight[idx] += reverbGain * inputBuffer[i];
|
|
86
90
|
}
|
|
87
|
-
// copy as its mono
|
|
88
|
-
reverbRight.set(reverbLeft);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
const chorusSend = voice.modulatedGenerators[generatorTypes.chorusEffectsSend];
|
|
@@ -97,8 +99,9 @@ export function panVoice(voice,
|
|
|
97
99
|
const chorusRightGain = gainRight * chorusGain;
|
|
98
100
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
99
101
|
{
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
const idx = i + startIndex;
|
|
103
|
+
chorusLeft[idx] += chorusLeftGain * inputBuffer[i];
|
|
104
|
+
chorusRight[idx] += chorusRightGain * inputBuffer[i];
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
}
|
|
@@ -108,14 +111,14 @@ export function panVoice(voice,
|
|
|
108
111
|
{
|
|
109
112
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
110
113
|
{
|
|
111
|
-
outputLeft[i] += gainLeft * inputBuffer[i];
|
|
114
|
+
outputLeft[i + startIndex] += gainLeft * inputBuffer[i];
|
|
112
115
|
}
|
|
113
116
|
}
|
|
114
117
|
if (gainRight > 0)
|
|
115
118
|
{
|
|
116
119
|
for (let i = 0; i < inputBuffer.length; i++)
|
|
117
120
|
{
|
|
118
|
-
outputRight[i] += gainRight * inputBuffer[i];
|
|
121
|
+
outputRight[i + startIndex] += gainRight * inputBuffer[i];
|
|
119
122
|
}
|
|
120
123
|
}
|
|
121
124
|
}
|
|
@@ -18,6 +18,8 @@ import { generatorTypes } from "../../../soundfont/basic_soundfont/generator_typ
|
|
|
18
18
|
* @param reverbOutputRight {Float32Array} right output for reverb
|
|
19
19
|
* @param chorusOutputLeft {Float32Array} left output for chorus
|
|
20
20
|
* @param chorusOutputRight {Float32Array} right output for chorus
|
|
21
|
+
* @param startIndex {number}
|
|
22
|
+
* @param sampleCount {number}
|
|
21
23
|
* @this {MidiAudioChannel}
|
|
22
24
|
* @returns {boolean} true if the voice is finished
|
|
23
25
|
*/
|
|
@@ -25,7 +27,8 @@ export function renderVoice(
|
|
|
25
27
|
voice, timeNow,
|
|
26
28
|
outputLeft, outputRight,
|
|
27
29
|
reverbOutputLeft, reverbOutputRight,
|
|
28
|
-
chorusOutputLeft, chorusOutputRight
|
|
30
|
+
chorusOutputLeft, chorusOutputRight,
|
|
31
|
+
startIndex, sampleCount
|
|
29
32
|
)
|
|
30
33
|
{
|
|
31
34
|
// check if release
|
|
@@ -168,7 +171,7 @@ export function renderVoice(
|
|
|
168
171
|
|
|
169
172
|
|
|
170
173
|
// SYNTHESIS
|
|
171
|
-
const bufferOut = new Float32Array(
|
|
174
|
+
const bufferOut = new Float32Array(sampleCount);
|
|
172
175
|
|
|
173
176
|
// wave table oscillator
|
|
174
177
|
switch (this.synth.interpolationType)
|
|
@@ -191,14 +194,20 @@ export function renderVoice(
|
|
|
191
194
|
LowpassFilter.apply(voice, bufferOut, lowpassExcursion, this.synth.filterSmoothingFactor);
|
|
192
195
|
|
|
193
196
|
// vol env
|
|
194
|
-
VolumeEnvelope.apply(
|
|
197
|
+
VolumeEnvelope.apply(
|
|
198
|
+
voice,
|
|
199
|
+
bufferOut,
|
|
200
|
+
volumeExcursionCentibels,
|
|
201
|
+
this.synth.volumeEnvelopeSmoothingFactor
|
|
202
|
+
);
|
|
195
203
|
|
|
196
|
-
this.
|
|
204
|
+
this.panAndMixVoice(
|
|
197
205
|
voice,
|
|
198
206
|
bufferOut,
|
|
199
207
|
outputLeft, outputRight,
|
|
200
208
|
reverbOutputLeft, reverbOutputRight,
|
|
201
|
-
chorusOutputLeft, chorusOutputRight
|
|
209
|
+
chorusOutputLeft, chorusOutputRight,
|
|
210
|
+
startIndex
|
|
202
211
|
);
|
|
203
212
|
return voice.finished;
|
|
204
213
|
}
|
package/src/synthetizer/audio_engine/engine_methods/soundfont_management/embedded_sound_bank.js
CHANGED
|
@@ -24,7 +24,6 @@ export function setEmbeddedSoundFont(font, offset)
|
|
|
24
24
|
{
|
|
25
25
|
// the embedded bank is set as the first bank in the manager,
|
|
26
26
|
// with a special ID that does not clear when reloadManager is performed.
|
|
27
|
-
this.soundfontBankOffset = offset;
|
|
28
27
|
const loadedFont = loadSoundFont(font);
|
|
29
28
|
this.soundfontManager.addNewSoundFont(loadedFont, EMBEDDED_SOUND_BANK_ID, offset);
|
|
30
29
|
// rearrange so the embedded is first (most important as it overrides all others)
|
|
@@ -172,6 +172,12 @@ export const SYNTHESIZER_GAIN = 1.0;
|
|
|
172
172
|
class SpessaSynthProcessor
|
|
173
173
|
{
|
|
174
174
|
|
|
175
|
+
/**
|
|
176
|
+
* Manages sound banks.
|
|
177
|
+
* @type {SoundFontManager}
|
|
178
|
+
*/
|
|
179
|
+
soundfontManager = new SoundFontManager(this.updatePresetList.bind(this));
|
|
180
|
+
|
|
175
181
|
/**
|
|
176
182
|
* Cached voices for all presets for this synthesizer.
|
|
177
183
|
* Nesting goes like this:
|
|
@@ -210,13 +216,6 @@ class SpessaSynthProcessor
|
|
|
210
216
|
*/
|
|
211
217
|
tunings = [];
|
|
212
218
|
|
|
213
|
-
|
|
214
|
-
/**
|
|
215
|
-
* Bank offset for things like embedded RMIDIS. Added for every program change
|
|
216
|
-
* @type {number}
|
|
217
|
-
*/
|
|
218
|
-
soundfontBankOffset = 0;
|
|
219
|
-
|
|
220
219
|
/**
|
|
221
220
|
* The volume gain, set by user
|
|
222
221
|
* @type {number}
|
|
@@ -345,6 +344,7 @@ class SpessaSynthProcessor
|
|
|
345
344
|
*/
|
|
346
345
|
effectsEnabled;
|
|
347
346
|
|
|
347
|
+
|
|
348
348
|
/**
|
|
349
349
|
* for applying the snapshot after an override sound bank too
|
|
350
350
|
* @type {SynthesizerSnapshot}
|
|
@@ -408,11 +408,6 @@ class SpessaSynthProcessor
|
|
|
408
408
|
this.tunings.push([]);
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
/**
|
|
412
|
-
* @type {SoundFontManager}
|
|
413
|
-
*/
|
|
414
|
-
this.soundfontManager = new SoundFontManager(this.updatePresetList.bind(this));
|
|
415
|
-
|
|
416
411
|
for (let i = 0; i < this.midiOutputsCount; i++)
|
|
417
412
|
{
|
|
418
413
|
this.createMidiChannel(false);
|
|
@@ -496,10 +491,17 @@ class SpessaSynthProcessor
|
|
|
496
491
|
* @param outputs {Float32Array[]} output stereo channels (L, R)
|
|
497
492
|
* @param reverb {Float32Array[]} reverb stereo channels (L, R)
|
|
498
493
|
* @param chorus {Float32Array[]} chorus stereo channels (L, R)
|
|
499
|
-
|
|
500
|
-
|
|
494
|
+
* @param startIndex {number} start offset of the passed arrays, rendering starts at this index, defaults to 0
|
|
495
|
+
* @param sampleCount {number} the length of the rendered buffer, defaults to float32array length - startOffset
|
|
496
|
+
*/
|
|
497
|
+
renderAudio(outputs,
|
|
498
|
+
reverb,
|
|
499
|
+
chorus,
|
|
500
|
+
startIndex = 0,
|
|
501
|
+
sampleCount = 0
|
|
502
|
+
)
|
|
501
503
|
{
|
|
502
|
-
this.renderAudioSplit(reverb, chorus, Array(16).fill(outputs));
|
|
504
|
+
this.renderAudioSplit(reverb, chorus, Array(16).fill(outputs), startIndex, sampleCount);
|
|
503
505
|
}
|
|
504
506
|
|
|
505
507
|
/**
|
|
@@ -508,8 +510,15 @@ class SpessaSynthProcessor
|
|
|
508
510
|
* @param reverbChannels {Float32Array[]} reverb stereo channels (L, R)
|
|
509
511
|
* @param chorusChannels {Float32Array[]} chorus stereo channels (L, R)
|
|
510
512
|
* @param separateChannels {Float32Array[][]} a total of 16 stereo pairs (L, R) for each MIDI channel
|
|
511
|
-
|
|
512
|
-
|
|
513
|
+
* @param startIndex {number} start offset of the passed arrays, rendering starts at this index, defaults to 0
|
|
514
|
+
* @param sampleCount {number} the length of the rendered buffer, defaults to float32array length - startOffset
|
|
515
|
+
*/
|
|
516
|
+
renderAudioSplit(reverbChannels,
|
|
517
|
+
chorusChannels,
|
|
518
|
+
separateChannels,
|
|
519
|
+
startIndex = 0,
|
|
520
|
+
sampleCount = 0
|
|
521
|
+
)
|
|
513
522
|
{
|
|
514
523
|
// process event queue
|
|
515
524
|
const time = this.currentSynthTime;
|
|
@@ -522,6 +531,10 @@ class SpessaSynthProcessor
|
|
|
522
531
|
const chrL = chorusChannels[0];
|
|
523
532
|
const chrR = chorusChannels[1];
|
|
524
533
|
|
|
534
|
+
// validate
|
|
535
|
+
startIndex = Math.max(startIndex, 0);
|
|
536
|
+
const quantumSize = sampleCount || separateChannels[0][0].length - startIndex;
|
|
537
|
+
|
|
525
538
|
// for every channel
|
|
526
539
|
this.totalVoicesAmount = 0;
|
|
527
540
|
this.midiAudioChannels.forEach((channel, index) =>
|
|
@@ -538,7 +551,8 @@ class SpessaSynthProcessor
|
|
|
538
551
|
channel.renderAudio(
|
|
539
552
|
separateChannels[ch][0], separateChannels[ch][1],
|
|
540
553
|
revL, revR,
|
|
541
|
-
chrL, chrR
|
|
554
|
+
chrL, chrR,
|
|
555
|
+
startIndex, quantumSize
|
|
542
556
|
);
|
|
543
557
|
|
|
544
558
|
this.totalVoicesAmount += channel.voices.length;
|
|
@@ -550,7 +564,7 @@ class SpessaSynthProcessor
|
|
|
550
564
|
});
|
|
551
565
|
|
|
552
566
|
// advance the time appropriately
|
|
553
|
-
this.currentSynthTime +=
|
|
567
|
+
this.currentSynthTime += quantumSize * this.sampleTime;
|
|
554
568
|
}
|
|
555
569
|
|
|
556
570
|
// noinspection JSUnusedGlobalSymbols
|