57 logMsg(
"AmbisonicPanner: added %ith input\n",
mInputs.size());
75 logMsg(
"AmbisonicPanner: added %ith input\n",
mInputs.size());
90 unsigned i, c, k, numFrames;
91 unsigned numInputs = mInputs.size();
93 mInBuffer->mNumFrames = numFrames = outputBuffer.mNumFrames;
95 outputBuffer.zeroBuffers();
98 logMsg(
"AmbisonicMixer::nextBuffer");
103 if (outputBuffer.mNumChannels < mNumChannels)
104 logMsg(
kLogError,
"AmbisonicMixer requires %d output channels, found only %d ???\n", mNumChannels, outputBuffer.mNumChannels);
107 for (i = 0; i < numInputs; i++) {
116 for (c = 0; c < mNumChannels; c++) {
117 outPtr = outputBuffer.buffer(c);
118 inPtr = mInBuffer->buffer(c);
119 for (k = 0; k < numFrames; k++)
120 *outPtr++ += *inPtr++;
127 for (c = 0; c < mNumChannels; c++) {
128 outPtr = outputBuffer.buffer(c);
130 for (i = 0; i < numFrames; i++)
131 *outPtr++ *= mInvNumInputs;
204 logMsg(
kLogWarning,
"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",
255 logMsg(
kLogError,
"AmbisonicRotator; Attempted to add control signal to invalid axis channel ???\n");
267 logMsg(
kLogWarning,
"Attempt to set Tilt control for a hybrid order rotator failed.\n");
279 logMsg(
kLogWarning,
"Attempt to set Tumble control for a hybrid order rotator failed.\n");
298 unsigned numFrames = mNumFrames = outputBuffer.mNumFrames;
299 unsigned numChannels = mNumChannels;
300 unsigned greaterOrder = mGreaterOrder;
305 if (outputBuffer.mNumChannels < numChannels) {
306 logMsg(
kLogError,
"AmbisonicRotator needs a buffer with %d channels, found only %d\n", numChannels, outputBuffer.mNumChannels);
307 throw RunTimeError(
"Insufficient number of channels in buffer passed.");
312 inputBuffer = mInputPort->mBuffer;
315 mInputPort->mUGen->nextBuffer(*inputBuffer);
322 for (i = 0; i < mNumChannelsGreaterOrder; i++) {
323 mOutPtr[i] = outputBuffer.buffer(mChannelIndex[i]);
326 for (i = 0; i < numChannels; i++) {
327 mInPtr[i] = inputBuffer->
buffer(mInputChannelIndex[i]);
331 for (i = 0; i < numFrames; i++)
332 for (
unsigned j = 0; j < numChannels; j++)
333 *mOutPtr[j]++ = *mInPtr[j]++;
338 for (i = 0; i < numChannels; i++)
339 mOutPtr[i] = outputBuffer.buffer(mChannelIndex[i]);
342 for (i = 0; i < greaterOrder; i++) {
343 mSinAngle[i] = sinf((i+1) * mTilt);
344 mCosAngle[i] = cosf((i+1) * mTilt);
355 for (i = 0; i < numChannels; i++)
356 mOutPtr[i] = outputBuffer.buffer(mChannelIndex[i]);
359 for (i = 0; i < greaterOrder; i++) {
360 mSinAngle[i] = sinf((i+1) * mTumble);
361 mCosAngle[i] = cosf((i+1) * mTumble);
372 for (i = 0; i < numChannels; i++)
373 mOutPtr[i] = outputBuffer.buffer(mChannelIndex[i]);
376 for (i = 0; i < greaterOrder; i++) {
377 mSinAngle[i] = sinf((i+1) * mRotate);
378 mCosAngle[i] = cosf((i+1) * mRotate);
382 if (mOrder.horizontalOrder)
383 rotateFirstOrderHorizontal();
385 if (mOrder.verticalOrder > 1)
386 rotateSecondOrderVertical();
415 sample temp1, temp2, temp3;
422 *outPtr[4]++ = 0.5 * (
mCosAngle[1] - 1) * (*outPtr[8]) + 0.5 *
mSinAngle[1] * (*outPtr[7]) + 0.25 * (
mCosAngle[1] + 3) * (*outPtr[4]);
437 sample temp1, temp2, temp3, temp4, temp5;
448 *outPtr[9]++ = 0.125 * (3 *
mCosAngle[1] + 5) * (*outPtr[9]) + 1.5 *
mSinAngle[1] * (*outPtr[12]) + 0.515625 * (
mCosAngle[1] - 1) * (*outPtr[13]);
452 *outPtr[13]++ = 0.454545454545 * (mCosAngle[1] - 1) * temp1 + + 1.818181818182 *
mSinAngle[1] * temp4 + 0.125 * (3 + 5 * mCosAngle[1]) * (*outPtr[13]);
453 *outPtr[14]++ = 0.227272727273 * (- mCosAngle[0] + mCosAngle[2]) * temp2 + 0.454545454545 * (
mSinAngle[0] - 3 *
mSinAngle[2]) * temp3 + 0.0625 * (mCosAngle[0] + 15 * mCosAngle[2]) * (*outPtr[14]) - 0.181818181818 * (
mSinAngle[0] + 5 *
mSinAngle[2]) * (*outPtr[15]);
454 *outPtr[15]++ = 0.15625 * (- 3 *
mSinAngle[0] +
mSinAngle[2]) * temp2 + 0.9375 * (- mCosAngle[0] + mCosAngle[2]) * temp3 + 0.12890625 * (
mSinAngle[0] + 5 *
mSinAngle[2]) * temp5 + 0.125 * (3 * mCosAngle[0] + 5 * mCosAngle[2]) * (*outPtr[15]);
477 sample temp1, temp2, temp3;
485 *outPtr[4]++ = 0.5 * (1 -
mCosAngle[1]) * (*outPtr[8]) - 0.5 *
mSinAngle[1] * (*outPtr[6]) + 0.25 * (3 +
mCosAngle[1]) * (*outPtr[5]);
497 sample temp1, temp2, temp3, temp4, temp5;
509 *outPtr[10]++ = 0.125 * (5 + 3 *
mCosAngle[1]) * (*outPtr[10]) - 1.5 *
mSinAngle[1] * (*outPtr[12]) + 0.515625 * (1 -
mCosAngle[1]) * (*outPtr[14]);
512 *outPtr[13]++ = 0.227272727273 * (mCosAngle[0] - mCosAngle[2]) * temp1 + 0.454545454545 * (-
mSinAngle[0] + 3 *
mSinAngle[2]) * temp3 + 0.0625 * (mCosAngle[0] + 15 * mCosAngle[2]) * (*outPtr[13]) - 0.181818181818 * (
mSinAngle[0] + 5 *
mSinAngle[2]) * (*outPtr[15]);
513 *outPtr[14]++ = 0.454545454545 * (1 - mCosAngle[1]) * temp2 + 1.818181818182 *
mSinAngle[1] * temp4 + 0.125 * (3 + 5 * mCosAngle[1]) * (*outPtr[14]);
514 *outPtr[15]++ = 0.15625 * (3 *
mSinAngle[0] -
mSinAngle[2]) * temp1 + 0.9375 * (mCosAngle[0] - mCosAngle[2]) * temp3 + 0.12890625 * (
mSinAngle[0] + 5 *
mSinAngle[2]) * temp5 + 0.125 * (3 * mCosAngle[0] + 5 * mCosAngle[2]) * (*outPtr[15]);
613 #define PYTHAG(a, b) ((at = fabs(a)) > (bt = fabs(b)) ? \
614 (ct = bt/at, at*sqrt(1.0+ct*ct)): (bt ? (ct = at/bt, bt*sqrt(1.0+ct*ct)): 0.0))
617 #define MAX(a, b) (maxarg1 = (a), maxarg2 = (b), (maxarg1) > (maxarg2) ? \
618 (maxarg1) : (maxarg2))
620 #define SIGN(a, b) ((b) < 0.0 ? -fabs(a): fabs(a))
632 int flag, i, its, j, jj, k, l, nm;
633 double c, f, h, s, x, y, z;
634 double anorm = 0.0, g = 0.0, scale = 0.0;
638 double* rv1 =
new double [n];
641 for (i = 0; i < n; i++) {
646 for (k = i; k < m; k++)
647 scale += fabs(a[k][i]);
649 for (k = i; k < m; k++) {
651 s += a[k][i]*a[k][i];
654 g = -
SIGN(sqrt(s), f);
658 for (j = l; j < n; j++) {
659 for (s = 0.0, k = i; k < m; k++)
660 s += a[k][i]*a[k][j];
662 for (k = i; k < m; k++)
663 a[k][j] += f*a[k][i];
666 for (k = i; k < m; k++)
672 if (i < m && i != n - 1) {
673 for (k = l; k < n; k++)
674 scale += fabs(a[i][k]);
676 for (k = l; k < n; k++) {
678 s += a[i][k]*a[i][k];
681 g = -
SIGN(sqrt(s), f);
684 for (k = l; k < n; k++)
687 for (j = l; j < m; j++) {
688 for (s = 0.0, k = l; k < n; k++)
689 s += a[j][k]*a[i][k];
690 for (k = l; k < n; k++)
694 for (k = l; k < n; k++)
698 anorm =
MAX(anorm, (fabs(w[i]) + fabs(rv1[i])));
701 for (i = n - 1; 0 <= i; i--)
707 for (j = l; j < n; j++)
708 v[j][i] = (a[i][j]/a[i][l])/g;
710 for (j = l; j < n; j++)
712 for (s = 0.0, k = l; k < n; k++)
713 s += a[i][k]*v[k][j];
714 for (k = l; k < n; k++)
715 v[k][j] += s*v[k][i];
718 for (j = l; j < n; j++)
719 v[i][j] = v[j][i] = 0.0;
726 for (i = n - 1; 0 <= i; i--)
731 for (j = l; j < n; j++)
738 for (j = l; j < n; j++)
740 for (s = 0.0, k = l; k < m; k++)
741 s += a[k][i]*a[k][j];
743 for (k = i; k < m; k++)
744 a[k][j] += f*a[k][i];
747 for (j = i; j < m; j++)
751 for (j = i; j < m; j++)
756 for (k = n - 1; 0 <= k; k--)
758 for (its = 0; its < 30; its++)
761 for (l = k; 0 <= l; l--)
764 if (fabs(rv1[l]) + anorm == anorm)
769 if (fabs(w[nm]) + anorm == anorm)
776 for (i = l; i <= k; i++) {
778 if (fabs(f) + anorm != anorm)
786 for (j = 0; j < m; j++)
790 a[j][nm] = y*c + z*s;
802 for (j = 0; j < n; j++)
803 v[j][k] = (-v[j][k]);
814 f = ((y - z)*(y + z) + (g - h)*(g + h))/(2.0*h*y);
816 f = ((x - z)*(x + z) + h*((y/(f +
SIGN(g, f))) - h))/x;
819 for (j = l; j <= nm; j++)
834 for (jj = 0; jj < n; jj++)
838 v[jj][j] = x*c + z*s;
839 v[jj][i] = z*c - x*s;
851 for (jj = 0; jj < m; jj++)
855 a[jj][j] = y*c + z*s;
856 a[jj][i] = z*c - y*s;
870 float x,y,z,x2,y2,z2;
873 y = z = y2 = z2 = 0.f;
877 unsigned channel = 1;
883 float cosel = cosf(elevation);
884 x = cosf(azimuth) * cosel;
885 y = sinf(azimuth) * cosel;
887 weights[channel++] = x;
888 weights[channel++] = y;
894 weights[channel++] = z;
901 weights[channel++] = x2 - y2;
902 weights[channel++] = 2.f * x * y;
909 weights[channel++] = 2.f * z * x;
910 weights[channel++] = 2.f * z * y;
911 weights[channel++] = (1.5f * z2) - 0.5f;
916 weights[channel++] = x * (x2 - 3.f*y2);
917 weights[channel++] = y * (y2 - 3.f*x2);
921 float pre = 8.f/11.f;
923 weights[channel++] = z * (x2-y2) * 0.5f;
924 weights[channel++] = x * y * z;
925 weights[channel++] = pre * x * (5.f*z2 - 1.f);
926 weights[channel++] = pre * y * (5.f*z2 - 1.f);
927 weights[channel++] = z * 0.5 * (5.f*z2 - 3.f);
935 float x,y,z,x2,y2,z2;
938 y= z = y2 = z2 = 0.f;
948 float cosel = cosf(elevation);
949 x = cosf(azimuth) * cosel;
950 y = sinf(azimuth) * cosel;
966 weights[4] = x2 - y2;
967 weights[5] = 2.f * x * y;
970 weights[9] = x * (x2 - 3.f*y2);
971 weights[10]= y * (y2 - 3.f*x2);
978 weights[6] = 2.f * z * x;
979 weights[7] = 2.f * z * y;
980 weights[8] = (1.5f * z2) - 0.5f;
983 float pre = 8.f/11.f;
985 weights[11] = z * (x2-y2) * 0.5f;
986 weights[12] = x * y * z;
987 weights[13] = pre * x * (5.f*z2 - 1.f);
988 weights[14] = pre * y * (5.f*z2 - 1.f);
989 weights[15] = z * 0.5 * (5.f*z2 - 3.f);
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
void logMsg(const char *format,...)
These are the public logging messages.
unsigned mNumFrames
num frames used in each buffer
SampleBufferVector mOutPtr
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
void rotateThirdOrderHorizontal()
void setNthInput(float amount, Axes axis)
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...
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
AmbisonicMixer(unsigned order=1)
virtual void nextBuffer(Buffer &outputBuffer)
get a buffer of Frames – this is the core CSL "pull" function; the given buffer can be written into...
void rotateSecondOrderHorizontal()
Ambisonic order structure (separate definition for horizontal and vertical order): ...
void rotateFirstOrderHorizontal()
UGenVector mInputs
vector of pointers to the loudspeakers
void setRotate(float amount)
unsigned mNumChannelsGreaterOrder
static unsigned blockSize()
the default block size
unsigned * mInputChannelIndex
bool isUniform
Returns true if horizontal and verical orders are identical.
virtual unsigned numChannels()
float sample
(could be changed to int, or double)
unsigned mNumChannels
my "expected" number of output channels
BufferContentType mType
Data type flag set the internal size variables (no buffer allocation takes place) ...
void addInput(AmbisonicUnitGenerator &input)
methods for adding/removing inputs to the mixer.
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
Number of active inputs.
virtual bool isActive()
query whether I'm currently active (Envelopes can go inactive)
AmbisonicRotator(AmbisonicUnitGenerator &input)
initializes with no rotation
void rotateThirdOrderVertical()
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
really compute the next buffer given an offset base channel; this is called by nextBuffer, possibly multiple times
void initialize()
Initializing method called by constructors.
~AmbisonicMixer()
Destructor.
UnitGenerator * mUGen
my unit generator (pointer or NULL)
void setTumble(float amount)
void setTilt(float amount)
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Ambisonic Abstract Base Class.
AmbisonicOrder mOrder
the order of the Unit Generator
void allocateBuffers()
fcn to malloc storage buffers
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 ...
void removeOutput(UnitGenerator *ugen)
SampleBufferVector mInPtr
void rotateSecondOrderVertical()
float mInvNumInputs
the inverse of the number of inputs (used for normalization)
Buffer * mInBuffer
buffer for the input framestream
void fumaIndexedEncodingWeights(SampleBuffer weights, const AmbisonicOrder &order, sample &azimuth, sample &elevation)
Utility function that calculates fuma encoding weights for a given order, azimuth and elevation...
void initialize(UnitGenerator &input)
bool mIsPopulated
does the buffer have data?
void singularValueDecomposition(sample **a, int m, int n, sample *w, sample **v)
Utility function used in calculating the inverse of a matrix, used in AmbisonicDecoder for the pseudo...
Base class of CSL exceptions (written upper-case). Has a string message.