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 {
// runs after the constructor
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; // Global Spatializer Reverb stereo width. >= 0 and <= 1.
this.Superpowered.Spatializer.reverbDamp = 0.5; // Global Spatializer Reverb high frequency damping. >= 0 and <= 1.
this.Superpowered.Spatializer.reverbRoomSize = 0.6; // Global Spatializer Reverb room size. >= 0 and <= 1.
this.Superpowered.Spatializer.reverbPredelayMs = 0; // Global Spatializer Reverb pre-delay in milliseconds. 0 to 500.
this.Superpowered.Spatializer.reverbLowCutHz = 100;
}
// messages are received from the main scope through this method.
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;
}
// Runs before the node is destroyed.
// Clean up memory and objects here (such as free allocated linear memory or destruct Superpowered objects).
onDestruct() {
this.effect.destruct();
this.reverbOutput.free();
}
// This is the process loop which is passed pointers to buffers.
// from the WebAudio API (inputBuffer and outputBuffer), with the buffersize (128 samples when running as a native AudioWorklet).
processAudio(inputBuffer, outputBuffer, buffersize) {
if (!this.effect.process(
inputBuffer.pointer, // Pointer to floating point numbers. 32-bit left channel or interleaved stereo input.
0, // Pointer to floating point numbers. 32-bit right channel input. Can be null, inputLeft will be used in this case as interleaved stereo input.
outputBuffer.pointer, // Pointer to floating point numbers. 32-bit left channel or interleaved stereo output.
0, // Pointer to floating point numbers. 32-bit right channel output. Can be null, outputLeft will be used in this case as interleaved stereo output.
buffersize, // Number of frames to process. Valid between 64-8192.
false // If true, audio will be added to whatever content is in outputLeft or outputRight.
)) this.Superpowered.memoryCopy(outputBuffer.pointer, inputBuffer.pointer, buffersize * 8);
// Output the global spatializer reverb into a buffer, then mix it into the output.
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) {
// Ensure the samplerate is in sync on every audio processing callback
spatializer->samplerate = samplerate;
// Render the output buffers
bool outputChanged = spatializer->process(interleavedInput, interleavedOutput, numberOfFrames);
// Output the global spatializer reverb into a buffer, then mix it into the output.
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; // Global Spatializer Reverb stereo width. >= 0 and <= 1.
Superpowered.Spatializer.reverbDamp = 0.5; // Global Spatializer Reverb high frequency damping. >= 0 and <= 1.
Superpowered.Spatializer.reverbRoomSize = 0.6; // Global Spatializer Reverb room size. >= 0 and <= 1.
Superpowered.Spatializer.reverbPredelayMs = 0; // Global Spatializer Reverb pre-delay in milliseconds. 0 to 500.
Superpowered.Spatializer.reverbLowCutHz = 100; // Global Spatializer Reverb frequency of the low cut in Hz (-12 db point). Default: 0 (no low frequency cut).
Superpowered::Spatializer::reverbWidth = 1f; // Global Spatializer Reverb stereo width. >= 0 and <= 1.
Superpowered::Spatializer::reverbDamp = 0.5f; // Global Spatializer Reverb high frequency damping. >= 0 and <= 1.
Superpowered::Spatializer::reverbRoomSize = 0.6f; // Global Spatializer Reverb room size. >= 0 and <= 1.
Superpowered::Spatializer::reverbPredelayMs = 0f; // Global Spatializer Reverb pre-delay in milliseconds. 0 to 500.
Superpowered::Spatializer::reverbLowCutHz = 100f; // Global Spatializer Reverb frequency of the low cut in Hz (-12 db point). Default: 0 (no low frequency cut).

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

PROPERTY
Global Spatializer Reverb high frequency damping.
TypeMinMaxDefault
Number
010.5

reverbDamp

PROPERTY
Global Spatializer Reverb high frequency damping.
TypeMinMaxDefault
float
010.5

reverbLowCutHz

PROPERTY
Global Spatializer Reverb frequency of the low cut in Hz (-12 db point).
TypeMinMaxDefault
Number
0 (no low frequency cut)

reverbLowCutHz

PROPERTY
Global Spatializer Reverb frequency of the low cut in Hz (-12 db point).
TypeMinMaxDefault
float
0 (no low frequency cut)

reverbPredelayMs

PROPERTY
Global Spatializer Reverb pre-delay in milliseconds.
TypeMinMaxDefault
Number
05000

reverbPredelayMs

PROPERTY
Global Spatializer Reverb pre-delay in milliseconds.
TypeMinMaxDefault
float
05000

reverbRoomSize

PROPERTY
Global Spatializer Reverb room size.
TypeMinMaxDefault
Number
010.8

reverbRoomSize

PROPERTY
Global Spatializer Reverb room size.
TypeMinMaxDefault
float
010.8

reverbWidth

PROPERTY
Global Spatializer Reverb stereo width.
TypeMinMaxDefault
Number
011

reverbWidth

PROPERTY
Global Spatializer Reverb stereo width.
TypeMinMaxDefault
float
011

Static Methods

  • reverbProcess

    METHOD
    Outputs 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().
    Parameters
    NameTypeDescription
    outputNumber (pointer in Linear Memory)Pointer to floating point numbers. 32-bit interleaved stereo output.
    numberOfFramesNumberNumber of frames to process.
    Returns
    TypeDescription
    BooleanIf 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

    METHOD
    Outputs 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().
    Parameters
    NameTypeDefaultDescription
    outputfloat *Pointer to floating point numbers. 32-bit interleaved stereo output.
    numberOfFramesunsigned intNumber of frames to process.
    Returns
    TypeDescription
    boolIf 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

PROPERTY
Azimuth in degrees.
TypeMinMaxDefault
Number
03600

azimuth

PROPERTY
Azimuth in degrees.
TypeMinMaxDefault
float
03600

elevation

PROPERTY
Elevation in degrees.
TypeMinMaxDefault
Number
-90900

elevation

PROPERTY
Elevation in degrees.
TypeMinMaxDefault
float
-90900

inputVolume

PROPERTY
Input volume (gain).
TypeMinMaxDefault
Number
1

inputVolume

PROPERTY
Input volume (gain).
TypeMinMaxDefault
float
1

occlusion

PROPERTY
Occlusion factor.
TypeMinMaxDefault
Number
010

occlusion

PROPERTY
Occlusion factor.
TypeMinMaxDefault
float
010

reverbmix

PROPERTY
The ratio of how much audio the Global Spatializer Reverb can collect from this instance.
TypeMinMaxDefault
Number
010

reverbmix

PROPERTY
The ratio of how much audio the Global Spatializer Reverb can collect from this instance.
TypeMinMaxDefault
float
010

samplerate

PROPERTY
Sample rate of the input/output audio in Hz.
TypeMinMaxDefault
Number

samplerate

PROPERTY
Sample rate of the input/output audio in Hz.
TypeMinMaxDefault
unsigned int

sound2

PROPERTY
Alternative sound option.
TypeMinMaxDefault
Boolean
false

sound2

PROPERTY
Alternative sound option.
TypeMinMaxDefault
bool
false

Methods

  • constructor

    METHOD
    Creates a Spatializer instance.
    Parameters
    NameTypeDescription
    samplerateNumberThe initial sample rate in Hz.
    Returns
    TypeDescription
    Superpowered.SpatializerThe constructed instance.
  • constructor

    METHOD
    Creates a Spatializer instance.
    Parameters
    NameTypeDefaultDescription
    samplerateunsigned intThe initial sample rate in Hz.
    Returns
    TypeDescription
    Superpowered::SpatializerThe constructed instance.
  • process

    METHOD
    Processes the audio. It's never blocking for real-time usage. You can change all properties on any thread, concurrently with process().
    Parameters
    NameTypeDescription
    inputLeftNumber (pointer in Linear Memory)32-bit left channel or interleaved stereo input.
    inputRightNumber (pointer in Linear Memory)32-bit right channel input. Can be NULL, inputLeft will be used in this case as interleaved stereo input.
    outputLeftNumber (pointer in Linear Memory)32-bit left channel or interleaved stereo output.
    outputRightNumber (pointer in Linear Memory)32-bit right channel output. Can be NULL, outputLeft will be used in this case as interleaved stereo output.
    numberOfFramesNumberNumber of frames to process.
    outputAddBooleanIf true, audio will be added to whatever content is in outputLeft or outputRight.
    Returns
    TypeDescription
    BooleanIf 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

    METHOD
    Processes the audio. It's never blocking for real-time usage. You can change all properties on any thread, concurrently with process().
    Parameters
    NameTypeDefaultDescription
    inputLeftfloat *32-bit left channel or interleaved stereo input.
    inputRightfloat *32-bit right channel input. Can be NULL, inputLeft will be used in this case as interleaved stereo input.
    outputLeftfloat *32-bit left channel or interleaved stereo output.
    outputRightfloat *32-bit right channel output. Can be NULL, outputLeft will be used in this case as interleaved stereo output.
    numberOfFramesunsigned intNumber of frames to process.
    outputAddboolIf true, audio will be added to whatever content is in outputLeft or outputRight.
    Returns
    TypeDescription
    boolIf 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.
v1.0.32