top of page

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.....

// create instance of ADT with folderPath on desktop with '205' as beginning of filename
~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 speakers
   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".standardizePath;
~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).gain_(6.95);
~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 - REMEMBE TO CHANGE THE SYNTHDEF
~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).gain_( -3.74)
~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

bottom of page