Skip to content

Commit

Permalink
add effects configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
spessasus committed Jun 21, 2024
1 parent 6dbe44f commit aa8b96a
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 22 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "SpessaSynth",
"version": "3.0.2",
"version": "3.1.0",
"dependencies": {
"@types/webaudioapi": "^0.0.27",
"express": "^4.18.2",
Expand Down
2 changes: 1 addition & 1 deletion src/spessasynth_lib/soundfont/chunk/modulators.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export const defaultModulators = [

// reverb effects to send
// 1000 to align with the reverbSend (overriding it works anyways)
new Modulator({srcEnum: 0x00DB, dest: generatorTypes.reverbEffectsSend, amt: 1000, secSrcEnum: 0x0, transform: 0}),
new Modulator({srcEnum: 0x00DB, dest: generatorTypes.reverbEffectsSend, amt: 200, secSrcEnum: 0x0, transform: 0}),

// chorus effects to send
new Modulator({srcEnum: 0x00DD, dest: generatorTypes.chorusEffectsSend, amt: 200, secSrcEnum: 0x0, transform: 0}),
Expand Down
21 changes: 21 additions & 0 deletions src/spessasynth_lib/synthetizer/audio_effects/effects_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { DEFAULT_CHORUS_CONFIG } from './fancy_chorus.js'

/**
* @typedef {Object} EffectsConfig
* @property {boolean} chorusEnabled - indicates if the chorus effect is enabled.
* @property {ChorusConfig} chorusConfig - the configuration for chorus. Pass undefined to use defaults
* @property {boolean} reverbEnabled - indicates if the reverb effect is enabled.
* @property {AudioBuffer} reverbImpulseResponse - the impulse response for the reverb. Pass undefined to use defaults
*/


/**
* @type {EffectsConfig}
*/
export const DEFAULT_EFFECTS_CONFIG = {
chorusEnabled: true,
chorusConfig: DEFAULT_CHORUS_CONFIG,

reverbEnabled: true,
reverbImpulseResponse: undefined // will load the integrated one
}
46 changes: 36 additions & 10 deletions src/spessasynth_lib/synthetizer/audio_effects/fancy_chorus.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@
* }} ChorusNode
*/

/**
* @typedef {Object} ChorusConfig
* @property {number} nodesAmount - the amount of delay nodes (for each channel) and the corresponding oscillators
* @property {number} defaultDelay - the initial delay, in seconds
* @property {number} delayVariation - the difference between delays in the delay nodes
* @property {number} stereoDifference - the difference of delays between two channels (added to the left channel and subtracted from the right)
*
* @property {number} oscillatorFrequency - the initial delay oscillator frequency, in Hz.
* @property {number} oscillatorFrequencyVariation - the difference between frequencies of oscillators, in Hz
* @property {number} oscillatorGain - how much will oscillator alter the delay in delay nodes, in seconds
*/


const NODES_AMOUNT = 3;
const DEFAULT_DELAY = 0.02;
const DELAY_VARIATION = 0.01;
Expand All @@ -19,13 +32,25 @@ const STEREO_DIFF = 0.01;
const OSC_FREQ = 0.3;
const OSC_FREQ_VARIATION = 0.1;
const OSC_GAIN = 0.002;

export const DEFAULT_CHORUS_CONFIG = {
nodesAmount: NODES_AMOUNT,
defaultDelay: DEFAULT_DELAY,
delayVariation: DELAY_VARIATION,
stereoDifference: STEREO_DIFF,
oscillatorFrequency: OSC_FREQ,
oscillatorFrequencyVariation: OSC_FREQ_VARIATION,
oscillatorGain: OSC_GAIN
};

export class FancyChorus
{
/**
* Creates a fancy chorus effect
* @param output {AudioNode}
* @param config {ChorusConfig}
*/
constructor(output) {
constructor(output, config = DEFAULT_CHORUS_CONFIG) {
const context = output.context;

this.input = new ChannelSplitterNode(context,
Expand All @@ -46,15 +71,15 @@ export class FancyChorus
* @type {ChorusNode[]}
*/
const chorusNodesRight = [];
let freq = OSC_FREQ;
let delay = DEFAULT_DELAY;
for (let i = 0; i < NODES_AMOUNT; i++) {
let freq = config.oscillatorFrequency;
let delay = config.defaultDelay;
for (let i = 0; i < config.nodesAmount; i++) {
// left node
this.createChorusNode(freq, delay - STEREO_DIFF, chorusNodesLeft, 0, merger, 0, context);
this.createChorusNode(freq, delay - config.stereoDifference, chorusNodesLeft, 0, merger, 0, context, config);
// right node
this.createChorusNode(freq, delay + STEREO_DIFF, chorusNodesRight, 1, merger, 1, context);
freq += OSC_FREQ_VARIATION;
delay += DELAY_VARIATION;
this.createChorusNode(freq, delay + config.stereoDifference, chorusNodesRight, 1, merger, 1, context, config);
freq += config.oscillatorFrequencyVariation;
delay += config.delayVariation;
}

merger.connect(output);
Expand All @@ -68,15 +93,16 @@ export class FancyChorus
* @param output {AudioNode}
* @param outputNum {number}
* @param context {BaseAudioContext}
* @param config {ChorusConfig}
*/
createChorusNode(freq, delay, list, input, output, outputNum, context)
createChorusNode(freq, delay, list, input, output, outputNum, context, config)
{
const oscillator = new OscillatorNode(context, {
type: "triangle",
frequency: freq
});
const gainNode = new GainNode(context, {
gain: OSC_GAIN
gain: config.oscillatorGain
});
const delayNode = new DelayNode(context, {
delayTime: delay
Expand Down
24 changes: 17 additions & 7 deletions src/spessasynth_lib/synthetizer/synthetizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
workletMessageType,
} from './worklet_system/worklet_utilities/worklet_message.js'
import { SpessaSynthInfo } from '../utils/loggin.js'
import { DEFAULT_EFFECTS_CONFIG } from './audio_effects/effects_config.js'


/**
Expand Down Expand Up @@ -65,13 +66,13 @@ export class Synthetizer {
* parsedMIDI: MIDI,
* snapshot: SynthesizerSnapshot
* }} if set, starts playing this immediately and restores the values
* @param reverbBuffer {AudioBuffer} optional impulse response for the convolver.
* @param effectsConfig {EffectsConfig} optional configuration for the audio effects.
*/
constructor(targetNode,
soundFontBuffer,
enableEventSystem = true,
startRenderingData = undefined,
reverbBuffer = undefined) {
effectsConfig = DEFAULT_EFFECTS_CONFIG) {
SpessaSynthInfo("%cInitializing SpessaSynth synthesizer...", consoleColors.info);
this.context = targetNode.context;

Expand All @@ -80,9 +81,7 @@ export class Synthetizer {
* @type {EventHandler}
*/
this.eventHandler = new EventHandler();
this.reverbProcessor = getReverbProcessor(this.context, reverbBuffer);
this.chorusProcessor = new FancyChorus(targetNode);
this.reverbProcessor.connect(targetNode);


/**
* the new channels will have their audio sent to the moduled output by this constant.
Expand Down Expand Up @@ -154,8 +153,19 @@ export class Synthetizer {
*/
this.sequencerCallbackFunction = undefined;

this.worklet.connect(this.reverbProcessor, 0);
this.worklet.connect(this.chorusProcessor.input, 1);
// add reverb
if(effectsConfig.reverbEnabled)
{
this.reverbProcessor = getReverbProcessor(this.context, effectsConfig.reverbImpulseResponse);
this.reverbProcessor.connect(targetNode);
this.worklet.connect(this.reverbProcessor, 0);
}

if(effectsConfig.chorusEnabled)
{
this.chorusProcessor = new FancyChorus(targetNode, effectsConfig.chorusConfig);
this.worklet.connect(this.chorusProcessor.input, 1);
}

// connect all outputs to the output node
for (let i = 2; i < this.channelsAmount + 2; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const WORKLET_SYSTEM_REVERB_DIVIDER = 1000;
export const WORKLET_SYSTEM_REVERB_DIVIDER = 200;
export const WORKLET_SYSTEM_CHORUS_DIVIDER = 500;
/**
* stereo_panner.js
Expand Down
19 changes: 17 additions & 2 deletions src/website/manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ const RENDER_AUDIO_TIME_INTERVAL = 500;
synth = new Synthetizer(offline.destination, this.sf, false, {
parsedMIDI: parsedMid,
snapshot: snapshot
}, this.impulseResponse);
}, {
reverbEnabled: true,
chorusEnabled: true,
chorusConfig: undefined,
reverbImpulseResponse: this.impulseResponse
});
}
catch (e) {
window.alert(this.localeManager.getLocaleString("locale.outOfMemory"));
Expand Down Expand Up @@ -164,7 +169,17 @@ const RENDER_AUDIO_TIME_INTERVAL = 500;
this.impulseResponse = await context.decodeAudioData(data);

// set up synthetizer
this.synth = new Synthetizer(context.destination, this.soundFont, undefined, undefined, this.impulseResponse);
this.synth = new Synthetizer(
context.destination,
this.soundFont,
undefined,
undefined,
{
chorusEnabled: true,
chorusConfig: undefined,
reverbImpulseResponse: this.impulseResponse,
reverbEnabled: true
});

// set up midi access
this.midHandler = new MIDIDeviceHandler();
Expand Down

0 comments on commit aa8b96a

Please sign in to comment.