SuperCollider CLASSES (extension)

FoaTransform
ExtensionExtension

First Order Ambisonic (FOA) transformer
Inherits from: FoaUGen : Object

Description

Transforms (spatial domain filter) a first order ambisonic signal (B-format). FoaTransform applies dynamic transforms, for static transforms see FoaXform.

NOTE: FoaTransform is a convenience wrapper around the various transformer UGens.

Class Methods

*ar (in, kind ... args)

Arguments:

in

The input signal, an array: [in0, in1, ... inN]

kind

The kind of transform to apply.  

'rtt' rotAngle = 0, tilAngle = 0, tumAngle = 0, mul = 1, add = 0
FoaRTT
'mirror' theta = 0, phi = 0, mul = 1, add = 0
FoaMirror
'directO' angle = 0, mul = 1, add = 0
FoaDirectO
'direct' angle = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaDirect
'dominate' gain = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaDominate
'zoom' angle = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaZoom
'focus' angle = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaFocus
'push' angle = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaPush
'press' angle = 0, theta = 0, phi = 0, mul = 1, add = 0
FoaPress
'asymmetry' angle = 0, mul = 1, add = 0
FoaAsymmetry
'balance' angle = 0, mul = 1, add = 0
FoaBalance
'nfc' distance = 1, mul = 1, add = 0
FoaNFC
'proximity' distance = 1, mul = 1, add = 0
FoaProximity
NOTE: Axial transforms - except as noted, all take args of angle = 0, mul = 1, add = 0 as defaults
'rotate'
FoaRotate
'tilt'
FoaTilt
'tumble'
FoaTumble
'directX'
FoaDirectX
'directY'
FoaDirectY
'directZ'
FoaDirectZ
'dominateX' gain = 0, mul = 1, add = 0
FoaDominateX
'dominateY' gain = 0, mul = 1, add = 0
FoaDominateY
'dominateZ' gain = 0, mul = 1, add = 0
FoaDominateZ
'zoomX'
FoaZoomX
'zoomY'
FoaZoomY
'zoomZ'
FoaZoomZ
'focusX'
FoaFocusX
'focusY'
FoaFocusY
'focusZ'
FoaFocusZ
'pushX'
FoaPushX
'pushY'
FoaPushY
'pushZ'
FoaPushZ
'pressX'
FoaPressX
'pressY'
FoaPressY
'pressZ'
FoaPressZ
... args

Arguments (listed above with each 'kind') for the wrapped transformer UGens. Arguments can NOT be passed in through keyword through the FoaTransform wrapper. You can pass values in by keyword if you use the transform UGens directly.

Inherited class methods

Instance Methods

Inherited instance methods

Examples

The examples below are intended to briefly illustrate some of the first order tranform options made available in the Ambisonic Toolkit. The user is encouraged to carefully review the features of the individual transforms to gain a deeper understanding of the flexibility of these tools.

Available transformers include rotations, mirroring, directivity (spatial low pass fitering), dominance (image warping), and a variety of dominance related transforms.

As the Ambisonic technique is a hierarchal system, numerous options for playback are possible. These include two channel stereo, two channel binaural, pantophonic and full 3D periphonic. With the examples below, we'll take advantage of this by first choosing a suitable decoder with with to audition.

Choose a decoder

Choose a decoder suitable for your system, as illustrated here. You'll end up definining ~decoder and ~renderDecode .

NOTE: If you choose a kernel decoder, FoaDecoderKernel, be sure to free the kernel after use.

Rotate (soundfile)

Rotation is one of the most used soundfield transforms. In this case we'll it to centre the subject of a field recording.

The soundfield is controlled by MouseX, which specifies the rotation angle (pi to -pi; left to right of display).

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: A UGen type transformer, see FoaRotate for further details.
// ------------------------------------------------------------
// rotate transformer
// b-format soundfile read from disk

// choose transformer
~transformer = 'rotate'



// read a whole sound into memory
// remember to free the buffer later!
// (boot the server, if you haven't!)
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Courville-Dialogue.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Hodges-Purcell.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Leonard-Orfeo_Trio.wav")


(
{
    var sig;                            // audio signal
    var azim;                           // azimuth control


    // display transformer & decoder
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // azimuth -> hard left     = back
    //            centre        = centre
    //            hard right    = back
    azim = MouseX.kr(pi, -pi);


    // ------------------------------------------------------------
    // test sig
    sig = PlayBuf.ar(~sndbuf.numChannels, ~sndbuf, BufRateScale.kr(~sndbuf), doneAction:2);   // soundfile

    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, azim);


    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)

// free buffer
~sndbuf.free
// ------------------------------------------------------------
NOTE: Soundfile Credits

DominateX (soundfile)

Dominance specified in gain is a classic Ambisonic production technique. Here we apply gain across the X axis. With these example recordings, we adjust both the stage width and the subject to reverb balance.

The soundfield is controlled by MouseY, which specifies the dominance gain (4.5 dB to -4.5 dB; top to bottom of display).

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: A UGen type transformer, see FoaDominateX for further details.
// ------------------------------------------------------------
// dominateX transformer
// b-format soundfile read from disk

// choose transformer
~transformer = 'dominateX'



// read a whole sound into memory
// remember to free the buffer later!
// (boot the server, if you haven't!)
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Courville-Dialogue.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Hodges-Purcell.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Leonard-Orfeo_Trio.wav")


(
{
    var sig;                            // audio signal
    var gain;                           // gain control


    // display transformer & decoder
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // gain ---> top            = +4.5db for front
    //            bottom        = -4.5db for front
    gain = MouseY.kr(4.5, 4.5.neg);


    // ------------------------------------------------------------
    // test sig
    sig = PlayBuf.ar(~sndbuf.numChannels, ~sndbuf, BufRateScale.kr(~sndbuf), doneAction:2);   // soundfile

    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, gain);


    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)

// free buffer
~sndbuf.free
// ------------------------------------------------------------
NOTE: Soundfile Credits

Focus

Here we encode four channels of decorrelated and comb filtered PinkNoise as a decorrelated soundfield, resulting in a maximally diffuse soundfield. FoaFocus is used to "focus" on various parts of the soundfield. At extremes, it becomes a planewave (infinite distance, in an anechoic environment) arriving from some direction. This technique gives the opportunity to continuously modulate between a directional and a diffuse soundfield.

The soundfield is controlled by MouseX and MouseY, where MouseX specifies the incident azimuth angle (pi to -pi; left to right of display) and MouseY the FoaFocus angle (0 to pi/2; bottom to top of display). With the mouse at the bottom of the display, the soundfield remains decorrelated. Placed at the top of the display, the soundfield becomes directional, and varying left/right position will vary the incident azimuth of the resulting planewave.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: A UGen type transformer, see FoaFocus for further details.
// ------------------------------------------------------------
// focus transformer
// decorrelated, comb filtered pink noise source


// define encoder matrix
~encoder = FoaEncoderMatrix.newAtoB

// choose transformer
~transformer = 'focus'

(
{
    var sig;                // audio signal
    var angle, azim;            // angle and azimuth control
    var freq;


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.kind).postln;
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // frequencies
    freq = 220;

    // angle ---> top         = push to plane wave
    //          bottom    = omni-directional
    angle = MouseY.kr(pi/2, 0);

    // azimuth -> hard left     = back
    //          centre     = centre
    //          hard right     = back
    azim = MouseX.kr(pi, -pi);


    // ------------------------------------------------------------
    // test sig
    sig = PinkNoise.ar([1, 1, 1, 1]); // 4 channels decorrelated pink noise

    // ------------------------------------------------------------
    // comb filter
    sig = HPF.ar(sig, freq);
    sig = CombL.ar(sig, freq.reciprocal, freq.reciprocal, mul: 9.neg.dbamp);


    // ------------------------------------------------------------
    // encode
    sig = FoaEncode.ar(sig, ~encoder);

    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, angle, azim);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)
// ------------------------------------------------------------

Push and RTT

Here we encode four channels of Klank resonated Dust from A-format. FoaPush is used to "push" the soundfield so that it becomes a planewave (infinite distance, in an anechoic environment) arriving from some direction. This technique gives the opportunity to continuously modulate between a directional and a spatially active soundfield. Additionally, FoaRTT is used to continuously reorient the granular stream so that individual A-format directions don't predominate, and the complete soundfield is filled with activity.

The soundfield is controlled by MouseX and MouseY, where MouseX specifies the incident azimuth angle (pi to -pi; left to right of display) and MouseY the FoaPush angle (0 to pi/2; bottom to top of display). With the mouse at the bottom of the display, the soundfield remains decorrelated. Placed at the top of the display, the soundfield becomes directional, and varying left/right position will vary the incident azimuth of the resulting planewave.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformers, see FoaPush and FoaRTT for further details.
// ------------------------------------------------------------
// push and rtt transformer
// granular klank stream source


// define encoder matrix
~encoder = FoaEncoderMatrix.newAtoB

// choose transformer
~transformer1 = 'rtt'
~transformer2 = 'push'

(
{
    var sig;                     // audio signal
    var angle, azim;            // angle and azimuth control
    var freq;

    // ir...
    var gain = -18;

    var freqs = [50.0, 7000.0], gains = [-24, 0], rtimes = [0.1, 2.0];
    var frequencies, amplitudes, ringTimes;
    var numModes = 20;

    var density = 20;                  // grain/klank density

    var rttFreq = 10 * density;


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.kind).postln;
    "Ambisonic transforming via % transformer".format(~transformer1).postln;
    "Ambisonic transforming via % transformer".format(~transformer2).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;


    // calculate klank args
    frequencies = Array.rand(numModes, freqs.at(0), freqs.at(1)).sort;
    amplitudes = Array.rand(numModes, gains.at(0), gains.at(1)).sort.reverse.dbamp;
    ringTimes = Array.rand(numModes, rtimes.at(0), rtimes.at(1)).sort.reverse;


    // angle ---> top         = push to plane wave
    //          bottom    = omni-directional
    angle = MouseY.kr(pi/2, 0);

    // azimuth -> hard left     = back
    //          centre     = centre
    //          hard right     = back
    azim = MouseX.kr(pi, -pi);


    // ------------------------------------------------------------
    // test sig
    sig = Dust.ar(Array.fill(4, density / 4));

    // ------------------------------------------------------------
    // encode
    sig = FoaEncode.ar(sig, ~encoder);

    // ------------------------------------------------------------
    // transform 1 (rtt)
    sig = FoaTransform.ar(
        sig,
        ~transformer1,
        LFSaw.ar(rttFreq, pi, add: pi),
        LFSaw.ar(rttFreq**(1/3), pi, add: pi),
        LFSaw.ar(rttFreq**(2/3), pi, add: pi)
    );


    // ------------------------------------------------------------
    // Klank
    sig = gain.dbamp * Klank.ar(
        `[ frequencies, amplitudes, ringTimes ],
        sig
    );


    // ------------------------------------------------------------
    // transform 2 (push)
    sig = FoaTransform.ar(sig, ~transformer2, angle, azim);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)
// ------------------------------------------------------------

Push and RTT with Spread Encoder (soundfile)

Here we encode the mono component of a stereo soundfile via the FoaEncoderKernel: *newSpread encoder. FoaPush is used to "push" the soundfield so that it becomes a planewave (infinite distance, in an anechoic environment) arriving from some direction. This technique gives the opportunity to continuously modulate between a directional and a spatially spread soundfield. Additionally, FoaRTT is used to continuously reorient the frequency spread soundfield so that individual frequencies are moved throughout the space, and the complete soundfield is constantly in motion.

The soundfield is controlled by MouseX and MouseY, where MouseX specifies the incident azimuth angle (pi to -pi; left to right of display) and MouseY the FoaPush angle (0 to pi/2; bottom to top of display). With the mouse at the bottom of the display, the soundfield remains decorrelated. Placed at the top of the display, the soundfield becomes directional, and varying left/right position will vary the incident azimuth of the resulting planewave.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformers, see FoaPush, FoaRTT and FoaEncoderKernel: *newSpread for further details.
// ------------------------------------------------------------
// push and rtt transformer
// spreader encoder
// stereo soundfile read from disk


// define encoder matrix
~encoder = FoaEncoderKernel.newSpread(0000)
~encoder = FoaEncoderKernel.newSpread(0001)
~encoder = FoaEncoderKernel.newSpread(0006)
~encoder = FoaEncoderKernel.newSpread(0008)
~encoder = FoaEncoderKernel.newSpread(0010)
~encoder = FoaEncoderKernel.newSpread(0012)

// free kernel (when you swap encoders!)
~encoder.free

// inspect
~encoder
~encoder.kind
~encoder.numChannels
~encoder.dirChannels.raddeg


// read a whole sound into memory
// remember to free the buffer later!
// (boot the server, if you haven't!)
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/stereo/The_City_Waites-The_Downfall.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/stereo/The_City_Waites-An_Old.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/stereo/Aurora_Surgit-Lux_Aeterna.wav")
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/stereo/Aurora_Surgit-Dies_Irae.wav")

// free buffer (when you swap buffers!)
~sndbuf.free


(
{
    var sig;                            // audio signal
    var angle, azim;                    // angle and azimuth control


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.kind).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // angle ---> top           = push to plane wave
    //            bottom        = omni-directional
    angle = MouseY.kr(pi/2, 0);

    // azimuth -> hard left     = back
    //            centre        = centre
    //            hard right    = back
    azim = MouseX.kr(pi, -pi);

    // ------------------------------------------------------------
    // test sig
    sig = PlayBuf.ar(~sndbuf.numChannels, ~sndbuf, BufRateScale.kr(~sndbuf), doneAction:2);   // soundfile
    sig = 0.5 * sig.sum; // to mono


    // ------------------------------------------------------------
    // encode
    sig = FoaEncode.ar(sig, ~encoder);

    // ------------------------------------------------------------
    // transform
    sig = FoaRTT.ar(sig,
        LFNoise2.kr(1.0/5.0, pi),
        LFNoise2.kr(1.0/5.0, pi),
        LFNoise2.kr(1.0/5.0, pi)
    );
    sig = FoaTransform.ar(sig, 'push', angle, azim);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)

// free buffer
~sndbuf.free
// free kernel
~encoder.free
// ------------------------------------------------------------

X-axis: FocusX, ZoomX & PushX

With this example we encode four channels of comb filtered Dust as planewaves arriving from the cardinal directions. FoaFocusX, FoaZoomX and FoaPushX are used to distort the soundfield. At extremes, encoded planewaves are distorted to arrive from the same direction. This example allows one to get compare these transforms on the x-axis.

The soundfield is controlled by MouseY, with angle varying between -pi/2 and pi/2. With the mouse in the centre of the display, the soundfield remains unchanged. Placed at the top or bottom of the display, the soundfield is distorted.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformers, see FoaFocusX, FoaZoomX & FoaPushX for further details.
// ------------------------------------------------------------
// x-axis transformers
// comb filtered dust noise source, at cardinal points


// define encoder matricies, for each cardinal point
(
~encoder = [
    FoaEncoderMatrix.newDirection,
    FoaEncoderMatrix.newDirection(pi/2),
    FoaEncoderMatrix.newDirection(pi),
    FoaEncoderMatrix.newDirection(pi.neg/2)
]
)

// choose transformer
~transformer = 'focusX'
~transformer = 'zoomX'
~transformer = 'pushX'

(
{
    var sig;                            // audio signal
    var angle;                          // angle control
    var freq;
    var density = 10;                   // grain density


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.at(0).kind).postln;
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // frequencies
    freq = 220 * [ 4, 5, 7, 6 ] / 4;

    // angle ---> top           = pi/2
    //            bottom        = -pi/2
    angle = MouseY.kr(pi/2, pi.neg/2);


    // ------------------------------------------------------------
    // test sig
    sig = Dust.ar(Array.fill(4, density / 4));


    // ------------------------------------------------------------
    // comb filter
    sig = BPF.ar(sig, freq, mul: 18.dbamp);
    sig = CombL.ar(sig, freq.reciprocal, freq.reciprocal, mul: 9.neg.dbamp);


    // ------------------------------------------------------------
    // encode
    sig = Mix.fill(sig.numChannels, { arg i;  FoaEncode.ar(sig.at(i), ~encoder.at(i)) });


    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, angle);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)
// ------------------------------------------------------------

Y-axis: Balance and Asymmetry

With with the above example we encode four channels of comb filtered Dust as planewaves arriving from the cardinal directions. FoaZoomY and FoaAsymmetry are used to distort the soundfield. At extremes, encoded planewaves are distorted to arrive from the same direction. This example allows one to get compare these transforms on the x-axis.

The soundfield is controlled by MouseX, with angle varying between -pi/2 and pi/2. With the mouse in the centre of the display, the soundfield remains unchanged. Placed at the left or right of the display, the soundfield is distorted.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformers, see FoaZoomY and FoaAsymmetry for further details.
// ------------------------------------------------------------
// y-axis transformers
// comb filtered dust noise source, at cardinal points


// define encoder matricies, for each cardinal point
(
~encoder = [
    FoaEncoderMatrix.newDirection,
    FoaEncoderMatrix.newDirection(pi/2),
    FoaEncoderMatrix.newDirection(pi),
    FoaEncoderMatrix.newDirection(pi.neg/2)
]
)

// choose transformer
~transformer = 'balance'
~transformer = 'asymmetry'

(
{
    var sig;                            // audio signal
    var angle;                          // angle control
    var freq;
    var density = 10;                   // grain density


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.at(0).kind).postln;
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // frequencies
    freq = 220 * [ 4, 5, 7, 6 ] / 4;

    // angle ---> left          = pi/2
    //            right         = -pi/2
    angle = MouseX.kr(pi/2, pi.neg/2);


    // ------------------------------------------------------------
    // test sig
    sig = Dust.ar(Array.fill(4, density / 4));


    // ------------------------------------------------------------
    // comb filter
    sig = BPF.ar(sig, freq, mul: 18.dbamp);
    sig = CombL.ar(sig, freq.reciprocal, freq.reciprocal, mul: 9.neg.dbamp);


    // ------------------------------------------------------------
    // encode
    sig = Mix.fill(sig.numChannels, { arg i;  FoaEncode.ar(sig.at(i), ~encoder.at(i)) });


    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, angle);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)
// ------------------------------------------------------------

Proximity

FoaProximity facilitates the introduction of the proximity effect to encoded signals. At extremes, the proximity effect introduces a strong bass boost, as well as phase differences. The proximity effect can be an important contributor to perceptions of nearness.

The soundfield is controlled by MouseY, with distance varying between 0.05 and 0.5 meter. With the mouse at the bottom of the display, the soundfield receives the strongest effect, contributing to as sense of nearness.

WARNING: As FoaProximity includes a 1st-order integration, signals must be highpass filtered before application. HPF is usually a suitable choice to control low frequency boost.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformer, see FoaProximity for further details.
// ------------------------------------------------------------
// proximity transform
// comb filtered dust noise source, panned across the front


// define encoder matricies
(
~encoder = [
    FoaEncoderMatrix.newDirection(pi/6),
    FoaEncoderMatrix.newDirection(pi/12),
    FoaEncoderMatrix.newDirection(pi.neg/12),
    FoaEncoderMatrix.newDirection(pi.neg/6)
]
)

// choose transformer
~transformer = 'proximity'

(
{
    var sig;                            // audio signal
    var dist;                           // distance control
    var freq;
    var density = 10;                   // grain density


    // display encoder and decoder
    "Ambisonic encoding via % encoder".format(~encoder.at(0).kind).postln;
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // frequencies
    freq = 220 * [ 4, 5, 7, 6 ] / 4;

    // dist  ---> top           = 0.5
    //            bottom        = 0.05
    dist = MouseY.kr(0.5, 0.05);


    // ------------------------------------------------------------
    // test sig
    sig = Dust.ar(Array.fill(4, density / 4));


    // ------------------------------------------------------------
    // comb filter
    sig = BPF.ar(sig, freq, mul: 18.dbamp);
    sig = CombL.ar(sig, freq.reciprocal, freq.reciprocal, mul: 9.neg.dbamp);


    // ------------------------------------------------------------
    // encode
    sig = Mix.fill(sig.numChannels, { arg i;  FoaEncode.ar(sig.at(i), ~encoder.at(i)) });


    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, dist);



    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)
// ------------------------------------------------------------

NFC (soundfile)

FoaNFC facilitates the reduction or removal of the proximity effect from encoded signals. The proximity effect can be an important contributor to perceptions of nearness.

The soundfield is controlled by MouseY, with distance varying between 0.5 and 0.05 meter. With the mouse at the top of the display, the soundfield receives the strongest effect (removal), contributing to as sense of distance.

If you haven't already choosen a ~decoder and defined ~renderDecode, do so now.

NOTE: UGen type transformer, see FoaNFC for further details.
// ------------------------------------------------------------
// NFC transform
// b-format soundfile read from disk




// read a whole sound into memory
// remember to free the buffer later!
// (boot the server, if you haven't!)
~sndbuf = Buffer.read(s, Atk.userSoundsDir ++ "/b-format/Anderson-Nearfield.wav")


// choose transformer
~transformer = 'nfc'


(
{
    var sig;                            // audio signal
    var dist;                           // distance control



    // display encoder and decoder
    "Ambisonic transforming via % transformer".format(~transformer).postln;
    "Ambisonic decoding via % decoder".format(~decoder.kind).postln;

    // dist  ---> top           = 0.05
    //            bottom        = 1.0
    dist = MouseY.kr(0.05, 1.0);


    // ------------------------------------------------------------
    // test sig
    sig = PlayBuf.ar(~sndbuf.numChannels, ~sndbuf, BufRateScale.kr(~sndbuf), doneAction:2);   // soundfile


    // ------------------------------------------------------------
    // transform
    sig = FoaTransform.ar(sig, ~transformer, dist);


    // ------------------------------------------------------------
    // decode (via ~renderDecode)
    ~renderDecode.value(sig, ~decoder)

}.scope;
)

// free buffer
~sndbuf.free
// ------------------------------------------------------------
NOTE: Soundfile Credits