#include "Analyzer.h" struct Analyzer::Data { Data(int size_); void clear(); void copyFrom (const Data& other); const juce::CriticalSection& getLock() const; const int size; juce::HeapBlock mags; juce::HeapBlock angles; private: juce::CriticalSection lock; JUCE_DECLARE_NON_COPYABLE(Data) }; Analyzer::Data::Data (int size_) : size (size_), mags (size), angles (size) { clear(); } void Analyzer::Data::clear() { juce::zeromem(mags, sizeof(float) * size); juce::zeromem(angles, sizeof(float) * size); } void Analyzer::Data::copyFrom (const Data& other) { if (other.size == size) { memcpy(mags, other.mags, sizeof(float) * size); memcpy(angles, other.angles, sizeof(float) * size); } } const juce::CriticalSection& Analyzer::Data::getLock() const { return lock; } RmsEnvelope::RmsEnvelope (int envsize, double rmsLength, double updatetime) : rms (rmsLength), rmsVals (envsize+1), updateTime (updatetime), sampleRate (44100) { clear(); } void RmsEnvelope::setSampleRate (double newSampleRate) { sampleRate = newSampleRate; rms.setSampleRate(sampleRate); clear(); } void RmsEnvelope::clear() { rms.clear(); rmsVals.clear(); updateIndex = 0; } bool RmsEnvelope::process (const float inL, const float inR) { rms.process(inL, inR); const int ovSize = int(updateTime * sampleRate); jassert(ovSize > 100); if (++updateIndex >= ovSize) { updateIndex = 0; const float rmsVal = rms.getRms(); rmsVals.push(rmsVal); return true; } return false; } void RmsEnvelope::processBlock (const float* inL, const float* inR, int numSamples) { ScopedLock lock(processLock); const int ovSize = int(updateTime * sampleRate); jassert(ovSize > 100); int idx = 0; while (numSamples > 0) { const int curNumSamples = jmin(ovSize-updateIndex, numSamples); rms.processBlock(&inL[idx], &inR[idx], curNumSamples); numSamples -= curNumSamples; idx += curNumSamples; updateIndex += curNumSamples; if (updateIndex >= ovSize) { updateIndex = 0; const float rmsVal = rms.getRms(); rmsVals.push(rmsVal); } } } bool RmsEnvelope::getData (Array& data) const { const int dataLength = getDataLength(); if (data.size() < dataLength) { ScopedTryLock lock(processLock); if (! lock.isLocked()) return false; for (int i=0; iclear(); } void Analyzer::processBlock (const float* inL, const float* inR, int numSamples) { for (int i=0; i= fftBlockSize) { processFFT(); fftIndex = 0; } } } int Analyzer::getFFTSize() const { return fftBlockSize; } int Analyzer::getNumBins() const { return numBins; } bool Analyzer::getData (Data& d) const { ScopedTryLock lock(data->getLock()); if (lock.isLocked()) { d.copyFrom(*data); return true; } return false; } void Analyzer::setSampleRate (double newSampleRate) { if (sampleRate != newSampleRate) { sampleRate = newSampleRate; fftBlockSize = 512 * jmax(1, int(sampleRate / 44100)); numBins = fftBlockSize / 2 + 1; fft = new ffft::FFTReal (fftBlockSize); x.realloc(fftBlockSize); f.realloc(fftBlockSize); window.realloc(fftBlockSize); data = new Data(numBins); { const float alpha = 0.16f; const float a0 = 0.5f * (1-alpha); const float a1 = 0.5f; const float a2 = alpha*0.5f; for (int i=0; ido_fft(f, x); const int imagOffset = fftBlockSize / 2; const float weight = 1.f / fftBlockSize; { ScopedLock lock(data->getLock()); data->mags[0] = f[0]*f[0] * weight; data->mags[imagOffset] = f[imagOffset]*f[imagOffset] * weight; data->angles[0] = 0; data->angles[numBins-1] = 0; for (int i=1; imags[i] = (re*re + im*im) * weight; data->angles[i] = atan2(im, re); } } }