Last active
February 27, 2017 11:51
-
-
Save seph14/c1737eb85da86258ff316041b65d2ac1 to your computer and use it in GitHub Desktop.
MultiChannelSpectralNode.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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