decoding HOA5 to speaker ring via SuperCollider with ADT and ATK using allrad
// path to ADT repository folder
ADT.userADTDir_("/Users/weiyang/Repositories/adt/");
/////// set speaker directions ////////
~directions = [
[ 21.8, 338.2, 68.2, 291.8, 111.8, 248.2, 158.2, 201.8, 56.6, 303.4, 123.4, 236.6, 0.0, 180, 90.0, 270.0 ], // azimuths
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 30.0, 30.0, 30.0, 30.0, 30.0, 30.0, 70.0, 70.0 ] // elevations
].degrad.flop
////// INSTANTIATE THE ADT CLASS ////////
~order = 5
~name = "default-dome-8-6-2" //the actual 16.2 dome format..... aka. the default template in the SpatGris.....
~adt = ADT.new(
folderPath: nil, // nil, write to default path
directions: ~directions,
match: 'amp',
order: ~order,
format: ['ACN', 'N3D'], // AtkHoa.format
filename: ~name,
ymlOnly: true // write only yml to the folderPath, the rest get written to the ADT repo folder
)
// allrad - takes some time - wait!!
(
~imagSpeakers = nil; // default ADT
// ~imagSpeakers = [0, -0.5pi, 1.5]; // use with ATK
~adt.allrad(~imagSpeakers)
)
// use with the ATK
// Quarks.install("atk-sc3"); // install ATK if not already
~adt.matrixNames.do({ |name| name.postln; })
~matrixName = ~adt.matrixNames[0]; // choose the first matrix: basic decoder
~matrixName = ~adt.matrixNames[1]; // controlled opposites decoder
~matrixName = ~adt.matrixNames[2]; //energy decoder - use this...
~matrixName = ~name ++ "-allrad-beam-energy-match-amp.yml" // by hand
//speaker decoder
~spkrDecoder = HoaMatrixDecoder.newFromFile(~matrixName, order: ~order);
/// sub decoding - placed at hard left and hard right
~subDirections = [ 90.0, -90.0 ].degrad
~subOrder = 1;
// using newDirections
~subDecoder = HoaMatrixDecoder.newDirections(~subDirections, \controlled, \amp, ~subOrder) //use 1st order to use as much of the soundfield as possible
//__________________step 1: write out the decodeSig: HOA5 -> 16 channels
(
~spkrDecodeSynth = CtkSynthDef(\spkrDecode, {|hoaBuffer=0, gain=0.0|
var order = 5;
var numChannels = order.asHoaOrder.size;
var amp = gain.dbamp;
var hoaSig, decodeSig;
hoaSig = PlayBuf.ar(numChannels, hoaBuffer, BufRateScale.kr(hoaBuffer));
decodeSig = HoaDecodeMatrix.ar(hoaSig, ~spkrDecoder); //for speaker rings
decodeSig = decodeSig * amp;
Out.ar(0, decodeSig);
});
)
(
~subDecodeSynth = CtkSynthDef(\subDecode, {|hoaBuffer=0, gain=0.0|
var order = 5;
var numChannels = order.asHoaOrder.size;
var amp = gain.dbamp;
var hoaSig, decodeSig;
hoaSig = PlayBuf.ar(numChannels, hoaBuffer, BufRateScale.kr(hoaBuffer));
decodeSig = HoaDecodeMatrix.ar(hoaSig.keep(1.asHoaOrder.size), ~subDecoder); // for subs
decodeSig = decodeSig * amp;
Out.ar(0, decodeSig);
});
)
// import the HOA5 file
~hoaPath = "/Users/weiyang/Downloads/YANG_A_VOI(CE)_D_HOA5.wav";
~hoaBuffer = CtkBuffer.playbuf(~hoaPath);
~hoaBuffer.numChannels
~outputDuration = ~hoaBuffer.duration
// deocde for the speakers
~spkrScore = CtkScore.new;
~spkrScore.add(~hoaBuffer);
~spkrOutputPath = "/Users/weiyang/Downloads/________test______/speakers_int24.wav"; //decoded speaker sig
~spkrNote = ~spkrDecodeSynth.note(0, ~outputDuration).hoaBuffer_(~hoaBuffer);
~spkrScore.add(~spkrNote)
~spkrScore.write(
path: ~spkrOutputPath.standardizePath,
duration: ~outputDuration,
sampleRate: 48000,
headerFormat: "WAV",
sampleFormat: "int24",
options: ServerOptions.new.numOutputBusChannels_(16) //speaker decode
)
// deocde for the subs
~subScore = CtkScore.new;
~subScore.add(~hoaBuffer);
~subOutputPath = "/Users/weiyang/Downloads/________test______/subs_int24_0.5pi.wav"; //decode subs
~subNote = ~subDecodeSynth.note(0, ~outputDuration).hoaBuffer_(~hoaBuffer);
~subScore.add(~subNote)
~subScore.write(
path: ~subOutputPath.standardizePath,
duration: ~outputDuration,
sampleRate: 48000,
headerFormat: "WAV",
sampleFormat: "int24",
options: ServerOptions.new.numOutputBusChannels_(2) //sub decode
)
​
//now the decoded sound files are ready for de-interleaving using tools such as sndfile
​