43 #include "CASpectralProcessor.h"
44 #include "CABitOperations.h"
47 #include <vecLib/vectorOps.h>
50 #define OFFSETOF(class, field)((size_t)&((class*)0)->field)
52 CASpectralProcessor::CASpectralProcessor(UInt32 inFFTSize, UInt32 inHopSize, UInt32 inNumChannels, UInt32 inMaxFrames)
53 : mFFTSize(inFFTSize), mHopSize(inHopSize), mNumChannels(inNumChannels), mMaxFrames(inMaxFrames),
54 mLog2FFTSize(Log2Ceil(mFFTSize)),
55 mFFTMask(mFFTSize - 1),
56 mFFTByteSize(mFFTSize * sizeof(Float32)),
57 mIOBufSize(NextPowerOfTwo(mFFTSize + mMaxFrames)),
58 mIOMask(mIOBufSize - 1),
60 mInputPos(0), mOutputPos(-mFFTSize & mIOMask),
61 mInFFTPos(0), mOutFFTPos(0),
62 mSpectralFunction(0), mUserData(0)
64 mWindow.alloc(mFFTSize,
false);
67 mChannels.alloc(mNumChannels);
68 mSpectralBufferList.allocBytes(OFFSETOF(SpectralBufferList, mDSPSplitComplex[mNumChannels]),
true);
69 mSpectralBufferList->mNumberSpectra = mNumChannels;
70 for (UInt32 i = 0; i < mNumChannels; ++i)
72 mChannels[i].mInputBuf.alloc(mIOBufSize,
true);
73 mChannels[i].mOutputBuf.alloc(mIOBufSize,
true);
74 mChannels[i].mFFTBuf.alloc(mFFTSize,
true);
75 mChannels[i].mSplitFFTBuf.alloc(mFFTSize,
true);
76 mSpectralBufferList->mDSPSplitComplex[i].realp = mChannels[i].mSplitFFTBuf();
77 mSpectralBufferList->mDSPSplitComplex[i].imagp = mChannels[i].mSplitFFTBuf() + (mFFTSize >> 1);
80 mFFTSetup = vDSP_create_fftsetup (mLog2FFTSize, FFT_RADIX2);
84 CASpectralProcessor::~CASpectralProcessor()
88 mSpectralBufferList.free();
89 vDSP_destroy_fftsetup(mFFTSetup);
92 void CASpectralProcessor::Reset()
95 mOutputPos = -mFFTSize & mIOMask;
99 for (UInt32 i = 0; i < mNumChannels; ++i)
101 memset(mChannels[i].mInputBuf(), 0, mIOBufSize *
sizeof(Float32));
102 memset(mChannels[i].mOutputBuf(), 0, mIOBufSize *
sizeof(Float32));
103 memset(mChannels[i].mFFTBuf(), 0, mFFTSize *
sizeof(Float32));
107 const double two_pi = 2. * M_PI;
109 void CASpectralProcessor::HanningWindow()
113 double w = two_pi / (double)(mFFTSize - 1);
114 for (UInt32 i = 0; i < mFFTSize; ++i)
116 mWindow[i] = (0.5 - 0.5 * cos(w * (
double)i));
120 void CASpectralProcessor::SineWindow()
122 double w = M_PI / (double)(mFFTSize - 1);
123 for (UInt32 i = 0; i < mFFTSize; ++i)
125 mWindow[i] = sin(w * (
double)i);
129 void CASpectralProcessor::Process(UInt32 inNumFrames, AudioBufferList* inInput, AudioBufferList* outOutput)
132 CopyInput(inNumFrames, inInput);
135 while (mInputSize >= mFFTSize)
140 ProcessSpectrum(mFFTSize, mSpectralBufferList());
147 CopyOutput(inNumFrames, outOutput);
150 void CASpectralProcessor::DoWindowing()
152 Float32 *win = mWindow();
154 for (UInt32 i=0; i<mNumChannels; ++i) {
155 Float32 *x = mChannels[i].mFFTBuf();
156 vDSP_vmul(x, 1, win, 1, x, 1, mFFTSize);
163 void CASpectralProcessor::CopyInput(UInt32 inNumFrames, AudioBufferList* inInput)
165 UInt32 numBytes = inNumFrames *
sizeof(Float32);
166 UInt32 firstPart = mIOBufSize - mInputPos;
169 if (firstPart < inNumFrames) {
170 UInt32 firstPartBytes = firstPart *
sizeof(Float32);
171 UInt32 secondPartBytes = numBytes - firstPartBytes;
172 for (UInt32 i=0; i<mNumChannels; ++i) {
173 memcpy(mChannels[i].mInputBuf + mInputPos, inInput->mBuffers[i].mData, firstPartBytes);
174 memcpy(mChannels[i].mInputBuf, (UInt8*)inInput->mBuffers[i].mData + firstPartBytes, secondPartBytes);
177 UInt32 numBytes = inNumFrames *
sizeof(Float32);
178 for (UInt32 i=0; i<mNumChannels; ++i) {
179 memcpy(mChannels[i].mInputBuf + mInputPos, inInput->mBuffers[i].mData, numBytes);
184 mInputSize += inNumFrames;
185 mInputPos = (mInputPos + inNumFrames) & mIOMask;
188 void CASpectralProcessor::CopyOutput(UInt32 inNumFrames, AudioBufferList* outOutput)
192 UInt32 numBytes = inNumFrames *
sizeof(Float32);
193 UInt32 firstPart = mIOBufSize - mOutputPos;
194 if (firstPart < inNumFrames) {
195 UInt32 firstPartBytes = firstPart *
sizeof(Float32);
196 UInt32 secondPartBytes = numBytes - firstPartBytes;
197 for (UInt32 i=0; i<mNumChannels; ++i) {
198 memcpy(outOutput->mBuffers[i].mData, mChannels[i].mOutputBuf + mOutputPos, firstPartBytes);
199 memcpy((UInt8*)outOutput->mBuffers[i].mData + firstPartBytes, mChannels[i].mOutputBuf, secondPartBytes);
200 memset(mChannels[i].mOutputBuf + mOutputPos, 0, firstPartBytes);
201 memset(mChannels[i].mOutputBuf, 0, secondPartBytes);
204 for (UInt32 i=0; i<mNumChannels; ++i) {
205 memcpy(outOutput->mBuffers[i].mData, mChannels[i].mOutputBuf + mOutputPos, numBytes);
206 memset(mChannels[i].mOutputBuf + mOutputPos, 0, numBytes);
210 mOutputPos = (mOutputPos + inNumFrames) & mIOMask;
213 void CASpectralProcessor::PrintSpectralBufferList()
215 UInt32 half = mFFTSize >> 1;
216 for (UInt32 i=0; i<mNumChannels; ++i) {
217 DSPSplitComplex &freqData = mSpectralBufferList->mDSPSplitComplex[i];
219 for (UInt32 j=0; j<half; j++){
220 printf(
" bin[%d]: %lf + %lfi\n", (
int) j, freqData.realp[j], freqData.imagp[j]);
226 void CASpectralProcessor::CopyInputToFFT()
229 UInt32 firstPart = mIOBufSize - mInFFTPos;
230 UInt32 firstPartBytes = firstPart *
sizeof(Float32);
231 if (firstPartBytes < mFFTByteSize) {
232 UInt32 secondPartBytes = mFFTByteSize - firstPartBytes;
233 for (UInt32 i=0; i<mNumChannels; ++i) {
234 memcpy(mChannels[i].mFFTBuf(), mChannels[i].mInputBuf() + mInFFTPos, firstPartBytes);
235 memcpy((UInt8*)mChannels[i].mFFTBuf() + firstPartBytes, mChannels[i].mInputBuf(), secondPartBytes);
238 for (UInt32 i=0; i<mNumChannels; ++i) {
239 memcpy(mChannels[i].mFFTBuf(), mChannels[i].mInputBuf() + mInFFTPos, mFFTByteSize);
242 mInputSize -= mHopSize;
243 mInFFTPos = (mInFFTPos + mHopSize) & mIOMask;
247 void CASpectralProcessor::OverlapAddOutput()
250 UInt32 firstPart = mIOBufSize - mOutFFTPos;
251 if (firstPart < mFFTSize) {
252 UInt32 secondPart = mFFTSize - firstPart;
253 for (UInt32 i=0; i<mNumChannels; ++i) {
254 float* out1 = mChannels[i].mOutputBuf() + mOutFFTPos;
255 vDSP_vadd(out1, 1, mChannels[i].mFFTBuf(), 1, out1, 1, firstPart);
256 float* out2 = mChannels[i].mOutputBuf();
257 vDSP_vadd(out2, 1, mChannels[i].mFFTBuf() + firstPart, 1, out2, 1, secondPart);
260 for (UInt32 i=0; i<mNumChannels; ++i) {
261 float* out1 = mChannels[i].mOutputBuf() + mOutFFTPos;
262 vDSP_vadd(out1, 1, mChannels[i].mFFTBuf(), 1, out1, 1, mFFTSize);
266 mOutFFTPos = (mOutFFTPos + mHopSize) & mIOMask;
270 void CASpectralProcessor::DoFwdFFT()
273 UInt32 half = mFFTSize >> 1;
274 for (UInt32 i=0; i<mNumChannels; ++i)
276 vDSP_ctoz((DSPComplex*)mChannels[i].mFFTBuf(), 2, &mSpectralBufferList->mDSPSplitComplex[i], 1, half);
277 vDSP_fft_zrip(mFFTSetup, &mSpectralBufferList->mDSPSplitComplex[i], 1, mLog2FFTSize, FFT_FORWARD);
282 void CASpectralProcessor::DoInvFFT()
285 UInt32 half = mFFTSize >> 1;
286 for (UInt32 i=0; i<mNumChannels; ++i)
288 vDSP_fft_zrip(mFFTSetup, &mSpectralBufferList->mDSPSplitComplex[i], 1, mLog2FFTSize, FFT_INVERSE);
289 vDSP_ztoc(&mSpectralBufferList->mDSPSplitComplex[i], 1, (DSPComplex*)mChannels[i].mFFTBuf(), 2, half);
290 float scale = 0.5 / mFFTSize;
291 vDSP_vsmul(mChannels[i].mFFTBuf(), 1, &scale, mChannels[i].mFFTBuf(), 1, mFFTSize );
296 void CASpectralProcessor::SetSpectralFunction(SpectralFunction inFunction,
void* inUserData)
298 mSpectralFunction = inFunction;
299 mUserData = inUserData;
302 void CASpectralProcessor::ProcessSpectrum(UInt32 inFFTSize, SpectralBufferList* inSpectra)
304 if (mSpectralFunction)
305 (mSpectralFunction)(inSpectra, mUserData);
308 #pragma mark ___Utility___
310 void CASpectralProcessor::GetMagnitude(AudioBufferList* list, Float32* min, Float32* max)
312 UInt32 half = mFFTSize >> 1;
313 for (UInt32 i=0; i<mNumChannels; ++i) {
314 DSPSplitComplex &freqData = mSpectralBufferList->mDSPSplitComplex[i];
316 Float32* b = (Float32*) list->mBuffers[i].mData;
318 vDSP_zvabs(&freqData,1,b,1,half);
320 vDSP_maxmgv(b, 1, &max[i], half);
321 vDSP_minmgv(b, 1, &min[i], half);
327 void CASpectralProcessor::GetFrequencies(Float32* freqs, Float32 sampleRate)
329 UInt32 half = mFFTSize >> 1;
331 for (UInt32 i=0; i< half; i++){
332 freqs[i] = ((Float32)(i))*sampleRate/((Float32)mFFTSize);
337 bool CASpectralProcessor::ProcessForwards(UInt32 inNumFrames, AudioBufferList* inInput)
340 CopyInput(inNumFrames, inInput);
342 bool processed =
false;
344 while (mInputSize >= mFFTSize)
349 ProcessSpectrum(mFFTSize, mSpectralBufferList());
356 bool CASpectralProcessor::ProcessBackwards(UInt32 inNumFrames, AudioBufferList* outOutput)
359 ProcessSpectrum(mFFTSize, mSpectralBufferList());
365 CopyOutput(inNumFrames, outOutput);