diff options
Diffstat (limited to 'noatun/library/noatunarts')
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); +}; + + +}; + + |