FX Class: Spatializer
Interactive example
Overview
Spatialization puts a sound into the 3D space. A virtual model of a space is constructed and the sound is positioned within it. The Superpowered Spatializer has exceptionally low CPU usage and one instance allocates around 140 kb memory only.
Another unique feature of is the "musicality" of this API. Other spatializers may sound good with game sound effects, but also add a phasey artifact to musical elements. This Spatializer class can also be used for musical instruments.
Implementation example
The azimuth
and elevation
properties control the direction of the sound in the 3D space.
The distance can be controlled by inputVolume
, while the occlusion
property can add the sensation of "objects between the sound and the listener" (such as a wall).
The Spatializer class also has one Global Spatializer Reverb instance to simulate "room sound". It collects audio from all Superpowered Spatializer instances and puts a reverb on the signal. The reverbmix
controls the ratio of how much audio the Global Spatializer Reverb can collect from a Spatializer instance.
class SuperpoweredSpatializerStageProcessor extends SuperpoweredWebAudio.AudioWorkletProcessor {
onReady() {
this.effect = new this.Superpowered.Spatializer(
this.samplerate
);
this.effect.reverbmix = 0.1;
this.reverbOutput = new this.Superpowered.Float32Buffer(4096);
this.Superpowered.Spatializer.reverbWidth = 1;
this.Superpowered.Spatializer.reverbDamp = 0.5;
this.Superpowered.Spatializer.reverbRoomSize = 0.6;
this.Superpowered.Spatializer.reverbPredelayMs = 0;
this.Superpowered.Spatializer.reverbLowCutHz = 100;
}
onMessageFromMainScope(message) {
if (typeof message.inputVolume !== 'undefined') this.effect.inputVolume = message.inputVolume;
if (typeof message.azimuth !== 'undefined') this.effect.azimuth = message.azimuth;
if (typeof message.elevation !== 'undefined') this.effect.elevation = message.elevation;
if (typeof message.reverbmix !== 'undefined') this.effect.reverbmix = message.reverbmix;
if (typeof message.occlusion !== 'undefined') this.effect.occlusion = message.occlusion;
if (typeof message.sound2 !== 'undefined') this.effect.sound2 = message.sound2;
if (typeof message.reverbWidth !== 'undefined') this.Superpowered.Spatializer.reverbWidth = message.reverbWidth;
if (typeof message.reverbDamp !== 'undefined') this.Superpowered.Spatializer.reverbDamp = message.reverbDamp;
if (typeof message.reverbRoomSize !== 'undefined') this.Superpowered.Spatializer.reverbRoomSize = message.reverbRoomSize;
if (typeof message.reverbPredelayMs !== 'undefined') this.Superpowered.Spatializer.reverbPredelayMs = message.reverbPredelayMs;
if (typeof message.reverbLowCutHz !== 'undefined') this.Superpowered.Spatializer.reverbLowCutHz = message.reverbLowCutHz;
}
onDestruct() {
this.effect.destruct();
this.reverbOutput.free();
}
processAudio(inputBuffer, outputBuffer, buffersize) {
if (!this.effect.process(
inputBuffer.pointer,
0,
outputBuffer.pointer,
0,
buffersize,
false
)) this.Superpowered.memoryCopy(outputBuffer.pointer, inputBuffer.pointer, buffersize * 8);
if (this.Superpowered.Spatializer.reverbProcess(this.reverbOutput.pointer, buffersize)) this.Superpowered.Add1(this.reverbOutput.pointer, outputBuffer.pointer, buffersize * 2);
}
}
#include "SuperpoweredSpatializer.h"
void initSpatializerEffect() {
const unsigned int sampleRate = 44100;
spatializer = new Superpowered::Spatializer(sampleRate);
}
void configureEffect() {
spatializer->inputVolume = 0.5;
spatializer->azimuth = 45;
spatializer->elevation = 0;
spatializer->reverbmix = 0.5;
spatializer->occlusion = 0;
spatializer->sound2 = false;
spatializer->reverbWidth = 0.3;
}
void processAudio(float *interleavedInput, float *interleavedOutput, unsigned int numberOfFrames, unsigned int samplerate) {
spatializer->samplerate = samplerate;
bool outputChanged = spatializer->process(interleavedInput, interleavedOutput, numberOfFrames);
float reverbOutput[numberOfFrames * 2];
if (Superpowered::Spatializer::reverbProcess(reverbOutput, numberOfFrames)) Superpowered::Add1(reverbOutput, interleavedOutput, numberOfFrames * 2);
...
}
You can also set the global reverb settings anywhere in you application that has access to the Superpowered context. These settings will be applied to all instances of the Spatializer (more information on the Reverb class
).
Superpowered.Spatializer.reverbWidth = 1;
Superpowered.Spatializer.reverbDamp = 0.5;
Superpowered.Spatializer.reverbRoomSize = 0.6;
Superpowered.Spatializer.reverbPredelayMs = 0;
Superpowered.Spatializer.reverbLowCutHz = 100;
Superpowered::Spatializer::reverbWidth = 1f;
Superpowered::Spatializer::reverbDamp = 0.5f;
Superpowered::Spatializer::reverbRoomSize = 0.6f;
Superpowered::Spatializer::reverbPredelayMs = 0f;
Superpowered::Spatializer::reverbLowCutHz = 100f;
Please note the Global Reverb is fully optional, you can just remove all code related to the Global Reverb if not needed.
Static Properties
reverbDamp
PROPERTYGlobal Spatializer Reverb high frequency damping.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 0.5 |
reverbDamp
PROPERTYGlobal Spatializer Reverb high frequency damping.
Type | Min | Max | Default |
---|
float | 0 | 1 | 0.5 |
reverbLowCutHz
PROPERTYGlobal Spatializer Reverb frequency of the low cut in Hz (-12 db point).
Type | Min | Max | Default |
---|
Number | | | 0 (no low frequency cut) |
reverbLowCutHz
PROPERTYGlobal Spatializer Reverb frequency of the low cut in Hz (-12 db point).
Type | Min | Max | Default |
---|
float | | | 0 (no low frequency cut) |
reverbPredelayMs
PROPERTYGlobal Spatializer Reverb pre-delay in milliseconds.
Type | Min | Max | Default |
---|
Number | 0 | 500 | 0 |
reverbPredelayMs
PROPERTYGlobal Spatializer Reverb pre-delay in milliseconds.
Type | Min | Max | Default |
---|
float | 0 | 500 | 0 |
reverbRoomSize
PROPERTYGlobal Spatializer Reverb room size.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 0.8 |
reverbRoomSize
PROPERTYGlobal Spatializer Reverb room size.
Type | Min | Max | Default |
---|
float | 0 | 1 | 0.8 |
reverbWidth
PROPERTYGlobal Spatializer Reverb stereo width.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 1 |
reverbWidth
PROPERTYGlobal Spatializer Reverb stereo width.
Type | Min | Max | Default |
---|
float | 0 | 1 | 1 |
Static Methods
reverbProcess
METHODOutputs the Global Spatializer Reverb. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. Should be called after every Superpowered Spatializer's process() method. It's never blocking for real-time usage. You can change all properties of the globalReverb on any thread, concurrently with process().
ParametersName | Type | Description |
---|
output | Number (pointer in Linear Memory) | Pointer to floating point numbers. 32-bit interleaved stereo output. |
numberOfFrames | Number | Number of frames to process. |
ReturnsType | Description |
---|
Boolean | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, the contents of output are not changed. |
reverbProcess
METHODOutputs the Global Spatializer Reverb. Always call it in the audio processing callback, regardless if the effect is enabled or not for smooth, audio-artifact free operation. Should be called after every Superpowered Spatializer's process() method. It's never blocking for real-time usage. You can change all properties of the globalReverb on any thread, concurrently with process().
ParametersName | Type | Default | Description |
---|
output | float * | | Pointer to floating point numbers. 32-bit interleaved stereo output. |
numberOfFrames | unsigned int | | Number of frames to process. |
ReturnsType | Description |
---|
bool | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, the contents of output are not changed. |
Properties
azimuth
PROPERTYAzimuth in degrees.
Type | Min | Max | Default |
---|
Number | 0 | 360 | 0 |
azimuth
PROPERTYAzimuth in degrees.
Type | Min | Max | Default |
---|
float | 0 | 360 | 0 |
elevation
PROPERTYElevation in degrees.
Type | Min | Max | Default |
---|
Number | -90 | 90 | 0 |
elevation
PROPERTYElevation in degrees.
Type | Min | Max | Default |
---|
float | -90 | 90 | 0 |
occlusion
PROPERTYOcclusion factor.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 0 |
occlusion
PROPERTYOcclusion factor.
Type | Min | Max | Default |
---|
float | 0 | 1 | 0 |
reverbmix
PROPERTYThe ratio of how much audio the Global Spatializer Reverb can collect from this instance.
Type | Min | Max | Default |
---|
Number | 0 | 1 | 0 |
reverbmix
PROPERTYThe ratio of how much audio the Global Spatializer Reverb can collect from this instance.
Type | Min | Max | Default |
---|
float | 0 | 1 | 0 |
samplerate
PROPERTYSample rate of the input/output audio in Hz.
samplerate
PROPERTYSample rate of the input/output audio in Hz.
Type | Min | Max | Default |
---|
unsigned int | | | |
sound2
PROPERTYAlternative sound option.
Type | Min | Max | Default |
---|
Boolean | | | false |
sound2
PROPERTYAlternative sound option.
Type | Min | Max | Default |
---|
bool | | | false |
Methods
constructor
METHODCreates a Spatializer instance.
ParametersName | Type | Description |
---|
samplerate | Number | The initial sample rate in Hz. |
ReturnsType | Description |
---|
Superpowered.Spatializer | The constructed instance. |
constructor
METHODCreates a Spatializer instance.
ParametersName | Type | Default | Description |
---|
samplerate | unsigned int | | The initial sample rate in Hz. |
ReturnsType | Description |
---|
Superpowered::Spatializer | The constructed instance. |
process
METHODProcesses the audio. It's never blocking for real-time usage. You can change all properties on any thread, concurrently with process().
ParametersName | Type | Description |
---|
inputLeft | Number (pointer in Linear Memory) | 32-bit left channel or interleaved stereo input. |
inputRight | Number (pointer in Linear Memory) | 32-bit right channel input. Can be NULL, inputLeft will be used in this case as interleaved stereo input. |
outputLeft | Number (pointer in Linear Memory) | 32-bit left channel or interleaved stereo output. |
outputRight | Number (pointer in Linear Memory) | 32-bit right channel output. Can be NULL, outputLeft will be used in this case as interleaved stereo output. |
numberOfFrames | Number | Number of frames to process. |
outputAdd | Boolean | If true, audio will be added to whatever content is in outputLeft or outputRight. |
ReturnsType | Description |
---|
Boolean | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, the contents of output are not changed. |
process
METHODProcesses the audio. It's never blocking for real-time usage. You can change all properties on any thread, concurrently with process().
ParametersName | Type | Default | Description |
---|
inputLeft | float * | | 32-bit left channel or interleaved stereo input. |
inputRight | float * | | 32-bit right channel input. Can be NULL, inputLeft will be used in this case as interleaved stereo input. |
outputLeft | float * | | 32-bit left channel or interleaved stereo output. |
outputRight | float * | | 32-bit right channel output. Can be NULL, outputLeft will be used in this case as interleaved stereo output. |
numberOfFrames | unsigned int | | Number of frames to process. |
outputAdd | bool | | If true, audio will be added to whatever content is in outputLeft or outputRight. |
ReturnsType | Description |
---|
bool | If process() returns with true, the contents of output are replaced with the audio output. If process() returns with false, the contents of output are not changed. |