Skip to content

Instantly share code, notes, and snippets.

@seph14
Last active February 27, 2017 11:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seph14/c1737eb85da86258ff316041b65d2ac1 to your computer and use it in GitHub Desktop.
Save seph14/c1737eb85da86258ff316041b65d2ac1 to your computer and use it in GitHub Desktop.
MultiChannelSpectralNode.cpp
#include "MultiChannelSpectralNode.h"
using namespace ci;
using namespace ci::audio;
using namespace std;
MultiChannelSpectralNode::MultiChannelSpectralNode( const Format &format )
: MonitorNode( format ), mFftSize( format.getFftSize() ), mWindowType( format.getWindowType() ),
mSmoothingFactor( 0.5f ), mLastFrameMagSpectrumComputed( 0 ) { }
MultiChannelSpectralNode::~MultiChannelSpectralNode(){}
void MultiChannelSpectralNode::initialize(){
MonitorNode::initialize();
if( mFftSize < mWindowSize )
mFftSize = mWindowSize;
if( ! isPowerOf2( mFftSize ) )
mFftSize = nextPowerOf2( static_cast<uint32_t>( mFftSize ) );
mFft = unique_ptr<dsp::Fft>( new dsp::Fft( mFftSize ) );
mFftBuffer = audio::Buffer( mFftSize );
mBufferSpectral = audio::BufferSpectral( mFftSize );
mMagSpectrum.resize(getNumChannels());
for(int i = 0; i < getNumChannels(); i++){
mMagSpectrum[i].resize( mFftSize / 2 );
}
mWindowingTable = makeAlignedArray<float>( mWindowSize );
generateWindow( mWindowType, mWindowingTable.get(), mWindowSize );
}
void MultiChannelSpectralNode::prepareProcessing(){
uint64_t numFramesProcessed = getContext()->getNumProcessedFrames();
if( mLastFrameMagSpectrumComputed == numFramesProcessed )
return;
mLastFrameMagSpectrumComputed = numFramesProcessed;
fillCopiedBuffer();
}
const std::vector<float>& MultiChannelSpectralNode::getMagSpectrum(size_t channel){
if(channel >= getNumChannels()) return mMagSpectrum[0];
// window the copied buffer and compute forward FFT transform
dsp::mul( mCopiedBuffer.getChannel(channel), mWindowingTable.get(), mFftBuffer.getData(), mWindowSize );
mFft->forward( &mFftBuffer, &mBufferSpectral );
float *real = mBufferSpectral.getReal();
float *imag = mBufferSpectral.getImag();
// remove Nyquist component
imag[0] = 0.0f;
// compute normalized magnitude spectrum
const float magScale = 10.f / mFft->getSize();
const size_t specSize = mMagSpectrum[channel].size();
for( size_t i = 0; i < specSize; i++ ) {
float re = real[i];
float im = imag[i];
mMagSpectrum[channel][i] = mMagSpectrum[channel][i] * mSmoothingFactor + std::sqrt( re * re + im * im ) * magScale * ( 1 - mSmoothingFactor );
}
return mMagSpectrum[channel];
}
float MultiChannelSpectralNode::getSpectralCentroid(size_t channel){
const auto &magSpectrum = getMagSpectrum(channel);
return dsp::spectralCentroid( magSpectrum.data(), magSpectrum.size(), getSampleRate() );
}
void MultiChannelSpectralNode::setSmoothingFactor( float factor ){
mSmoothingFactor = math<float>::clamp( factor );
}
float MultiChannelSpectralNode::getFreqForBin( size_t bin ){
return bin * getSampleRate() / (float)getFftSize();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment