summaryrefslogtreecommitdiffstats
path: root/noatun/library/noatunarts
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commite2de64d6f1beb9e492daf5b886e19933c1fa41dd (patch)
tree9047cf9e6b5c43878d5bf82660adae77ceee097a /noatun/library/noatunarts
downloadtdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.tar.gz
tdemultimedia-e2de64d6f1beb9e492daf5b886e19933c1fa41dd.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdemultimedia@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'noatun/library/noatunarts')
-rw-r--r--noatun/library/noatunarts/Equalizer.mcopclass4
-rw-r--r--noatun/library/noatunarts/EqualizerSSE.mcopclass4
-rw-r--r--noatun/library/noatunarts/Equalizer_impl.cpp472
-rw-r--r--noatun/library/noatunarts/FFTScope.mcopclass4
-rw-r--r--noatun/library/noatunarts/FFTScopeStereo.mcopclass4
-rw-r--r--noatun/library/noatunarts/FFTScopes.cpp422
-rw-r--r--noatun/library/noatunarts/Listener.mcopclass4
-rw-r--r--noatun/library/noatunarts/Makefile.am33
-rw-r--r--noatun/library/noatunarts/RawScope.mcopclass4
-rw-r--r--noatun/library/noatunarts/RawScopeStereo.mcopclass4
-rw-r--r--noatun/library/noatunarts/Session.mcopclass4
-rw-r--r--noatun/library/noatunarts/Session_impl.cpp82
-rw-r--r--noatun/library/noatunarts/StereoEffectStack.mcopclass4
-rw-r--r--noatun/library/noatunarts/StereoEffectStack_impl.cpp253
-rw-r--r--noatun/library/noatunarts/StereoVolumeControl.mcopclass4
-rw-r--r--noatun/library/noatunarts/StereoVolumeControlSSE.mcopclass4
-rw-r--r--noatun/library/noatunarts/StereoVolumeControl_impl.cpp181
-rw-r--r--noatun/library/noatunarts/fft.c384
-rw-r--r--noatun/library/noatunarts/fft.h88
-rw-r--r--noatun/library/noatunarts/noatunarts.idl91
20 files changed, 2050 insertions, 0 deletions
diff --git a/noatun/library/noatunarts/Equalizer.mcopclass b/noatun/library/noatunarts/Equalizer.mcopclass
new file mode 100644
index 00000000..85dac1eb
--- /dev/null
+++ b/noatun/library/noatunarts/Equalizer.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::Equalizer,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/EqualizerSSE.mcopclass b/noatun/library/noatunarts/EqualizerSSE.mcopclass
new file mode 100644
index 00000000..9002a4ad
--- /dev/null
+++ b/noatun/library/noatunarts/EqualizerSSE.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::EqualizerSSE,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
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
+
diff --git a/noatun/library/noatunarts/FFTScope.mcopclass b/noatun/library/noatunarts/FFTScope.mcopclass
new file mode 100644
index 00000000..65826259
--- /dev/null
+++ b/noatun/library/noatunarts/FFTScope.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::FFTScope,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/FFTScopeStereo.mcopclass b/noatun/library/noatunarts/FFTScopeStereo.mcopclass
new file mode 100644
index 00000000..f463a2ed
--- /dev/null
+++ b/noatun/library/noatunarts/FFTScopeStereo.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::FFTScopeStereo,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
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
diff --git a/noatun/library/noatunarts/Listener.mcopclass b/noatun/library/noatunarts/Listener.mcopclass
new file mode 100644
index 00000000..81f19d38
--- /dev/null
+++ b/noatun/library/noatunarts/Listener.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::Listener,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/Makefile.am b/noatun/library/noatunarts/Makefile.am
new file mode 100644
index 00000000..a08e279d
--- /dev/null
+++ b/noatun/library/noatunarts/Makefile.am
@@ -0,0 +1,33 @@
+INCLUDES= -I$(kde_includes)/arts $(all_includes)
+KDE_OPTIONS = nofinal
+
+lib_LTLIBRARIES = libnoatunarts.la
+libnoatunarts_la_SOURCES = noatunarts.cc fft.c Equalizer_impl.cpp \
+ FFTScopes.cpp StereoEffectStack_impl.cpp \
+ StereoVolumeControl_impl.cpp Session_impl.cpp
+libnoatunarts_la_COMPILE_FIRST = noatunarts.h
+libnoatunarts_la_LDFLAGS = $(all_libraries) -avoid-version -no-undefined
+libnoatunarts_la_LIBADD = -lkmedia2_idl -lsoundserver_idl -lartsflow
+libnoatunarts_la_METASOURCES = AUTO
+
+noatunarts.mcoptype: noatunarts.h
+noatunarts.mcopclass: noatunarts.h
+
+noatunarts.cc noatunarts.h: noatunarts.idl
+ $(MCOPIDL) -t -I$(kde_includes)/arts $(srcdir)/noatunarts.idl
+
+mcoptypedir = $(libdir)/mcop
+mcoptype_DATA = noatunarts.mcoptype noatunarts.mcopclass
+
+mcopclassdir = $(libdir)/mcop/Noatun
+mcopclass_DATA = Equalizer.mcopclass FFTScopeStereo.mcopclass StereoEffectStack.mcopclass \
+ EqualizerSSE.mcopclass RawScope.mcopclass StereoVolumeControl.mcopclass \
+ FFTScope.mcopclass RawScopeStereo.mcopclass StereoVolumeControlSSE.mcopclass \
+ Session.mcopclass Listener.mcopclass
+
+noatuninclude_HEADERS= noatunarts.h
+
+noatunincludedir = $(includedir)/noatun
+
+DISTCLEANFILES = noatunarts.cc noatunarts.h noatunarts.mcopclass noatunarts.mcoptype
+
diff --git a/noatun/library/noatunarts/RawScope.mcopclass b/noatun/library/noatunarts/RawScope.mcopclass
new file mode 100644
index 00000000..fb3d95be
--- /dev/null
+++ b/noatun/library/noatunarts/RawScope.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::RawScope,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/RawScopeStereo.mcopclass b/noatun/library/noatunarts/RawScopeStereo.mcopclass
new file mode 100644
index 00000000..cad987ee
--- /dev/null
+++ b/noatun/library/noatunarts/RawScopeStereo.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::RawScopeStereo,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/Session.mcopclass b/noatun/library/noatunarts/Session.mcopclass
new file mode 100644
index 00000000..036b8409
--- /dev/null
+++ b/noatun/library/noatunarts/Session.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::Session,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/Session_impl.cpp b/noatun/library/noatunarts/Session_impl.cpp
new file mode 100644
index 00000000..63912801
--- /dev/null
+++ b/noatun/library/noatunarts/Session_impl.cpp
@@ -0,0 +1,82 @@
+#include "noatunarts.h"
+#include <list>
+#include <algorithm>
+
+using namespace Arts;
+using namespace std;
+
+static bool compareArtsObjects(const Noatun::Listener &left, const Noatun::Listener &right)
+{
+ return left._isEqual(right);
+}
+
+list<Noatun::Listener>::iterator find(list<Noatun::Listener> &v, const Noatun::Listener &is,
+ bool (*compare)(const Noatun::Listener& left, const Noatun::Listener& right))
+{
+ for (list<Noatun::Listener>::iterator i=v.begin(); i!=v.end(); ++i)
+ {
+ if ((*compare)(is, *i))
+ return i;
+ }
+
+ return v.end();
+}
+
+static void sendMessage(Noatun::Listener l)
+{
+ l.message();
+}
+
+namespace Noatun
+{
+
+class Session_impl : public Session_skel
+{
+ list<Listener> listeners;
+
+ long mPid;
+
+public:
+
+ ~Session_impl()
+ {
+ for_each(listeners.begin(), listeners.end(), sendMessage);
+ }
+
+ long pid() { return mPid; }
+ void pid(long p) { mPid=p; }
+
+
+ void addListener(Noatun::Listener listener)
+ {
+ listeners.push_back(listener);
+ }
+
+ void removeListener(Noatun::Listener listener)
+ {
+ list<Listener>::iterator i=
+ find(listeners, listener, &compareArtsObjects);
+ if (i!=listeners.end())
+ listeners.erase(i);
+ }
+
+};
+
+class Listener_impl : public Listener_skel
+{
+
+private:
+ virtual void message()
+ {
+ // hmm
+ }
+
+};
+
+
+REGISTER_IMPLEMENTATION(Session_impl);
+REGISTER_IMPLEMENTATION(Listener_impl);
+
+
+} // namespace Noatun
+
diff --git a/noatun/library/noatunarts/StereoEffectStack.mcopclass b/noatun/library/noatunarts/StereoEffectStack.mcopclass
new file mode 100644
index 00000000..71c9a9cf
--- /dev/null
+++ b/noatun/library/noatunarts/StereoEffectStack.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::StereoEffectStack,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/StereoEffectStack_impl.cpp b/noatun/library/noatunarts/StereoEffectStack_impl.cpp
new file mode 100644
index 00000000..684d9694
--- /dev/null
+++ b/noatun/library/noatunarts/StereoEffectStack_impl.cpp
@@ -0,0 +1,253 @@
+#include "noatunarts.h"
+
+#include <artsflow.h>
+#include <flowsystem.h>
+#include <stdsynthmodule.h>
+#include <debug.h>
+
+using namespace std;
+using namespace Arts;
+
+namespace Noatun
+{
+class StereoEffectStack_impl : public StereoEffectStack_skel, public StdSynthModule
+{
+ public:
+ long nextID;
+
+ struct EffectEntry
+ {
+ StereoEffect effect;
+ string name;
+ long id;
+ };
+ list<EffectEntry *> fx;
+
+ void xconnect(bool connect, Object from, string fromP, Object to, string toP)
+ {
+ if(connect)
+ from._node()->connect(fromP,to._node(),toP);
+ else
+ from._node()->disconnect(fromP,to._node(),toP);
+ }
+
+ void xvirtualize(bool connect, string myPort, Object impl, string implPort)
+ {
+ if(connect)
+ _node()->virtualize(myPort,impl._node(),implPort);
+ else
+ _node()->devirtualize(myPort,impl._node(),implPort);
+ }
+
+ void internalconnect(bool c)
+ {
+ if(fx.empty())
+ {
+ /* no effects - forward input through to output */
+ xvirtualize(c,"outleft",Object::_from_base(this->_copy()),"inleft");
+ xvirtualize(c,"outright",Object::_from_base(this->_copy()),"inright");
+ }
+ else
+ {
+ list<EffectEntry *>::iterator ei;
+ EffectEntry *laste = 0;
+
+ long count = 0;
+ for(ei = fx.begin(); ei != fx.end(); ei++, count++)
+ {
+ EffectEntry *e = *ei;
+ if(count == 0) /* top of chain? virtualize to effect */
+ {
+ xvirtualize(c,"inleft",e->effect,"inleft");
+ xvirtualize(c,"inright",e->effect,"inright");
+ }
+ else /* not top? connect last effect to current effect */
+ {
+ xconnect(c,laste->effect,"outleft",e->effect,"inleft");
+ xconnect(c,laste->effect,"outright",e->effect,"inright");
+ }
+ laste = e;
+ }
+ /* end: virtualize effect output to our output */
+ xvirtualize(c,"outleft",laste->effect,"outleft");
+ xvirtualize(c,"outright",laste->effect,"outright");
+ }
+ }
+ void disconnect() { internalconnect(false); }
+ void reconnect() { internalconnect(true); }
+
+
+ long insertAfter(long after, StereoEffect effect, const string &name)
+ {
+ arts_return_val_if_fail(!effect.isNull(),0);
+ disconnect();
+
+ list<EffectEntry*>::iterator i = fx.begin();
+
+ bool found=false;
+ // seek through until we find 'after'
+ while(i != fx.end())
+ if((*i)->id == after)
+ {
+ found = true;
+ break;
+ }
+ else
+ i++;
+
+ long newId=0;
+ if (found)
+ {
+ i++;
+ EffectEntry *e = new EffectEntry;
+ e->effect=effect;
+ e->name=name;
+ e->id=nextID++;
+ fx.insert(i, e);
+ newId=e->id;
+ }
+ else
+ arts_warning("StereoEffectStack::insertAfter failed. "
+ "id %d not found?", after);
+
+ reconnect();
+ return newId;
+
+ }
+
+ void move(long after, long item)
+ {
+ arts_return_if_fail(item != 0);
+ disconnect();
+
+ list<EffectEntry*>::iterator iAfter=fx.begin();
+ bool found=false;
+ if (after)
+ while(iAfter != fx.end())
+ if((*iAfter)->id == after)
+ {
+ found = true;
+ iAfter++;
+ break;
+ }
+ else
+ iAfter++;
+ else
+ found=true;
+
+ list<EffectEntry*>::iterator iItem=fx.begin();
+ while (iItem != fx.end())
+ if((*iItem)->id == item)
+ {
+ found &= true;
+ break;
+ }
+ else
+ iItem++;
+ if (!found)
+ arts_warning("StereoEffectStack::move couldn't find items");
+ else
+ {
+ fx.insert(iAfter, *iItem);
+ fx.erase(iItem);
+ }
+
+ reconnect();
+
+ }
+
+ vector<long> *effectList()
+ {
+ vector<long> *items=new vector<long>;
+ for (list<EffectEntry*>::iterator i=fx.begin(); i!=fx.end();i++)
+ items->push_back((*i)->id);
+ return items;
+ }
+
+ // as stolen from stereoeffectstack_impl.cc
+ StereoEffectStack_impl() : nextID(1)
+ {
+ reconnect();
+ }
+
+ ~StereoEffectStack_impl()
+ {
+ // disconnect remaining effects
+ EffectEntry *laste = 0;
+ list<EffectEntry *>::iterator ei;
+
+ for(ei = fx.begin(); ei != fx.end(); ei++)
+ {
+ EffectEntry *e = *ei;
+ if(laste)
+ {
+ xconnect(false,laste->effect,"outleft",e->effect,"inleft");
+ xconnect(false,laste->effect,"outright",e->effect,"inright");
+ }
+ laste = e;
+ }
+ // delete remaining effect entries
+ for(ei = fx.begin(); ei != fx.end(); ei++)
+ delete *ei;
+ fx.clear();
+ }
+ long insertTop(StereoEffect effect, const string& name)
+ {
+ arts_return_val_if_fail(!effect.isNull(),0);
+
+ disconnect();
+ EffectEntry *e = new EffectEntry();
+ e->effect = effect;
+ e->name = name;
+ e->id = nextID++;
+ fx.push_front(e);
+ reconnect();
+ return e->id;
+ }
+ long insertBottom(StereoEffect effect, const string& name)
+ {
+ arts_return_val_if_fail(!effect.isNull(),0);
+
+ disconnect();
+ EffectEntry *e = new EffectEntry();
+ e->effect = effect;
+ e->name = name;
+ e->id = nextID++;
+ fx.push_back(e);
+ reconnect();
+ return e->id;
+ }
+
+ void remove(long ID)
+ {
+ arts_return_if_fail(ID != 0);
+
+ bool found = false;
+ disconnect();
+ list<EffectEntry *>::iterator ei = fx.begin();
+
+ while(ei != fx.end())
+ {
+ if((*ei)->id == ID) {
+ found = true;
+ delete (*ei);
+ fx.erase(ei);
+ ei = fx.begin();
+ }
+ else ei++;
+ }
+ if(!found) {
+ arts_warning("StereoEffectStack::remove failed. id %d not found?",
+ ID);
+ }
+ reconnect();
+ }
+
+ AutoSuspendState autoSuspend() { return asSuspend; }
+
+};
+
+REGISTER_IMPLEMENTATION(StereoEffectStack_impl);
+
+}
+
diff --git a/noatun/library/noatunarts/StereoVolumeControl.mcopclass b/noatun/library/noatunarts/StereoVolumeControl.mcopclass
new file mode 100644
index 00000000..c4aded7e
--- /dev/null
+++ b/noatun/library/noatunarts/StereoVolumeControl.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::StereoVolumeControl,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/StereoVolumeControlSSE.mcopclass b/noatun/library/noatunarts/StereoVolumeControlSSE.mcopclass
new file mode 100644
index 00000000..9a979f30
--- /dev/null
+++ b/noatun/library/noatunarts/StereoVolumeControlSSE.mcopclass
@@ -0,0 +1,4 @@
+Interface=Noatun::StereoVolumeControlSSE,Arts::StereoEffect,Arts::Object
+Language=C++
+Library=libnoatunarts.la
+
diff --git a/noatun/library/noatunarts/StereoVolumeControl_impl.cpp b/noatun/library/noatunarts/StereoVolumeControl_impl.cpp
new file mode 100644
index 00000000..425704f6
--- /dev/null
+++ b/noatun/library/noatunarts/StereoVolumeControl_impl.cpp
@@ -0,0 +1,181 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <artsflow.h>
+#include <stdsynthmodule.h>
+#include <flowsystem.h>
+#include "noatunarts.h"
+
+using namespace Arts;
+
+namespace Noatun
+{
+
+class StereoVolumeControl_impl : virtual public StereoVolumeControl_skel,
+ virtual public StdSynthModule
+{
+ float mPercent;
+ float level;
+public:
+ StereoVolumeControl_impl() : mPercent(1.0), level(0.0)
+ { }
+
+ /*attribute float scaleFactor;*/
+ void percent(float p) { mPercent=p; }
+ float percent() { return mPercent; }
+
+ void calculateBlock(unsigned long samples)
+ {
+ register float *left=inleft;
+ register float *right=inright;
+ register float *oleft=outleft;
+ register float *oright=outright;
+
+ level = *right + *left;
+
+ register float p=mPercent;
+
+ register float *end=left+samples;
+
+ while (left<end)
+ {
+ *oleft=*left * p;
+ *oright=*right * p;
+
+ ++left;
+ ++right;
+ ++oleft;
+ ++oright;
+ }
+ }
+
+ AutoSuspendState autoSuspend()
+ {
+ return (level < 0.001) ? asSuspend : asNoSuspend;
+ }
+};
+
+class StereoVolumeControlSSE_impl : virtual public Noatun::StereoVolumeControlSSE_skel,
+ virtual public StdSynthModule
+{
+ float mPercent;
+ float level;
+
+public:
+ StereoVolumeControlSSE_impl() : mPercent(1.0), level(0.0)
+ { }
+
+ /*attribute float scaleFactor;*/
+ void percent(float p) { mPercent=p; }
+ float percent() { return mPercent; }
+
+ void calculateBlock(unsigned long samples)
+ {
+#ifdef HAVE_X86_SSE
+ float *left=inleft;
+ float *right=inright;
+ float *oleft=outleft;
+ float *oright=outright;
+
+ level = *right + *left;
+
+ // need to copy the data members to locals to get enough
+ // spare registers (malte)
+
+ long p = (long)(mPercent*100.0);
+ __asm__ __volatile__(
+ "pushl $100 \n"
+ "fildl (%%esp) \n"
+#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+ "addl $4, %%esp \n"
+#endif
+ "fildl %5 \n"
+ "fdivp \n" // percent / 100.0
+#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+ "pushl $100 \n"
+#endif
+ "fstps (%%esp) \n"
+ "movss (%%esp), %%xmm1 \n"
+ "shufps $0x00, %%xmm1, %%xmm1 \n" // percentage in all of xmm1
+ "addl $4, %%esp \n"
+#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+ "subl $4, %4 \n"
+ "jl .l2 \n" // samples < 4
+#else
+ "pushl %4 \n" // save sample count
+ "shrl $2, %4 \n"
+ "jz .l2 \n" // samples < 4
+#endif
+ "xorl %%ecx, %%ecx \n"
+
+ ".l1: \n"
+ // left
+ "movups (%0, %%ecx, 8), %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "movl %2, %%eax \n"
+ "movups %%xmm0, (%%eax, %%ecx, 8) \n"
+ // right
+ "movups (%1, %%ecx, 8), %%xmm0 \n"
+ "mulps %%xmm1, %%xmm0 \n"
+ "movl %3, %%eax \n"
+ "movups %%xmm0, (%%eax, %%ecx, 8) \n"
+
+ "incl %%ecx \n"
+ "incl %%ecx \n"
+#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)
+ "subl $4, %4 \n"
+ "jge .l1 \n"
+ ".l2: \n"
+ "addl $4, %4 \n"
+#else
+ "decl %4 \n"
+ "jnz .l1 \n"
+ ".l2: \n"
+ "popl %4 \n" // restore sample count
+ "andl $3, %4 \n"
+#endif
+ "jz .l4 \n"
+
+ // calculate remaining samples for samples % 4 != 0
+ "shll $1, %%ecx \n"
+ ".l3: \n"
+ "movss (%0, %%ecx, 4), %%xmm0 \n" // load left
+ "movss (%1, %%ecx, 4), %%xmm2 \n" // load right
+ "shufps $0x00, %%xmm2, %%xmm0 \n" // both channels in xmm0
+ "mulps %%xmm1, %%xmm0 \n"
+ "movl %2, %%eax \n"
+ "movss %%xmm0, (%%eax, %%ecx, 4) \n" // store left
+ "shufps $0x02, %%xmm0, %%xmm0 \n"
+ "movl %3, %%eax \n"
+ "movss %%xmm0, (%%eax, %%ecx, 4) \n" // store right
+ "incl %%ecx \n"
+ "decl %4 \n"
+ "jnz .l3 \n"
+
+ ".l4: \n"
+ "emms \n"
+ :
+ : "r" (left), // %0
+ "r" (right), // %1
+ "m" (oleft), // %2
+ "m" (oright), // %3
+ "r" (samples), // %4
+ "m" (p) // %5
+ : "eax", "ecx"
+ );
+#endif
+ }
+
+ AutoSuspendState autoSuspend()
+ {
+ return (level < 0.001) ? asSuspend : asNoSuspend;
+ }
+};
+
+REGISTER_IMPLEMENTATION(StereoVolumeControlSSE_impl);
+REGISTER_IMPLEMENTATION(StereoVolumeControl_impl);
+
+}
+
diff --git a/noatun/library/noatunarts/fft.c b/noatun/library/noatunarts/fft.c
new file mode 100644
index 00000000..86d647fb
--- /dev/null
+++ b/noatun/library/noatunarts/fft.c
@@ -0,0 +1,384 @@
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include "fft.h"
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ band pass filter for the Eq. This is a modification of Kai Lassfolk's work, as
+ removed from the Sound Processing Kit:
+
+ Sound Processing Kit - A C++ Class Library for Audio Signal Processing
+ Copyright (C) 1995-1998 Kai Lassfolk
+
+ 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; if not, write to the Free
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#define SAMPLERATE 44100
+
+#ifndef M_PI
+#define M_PI DDC_PI
+#endif
+
+void BandPassInit(struct BandPassInfo *ip, float center, float bw)
+{
+ ip->center = center;
+ ip->bandwidth = bw;
+
+ ip->C = 1.0 / tan(M_PI * bw / SAMPLERATE);
+ ip->D = 2 * cos(2 * M_PI * center / SAMPLERATE);
+
+ ip->a[0] = 1.0 / (1.0 + ip->C);
+ ip->a[1] = 0.0;
+ ip->a[2] = -ip->a[0];
+
+ ip->b[0] = -ip->C * ip->D * ip->a[0];
+ ip->b[1] = (ip->C - 1.0) * ip->a[0];
+
+ ip->bufferX[0] = ip->bufferX[1] = 0.0;
+ ip->bufferY[0] = ip->bufferY[1] = 0.0;
+}
+void BandPassSSE(struct BandPassInfo *ip, float *inbuffer, float *outbuffer, unsigned long samples)
+{
+#ifdef HAVE_X86_SSE
+ __asm__(
+ "testl %0, %0 \n"
+ "jz .l5 \n" /* if (!samples) */
+
+ "movl %1, %%ecx \n"
+ "movups 0x10(%%ecx), %%xmm2 \n" /* ip->a[0] */
+ "shufps $0x00, %%xmm2, %%xmm2 \n" /* ip->a[0] all over xmm3 */
+ "movups 0x14(%%ecx), %%xmm4 \n" /* xmm4 = {ip->a[1], ip->a[2], ip->b} */
+ "movups 0x24(%%ecx), %%xmm5 \n" /* xmm5 = {ip->bufferX, ip->bufferY} */
+ "xorl %%ecx, %%ecx \n" /* i = 0 */
+ "movl $1, %%edx \n" /* j = 1 */
+ "prefetcht0 (%2) \n"
+ ".l1: \n"
+
+ "decl %%edx \n" /* --j */
+ "jnz .l4 \n" /* if (j) */
+
+ /* only load single values if less than four remain in inbuffer */
+ "testl $0xfffffffc, %0 \n"
+ "jnz .l2 \n"
+ "movss (%2, %%ecx, 4), %%xmm3\n"
+ "movl $1, %%edx \n"
+ "jmp .l3 \n"
+ ".l2: \n"
+ /* {inbuffer[i], inbuffer[i+1], inbuffer[i+2], inbuffer[i+3]} * ip->a[0] */
+ "movups (%2, %%ecx, 4), %%xmm3\n"
+ "movl $3, %%edx \n" /* j = 3 */
+ ".l3: \n"
+ "movaps %%xmm3, %%xmm6 \n"
+ "mulps %%xmm2, %%xmm3 \n"
+ ".l4: \n"
+
+ /* {ip->a[1], ip->a[2], ip->b} * {ip->bufferX, ip->bufferY} */
+ "movaps %%xmm4, %%xmm0 \n"
+ "mulps %%xmm5, %%xmm0 \n"
+ "movaps %%xmm0, %%xmm1 \n"
+ /* xmm0 = {xmm0[0] + xmm0[1], <unused>, xmm0[2] + xmm0[3], <unused>} */
+ "shufps $0xb1, %%xmm0, %%xmm1 \n"
+ "addps %%xmm1, %%xmm0 \n"
+ /* xmm0[0] -= xmm0[2] */
+ "movhlps %%xmm0, %%xmm1 \n"
+ "subss %%xmm1, %%xmm0 \n"
+ "addss %%xmm3, %%xmm0 \n" /* xmm0[0] += inbuffer[i] * ip->a[0] */
+ "movss %%xmm0, (%3, %%ecx, 4)\n" /* outbuffer[i] = xmm0[0] */
+
+ /* xmm5 = {inbuffer[i], xmm5[0], outbuffer[i], xmm5[2]} */
+ "shufps $0x24, %%xmm5, %%xmm0 \n"
+ "shufps $0x81, %%xmm0, %%xmm5 \n"
+ "movss %%xmm6, %%xmm5 \n"
+
+ /* right-shift xmm3 (inbuffer * ip->a[0]) and xmm6 (inbuffer) */
+ "shufps $0x39, %%xmm3, %%xmm3 \n"
+ "shufps $0x39, %%xmm6, %%xmm6 \n"
+
+ "incl %%ecx \n" /* ++i */
+ "decl %0 \n"
+ "jnz .l1 \n"
+
+ "movl %1,%%ecx \n"
+ "movups %%xmm5, 0x24(%%ecx) \n" /* {ip->bufferX, ip->bufferY} = xmm5 */
+ "emms \n"
+ ".l5: \n"
+ :
+ : "r" (samples), /* %0 */
+ "m" (ip), /* %1 */
+ "r" (inbuffer), /* %2 */
+ "r" (outbuffer) /* %3 */
+ : "ecx", "edx");
+#endif
+}
+
+void BandPass(struct BandPassInfo *ip, float *inbuffer, float *outbuffer, unsigned long samples)
+{
+ unsigned long i;
+ for (i=0; i<samples; ++i)
+ {
+ outbuffer[i] = ip->a[0] * inbuffer[i] + ip->a[1] * ip->bufferX[0] + ip->a[2]
+ * ip->bufferX[1] - ip->b[0] * ip->bufferY[0] - ip->b[1]
+ * ip->bufferY[1];
+
+ ip->bufferX[1] = ip->bufferX[0];
+ ip->bufferX[0] = inbuffer[i];
+ ip->bufferY[1] = ip->bufferY[0];
+ ip->bufferY[0] = outbuffer[i];
+ }
+}
+
+
+/*============================================================================
+
+ fftmisc.c - Don Cross <dcross@intersrv.com>
+
+ http://www.intersrv.com/~dcross/fft.html
+
+ Helper routines for Fast Fourier Transform implementation.
+ Contains common code for fft_float() and fft_double().
+
+ See also:
+ fourierf.c
+ fourierd.c
+ ..\include\fourier.h
+
+ Revision history:
+
+1998 September 19 [Don Cross]
+ Improved the efficiency of IsPowerOfTwo().
+ Updated coding standards.
+
+============================================================================*/
+
+
+#define BITS_PER_WORD (sizeof(unsigned) * 8)
+
+
+static int IsPowerOfTwo ( unsigned x )
+{
+ if ( x < 2 )
+ return FALSE;
+
+ if ( x & (x-1) ) /* Thanks to 'byang' for this cute trick! */
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static unsigned NumberOfBitsNeeded ( unsigned PowerOfTwo )
+{
+ unsigned i;
+
+ if ( PowerOfTwo < 2 )
+ {
+ fprintf (
+ stderr,
+ ">>> Error in fftmisc.c: argument %d to NumberOfBitsNeeded is too small.\n",
+ PowerOfTwo );
+
+ exit(1);
+ }
+
+ for ( i=0; ; i++ )
+ {
+ if ( PowerOfTwo & (1 << i) )
+ return i;
+ }
+}
+
+
+
+static unsigned ReverseBits ( unsigned ind, unsigned NumBits )
+{
+ unsigned i, rev;
+
+ for ( i=rev=0; i < NumBits; i++ )
+ {
+ rev = (rev << 1) | (ind & 1);
+ ind >>= 1;
+ }
+
+ return rev;
+}
+
+/*
+static double Index_to_frequency ( unsigned NumSamples, unsigned Index )
+{
+ if ( Index >= NumSamples )
+ return 0.0;
+ else if ( Index <= NumSamples/2 )
+ return (double)Index / (double)NumSamples;
+
+ return -(double)(NumSamples-Index) / (double)NumSamples;
+}
+*/
+#undef TRUE
+#undef FALSE
+#undef BITS_PER_WORD
+/*============================================================================
+
+ fourierf.c - Don Cross <dcross@intersrv.com>
+
+ http://www.intersrv.com/~dcross/fft.html
+
+ Contains definitions for doing Fourier transforms
+ and inverse Fourier transforms.
+
+ This module performs operations on arrays of 'float'.
+
+ Revision history:
+
+1998 September 19 [Don Cross]
+ Updated coding standards.
+ Improved efficiency of trig calculations.
+
+============================================================================*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "fft.h"
+
+#define CHECKPOINTER(p) CheckPointer(p,#p)
+
+static void CheckPointer ( const void *p, const char *name )
+{
+ if ( p == NULL )
+ {
+ fprintf ( stderr, "Error in fft_float(): %s == NULL\n", name );
+ exit(1);
+ }
+}
+
+
+void fft_float (
+ unsigned NumSamples,
+ int InverseTransform,
+ float *RealIn,
+ float *ImagIn,
+ float *RealOut,
+ float *ImagOut )
+{
+ unsigned NumBits; /* Number of bits needed to store indices */
+ unsigned i, j, k, n;
+ unsigned BlockSize, BlockEnd;
+
+ double angle_numerator = 2.0 * DDC_PI;
+ double tr, ti; /* temp real, temp imaginary */
+
+ if ( !IsPowerOfTwo(NumSamples) )
+ {
+ fprintf (
+ stderr,
+ "Error in fft(): NumSamples=%u is not power of two\n",
+ NumSamples );
+
+ exit(1);
+ }
+
+ if ( InverseTransform )
+ angle_numerator = -angle_numerator;
+
+ CHECKPOINTER ( RealIn );
+ CHECKPOINTER ( RealOut );
+ CHECKPOINTER ( ImagOut );
+
+ NumBits = NumberOfBitsNeeded ( NumSamples );
+
+ /*
+ ** Do simultaneous data copy and bit-reversal ordering into outputs...
+ */
+
+ for ( i=0; i < NumSamples; i++ )
+ {
+ j = ReverseBits ( i, NumBits );
+ RealOut[j] = RealIn[i];
+ ImagOut[j] = (ImagIn == NULL) ? 0.0 : ImagIn[i];
+ }
+
+ /*
+ ** Do the FFT itself...
+ */
+
+ BlockEnd = 1;
+ for ( BlockSize = 2; BlockSize <= NumSamples; BlockSize <<= 1 )
+ {
+ double delta_angle = angle_numerator / (double)BlockSize;
+ double sm2 = sin ( -2 * delta_angle );
+ double sm1 = sin ( -delta_angle );
+ double cm2 = cos ( -2 * delta_angle );
+ double cm1 = cos ( -delta_angle );
+ double w = 2 * cm1;
+ double ar[3], ai[3];
+
+ for ( i=0; i < NumSamples; i += BlockSize )
+ {
+ ar[2] = cm2;
+ ar[1] = cm1;
+
+ ai[2] = sm2;
+ ai[1] = sm1;
+
+ for ( j=i, n=0; n < BlockEnd; j++, n++ )
+ {
+ ar[0] = w*ar[1] - ar[2];
+ ar[2] = ar[1];
+ ar[1] = ar[0];
+
+ ai[0] = w*ai[1] - ai[2];
+ ai[2] = ai[1];
+ ai[1] = ai[0];
+
+ k = j + BlockEnd;
+ tr = ar[0]*RealOut[k] - ai[0]*ImagOut[k];
+ ti = ar[0]*ImagOut[k] + ai[0]*RealOut[k];
+
+ RealOut[k] = RealOut[j] - tr;
+ ImagOut[k] = ImagOut[j] - ti;
+
+ RealOut[j] += tr;
+ ImagOut[j] += ti;
+ }
+ }
+
+ BlockEnd = BlockSize;
+ }
+
+ /*
+ ** Need to normalize if inverse transform...
+ */
+
+ if ( InverseTransform )
+ {
+ double denom = (double)NumSamples;
+
+ for ( i=0; i < NumSamples; i++ )
+ {
+ RealOut[i] /= denom;
+ ImagOut[i] /= denom;
+ }
+ }
+}
+
+
diff --git a/noatun/library/noatunarts/fft.h b/noatun/library/noatunarts/fft.h
new file mode 100644
index 00000000..e7f7804d
--- /dev/null
+++ b/noatun/library/noatunarts/fft.h
@@ -0,0 +1,88 @@
+#ifndef FFT_H
+#define FFT_H
+
+
+
+/* this is from ddcmath.h */
+
+#define DDC_PI (3.14159265358979323846)
+
+/*============================================================================
+
+ fourier.h - Don Cross <dcross@intersrv.com>
+
+ http://www.intersrv.com/~dcross/fft.html
+
+ Contains definitions for doing Fourier transforms
+ and inverse Fourier transforms.
+
+============================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** If you change anything here, make sure to check if
+** the offsets used in the asm version of BandPass() are affected
+*/
+struct BandPassInfo
+{
+ float center;
+ float bandwidth;
+
+ float C, D;
+ float a[3], b[2];
+
+ float bufferX[2];
+ float bufferY[2];
+
+};
+
+void BandPassInit(struct BandPassInfo *i, float center, float bw);
+void BandPassSSE(struct BandPassInfo *ip, float *inbuffer, float *outbuffer, unsigned long samples);
+void BandPass(struct BandPassInfo *ip, float *inbuffer, float *outbuffer, unsigned long samples);
+
+/*
+** fft() computes the Fourier transform or inverse transform
+** of the complex inputs to produce the complex outputs.
+** The number of samples must be a power of two to do the
+** recursive decomposition of the FFT algorithm.
+** See Chapter 12 of "Numerical Recipes in FORTRAN" by
+** Press, Teukolsky, Vetterling, and Flannery,
+** Cambridge University Press.
+**
+** Notes: If you pass ImaginaryIn = NULL, this function will "pretend"
+** that it is an array of all zeroes. This is convenient for
+** transforming digital samples of real number data without
+** wasting memory.
+*/
+
+void fft_float (
+ unsigned NumSamples, /* must be a power of 2 */
+ int InverseTransform, /* 0=forward FFT, 1=inverse FFT */
+ float *RealIn, /* array of input's real samples */
+ float *ImaginaryIn, /* array of input's imag samples */
+ float *RealOut, /* array of output's reals */
+ float *ImaginaryOut ); /* array of output's imaginaries */
+
+
+/*
+int IsPowerOfTwo ( unsigned x );
+unsigned NumberOfBitsNeeded ( unsigned PowerOfTwo );
+unsigned ReverseBits ( unsigned index, unsigned NumBits );
+*/
+
+/*
+** The following function returns an "abstract frequency" of a
+** given index into a buffer with a given number of frequency samples.
+** Multiply return value by sampling rate to get frequency expressed in Hz.
+*/
+/*
+double Index_to_frequency ( unsigned NumSamples, unsigned Index );
+*/
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* FFT_H */
diff --git a/noatun/library/noatunarts/noatunarts.idl b/noatun/library/noatunarts/noatunarts.idl
new file mode 100644
index 00000000..809e2bb6
--- /dev/null
+++ b/noatun/library/noatunarts/noatunarts.idl
@@ -0,0 +1,91 @@
+#include <artsflow.idl>
+
+module Noatun
+{
+
+interface Equalizer : Arts::StereoEffect
+{
+ attribute sequence<float> levelCenters;
+ attribute sequence<float> levelWidths;
+ attribute sequence<float> levels;
+
+ attribute long bands;
+ attribute long enabled;
+ attribute float preamp;
+ void set(sequence<float> levels, sequence<float> centers, sequence<float> widths);
+};
+
+interface EqualizerSSE : Arts::StereoEffect
+{
+ attribute sequence<float> levelCenters;
+ attribute sequence<float> levelWidths;
+ attribute sequence<float> levels;
+
+ attribute long bands;
+ attribute long enabled;
+ attribute float preamp;
+ void set(sequence<float> levels, sequence<float> centers, sequence<float> widths);
+};
+
+interface FFTScope : Arts::StereoEffect
+{
+ attribute float bandResolution;
+ sequence<float> scope();
+};
+
+interface FFTScopeStereo : Arts::StereoEffect
+{
+ attribute float bandResolution;
+ sequence<float> scopeRight();
+ sequence<float> scopeLeft();
+};
+
+interface RawScope : Arts::StereoEffect
+{
+ attribute long buffer;
+ sequence<float> scope();
+};
+
+interface RawScopeStereo : Arts::StereoEffect
+{
+ attribute long buffer;
+ sequence<float> scopeLeft();
+ sequence<float> scopeRight();
+};
+
+interface StereoEffectStack : Arts::StereoEffect
+{
+ long insertAfter(long after, Arts::StereoEffect effect, string name);
+ void move(long after, long item);
+ sequence<long> effectList();
+ long insertTop(Arts::StereoEffect effect, string name);
+ long insertBottom(Arts::StereoEffect effect, string name);
+ void remove(long ID);
+};
+
+interface StereoVolumeControl : Arts::StereoEffect
+{
+ attribute float percent;
+};
+
+interface StereoVolumeControlSSE : Arts::StereoEffect
+{
+ attribute float percent;
+};
+
+interface Listener
+{
+ void message();
+};
+
+interface Session
+{
+ attribute long pid;
+ void addListener(Noatun::Listener listener);
+ void removeListener(Noatun::Listener listener);
+};
+
+
+};
+
+