1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
|
/*############################################################################*/
/*# #*/
/*# Ambisonic C++ Library #*/
/*# CAmbisonicProcessor - Ambisonic Processor #*/
/*# Copyright © 2007 Aristotel Digenis #*/
/*# Copyright © 2017 Videolabs #*/
/*# #*/
/*# Filename: AmbisonicProcessor.h #*/
/*# Version: 0.2 #*/
/*# Date: 19/05/2007 #*/
/*# Author(s): Aristotel Digenis, Peter Stitt #*/
/*# Licence: LGPL (+ Proprietary) #*/
/*# #*/
/*############################################################################*/
#ifndef _AMBISONIC_PROCESSOR_H
#define _AMBISONIC_PROCESSOR_H
#include "AmbisonicBase.h"
#include "BFormat.h"
#include "kiss_fftr.h"
#include "AmbisonicPsychoacousticFilters.h"
#include "AmbisonicZoomer.h"
enum ProcessorDOR
{
kYaw, kRoll, kPitch, kNumProcessorDOR //(Degrees of Rotation)
};
enum ProcessorModes
{
kYawRollPitch, kYawPitchRoll,
kRollYawPitch, kRollPitchYaw,
kPitchYawRoll, kPitchRollYaw,
kNumProcessorModes
};
class CAmbisonicProcessor;
/// Struct for soundfield rotation.
class Orientation
{
public:
Orientation(float fYaw, float fPitch, float fRoll)
: fYaw(fYaw), fPitch(fPitch), fRoll(fRoll)
{
float fCosYaw = cosf(fYaw);
float fSinYaw = sinf(fYaw);
float fCosRoll = cosf(fRoll);
float fSinRoll = sinf(fRoll);
float fCosPitch = cosf(fPitch);
float fSinPitch = sinf(fPitch);
/* Conversion from yaw, pitch, roll (ZYX) to ZYZ convention to match rotation matrices
This method reduces the complexity of the rotation matrices since the Z0 and Z1 rotations are the same form */
float r33 = fCosPitch * fCosRoll;
if (r33 == 1.f)
{
fBeta = 0.f;
fGamma = 0.f;
fAlpha = atan2(fSinYaw, fCosYaw);
}
else
{
if (r33 == -1.f)
{
fBeta = M_PI;
fGamma = 0.f;
fAlpha = atan2(-fSinYaw, fCosYaw);
}
else
{
float r32 = -fCosYaw * fSinRoll + fCosRoll * fSinPitch * fSinYaw ;
float r31 = fCosRoll * fCosYaw * fSinPitch + fSinRoll * fSinYaw ;
fAlpha = atan2( r32 , r31 );
fBeta = acos( r33 );
float r23 = fCosPitch * fSinRoll;
float r13 = -fSinPitch;
fGamma = atan2( r23 , -r13 );
}
}
}
friend class CAmbisonicProcessor;
private:
/** rotation around the Z axis (yaw) */
float fYaw;
/** rotation around the Y axis (pitch) */
float fPitch;
/** rotation around the X axis (roll) */
float fRoll;
/** These angles are obtained from Yaw, Pitch and Roll (ZYX convention)**/
/** They follow the ZYZ convention to match the rotation equations **/
/** rotation around the Z axis */
float fAlpha;
/** rotation around the X axis */
float fBeta;
/** rotation around the new Z axis */
float fGamma;
};
/// Ambisonic processor.
/** This object is used to rotate the BFormat signal around all three axes.
Orientation structs are used to define the the soundfield's orientation. */
class CAmbisonicProcessor : public CAmbisonicBase
{
public:
CAmbisonicProcessor();
~CAmbisonicProcessor();
/**
Re-create the object for the given configuration. Previous data is
lost. The last argument is not used, it is just there to match with
the base class's form. Returns true if successful.
*/
bool Configure(unsigned nOrder, bool b3D, unsigned nBlockSize, unsigned nMisc);
/**
Not implemented.
*/
void Reset();
/**
Recalculate coefficients.
*/
void Refresh();
/**
Set yaw, roll, and pitch settings.
*/
void SetOrientation(Orientation orientation);
/**
Get yaw, roll, and pitch settings.
*/
Orientation GetOrientation();
/**
Rotate B-Format stream.
*/
void Process(CBFormat* pBFSrcDst, unsigned nSamples);
private:
void ProcessOrder1_3D(CBFormat* pBFSrcDst, unsigned nSamples);
void ProcessOrder2_3D(CBFormat* pBFSrcDst, unsigned nSamples);
void ProcessOrder3_3D(CBFormat* pBFSrcDst, unsigned nSamples);
void ProcessOrder1_2D(CBFormat* pBFSrcDst, unsigned nSamples);
void ProcessOrder2_2D(CBFormat* pBFSrcDst, unsigned nSamples);
void ProcessOrder3_2D(CBFormat* pBFSrcDst, unsigned nSamples);
void ShelfFilterOrder(CBFormat* pBFSrcDst, unsigned nSamples);
protected:
Orientation m_orientation;
float* m_pfTempSample;
kiss_fftr_cfg m_pFFT_psych_cfg;
kiss_fftr_cfg m_pIFFT_psych_cfg;
float* m_pfScratchBufferA;
float** m_pfOverlap;
unsigned m_nFFTSize;
unsigned m_nBlockSize;
unsigned m_nTaps;
unsigned m_nOverlapLength;
unsigned m_nFFTBins;
float m_fFFTScaler;
kiss_fft_cpx** m_ppcpPsychFilters;
kiss_fft_cpx* m_pcpScratch;
float m_fCosAlpha;
float m_fSinAlpha;
float m_fCosBeta;
float m_fSinBeta;
float m_fCosGamma;
float m_fSinGamma;
float m_fCos2Alpha;
float m_fSin2Alpha;
float m_fCos2Beta;
float m_fSin2Beta;
float m_fCos2Gamma;
float m_fSin2Gamma;
float m_fCos3Alpha;
float m_fSin3Alpha;
float m_fCos3Beta;
float m_fSin3Beta;
float m_fCos3Gamma;
float m_fSin3Gamma;
};
#endif // _AMBISONIC_PROCESSOR_H
|