Ambisonics#
Use of ambisonic with SATIE, simultaneously with other spatialization.
Overview#
An ambisonic pipeline can be used simultaneously and in parallel with the usual spatialization pipeline. Here we provide examples of use that include:
Configuration of ambisonic pipelines for decoding b-format produced by sound objects
Get ambisonic encoding with existing source plugin (mono)
Use of ambisonic live input
Use of several ambisonic effects when decoding the soundfield (rotations, mirror and beam forming)
Thanks to the SC-HOA library, current implementation supports ambisonic from order 1 to 5.
Start the server#
(
s = Server.supernova.local;
// instantiate a SatieConfiguration. Here we will use two stereo spatializer
~satieConfiguration = SatieConfiguration.new(
s,
[],
outBusIndex: [0],
ambiOrders: [1, 2, 3], // list ambisonic order handled by this satie instance
minOutputBusChannels: 4
);
// choose which ambisonic encoder you wish to use (\wave for plane or spherical wave encoding, \harmonic for better CPU performance)
~satieConfiguration.hoaEncoderType = \wave;
// list possible listeners:
~satieConfiguration.spatializers.keys;
~satieConfiguration.serverOptions.numOutputBusChannels = 64;
~satieConfiguration.serverOptions.numInputBusChannels = 8;
~satieConfiguration.serverOptions.memSize = 2.pow(18).asInteger;
~satieConfiguration.serverOptions.numWireBufs = 64 * 16;
// instantiate SATIE renderer and pass it the configuration
~satie = Satie.new(~satieConfiguration);
)
(
~satie.waitForBoot({
// instantiate two ambisonic decoders for order 1
~satie.replaceAmbiPostProcessor([\HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~satie.replaceAmbiPostProcessor([\HOABinaural], spatializerNumber: 1, order: 1, outputIndex: ~satieConfiguration.outBusIndex + 2);
// display some information
s.meter;
s.plotTree;
});
)
Instantiate some sources#
We can get usual mono sources encoded into b-format. Synthdefs are automatically generated according to the ambisonics orders selected in SatieConfiguration. For instance for the misDrone mono source, only order 1, 2 and 3 are generated and named as follows:
misDroneAmbi1
misDroneAmbi2
misDroneAmbi3
misDroneAmbi1_kamikaze
misDroneAmbi2_kamikaze
misDroneAmbi3_kamikaze
Here we instantiate a misDroneAmbi1_kamikaze
(
~testSynth2.free;
~satieConfiguration.ambiBus[0].do {|item| item.scope;};
~testSynth2 = ~satie.makeSourceInstance(\testSynth2, \misDroneAmbi1_kamikaze);
~testSynth2.set(\gainDB, 0, \aziDeg, 0, \eleDeg, 0);
~testSynth2.set(\gainDB, 0, \aziDeg, 45, \eleDeg, 45);
)
We can also read ambisonic live input. ambiIn source reads ACN_N3D format, but AcnSn3dIn and FuMaIn are able to read other ambisonic formats.
Note
NOTE: In order to hear this example, you need to send ambisonic format to SuperCollider’s inputs. This can be done by downloading b-format files from the internet and playing them in a DAW like reaper or ardour.
(
~testSynth.free;
~satieConfiguration.ambiBus[0].do {|item| item.scope;};
~testSynth = ~satie.makeSourceInstance(\testSynth2, \ambiInAmbi1, \default, synthArgs: [\bus, 0, \t_trig, 1, \gainDB, 0]);
)
Ambisonic decoding pipeline#
Decoding pipeline decodes the mix of b-format sound sources. The decode pipelines can be replaced while running, with the addition of the following effects:
Rotate along the Z axis
( // RotateAz
~satie.replaceAmbiPostProcessor([\RotateAz, \HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~ambipost = ~satie.getAmbiPostProc(order: 1, spatializerNumber: 0);
~ambipost.set(\rotateAziDeg, -180);
~ambipost.set(\rotateAziDeg, 90);
~ambipost.set(\rotateAziDeg, 180);
)
Rotate
( // Rotate
~satie.replaceAmbiPostProcessor([\Rotate, \HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~satie.getAmbiPostProc(order: 1, spatializerNumber: 0).set(\rotatePitchDeg, 0, \rotateRollDeg, 0, \rotateYawDeg, 0);
~satie.getAmbiPostProc(order: 1, spatializerNumber: 0).set(\rotatePitchDeg, 180, \rotateRollDeg, 180, \rotateYawDeg, 180);
)
Mirror
( // Mirror
~satie.replaceAmbiPostProcessor([\Mirror, \HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~ambipost = ~satie.getAmbiPostProc(order: 1, spatializerNumber: 0);
~ambipost.set(\mirrorFrontBack, 0);
~ambipost.set(\mirrorFrontBack, 1);
~ambipost.set(\mirrorLeftRight, 0);
~ambipost.set(\mirrorLeftRight, 1);
~ambipost.set(\mirrorUpDown, 0);
~ambipost.set(\mirrorUpDown, 1);
)
Dirac beam forming
( // Beam forming Dirac
~satie.replaceAmbiPostProcessor([\BeamDirac, \HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~ambipost = ~satie.getAmbiPostProc(order: 1, spatializerNumber: 0);
~ambipost.set(\beamDiracAziDeg, 0, \beamDiracEleDeg, 0);
~ambipost.set(\beamDiracAziDeg, 180, \beamDiracEleDeg, 45);
)
Cardioid beam forming
( // Beam forming Hyper Cardioid
~satie.replaceAmbiPostProcessor([\BeamCardio, \HOABinaural], spatializerNumber: 0, order: 1, outputIndex: ~satieConfiguration.outBusIndex);
~ambipost = ~satie.getAmbiPostProc(order: 1, spatializerNumber: 0);
~ambipost.set(\cardOrder, 3);
~ambipost.set(\beamCardioAzi, 0, \beamCardioEle, 0);
~ambipost.set(\beamCardioAzi, 180, \beamCardioEle, 45);
)