FX Class: Compressor 2
Interactive example
Behold, a great sounding side-chain compressor running in the browser that you've been looking for!
Overview
This compressor 2 effect is a slightly different compressor to the first version seen in Superpowered Compressor. Compressor 2, allows the use of an optional side-chain input and adjustable knee. The parameters, default values and ranges are also slightly tweaked for a different sound.
A side-chain compressor is used to reduce the volume of an audio source based on the input from another source. It is often used to artificially create a 'pumping' effect in music, but also used widely in broadcast and podcasts to duck music while a presenter is talking for example.
The outputGainDb
property is set with values between `-24` and `24` with a default of 0. The attackSec
and releaseSec
properties are limited to values between `0.0001` and `10` (in seconds). holdSec
is used to hold the gain reduction for a period of time between 0
and 1
before the compressor release begins. This is useful to limit unwanted noise with fast rates.
The thresholdDb
and ratio
properties are integral to the effect with the ratio specifying the amount of attenuation applied to the signal and threshold setting the level at which the compression effect is engaged.
The softKneeDb
represents the width of the compressors soft knee attenuation curve between `0` and `12` in decibels. automaticGain
allows the gain is set relative to compressor output at 0dB. Useful in digital environments.
Finally, there is a getGainReductionDb()
method which will return the maximum gain reduction in decibels since the last getGainReductionDb()
call.
Use process()
for use without a side-chain input or use processWithSidechain()
is the side-chain functionality is required.
The compressor2 class operates with 0 latency, doesn't allocate any internal buffers and needs less than 1 kb of memory.
Implementation example
The compressor is is an FX class, it expects both an input and output buffer. The process()
method should be called on every loop of the audio processing block.
class SuperpoweredCompressor2StageProcessor extends SuperpoweredWebAudio.AudioWorkletProcessor {
onReady() {
this.mixer = new this.Superpowered.StereoMixer(this.samplerate, 2, 2, 0, 0.501, 2, false);
this.player = new this.Superpowered.AdvancedAudioPlayer(this.samplerate, 2, 2, 0, 0.501, 2, false);
this.playerOutputBuffer = new this.Superpowered.Float32Buffer(4096);
this.sidechain = new this.Superpowered.AdvancedAudioPlayer(this.samplerate, 2, 2, 0, 0.501, 2, false);
this.sidechainOutputBuffer = new this.Superpowered.Float32Buffer(4096);
this.compressor = new this.Superpowered.Compressor2(
this.samplerate,
);
this.compressorOutputBuffer = new this.Superpowered.Float32Buffer(4096);
this.compressor.automaticGain = false;
this.compressor.enabled = true;
this.compressor.attackSec = 0.03;
this.compressor.holdSec = 0.21;
this.compressor.releaseSec = 0.5;
this.compressor.outputGainDb = 0;
this.compressor.ratio = 10;
this.compressor.thresholdDb = -50;
this.compressorGain = 1;
this.sidechainGain = 1;
this.loadAudio('/audio/samples/kicks.wav');
this.loadAudio('/audio/samples/pads.wav');
}
onDestruct() {
this.mixer.destruct();
this.player.destruct();
this.playerOutputBuffer.free();
this.sidechain.destruct();
this.sidechainOutputBuffer.free();
this.compressor.destruct();
}
loadAudio(url) {
this.Superpowered.downloadAndDecode(url, this);
}
onMessageFromMainScope(message) {
if (typeof message.inputGainDb !== 'undefined') this.compressor.inputGainDb = message.inputGainDb;
if (typeof message.outputGainDb !== 'undefined') this.compressor.outputGainDb = message.outputGainDb;
if (typeof message.attackSec !== 'undefined') this.compressor.attackSec = message.attackSec;
if (typeof message.releaseSec !== 'undefined') this.compressor.releaseSec = message.releaseSec;
if (typeof message.ratio !== 'undefined') this.compressor.ratio = message.ratio;
if (typeof message.thresholdDb !== 'undefined') this.compressor.thresholdDb = message.thresholdDb;
if (typeof message.hpCutOffHz !== 'undefined') this.compressor.hpCutOffHz = message.hpCutOffHz;
if (typeof message.holdSec !== 'undefined') this.compressor.holdSec = message.holdSec;
if (typeof message.automaticGain !== 'undefined') this.compressor.automaticGain = message.automaticGain;
if (typeof message.softKneeDb !== 'undefined') this.compressor.softKneeDb = message.softKneeDb;
if (typeof message.enabled !== 'undefined') this.compressor.enabled = Boolean(message.enabled);
if (typeof message.soloSidechain !== 'undefined') {
this.compressorGain = message.soloSidechain ? 0 : 1;
}
if (message.SuperpoweredLoaded) {
if (message.SuperpoweredLoaded.url.includes('kicks')) {
this.sidechain.openMemory(this.Superpowered.arrayBufferToWASM(message.SuperpoweredLoaded.buffer), true, false);
} else {
this.player.openMemory(this.Superpowered.arrayBufferToWASM(message.SuperpoweredLoaded.buffer), true, false);
}
}
}
processAudio(inputBuffer, outputBuffer, buffersize, parameters) {
switch (this.player.getLatestEvent()) {
case this.Superpowered.AdvancedAudioPlayer.PlayerEvent_Opened:
this.player.loop(0, this.player.getDurationMs(), true, 255, false, 0, false, false);
this.player.play();
}
switch (this.sidechain.getLatestEvent()) {
case this.Superpowered.AdvancedAudioPlayer.PlayerEvent_Opened:
this.sidechain.loop(0, this.sidechain.getDurationMs(), true, 255, false, 0, false, false);
this.sidechain.play();
}
if (!this.player.processStereo(this.playerOutputBuffer.pointer, false, buffersize , 1)) {
this.Superpowered.memorySet(this.playerOutputBuffer.pointer, 0, buffersize * 8);
}
if (!this.sidechain.processStereo(this.sidechainOutputBuffer.pointer, false, buffersize , 1)) {
this.Superpowered.memorySet(this.sidechainOutputBuffer.pointer, 0, buffersize * 8);
}
if (!this.compressor.processWithSidechain(this.playerOutputBuffer.pointer, this.sidechainOutputBuffer.pointer, this.compressorOutputBuffer.pointer, buffersize)) {
this.Superpowered.memorySet(this.compressorOutputBuffer.pointer, 0, buffersize * 8);
}
this.mixer.inputGain[0] = this.compressorGain;
this.mixer.inputGain[1] = this.compressorGain;
this.mixer.inputGain[2] = this.sidechainGain;
this.mixer.inputGain[3] = this.sidechainGain;
this.mixer.process(
this.compressorOutputBuffer.pointer,
this.sidechainOutputBuffer.pointer,
0,
0,
outputBuffer.pointer,
buffersize
);
}
}
#include "SuperpoweredCompressor2.h"
void initCompressor() {
unsigned int sampleRate = 44100;
sidechainCompressor = new Superpowered::Compressor2(sampleRate);
}
void configureCompressor() {
sidechainCompressor->outputGainDb = 0;
sidechainCompressor->attackSec = 0.01;
sidechainCompressor->holdSec = 0;
sidechainCompressor->releaseSec = 0.2;
sidechainCompressor->ratio = 10;
sidechainCompressor->thresholdDb = -16;
sidechainCompressor->softKneeDb = 3;
sidechainCompressor->automaticGain = false;
sidechainCompressor->enabled = true;
}
void processAudio(float *interleavedInput, float *interleavedOutput, unsigned int numberOfFrames, unsigned int samplerate) {
sidechainCompressor->samplerate = samplerate;
bool outputChanged = sidechainCompressor->processWithSidechain(interleavedInput, interleavedInput, interleavedOutput, numberOfFrames);
float gainReductionDb = sidechainCompressor->getGainReductionDb();
...
}
Properties
attackSec
PROPERTYAttack in seconds (not milliseconds!).
Type | Min | Max | Default |
---|
Number | 0.00001 | 10 | 0.05 (50 ms) |
attackSec
PROPERTYAttack in seconds (not milliseconds!).
Type | Min | Max | Default |
---|
float | 0.00001 | 10 | 0.05 (50 ms) |
automaticGain
PROPERTYIf true, gain is set relative to compressor output at 0dB. Useful in digital environments.
Type | Min | Max | Default |
---|
Boolean | | | true |
automaticGain
PROPERTYIf true, gain is set relative to compressor output at 0dB. Useful in digital environments.
Type | Min | Max | Default |
---|
bool | | | true |
holdSec
PROPERTYHold segment (in seconds, not milliseconds) before release starts, useful to limit unwanted noise with fast rates.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 0.005 (5ms) |
holdSec
PROPERTYHold segment (in seconds, not milliseconds) before release starts, useful to limit unwanted noise with fast rates.
Type | Min | Max | Default |
---|
float | 0 | 1 | 0.005 (5ms) |
outputGainDb
PROPERTYOutput gain in decibels.
Type | Min | Max | Default |
---|
Number | -24 | 24 | 0 |
outputGainDb
PROPERTYOutput gain in decibels.
Type | Min | Max | Default |
---|
float | -24 | 24 | 0 |
ratio
PROPERTYGain reduction ratio.
Type | Min | Max | Default |
---|
Number | 1 | 1000 | 4 |
ratio
PROPERTYGain reduction ratio.
Type | Min | Max | Default |
---|
float | 1 | 1000 | 4 |
releaseSec
PROPERTYRelease in seconds (not milliseconds!).
Type | Min | Max | Default |
---|
Number | 0.00001 | 10 | 0.05 (50ms) |
releaseSec
PROPERTYRelease in seconds (not milliseconds!).
Type | Min | Max | Default |
---|
float | 0.00001 | 10 | 0.05 (50ms) |
softKneeDb
PROPERTYWidth of soft knee in decibels.
Type | Min | Max | Default |
---|
Number | 0 | 12 | 6 |
softKneeDb
PROPERTYWidth of soft knee in decibels.
Type | Min | Max | Default |
---|
float | 0 | 12 | 6 |
thresholdDb
PROPERTYThreshold in decibels.
Type | Min | Max | Default |
---|
Number | -60 | 0 | -6 |
thresholdDb
PROPERTYThreshold in decibels.
Type | Min | Max | Default |
---|
float | -60 | 0 | -6 |
Inherited from FX Classenabled
PROPERTYTurns the effect on/off. The actual switch will happen on the next process() call for smooth, audio-artifact free operation.
Type | Min | Max | Default |
---|
Boolean | | | false |
enabled
PROPERTYTurns the effect on/off. The actual switch will happen on the next process() call for smooth, audio-artifact free operation.
Type | Min | Max | Default |
---|
bool | | | false |
samplerate
PROPERTYThe sample rate of the audio context, you must update if it changes.
samplerate
PROPERTYThe sample rate of the audio context, you must update if it changes.
Type | Min | Max | Default |
---|
unsigned int | | | |
Methods
constructor
METHODCreates an instance of the Compressor2 class.
ParametersName | Type | Description |
---|
samplerate | Number | The initial sample rate in Hz |
ReturnsType | Description |
---|
Superpowered.Compressor2 | The constructed instance. |
constructor
METHODCreates an instance of the Compressor2 class.
ParametersName | Type | Default | Description |
---|
samplerate | unsigned int | | The initial sample rate in Hz |
ReturnsType | Description |
---|
Superpowered::Compressor2 | The constructed instance. |
getGainReductionDb
METHODReturns the maximum gain reduction in decibels since the last getGainReductionDb() call.
ParametersNone
ReturnsType | Description |
---|
Number | Reduction in db. |
getGainReductionDb
METHODReturns the maximum gain reduction in decibels since the last getGainReductionDb() call.
ParametersNone
ReturnsType | Description |
---|
float | Reduction in db. |
processWithSidechain
METHODProcesses/renders the audio. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. It's never blocking for real-time usage. You can change all effect properties on any thread, concurrently with process().
ParametersName | Type | Description |
---|
input | Number | 32-bit interleaved stereo input. |
sidechain | Number | 32-bit interleaved stereo sidechain input. |
output | Number | 32-bit interleaved stereo output. |
numberOfFrames | Number | Number of frames to process. Recommendations for best performance: multiply of 4, minimum 64. |
ReturnsType | Description |
---|
Number | If returns with true, the contents of output are replaced with the audio output. If returns with false, it indicates silence. The contents of output are not changed in this case (not overwritten with zeros). |
processWithSidechain
METHODProcesses/renders the audio. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. It's never blocking for real-time usage. You can change all effect properties on any thread, concurrently with process().
ParametersName | Type | Default | Description |
---|
input | Number | | 32-bit interleaved stereo input. |
sidechain | Number | | 32-bit interleaved stereo sidechain input. |
output | Number | | 32-bit interleaved stereo output. |
numberOfFrames | Number | | Number of frames to process. Recommendations for best performance: multiply of 4, minimum 64. |
ReturnsType | Description |
---|
Boolean | If returns with true, the contents of output are replaced with the audio output. If returns with false, it indicates silence. The contents of output are not changed in this case (not overwritten with zeros). |
Inherited from FX Classdestruct
METHODDestructor to free Linear Memory.
ParametersNone
ReturnsNone
process
METHODProcesses/renders the audio. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. It's never blocking for real-time usage.
ParametersName | Type | Description |
---|
input | Number (pointer in Linear Memory) | 32-bit interleaved stereo input. |
output | Number (pointer in Linear Memory) | 32-bit interleaved stereo output. |
numberOfFrames | Number | Number of frames to process. Recommendations for best performance: multiply of 4, minimum 64. |
ReturnsType | Description |
---|
Boolean | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, it indicates silence. The contents of output are not changed in this case (not overwritten with zeros). |
process
METHODProcesses/renders the audio. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. It's never blocking for real-time usage. You can change all effect properties on any thread, concurrently with process().
ParametersName | Type | Default | Description |
---|
input | float * | | 32-bit interleaved stereo input. |
output | float * | | 32-bit interleaved stereo output. |
numberOfFrames | unsigned int | | Number of frames to process. Recommendations for best performance: multiply of 4, minimum 64. |
ReturnsType | Description |
---|
bool | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, it indicates silence. The contents of output are not changed in this case (not overwritten with zeros). |