diff options
Diffstat (limited to 'noatun/library/noatunarts/Equalizer_impl.cpp')
-rw-r--r-- | noatun/library/noatunarts/Equalizer_impl.cpp | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/noatun/library/noatunarts/Equalizer_impl.cpp b/noatun/library/noatunarts/Equalizer_impl.cpp new file mode 100644 index 00000000..5d852b17 --- /dev/null +++ b/noatun/library/noatunarts/Equalizer_impl.cpp @@ -0,0 +1,472 @@ +/* +Copyright (C) 2001 Charles Samuels <charles@kde.org> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +*/ + +#include "noatunarts.h" +#include "artsflow.h" +#include "fft.h" +#include <stdsynthmodule.h> +#include <math.h> +#include <cstring> + +using namespace std; +using namespace Arts; + +/** + * This class is _VERY_ picky + * which is why Noatun has it's own Equalizer class, + * that does all the error checking and sends it to here + **/ + +namespace Noatun +{ + +void resize(vector<float> &vec, unsigned int newsize) +{ + while (newsize < vec.size()) + vec.pop_back(); + while (newsize > vec.size()) + vec.push_back(0.0); +} + +class Equalizer_impl : public Equalizer_skel, public StdSynthModule +{ + vector<float> mLevels; + + vector<BandPassInfo> mBandLeft, mBandRight; + + vector<float> mLevelWidths; + vector<float> mLevelCenters; + + bool mEnabled; + float mPreamp; + + + float *mBuffer; + unsigned int mBufferLength; + + void reinit() + { + mBandLeft.clear(); + mBandRight.clear(); + for (unsigned int i=0; i< mLevelWidths.size(); ++i) + { + BandPassInfo nfo; + BandPassInit(&nfo, mLevelCenters[i], mLevelWidths[i]); + mBandLeft.push_back(nfo); + mBandRight.push_back(nfo); + } + + } + +public: + void set(const std::vector<float>& levels, const std::vector<float>& centers, const std::vector<float>& widths) + { + mLevelCenters=centers; + mLevelWidths=widths; + + mLevels=levels; + reinit(); + } + + vector<float>* levelCenters() + { + return new vector<float>(mLevelCenters); + } + + void levelCenters(const vector<float> &l) + { + mLevelCenters=l; + reinit(); + } + + vector<float>* levelWidths() + { + return new vector<float>(mLevelWidths); + } + + void levelWidths(const vector<float> &l) + { + mLevelWidths=l; + reinit(); + } + + vector<float>* levels() + { + return new vector<float>(mLevels); + } + + void levels(const vector<float> &l) + { + mLevels=l; + reinit(); + } + + long bands() + { + return mLevels.size(); + } + + void bands(long b) + { + resize(mLevels, (int)b); + resize(mLevelWidths, (int)b); + resize(mLevelCenters, (int)b); + reinit(); + } + + long enabled() + { + return (long)mEnabled; + } + + void enabled(long enabled) + { + mEnabled=(bool)enabled; + } + + float preamp() + { + return mPreamp; + } + + void preamp(float a) + { + mPreamp=a; + } + + void streamInit() + { + + } + + void streamStart() + { + + } + +/* BandPassInit(&nfoLeft, 15000.0, 5000.0); + * BandPassInit(&nfoLeft, 15000.0, 5000.0); + */ + + void calculateBlock(unsigned long samples) + { + // works by separating the bands + // multiplying, then adding + if (mEnabled && samples && &mLevels.front()) + { + + { // preamp; + + float *left=inleft; + float *right=inright; + float *end=left+samples; + + float *oleft=outleft; + float *oright=outright; + + while (left<end) + { + // see the _long_ comment in + // kdemultimedia/arts/modules/synth_std_equalizer_impl.cc + if (::fabs(*left) + ::fabs(*right) < 0.00000001) + goto copy; // if you apologize, it's becomes ok + *oleft=*left * mPreamp; + *oright=*right * mPreamp; + ++left; + ++right; + ++oleft; + ++oright; + } + } + + BandPassInfo *leftBand=&mBandLeft.front(); + BandPassInfo *rightBand=&mBandRight.front(); + float *level=&mLevels.front(); + float *end=&mLevels.back(); + float intensity=1.0/(float)mLevels.size(); + + if (mBufferLength != samples) + { + delete mBuffer; + mBuffer = new float[samples]; + mBufferLength = samples; + } + + register float *buffer=mBuffer; + register float *bufferEnd=buffer+samples; + while (level<end) + { + register float *buffIter, *outIter; + float levelAndIntensity=*level * intensity; + + BandPass(leftBand, outleft, buffer, samples); + for (buffIter=buffer, outIter=outleft; buffIter<bufferEnd; ++buffIter, ++outIter) + *outIter+=(*buffIter) * levelAndIntensity; + + BandPass(rightBand, outright, buffer, samples); + for (buffIter=buffer, outIter=outright; buffIter<bufferEnd; ++buffIter, ++outIter) + *outIter+=(*buffIter) * levelAndIntensity; + + ++level; + ++leftBand; + ++rightBand; + } + } + else + { + copy: + // ASM optimized, so much faster + memcpy(outleft, inleft, samples*sizeof(float)); + memcpy(outright, inright, samples*sizeof(float)); + } + + } + + Equalizer_impl() : mEnabled(false) + { + mBuffer=0; + mBufferLength=0; + } + + ~Equalizer_impl() + { + delete [] mBuffer; + } + + // speed hack! assume that someone else will + // suspend us + AutoSuspendState autoSuspend() { return asSuspend; } + +}; + + + + + + +class EqualizerSSE_impl : public EqualizerSSE_skel, public StdSynthModule +{ + vector<float> mLevels; + + vector<BandPassInfo> mBandLeft, mBandRight; + + vector<float> mLevelWidths; + vector<float> mLevelCenters; + + bool mEnabled; + float mPreamp; + + + + void reinit() + { + mBandLeft.clear(); + mBandRight.clear(); + for (unsigned int i=0; i< mLevelWidths.size(); ++i) + { + BandPassInfo nfo; + BandPassInit(&nfo, mLevelCenters[i], mLevelWidths[i]); + mBandLeft.push_back(nfo); + mBandRight.push_back(nfo); + } + + } + +public: + void set(const std::vector<float>& levels, const std::vector<float>& centers, const std::vector<float>& widths) + { + mLevelCenters=centers; + mLevelWidths=widths; + + mLevels=levels; + reinit(); + } + + vector<float>* levelCenters() + { + return new vector<float>(mLevelCenters); + } + + void levelCenters(const vector<float> &l) + { + mLevelCenters=l; + reinit(); + } + + vector<float>* levelWidths() + { + return new vector<float>(mLevelWidths); + } + + void levelWidths(const vector<float> &l) + { + mLevelWidths=l; + reinit(); + } + + vector<float>* levels() + { + return new vector<float>(mLevels); + } + + void levels(const vector<float> &l) + { + mLevels=l; + reinit(); + } + + long bands() + { + return mLevels.size(); + } + + void bands(long b) + { + resize(mLevels, (int)b); + resize(mLevelWidths, (int)b); + resize(mLevelCenters, (int)b); + reinit(); + } + + long enabled() + { + return (long)mEnabled; + } + + void enabled(long enabled) + { + mEnabled=(bool)enabled; + } + + float preamp() + { + return mPreamp; + } + + void preamp(float a) + { + mPreamp=a; + } + + void streamInit() + { + + } + + void streamStart() + { + + } + +/* BandPassInit(&nfoLeft, 15000.0, 5000.0); + * BandPassInit(&nfoLeft, 15000.0, 5000.0); + */ + + void calculateBlock(unsigned long samples) + { +#ifdef __i386__ + // works by separating the bands + // multiplying, then adding + if (mEnabled && samples) + { + if (*inleft + *inright == 0.0) + goto copy; // just shut up :) + + { // preamp; + + float *left=inleft; + float *right=inright; + float *end=left+samples; + + float *oleft=outleft; + float *oright=outright; + + while (left<end) + { + *oleft=*left * mPreamp; + *oright=*right * mPreamp; + ++left; + ++right; + ++oleft; + ++oright; + } + } + + BandPassInfo *leftBand=&mBandLeft.front(); + BandPassInfo *rightBand=&mBandRight.front(); + float *level=&mLevels.front(); + float *end=&mLevels.back(); + float intensity=1.0/(float)mLevels.size(); + + register float *buffer=new float[samples]; + register float *bufferEnd=buffer+samples; + while (level<end) + { + register float *buffIter, *outIter; + float levelAndIntensity=*level * intensity; + + BandPassSSE(leftBand, outleft, buffer, samples); + for (buffIter=buffer, outIter=outleft; buffIter<bufferEnd; ++buffIter, ++outIter) + *outIter+=(*buffIter) * levelAndIntensity; + + BandPassSSE(rightBand, outright, buffer, samples); + for (buffIter=buffer, outIter=outright; buffIter<bufferEnd; ++buffIter, ++outIter) + *outIter+=(*buffIter) * levelAndIntensity; + + ++level; + ++leftBand; + ++rightBand; + } + delete [] buffer; + } + else + { + copy: + // ASM optimized, so much faster + memcpy(outleft, inleft, samples*sizeof(float)); + memcpy(outright, inright, samples*sizeof(float)); + } +#else + (void)samples; // squelch warnings +#endif + } + + EqualizerSSE_impl() : mEnabled(false) + { + + } + + ~EqualizerSSE_impl() + { + } + + // speed hack! assume that someone else will + // suspend us + AutoSuspendState autoSuspend() { return asSuspend; } +}; + + +REGISTER_IMPLEMENTATION(Equalizer_impl); +REGISTER_IMPLEMENTATION(EqualizerSSE_impl); + +} + +#undef SAMPLES + |