summaryrefslogtreecommitdiffstats
path: root/noatun/library/noatunarts/FFTScopes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'noatun/library/noatunarts/FFTScopes.cpp')
-rw-r--r--noatun/library/noatunarts/FFTScopes.cpp422
1 files changed, 422 insertions, 0 deletions
diff --git a/noatun/library/noatunarts/FFTScopes.cpp b/noatun/library/noatunarts/FFTScopes.cpp
new file mode 100644
index 00000000..ab2a3bbb
--- /dev/null
+++ b/noatun/library/noatunarts/FFTScopes.cpp
@@ -0,0 +1,422 @@
+/*
+Copyright (C) 2000 Stefan Westerfeld <stefan@space.twc.de>
+ 2000 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 <cmath>
+#include <cstring>
+
+#include <iostream>
+
+using namespace std;
+using namespace Arts;
+
+namespace Noatun
+{
+
+#define SAMPLES 4096
+
+static void doFft(float combine, float *inBuffer, vector<float> &scope)
+{
+ float out_real[SAMPLES],out_img[SAMPLES];
+ fft_float(SAMPLES,0,inBuffer,0,out_real,out_img);
+
+ scope.clear();
+
+ int previous=0;
+ int index=20;
+
+ while (previous < 2048 && index < 2048)
+ {
+ int end = int(std::exp(double(index)*combine));
+ float xrange = 0.0;
+
+ while (previous < end)
+ {
+ xrange += (std::fabs(out_img[previous]) + std::fabs(out_real[previous]));
+ previous++;
+ }
+
+ xrange /= float(SAMPLES);
+ scope.push_back(xrange);
+
+ index++;
+ }
+}
+
+
+class FFTScopeStereo_impl : public FFTScopeStereo_skel, public StdSynthModule
+{
+protected:
+ vector<float> mScopeLeft;
+ vector<float> mScopeRight;
+
+ float mCombine;
+
+ float *mWindow;
+
+ float *mInBufferLeft, *mInBufferRight;
+ unsigned long mInBufferPos;
+
+public:
+ void bandResolution(float res) { mCombine=res; }
+ float bandResolution() { return mCombine; }
+ void streamInit()
+ {
+ unsigned long i;
+ for(i=0;i<SAMPLES;i++)
+ {
+ float x = (float)i/(float)SAMPLES;
+ // double it, since we're at half intensity without
+ // adding both channels
+ mWindow[i] = sin(x*DDC_PI)*sin(x*DDC_PI)*2;
+
+ mInBufferLeft[i] = 0;
+ mInBufferRight[i] = 0;
+ }
+ doFft(mCombine, mInBufferLeft, mScopeLeft);
+ doFft(mCombine, mInBufferRight, mScopeRight);
+ }
+ void streamStart()
+ {
+ mInBufferPos = 0;
+ }
+ vector<float> *scopeLeft()
+ {
+ return new vector<float>(mScopeLeft);
+ }
+ vector<float> *scopeRight()
+ {
+ return new vector<float>(mScopeRight);
+ }
+ /*
+ in audio stream inleft, inright;
+ out audio stream outleft, outright;
+ */
+ void calculateBlock(unsigned long samples)
+ {
+ unsigned long i;
+ for(i=0;i<samples;i++)
+ {
+ mInBufferLeft[mInBufferPos] = inleft[i]*mWindow[mInBufferPos];
+ mInBufferRight[mInBufferPos] = inright[i]*mWindow[mInBufferPos];
+ if(++mInBufferPos == SAMPLES)
+ {
+ doFft(mCombine, mInBufferLeft, mScopeLeft);
+ doFft(mCombine, mInBufferRight, mScopeRight);
+ mInBufferPos = 0;
+ }
+ /*
+ monitoring only tasks can't be done with that StereoEffect
+ interface nicely - copy input to output until there is
+ something better
+ */
+ outleft[i] = inleft[i];
+ outright[i] = inright[i];
+ }
+ }
+
+ FFTScopeStereo_impl() : mCombine(0.152492)
+ {
+ mWindow = new float[SAMPLES];
+ mInBufferLeft = new float[SAMPLES];
+ mInBufferRight = new float[SAMPLES];
+
+ }
+ ~FFTScopeStereo_impl()
+ {
+ delete [] mWindow;
+ delete [] mInBufferLeft;
+ delete [] mInBufferRight;
+ }
+
+ AutoSuspendState autoSuspend() { return asSuspend; }
+
+};
+
+class FFTScope_impl : public FFTScope_skel, public StdSynthModule
+{
+protected:
+ vector<float> mScope;
+
+ float mCombine;
+
+ float *mWindow;
+ float *mInBuffer;
+ unsigned long mInBufferPos;
+
+public:
+ void bandResolution(float res) { mCombine=res; }
+ float bandResolution() { return mCombine; }
+ void streamInit()
+ {
+ unsigned long i;
+ for(i=0;i<SAMPLES;i++)
+ {
+ float x = (float)i/(float)SAMPLES;
+ mWindow[i] = sin(x*DDC_PI)*sin(x*DDC_PI);
+ mInBuffer[i] = 0;
+ }
+ doFft(mCombine, mInBuffer, mScope); // initialize so that we never return an empty scope
+ }
+ void streamStart()
+ {
+ mInBufferPos = 0;
+ }
+ vector<float> *scope()
+ {
+ return new vector<float>(mScope);
+ }
+
+ /*
+ in audio stream inleft, inright;
+ out audio stream outleft, outright;
+ */
+ void calculateBlock(unsigned long samples)
+ {
+ unsigned long i;
+
+ float *inBufferIt=mInBuffer+mInBufferPos;
+ float *inleftIt=inleft;
+ float *inrightIt=inright;
+ float *windowIt=mWindow+mInBufferPos;
+
+ for(i=0;i<samples;i++)
+ {
+ *inBufferIt = (*inleftIt + *inrightIt)* (*windowIt);
+ if(++mInBufferPos == SAMPLES)
+ {
+ doFft(mCombine, mInBuffer, mScope);
+ mInBufferPos = 0;
+ inBufferIt=mInBuffer;
+ }
+ inBufferIt++;
+ inleftIt++;
+ inrightIt++;
+ windowIt++;
+ }
+ /*
+ monitoring only tasks can't be done with that StereoEffect
+ interface nicely - copy input to output until there is
+ something better
+ */
+ memcpy(outleft, inleft, sizeof(float)*samples);
+ memcpy(outright, inright, sizeof(float)*samples);
+
+ }
+
+ FFTScope_impl() : mCombine(0.152492)
+ {
+ mWindow = new float[SAMPLES];
+ mInBuffer = new float[SAMPLES];
+ }
+
+ ~FFTScope_impl()
+ {
+ delete [] mWindow;
+ delete [] mInBuffer;
+ }
+
+ AutoSuspendState autoSuspend() { return asSuspend; }
+};
+
+class RawScope_impl : public RawScope_skel, public StdSynthModule
+{
+protected:
+ float *mScope;
+
+ int mScopeLength;
+ float *mScopeEnd;
+ float *mCurrent;
+
+public:
+ vector<float> *scope()
+ {
+ vector<float> *buf = new vector<float>;
+ buf->resize(mScopeLength);
+ char *front = (char *)(&buf->front());
+ memcpy(front, mCurrent, (mScopeEnd - mCurrent) * sizeof(float));
+ memcpy(front + (mScopeEnd - mCurrent)*sizeof(float), mScope,
+ (mCurrent - mScope) * sizeof(float));
+ return buf;
+ }
+
+ void buffer(long len)
+ {
+ delete [] mScope;
+
+ mScopeLength=len;
+ mScope=new float[len];
+ mScopeEnd=mScope+mScopeLength;
+ mCurrent=mScope;
+
+ memset(mScope, 0, mScopeLength);
+ }
+
+ long buffer()
+ {
+ return mScopeLength;
+ }
+
+ void calculateBlock(unsigned long samples)
+ {
+ for (unsigned long i=0; i<samples; ++i)
+ {
+ for (; mCurrent<mScopeEnd && i<samples; ++mCurrent, ++i)
+ {
+ *mCurrent = inleft[i] + inright[i];
+ }
+ if (mCurrent>=mScopeEnd)
+ mCurrent=mScope;
+ }
+
+ memcpy(outleft, inleft, sizeof(float)*samples);
+ memcpy(outright, inright, sizeof(float)*samples);
+
+ }
+
+ RawScope_impl()
+ {
+ mScope=0;
+ buffer(512);
+
+ }
+
+ ~RawScope_impl()
+ {
+ delete [] mScope;
+ }
+
+ AutoSuspendState autoSuspend() { return asSuspend; }
+};
+
+class RawScopeStereo_impl : public RawScopeStereo_skel, public StdSynthModule
+{
+protected:
+ int mScopeLength;
+
+ float *mScopeLeft;
+ float *mScopeEndLeft;
+ float *mCurrentLeft;
+
+ float *mScopeRight;
+ float *mScopeEndRight;
+ float *mCurrentRight;
+
+public:
+ vector<float> *scopeLeft()
+ {
+ vector<float> *buf = new vector<float>;
+ buf->resize(mScopeLength);
+ char *front = (char *)(&buf->front());
+ memcpy(front, mCurrentLeft, (mScopeEndLeft - mCurrentLeft) * sizeof(float));
+ memcpy(front + (mScopeEndLeft - mCurrentLeft)*sizeof(float), mScopeLeft,
+ (mCurrentLeft - mScopeLeft) * sizeof(float));
+ return buf;
+ }
+
+ vector<float> *scopeRight()
+ {
+ vector<float> *buf = new vector<float>;
+ buf->resize(mScopeLength);
+ char *front = (char *)(&buf->front());
+ memcpy(front, mCurrentRight, (mScopeEndRight - mCurrentRight) * sizeof(float));
+ memcpy(front + (mScopeEndRight - mCurrentRight)*sizeof(float), mScopeRight,
+ (mCurrentRight - mScopeRight) * sizeof(float));
+ return buf;
+ }
+
+ void buffer(long len)
+ {
+ delete [] mScopeRight;
+ delete [] mScopeLeft;
+
+ mScopeLength=len;
+ mScopeRight=new float[len];
+ mScopeLeft=new float[len];
+ mScopeEndRight=mScopeRight+mScopeLength;
+ mScopeEndLeft=mScopeLeft+mScopeLength;
+ mCurrentRight=mScopeRight;
+ mCurrentLeft=mScopeLeft;
+
+ memset(mScopeRight, 0, mScopeLength);
+ memset(mScopeLeft, 0, mScopeLength);
+ }
+
+ long buffer()
+ {
+ return mScopeLength;
+ }
+
+ void calculateBlock(unsigned long samples)
+ {
+ for (unsigned long i=0; i<samples; ++i)
+ {
+ for (; mCurrentLeft<mScopeEndLeft && i<samples; ++mCurrentLeft, ++i)
+ {
+ *mCurrentLeft = inleft[i];
+ }
+ if (mCurrentLeft>=mScopeEndLeft)
+ mCurrentLeft=mScopeLeft;
+ }
+
+ for (unsigned long i=0; i<samples; ++i)
+ {
+ for (; mCurrentRight<mScopeEndRight && i<samples; ++mCurrentRight, ++i)
+ {
+ *mCurrentRight = inright[i];
+ }
+ if (mCurrentRight>=mScopeEndRight)
+ mCurrentRight=mScopeRight;
+ }
+
+ memcpy(outleft, inleft, sizeof(float)*samples);
+ memcpy(outright, inright, sizeof(float)*samples);
+ }
+
+ RawScopeStereo_impl()
+ {
+ mScopeLeft=mScopeRight=0;
+ buffer(512);
+
+ }
+
+ ~RawScopeStereo_impl()
+ {
+ delete [] mScopeRight;
+ delete [] mScopeLeft;
+ }
+
+ AutoSuspendState autoSuspend() { return asSuspend; }
+};
+
+
+
+REGISTER_IMPLEMENTATION(FFTScope_impl);
+REGISTER_IMPLEMENTATION(FFTScopeStereo_impl);
+REGISTER_IMPLEMENTATION(RawScope_impl);
+REGISTER_IMPLEMENTATION(RawScopeStereo_impl);
+
+}
+
+#undef SAMPLES