23 #define AMBI_INVSQRT2 (1/1.414213562)
24 #define INV_SQRT2 (1/1.414213562)
25 #define AMBI_INVSQRT2 (1/1.414213562)
68 return (
unsigned)floor(sqrt((
double)channels)-1);
82 return (
unsigned)pow(torder + 1.f, 2);
100 unsigned *channelIndex = indexArray;
108 unsigned currentOrder = 1;
109 unsigned hoaChannel = 1;
110 unsigned numChannelsCurrentOrder;
113 for (
unsigned i = 0; i < numChannelsGreaterOrder; i++)
117 while (n < nnumChannels) {
121 channelIndex[hoaChannel++] = n++;
122 channelIndex[hoaChannel++] = n++;
133 while(hoaChannel < numChannelsCurrentOrder) {
134 channelIndex[hoaChannel++] = n++;
137 hoaChannel = numChannelsCurrentOrder;
149 unsigned *channelIndex = indexArray;
156 unsigned currentOrder = 1;
157 unsigned numChannelsCurrentOrder;
160 while (n < nnumChannels) {
164 channelIndex[n] = n++;
165 channelIndex[n] = n++;
174 while(n < numChannelsCurrentOrder) {
175 channelIndex[n] = n++;
178 n = numChannelsCurrentOrder;
238 logMsg(
"AmbisonicEncoder::setInput");
247 unsigned numFrames = outputBuffer.mNumFrames;
251 logMsg(
"AmbisonicEncoder::nextBuffer");
253 if (outputBuffer.mNumChannels < mNumChannels)
254 logMsg(
kLogError,
"The AmbisonicEncoder requires %d output channels, found only %d ???\n", mNumChannels, outputBuffer.mNumChannels);
259 inputBuffer = mInputPort->mBuffer;
262 mInputPort->mUGen->nextBuffer(*inputBuffer);
272 for (
unsigned i = 0; i < mNumChannels; i++) {
276 for (
unsigned j = 0; j < numFrames; j++) {
278 *outPtr++ += (*inPtr++) * mWeights[i];
294 mDecodingMethod(method), mDecoderFlavour(flavour) {
301 mDecodingMethod(method), mDecoderFlavour(flavour) {
308 mDecodingMethod(method), mDecoderFlavour(flavour) {
366 "Reducing decoding order because encoded input does not contain enough channels for specified order.\n Input channels:(%d): horizontal order = %i, vertical order = %i\n",
376 unsigned channelIndex[numChannelsGreaterOrder];
377 unsigned invChannelIndex[numChannelsGreaterOrder];
380 memset(invChannelIndex , 0, numChannelsGreaterOrder *
sizeof(
unsigned));
392 for (
unsigned s = 0; s < numSpeakers; s++)
404 logMsg(
kLogWarning,
"AmbisonicDecoder: the in-phase decoding method is only well defined for non-hybrid systems - you have asked for an in phase decoder for a hybrid ambisonic decoding.\n");
409 logMsg(
kLogWarning,
"AmbisonicDecoder: the max-rE decoding method is only well defined for non-hybrid systems - you have asked for a max rE decoder for a hybrid ambisonic decoding.\n");
415 printf(
"Decoding from %i ambisonic channels to %i speakers", mNumChannels, numSpeakers);
418 case 0: printf(
" of basic flavour\n");
break;
419 case 1: printf(
" of in-phase flavour\n");
break;
420 case 2: printf(
" of max rE flavour\n");
break;
423 printf(
"Decoding Matrix:\n");
424 for (
unsigned s=0; s< numSpeakers; s++ ) {
425 printf(
"speaker %d\t",s);
462 sample invNumSpeakers = 1.f/((float)numSpeakers);
465 for (
unsigned s = 0; s < numSpeakers; s++) {
483 for (
unsigned n = 0; n < nnumChannels; n++) {
484 squareMatrix[n] =
new sample[nnumChannels];
488 for (
unsigned n = 0; n < nnumChannels; n++) {
489 invSquareMatrix[n] =
new sample[nnumChannels];
493 sample** transposedReEncodingMatrix = (
sample**) malloc(numSpeakers *
sizeof(
sample*));
494 for (
unsigned s = 0; s < numSpeakers; s++)
495 transposedReEncodingMatrix[s] =
new sample[nnumChannels];
500 for (
unsigned n = 0; n < nnumChannels; n++) {
502 for (
unsigned j = 0; j < nnumChannels; j++ ) {
503 squareMatrix[n][j] = 0.f;
505 for (
unsigned s = 0; s < numSpeakers; s++ ) {
507 squareMatrix[n][j] += transposedReEncodingMatrix[s][n] * transposedReEncodingMatrix[s][j];
520 for (
unsigned i = 0; i < nnumChannels; i++) {
521 u[i] = &(uu[nnumChannels*i]);
522 v[i] = &(vv[nnumChannels*i]);
523 for (
unsigned j = 0; j < nnumChannels; j++)
524 u[i][j] = squareMatrix[i][j];
530 for (
unsigned j = 0; j < nnumChannels; j++) {
536 for (
unsigned k = 0; k < nnumChannels; k++)
542 for (
unsigned i = 0; i < nnumChannels; i++) {
543 for (
unsigned j = 0; j < nnumChannels; j++) {
544 invSquareMatrix[i][j] = 0.0;
545 for (
unsigned k = 0; k < nnumChannels; k++)
546 invSquareMatrix[i][j] += v[i][k]*w[k]*u[j][k];
561 for (
unsigned s = 0; s < numSpeakers; s++ ) {
562 for (
unsigned n = 0; n < nnumChannels; n++) {
564 for (
unsigned j = 0; j < nnumChannels; j++) {
566 mDecodingMatrix[s][n] += transposedReEncodingMatrix[s][j] * invSquareMatrix[j][n];
572 for (
unsigned n = 0; n < nnumChannels; n++) {
573 delete [] squareMatrix[n];
574 delete [] invSquareMatrix[n];
576 for (
unsigned s = 0; s < numSpeakers; s++)
577 delete [] transposedReEncodingMatrix[s];
580 free(invSquareMatrix);
581 free(transposedReEncodingMatrix);
592 float **transposedReEncodingMatrix = transposeMatrix;
595 for (
unsigned s = 0; s < numSpeakers; s++) {
614 sample maxREParameters[][5] = { {1.0, 1.0, 1.0, 1.0, 1.0},
616 {0.f, 0.577, 0.775, 0.861, 0.906},
618 {0.f, 0.f, 0.4, 0.612, 0.732},
620 {0.f, 0.f, 0.f, 0.305, 0.501},
622 {0.f, 0.f, 0.f, 0.f, 0.246},
630 for (
unsigned l = 0; l < numSpeakers; l++) {
644 sample inPhaseParameters[][5] = {
645 {1.0, 1.0, 1.0, 1.0, 1.0},
646 {0.f, 0.333, 0.5, 0.6, 0.667},
647 {0.f, 0.f, 0.1, 0.2, 0.286},
648 {0.f, 0.f, 0.f, 0.029, 0.071},
649 {0.f, 0.f, 0.f, 0.f, 0.008},
653 unsigned M = tgreaterOrder;
656 for (
unsigned l = 0; l < numSpeakers; l++) {
669 unsigned numChannels = mNumChannels;
670 unsigned numSpeakers = mSpeakerLayout->numSpeakers();
671 unsigned numFrames = outputBuffer.mNumFrames;
674 if (outputBuffer.mNumChannels < numSpeakers) {
675 logMsg(
kLogError,
"AmbisonicDecoder needs a buffer with %d channels, found only %d\n", numChannels, outputBuffer.mNumChannels);
676 throw RunTimeError(
"Insufficient number of channels in buffer passed.");
679 outputBuffer.zeroBuffers();
683 inputBuffer = mInputPort->mBuffer;
686 mInputPort->mUGen->nextBuffer(*inputBuffer);
691 for (
unsigned n = 0; n < numChannels; n++) {
696 for (
unsigned l = 0; l < numSpeakers; l++) {
700 for (
unsigned i = 0; i < numFrames; i++) {
702 *outPtr++ += mDecodingMatrix[l][n] * inPtr[i];
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
AmbisonicDecoder(AmbisonicUnitGenerator &input, SpeakerLayout *layout=SpeakerLayout::defaultSpeakerLayout(), AmbisonicDecoderMethod method=kPROJECTION, AmbisonicDecoderFlavour flavour=kBASIC)
Defaults to standard speaker layout as defined in "HOA_SpeakerLayout" class and to Ambisonic order of...
void logMsg(const char *format,...)
These are the public logging messages.
void setOrder(AmbisonicOrder order)
Returns the Ambisonic order.
void singularValueDecomposition(sample **a, int m, int n, sample *w, sample **v)
unsigned mNumFrames
num frames used in each buffer
void makeMaxRE(unsigned greaterOrder)
Adjusts the decoding matrix D for Max rE flavour.
float elevation()
Returns the horizontal angle.
void asProjection()
Create the decoding matrix "D" using the projection method.
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Speaker * speakerAtIndex(unsigned speakerIndex) const
Returns the speaker at the specified index.
void channelIndexer(unsigned *indexArray)
Calculates a lookup table to map Ambisonic channel index to actually used UnitGenerator channel...
unsigned orderToChannels(const AmbisonicOrder order)
Returns the number of Ambisonic channels from a hybrid Ambisonic order: N = 2*M_h + 1 + (M_v + 1)^2 -...
Illegal operation at run time.
virtual SampleBuffer buffer(unsigned bufNum)
convenience accessors for sample buffers
void fumaEncodingWeights(SampleBuffer weights, const AmbisonicOrder &order, sample azimuth, sample elevation)
Utility function that calculates fuma encoding weights for a given order, azimuth and elevation...
SampleBuffer mWeights
Encoding weights for each order (per source)
unsigned greaterOrder(const AmbisonicOrder order)
Compares the horizontal and vertical Ambisonic order of a hybrid order and returns the largest...
void addOutput(UnitGenerator *ugen)
add to or return the UGen vector of outputs
AmbisonicDecoderFlavour mDecoderFlavour
AmbisonicUnitGenerator(unsigned order=0)
Initialize with uniform Ambisonic order. Defaults to zeroth order.
void zeroBuffers()
fill all data with 0
Ambisonic order structure (separate definition for horizontal and vertical order): ...
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
Does the DSP processing for the Ambisonic Decoder.
Represents a speaker as a position relative to the center of a space.
unsigned orderToHorizontalChannels(const AmbisonicOrder order)
Returns the number of horizontal Ambisonic channels from a hybrid Ambisonic order: N_h = 2*M_h + 1...
virtual ~AmbisonicUnitGenerator()
void asPseudoInverse()
create the decoding matrix "D" using the pseudoinverse method
bool isUniform
Returns true if horizontal and verical orders are identical.
void initialize(UnitGenerator &input, AmbisonicDecoderMethod method, AmbisonicDecoderFlavour flavour)
initializing method called by constructors
virtual unsigned numChannels()
void makeTransposedReEncodingMatrix(float **transposeMatrix)
Utility method that creates the transposed re-encoding matrix C'.
Temp Spatial Sound Source.
float sample
(could be changed to int, or double)
unsigned mNumChannels
my "expected" number of output channels
~AmbisonicDecoder()
Destructor.
void makeInPhase(unsigned greaterOrder)
Adjusts the decoding matrix D for in-phase flavour.
BufferContentType mType
Data type flag set the internal size variables (no buffer allocation takes place) ...
virtual ~AmbisonicEncoder()
Destructor.
void initialize()
Initializing method called by constructors.
float azimuth()
Sets the distance from the center.
void fumaEncodingWeights(SampleBuffer weights, const AmbisonicOrder &order, float azimuth, float elevation)
AmbisonicDecoderFlavour
Flag for the decoder flavour.
unsigned orderToVerticalChannels(const AmbisonicOrder order)
Returns the number of vertical Ambisonic channels from a hybrid Ambisonic order: N_v = (M_v + 1)^2 - ...
void invChannelIndexer(unsigned *indexArray)
Calculates a lookup table to map actually used UnitGenerator channel to Ambisonic channel index...
SpeakerLayout * mSpeakerLayout
void setCopyPolicy(BufferCopyPolicy ch)
get/set the receiver's buffer copy policy
UnitGenerator * mUGen
my unit generator (pointer or NULL)
void setInput(SpatialSource &input)
Set my input.
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
unsigned numSpeakers() const
ignore extra buffer channels
AmbisonicEncoder()
Default constructor.
Ambisonic Abstract Base Class.
AmbisonicOrder mOrder
the order of the Unit Generator
AmbisonicDecoderMethod
Flag for the decoding method.
SampleBuffer * SampleBufferVector
Multi-channel buffer data type, vector of (SampleBuffer)
Port – used to represent constant, control-rate or signal inputs and outputs in named maps; holds a ...
AmbisonicDecoderMethod mDecodingMethod
void removeOutput(UnitGenerator *ugen)
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
Does the DSP processing for the Ambisonic Encoder.
unsigned channelsToUniformOrder(const unsigned channels)
Port * mInputPort
Holds the input to be encoded.
SampleBufferVector mDecodingMatrix
bool mIsPopulated
does the buffer have data?
Base class of CSL exceptions (written upper-case). Has a string message.