diff options
42 files changed, 1198 insertions, 780 deletions
diff --git a/clear_cmake.sh b/clear_cmake.sh index 39e89ad7e..0da6e463f 100755 --- a/clear_cmake.sh +++ b/clear_cmake.sh @@ -60,4 +60,10 @@ cd Visual clear cd analyzer clear - +#clear effect +cd .. +cd .. +cd Effect +clear +cd srconverter +clear diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f1bfd39e2..79edd7152 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -28,6 +28,7 @@ SET(libqmmp_SRCS soundcore.cpp streamreader.cpp downloader.cpp + effect.cpp ) SET(libqmmp_MOC_HDRS @@ -46,6 +47,8 @@ SET(libqmmp_MOC_HDRS soundcore.h streamreader.h downloader.h + effectfactory.h + effect.h ) QT4_WRAP_CPP(libqmmp_MOC_SRCS ${libqmmp_MOC_HDRS}) diff --git a/lib/buffer.h b/lib/buffer.h index b04ea0ed8..c5ffadc0c 100644 --- a/lib/buffer.h +++ b/lib/buffer.h @@ -9,27 +9,34 @@ #include "constants.h" -class Buffer { +class Buffer +{ public: Buffer() { - data = new unsigned char[Buffer::size()]; - nbytes = 0; - rate = 0; + data = new unsigned char[Buffer::size()]; + nbytes = 0; + rate = 0; + exceeding = 0; } ~Buffer() { - delete data; - data = 0; - nbytes = 0; - rate = 0; + delete data; + data = 0; + nbytes = 0; + rate = 0; + exceeding = 0; } unsigned char *data; unsigned long nbytes; unsigned long rate; + unsigned long exceeding; - static unsigned long size() { return globalBlockSize; } + static unsigned long size() + { + return globalBlockSize; + } }; diff --git a/lib/decoder.cpp b/lib/decoder.cpp index d3beda1a1..4ae0637c7 100644 --- a/lib/decoder.cpp +++ b/lib/decoder.cpp @@ -8,35 +8,44 @@ #include <QStringList> #include <QApplication> #include <QSettings> +#include <math.h> +#include "effect.h" +#include "effectfactory.h" + #include "constants.h" #include "buffer.h" #include "output.h" #include "visual.h" #include "decoderfactory.h" #include "streamreader.h" -extern "C"{ -#include "equ/iir.h" +extern "C" +{ +#include "equ/iir.h" } #include "decoder.h" Decoder::Decoder(QObject *parent, DecoderFactory *d, QIODevice *i, Output *o) - : QThread(parent), fctry(d), in(i), out(o), blksize(0),m_eqInited(FALSE), + : QThread(parent), fctry(d), in(i), m_output(o),m_eqInited(FALSE), m_useEQ(FALSE) { - out->recycler()->clear(); + m_output->recycler()->clear(); int b[] = {0,0,0,0,0,0,0,0,0,0}; setEQ(b, 0); qRegisterMetaType<DecoderState>("DecoderState"); + + + blksize = Buffer::size(); + m_effects = Effect::create(this); } Decoder::~Decoder() { fctry = 0; in = 0; - out = 0; + m_output = 0; blksize = 0; } @@ -138,16 +147,16 @@ Decoder *Decoder::create(QObject *parent, const QString &source, qDebug(qPrintable(source)); DecoderFactory *fact = 0; - if(!input->open(QIODevice::ReadOnly)) + if (!input->open(QIODevice::ReadOnly)) { qDebug("Decoder: cannot open input"); return decoder; - } + } StreamReader* sreader = qobject_cast<StreamReader *>(input); - if(sreader) + if (sreader) { fact = Decoder::findByMime(sreader->contentType()); - if(!fact) + if (!fact) fact = Decoder::findByContent(sreader); } else @@ -157,7 +166,7 @@ Decoder *Decoder::create(QObject *parent, const QString &source, { decoder = fact->create(parent, input, output); } - if(!decoder) + if (!decoder) input->close(); return decoder; @@ -187,9 +196,9 @@ DecoderFactory *Decoder::findByMime(const QString& type) if (!blacklist.contains(files.at(i).section('/',-1))) { QStringList types = factories->at(i)->properties().contentType.split(";"); - for(int j=0; j<types.size(); ++j) + for (int j=0; j<types.size(); ++j) { - if(type == types[j] && !types[j].isEmpty()) + if (type == types[j] && !types[j].isEmpty()) return factories->at(i); } } @@ -290,7 +299,6 @@ void Decoder::error(const QString &e) ulong Decoder::produceSound(char *data, ulong output_bytes, ulong bitrate, int nch) { ulong sz = output_bytes < blksize ? output_bytes : blksize; - Buffer *b = output()->recycler()->get(); if (!m_eqInited) { @@ -301,12 +309,38 @@ ulong Decoder::produceSound(char *data, ulong output_bytes, ulong bitrate, int n { iir((void*) data,sz,nch); } - memcpy(b->data, data, sz); - if (sz != blksize) - memset(b->data + sz, 0, blksize - sz); + char *out_data = data; + char *prev_data = data; + ulong w = sz; + Effect* effect = 0; + foreach(effect, m_effects) + { + w = effect->process(prev_data, sz, &out_data); + + if(w <= 0) + { + // copy data if plugin can not procees it + w = sz; + out_data = new char[w]; + memcpy(out_data, prev_data, w); + } + if(data != prev_data) + delete prev_data; + prev_data = out_data; + } - b->nbytes = blksize; + Buffer *b = output()->recycler()->get(w); + + memcpy(b->data, out_data, w); + + if (data != out_data) + delete out_data; + + if (w < blksize + b->exceeding) + memset(b->data + w, 0, blksize + b->exceeding - w); + + b->nbytes = w;// blksize; b->rate = bitrate; output()->recycler()->add(); @@ -316,6 +350,20 @@ ulong Decoder::produceSound(char *data, ulong output_bytes, ulong bitrate, int n return sz; } +void Decoder::configure(long freq, int channels, int prec, int bitrate) +{ + Effect* effect = 0; + foreach(effect, m_effects) + { + effect->configure(freq, channels, prec); + freq = m_effects.at(0)->frequency(); + channels = effect->channels(); + prec = effect->resolution(); + } + if (m_output) + m_output->configure(freq, channels, prec, bitrate); +} + void Decoder::setEQ(int bands[10], int preamp) { set_preamp(0, 1.0 + 0.0932471 *preamp + 0.00279033 * preamp * preamp); diff --git a/lib/decoder.h b/lib/decoder.h index de1e2d00a..97a3e1da6 100644 --- a/lib/decoder.h +++ b/lib/decoder.h @@ -14,7 +14,6 @@ #include <QObject> #include <QStringList> - #include "filetag.h" class QObject; @@ -26,6 +25,7 @@ class Buffer; class Recycler; class Output; class Visualization; +class Effect; @@ -47,7 +47,7 @@ public: DecoderState(Type t) : m_type(t), m_error_msg(0), m_tag(0) - {} +{} DecoderState(const QString &e) : m_type(Error), m_tag(0) @@ -119,7 +119,7 @@ public: } Output *output() { - return out; + return m_output; } QMutex *mutex() @@ -165,6 +165,7 @@ signals: void stateChanged(const DecoderState&); protected: + void configure(long freq, int channels, int prec, int bitrate); void dispatch(DecoderState::Type); void dispatch(const DecoderState&); void dispatch(const FileTag&); @@ -173,9 +174,9 @@ protected: private: DecoderFactory *fctry; - QList<QObject*> listeners; + QList <Effect*> m_effects; QIODevice *in; - Output *out; + Output *m_output; QMutex mtx; QWaitCondition cnd; @@ -183,6 +184,7 @@ private: uint blksize; bool m_eqInited; bool m_useEQ; + }; #endif // DECODER_H diff --git a/lib/effect.cpp b/lib/effect.cpp new file mode 100644 index 000000000..c6d3ba0fb --- /dev/null +++ b/lib/effect.cpp @@ -0,0 +1,148 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include <QtGui> +#include <QStringList> +#include <QDir> +#include <QApplication> + +#include "effectfactory.h" +#include "constants.h" +#include "effect.h" + +Effect::Effect(QObject *parent) + : QObject(parent) +{} + +Effect::~Effect() +{} + +void Effect::configure(ulong freq, int chan, int res) +{ + m_freq = freq; + m_chan = chan; + m_res = res; + +} + +const ulong Effect::frequency() +{ + return m_freq; +} + +const int Effect::channels() +{ + return m_chan; +} + +const int Effect::resolution() +{ + return m_res; +} + +static QList<EffectFactory*> *factories = 0; +static QStringList files; + +static void checkFactories() +{ + if (! factories) + { + files.clear(); + factories = new QList<EffectFactory *>; + + QDir pluginsDir (qApp->applicationDirPath()); + pluginsDir.cdUp(); + pluginsDir.cd("./"LIB_DIR"/qmmp/Effect"); + foreach (QString fileName, pluginsDir.entryList(QDir::Files)) + { + QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); + QObject *plugin = loader.instance(); + if (loader.isLoaded()) + { + qDebug("Effect: plugin loaded - %s", qPrintable(fileName)); + } + EffectFactory *factory = 0; + if (plugin) + factory = qobject_cast<EffectFactory *>(plugin); + + if (factory) + { + factories->append(factory); + files << pluginsDir.absoluteFilePath(fileName); + } + } + } +} + +QList<Effect*> Effect::create(QObject *parent) +{ + checkFactories(); + QList<Effect*> effects; + EffectFactory *factory = 0; + foreach (factory, *factories) + { + if(isEnabled(factory)) + effects.append(factory->create(parent)); + } + return effects; +} + +QList<EffectFactory*> *Effect::effectFactories() +{ + checkFactories(); + return factories; +} + +QStringList Effect::effectFiles() +{ + checkFactories(); + return files; +} + +void Effect::setEnabled(EffectFactory* factory, bool enable) +{ + checkFactories(); + if(!factories->contains(factory)) + return; + + QString name = files.at(factories->indexOf(factory)).section('/',-1); + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + QStringList effList = settings.value("Effect/plugin_files").toStringList(); + + if(enable) + { + if (!effList.contains(name)) + effList << name; + } + else + effList.removeAll(name); + settings.setValue("Effect/plugin_files", effList); +} + +bool Effect::isEnabled(EffectFactory* factory) +{ + checkFactories(); + if(!factories->contains(factory)) + return FALSE; + QString name = files.at(factories->indexOf(factory)).section('/',-1); + QSettings settings ( QDir::homePath() +"/.qmmp/qmmprc", QSettings::IniFormat ); + QStringList effList = settings.value("Effect/plugin_files").toStringList(); + return effList.contains(name); +} + diff --git a/lib/effect.h b/lib/effect.h new file mode 100644 index 000000000..654c1c2b6 --- /dev/null +++ b/lib/effect.h @@ -0,0 +1,87 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EFFECT_H +#define EFFECT_H + +#include <QObject> +#include <QList> +#include <QStringList> + + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class EffectFactory; + +class Effect : public QObject +{ + Q_OBJECT +public: + Effect(QObject *parent = 0); + + virtual ~Effect(); + + /*/*! + * Adds effect to the input data pointer \b in_data with the size \b size. + * Result is stored in the output data \b out_data. + * Return value is the size of the output data. Output data size should not be more then \b size. + * Subclass should implement this function. + */ + virtual const ulong process(char *in_data, const ulong size, char **out_data) = 0; + + //virtual const ulong process(char *in_data, const ulong size, char *out_data) = 0; + //virtual bool process(char *in_data, char *out_data, const ulong maxsize, ulong &rbytes, ulong &wbytes) = 0; + + + virtual void configure(ulong freq, int chan, int res); + + /*! + * Returns frequency. + * This function should be reimplemented if subclass changes default samplerate. + */ + virtual const ulong frequency(); + + /*! + * Returns channel number. + * This function should be reimplemented if subclass changes default channel number. + */ + virtual const int channels(); + + /*! + * Returns resolution. + * This function should be reimplemented if subclass changes default resolution. + */ + virtual const int resolution(); + + + static QList<Effect*> create(QObject *parent); + static QList<EffectFactory*> *effectFactories(); + static QStringList effectFiles(); + static void setEnabled(EffectFactory* factory, bool enable = TRUE); + static bool isEnabled(EffectFactory* factory); + +private: + ulong m_freq; + int m_chan; + int m_res; +}; + +#endif diff --git a/lib/effectfactory.h b/lib/effectfactory.h new file mode 100644 index 000000000..96354cf6e --- /dev/null +++ b/lib/effectfactory.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EFFECTFACTORY_H +#define EFFECTFACTORY_H + +#include <QObject> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class QObject; +class QWidget; +class QTranslator; + +class Effect; + +struct EffectProperties +{ + QString name; + bool hasAbout; + bool hasSettings; +}; + +class EffectFactory +{ +public: + virtual const EffectProperties properties() const = 0; + virtual Effect *create(QObject *parent) = 0; + virtual void showSettings(QWidget *parent) = 0; + virtual void showAbout(QWidget *parent) = 0; + virtual QTranslator *createTranslator(QObject *parent) = 0; +}; + +Q_DECLARE_INTERFACE(EffectFactory, "EffectFactory/1.0"); + +#endif diff --git a/lib/iir.c b/lib/iir.c deleted file mode 100644 index 317fce8e4..000000000 --- a/lib/iir.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * PCM time-domain equalizer - * - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users sourceforge net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: iir.c,v 1.15 2005/10/17 01:57:59 liebremx Exp $ - */ - -#include <math.h> -#include "iir.h" - -/* Coefficients */ -sIIRCoefficients *iir_cf; - -/* Volume gain - * values should be between 0.0 and 1.0 - * Use the preamp from XMMS for now - * */ -float preamp[EQ_CHANNELS]; - -#ifdef BENCHMARK -#include "benchmark.h" -double timex = 0.0; -int count = 0; -unsigned int blength = 0; -#endif - -/* - * Global vars - */ -int rate; -int band_count; - -void set_preamp(int chn, float val) -{ - preamp[chn] = val; -} - -/* Init the filters */ -void init_iir() -{ - calc_coeffs(); -#if 0 - band_count = cfg.band_num; -#endif - - band_count = 10; - - rate = 44100; - - iir_cf = get_coeffs(&band_count, rate, TRUE); - clean_history(); -} - -#ifdef ARCH_X86 -/* Round function provided by Frank Klemm which saves around 100K - * CPU cycles in my PIII for each call to the IIR function with 4K samples - */ -__inline__ int round_trick(float floatvalue_to_round) -{ - float floattmp ; - int rounded_value ; - - floattmp = (int) 0x00FD8000L + (floatvalue_to_round); - rounded_value = *(int*)(&floattmp) - (int)0x4B7D8000L; - - if ( rounded_value != (short) rounded_value ) - rounded_value = ( rounded_value >> 31 ) ^ 0x7FFF; - return rounded_value; -} -#endif diff --git a/lib/iir.h b/lib/iir.h deleted file mode 100644 index de6fa04e5..000000000 --- a/lib/iir.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * PCM time-domain equalizer - * - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: iir.h,v 1.12 2005/10/17 01:57:59 liebremx Exp $ - */ -#ifndef IIR_H -#define IIR_H - -//#include <glib.h> -//#include "main.h" -#include "iir_cfs.h" - -/* - * Flush-to-zero to avoid flooding the CPU with underflow exceptions - */ -#ifdef SSE_MATH -#define FTZ 0x8000 -#define FTZ_ON { \ - unsigned int mxcsr; \ - __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \ - mxcsr |= FTZ; \ - __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \ -} -#define FTZ_OFF { \ - unsigned int mxcsr; \ - __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); \ - mxcsr &= ~FTZ; \ - __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); \ -} -#else -#define FTZ_ON -#define FTZ_OFF -#endif - -/* - * Function prototypes - */ -void init_iir(); -void clean_history(); -void set_gain(int index, int chn, float val); -void set_preamp(int chn, float val); - - -__inline__ int iir(void *d, int length, int nch); - -#ifdef ARCH_X86 -__inline__ int round_trick(float floatvalue_to_round); -#endif -#ifdef ARCH_PPC -__inline__ int round_ppc(float x); -#endif - -#define EQ_CHANNELS 2 -#define EQ_MAX_BANDS 10 - -extern float preamp[EQ_CHANNELS]; -extern sIIRCoefficients *iir_cf; -extern int rate; -extern int band_count; - -#ifdef BENCHMARK -extern double timex; -extern int count; -extern unsigned int blength; -#endif - -#endif /* #define IIR_H */ - diff --git a/lib/iir_cfs.c b/lib/iir_cfs.c deleted file mode 100644 index 88ecbadc6..000000000 --- a/lib/iir_cfs.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Coefficient stuff - * - * $Id: iir_cfs.c,v 1.1 2005/10/17 01:57:59 liebremx Exp $ - */ - -#include "iir_cfs.h" -#include <stdio.h> -#include <math.h> - -/*************************** - * IIR filter coefficients * - ***************************/ -static sIIRCoefficients iir_cf10_11k_11025[10] __attribute__((aligned)); -static sIIRCoefficients iir_cf10_22k_22050[10] __attribute__((aligned)); -static sIIRCoefficients iir_cforiginal10_44100[10] __attribute__((aligned)); -static sIIRCoefficients iir_cforiginal10_48000[10] __attribute__((aligned)); -static sIIRCoefficients iir_cf10_44100[10] __attribute__((aligned)); -static sIIRCoefficients iir_cf10_48000[10] __attribute__((aligned)); -static sIIRCoefficients iir_cf15_44100[15] __attribute__((aligned)); -static sIIRCoefficients iir_cf15_48000[15] __attribute__((aligned)); -static sIIRCoefficients iir_cf25_44100[25] __attribute__((aligned)); -static sIIRCoefficients iir_cf25_48000[25] __attribute__((aligned)); -static sIIRCoefficients iir_cf31_44100[31] __attribute__((aligned)); -static sIIRCoefficients iir_cf31_48000[31] __attribute__((aligned)); - -/****************************************************************** - * Definitions and data structures to calculate the coefficients - ******************************************************************/ -static const double band_f011k[] = -{ 31, 62, 125, 250, 500, 1000, 2000, 3000, 4000, 5500 -}; -static const double band_f022k[] = -{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 11000 -}; -static const double band_f010[] = -{ 31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000 -}; -static const double band_original_f010[] = -{ 60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000 -}; -static const double band_f015[] = -{ 25,40,63,100,160,250,400,630,1000,1600,2500,4000,6300,10000,16000 -}; -static const double band_f025[] = -{ 20,31.5,40,50,80,100,125,160,250,315,400,500,800, - 1000,1250,1600,2500,3150,4000,5000,8000,10000,12500,16000,20000 -}; -static const double band_f031[] = -{ 20,25,31.5,40,50,63,80,100,125,160,200,250,315,400,500,630,800, - 1000,1250,1600,2000,2500,3150,4000,5000,6300,8000,10000,12500,16000,20000 -}; - -#define GAIN_F0 1.0 -#define GAIN_F1 GAIN_F0 / M_SQRT2 - -#define SAMPLING_FREQ 44100.0 -#define TETA(f) (2*M_PI*(double)f/bands[n].sfreq) -#define TWOPOWER(value) (value * value) - -#define BETA2(tf0, tf) \ -(TWOPOWER(GAIN_F1)*TWOPOWER(cos(tf0)) \ - - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \ - + TWOPOWER(GAIN_F1) \ - - TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf))) -#define BETA1(tf0, tf) \ - (2.0 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf)) \ - + TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \ - - 2.0 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \ - - TWOPOWER(GAIN_F1) + TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf))) -#define BETA0(tf0, tf) \ - (0.25 * TWOPOWER(GAIN_F1) * TWOPOWER(cos(tf0)) \ - - 0.5 * TWOPOWER(GAIN_F1) * cos(tf) * cos(tf0) \ - + 0.25 * TWOPOWER(GAIN_F1) \ - - 0.25 * TWOPOWER(GAIN_F0) * TWOPOWER(sin(tf))) - -#define GAMMA(beta, tf0) ((0.5 + beta) * cos(tf0)) -#define ALPHA(beta) ((0.5 - beta)/2.0) - -struct { - sIIRCoefficients *coeffs; - const double *cfs; - double octave; - int band_count; - double sfreq; -} bands[] = { - { iir_cf10_11k_11025, band_f011k, 1.0, 10, 11025.0 }, - { iir_cf10_22k_22050, band_f022k, 1.0, 10, 22050.0 }, - { iir_cforiginal10_44100, band_original_f010, 1.0, 10, 44100.0 }, - { iir_cforiginal10_48000, band_original_f010, 1.0, 10, 48000.0 }, - { iir_cf10_44100, band_f010, 1.0, 10, 44100.0 }, - { iir_cf10_48000, band_f010, 1.0, 10, 48000.0 }, - { iir_cf15_44100, band_f015, 2.0/3.0, 15, 44100.0 }, - { iir_cf15_48000, band_f015, 2.0/3.0, 15, 48000.0 }, - { iir_cf25_44100, band_f025, 1.0/3.0, 25, 44100.0 }, - { iir_cf25_48000, band_f025, 1.0/3.0, 25, 48000.0 }, - { iir_cf31_44100, band_f031, 1.0/3.0, 31, 44100.0 }, - { iir_cf31_48000, band_f031, 1.0/3.0, 31, 48000.0 }, - { 0, 0, 0, 0, 0 } -}; - -/************* - * Functions * - *************/ - -/* Get the coeffs for a given number of bands and sampling frequency */ -sIIRCoefficients* get_coeffs(gint *bands, gint sfreq, gboolean use_xmms_original_freqs) -{ - sIIRCoefficients *iir_cf = 0; - switch(sfreq) - { - case 11025: iir_cf = iir_cf10_11k_11025; - *bands = 10; - break; - case 22050: iir_cf = iir_cf10_22k_22050; - *bands = 10; - break; - case 48000: - switch(*bands) - { - case 31: iir_cf = iir_cf31_48000; break; - case 25: iir_cf = iir_cf25_48000; break; - case 15: iir_cf = iir_cf15_48000; break; - default: - iir_cf = use_xmms_original_freqs ? - iir_cforiginal10_48000 : - iir_cf10_48000; - break; - } - break; - default: - switch(*bands) - { - case 31: iir_cf = iir_cf31_44100; break; - case 25: iir_cf = iir_cf25_44100; break; - case 15: iir_cf = iir_cf15_44100; break; - default: - iir_cf = use_xmms_original_freqs ? - iir_cforiginal10_44100 : - iir_cf10_44100; - break; - } - break; - } - return iir_cf; -} - -/* Get the freqs at both sides of F0. These will be cut at -3dB */ -static void find_f1_and_f2(double f0, double octave_percent, double *f1, double *f2) -{ - double octave_factor = pow(2.0, octave_percent/2.0); - *f1 = f0/octave_factor; - *f2 = f0*octave_factor; -} - -/* Find the quadratic root - * Always return the smallest root */ -static int find_root(double a, double b, double c, double *x0) { - double k = c-((b*b)/(4.*a)); - double h = -(b/(2.*a)); - double x1 = 0.; - if (-(k/a) < 0.) - return -1; - *x0 = h - sqrt(-(k/a)); - x1 = h + sqrt(-(k/a)); - if (x1 < *x0) - *x0 = x1; - return 0; -} - -/* Calculate all the coefficients as specified in the bands[] array */ -void calc_coeffs() -{ - int i, n; - double f1, f2; - double x0; - - n = 0; - for (; bands[n].cfs; n++) { - double *freqs = (double *)bands[n].cfs; - for (i=0; i<bands[n].band_count; i++) - { - - /* Find -3dB frequencies for the center freq */ - find_f1_and_f2(freqs[i], bands[n].octave, &f1, &f2); - /* Find Beta */ - if ( find_root( - BETA2(TETA(freqs[i]), TETA(f1)), - BETA1(TETA(freqs[i]), TETA(f1)), - BETA0(TETA(freqs[i]), TETA(f1)), - &x0) == 0) - { - /* Got a solution, now calculate the rest of the factors */ - /* Take the smallest root always (find_root returns the smallest one) - * - * NOTE: The IIR equation is - * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2]) - * Now the 2 factor has been distributed in the coefficients - */ - /* Now store the coefficients */ - bands[n].coeffs[i].beta = 2.0 * x0; - bands[n].coeffs[i].alpha = 2.0 * ALPHA(x0); - bands[n].coeffs[i].gamma = 2.0 * GAMMA(x0, TETA(freqs[i])); -#ifdef DEBUG - printf("Freq[%d]: %f. Beta: %.10e Alpha: %.10e Gamma %.10e\n", - i, freqs[i], bands[n].coeffs[i].beta, - bands[n].coeffs[i].alpha, bands[n].coeffs[i].gamma); -#endif - } else { - /* Shouldn't happen */ - bands[n].coeffs[i].beta = 0.; - bands[n].coeffs[i].alpha = 0.; - bands[n].coeffs[i].gamma = 0.; - printf(" **** Where are the roots?\n"); - } - }// for i - }//for n -} diff --git a/lib/iir_cfs.h b/lib/iir_cfs.h deleted file mode 100644 index c5885283b..000000000 --- a/lib/iir_cfs.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * PCM time-domain equalizer - * - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: iir_cfs.h,v 1.1 2005/10/17 01:57:59 liebremx Exp $ - */ -#ifndef IIR_CFS_H -#define IIR_CFS_H - -#include <math.h> -//#include <glib.h> - -/* Coefficients entry */ -typedef struct -{ - float beta; - float alpha; - float gamma; - float dummy; // Word alignment -}sIIRCoefficients; - - -sIIRCoefficients* get_coeffs(int *bands, int sfreq, bool use_xmms_original_freqs); -void calc_coeffs(); - -#endif diff --git a/lib/iir_fpu.c b/lib/iir_fpu.c deleted file mode 100644 index 47c97134d..000000000 --- a/lib/iir_fpu.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * PCM time-domain equalizer - * - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users sourceforge net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: iir_fpu.c,v 1.3 2005/11/13 20:02:58 lisanet Exp $ - */ - -#include <strings.h> -#include <stdlib.h> -#include <glib.h> -#include "iir.h" -#include "iir_fpu.h" - -static sXYData data_history[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned)); -static sXYData data_history2[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned)); -float gain[EQ_MAX_BANDS][EQ_CHANNELS] __attribute__((aligned)); -/* random noise */ -sample_t dither[256]; -gint di; - -void set_gain(gint index, gint chn, float val) -{ - gain[index][chn] = val; -} - -void clean_history() -{ - gint n; - /* Zero the history arrays */ - bzero(data_history, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS); - bzero(data_history2, sizeof(sXYData) * EQ_MAX_BANDS * EQ_CHANNELS); - /* this is only needed if we use fpu code and there's no other place for - the moment to init the dither array*/ - for (n = 0; n < 256; n++) { - dither[n] = (rand() % 4) - 2; - } - di = 0; -} - -__inline__ int iir(gpointer * d, gint length, gint nch) -{ -// FTZ_ON; - gint16 *data = (gint16 *) * d; - /* Indexes for the history arrays - * These have to be kept between calls to this function - * hence they are static */ - static gint i = 2, j = 1, k = 0; - - gint index, band, channel; - gint tempgint, halflength; - sample_t out[EQ_CHANNELS], pcm[EQ_CHANNELS]; - -#if 0 - // Load the correct filter table according to the sampling rate if needed - if (srate != rate) - { - band_count = eqcfg.band_num; - rate = srate; - iir_cf = get_coeffs(&band_count, rate, eqcfg.use_xmms_original_freqs); - clean_history(); - } -#endif - -#ifdef BENCHMARK - start_counter(); -#endif //BENCHMARK - - /** - * IIR filter equation is - * y[n] = 2 * (alpha*(x[n]-x[n-2]) + gamma*y[n-1] - beta*y[n-2]) - * - * NOTE: The 2 factor was introduced in the coefficients to save - * a multiplication - * - * This algorithm cascades two filters to get nice filtering - * at the expense of extra CPU cycles - */ - /* 16bit, 2 bytes per sample, so divide by two the length of - * the buffer (length is in bytes) - */ - halflength = (length >> 1); - for (index = 0; index < halflength; index+=nch) - { - /* For each channel */ - for (channel = 0; channel < nch; channel++) - { - pcm[channel] = data[index+channel] * 4; - /* Preamp gain */ - pcm[channel] *= preamp[channel]; - - /* add random noise */ - pcm[channel] += dither[di]; - - out[channel] = 0.; - /* For each band */ - for (band = 0; band < band_count; band++) - { - /* Store Xi(n) */ - data_history[band][channel].x[i] = pcm[channel]; - /* Calculate and store Yi(n) */ - data_history[band][channel].y[i] = - ( - /* = alpha * [x(n)-x(n-2)] */ - iir_cf[band].alpha * ( data_history[band][channel].x[i] - - data_history[band][channel].x[k]) - /* + gamma * y(n-1) */ - + iir_cf[band].gamma * data_history[band][channel].y[j] - /* - beta * y(n-2) */ - - iir_cf[band].beta * data_history[band][channel].y[k] - ); - /* - * The multiplication by 2.0 was 'moved' into the coefficients to save - * CPU cycles here */ - /* Apply the gain */ - out[channel] += data_history[band][channel].y[i]*gain[band][channel]; // * 2.0; - } /* For each band */ - - if (cfg.eq_extra_filtering) - { - /* Filter the sample again */ - for (band = 0; band < band_count; band++) - { - /* Store Xi(n) */ - data_history2[band][channel].x[i] = out[channel]; - /* Calculate and store Yi(n) */ - data_history2[band][channel].y[i] = - ( - /* y(n) = alpha * [x(n)-x(n-2)] */ - iir_cf[band].alpha * (data_history2[band][channel].x[i] - - data_history2[band][channel].x[k]) - /* + gamma * y(n-1) */ - + iir_cf[band].gamma * data_history2[band][channel].y[j] - /* - beta * y(n-2) */ - - iir_cf[band].beta * data_history2[band][channel].y[k] - ); - /* Apply the gain */ - out[channel] += data_history2[band][channel].y[i]*gain[band][channel]; - } /* For each band */ - } - - /* Volume stuff - Scale down original PCM sample and add it to the filters - output. This substitutes the multiplication by 0.25 - Go back to use the floating point multiplication before the - conversion to give more dynamic range - */ - out[channel] += pcm[channel]*0.25; - - /* remove random noise */ - out[channel] -= dither[di]*0.25; - - /* Round and convert to integer */ -#ifdef ARCH_PPC - tempgint = round_ppc(out[channel]); -#else -#ifdef ARCH_X86 - tempgint = round_trick(out[channel]); -#else - tempgint = (int)out[channel]; -#endif -#endif - - /* Limit the output */ - if (tempgint < -32768) - data[index+channel] = -32768; - else if (tempgint > 32767) - data[index+channel] = 32767; - else - data[index+channel] = tempgint; - } /* For each channel */ - - /* Wrap around the indexes */ - i = (i+1)%3; - j = (j+1)%3; - k = (k+1)%3; - /* random noise index */ - di = (di + 1) % 256; - - }/* For each pair of samples */ - -#ifdef BENCHMARK - timex += get_counter(); - blength += length; - if (count++ == 1024) - { - printf("FLOATING POINT: %f %d\n",timex/1024.0, blength/1024); - blength = 0; - timex = 0.; - count = 0; - } -#endif // BENCHMARK - -// FTZ_OFF; - return length; -} diff --git a/lib/iir_fpu.h b/lib/iir_fpu.h deleted file mode 100644 index 990eebf97..000000000 --- a/lib/iir_fpu.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * PCM time-domain equalizer - * - * Copyright (C) 2002-2005 Felipe Rivera <liebremx at users.sourceforge.net> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: iir_fpu.h,v 1.2 2005/11/01 15:59:20 lisanet Exp $$ - */ -#ifndef IIR_FPU_H -#define IIR_FPU_H - -#define sample_t double - -/* - * Normal FPU implementation data structures - */ -/* Coefficient history for the IIR filter */ -typedef struct -{ - sample_t x[3]; /* x[n], x[n-1], x[n-2] */ - sample_t y[3]; /* y[n], y[n-1], y[n-2] */ - sample_t dummy1; // Word alignment - sample_t dummy2; -}sXYData; - -#endif diff --git a/lib/lib.pro b/lib/lib.pro index 5c52041a2..7899f81b4 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -18,7 +18,9 @@ HEADERS += recycler.h \ streamreader.h \ downloader.h \ visual.h \ - visualfactory.h + visualfactory.h \ + effect.h \ + effectfactory.h SOURCES += recycler.cpp \ decoder.cpp \ output.cpp \ @@ -29,7 +31,8 @@ SOURCES += recycler.cpp \ streamreader.cpp \ downloader.cpp \ filetag.cpp \ - visual.cpp + visual.cpp \ + effect.cpp TARGET = qmmp CONFIG += release \ diff --git a/lib/qmmp/CMakeLists.txt b/lib/qmmp/CMakeLists.txt index 85c3b020e..42382b5cd 100644 --- a/lib/qmmp/CMakeLists.txt +++ b/lib/qmmp/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Input) add_subdirectory(Output) add_subdirectory(Visual) +add_subdirectory(Effect)
\ No newline at end of file diff --git a/lib/qmmp/Effect/CMakeLists.txt b/lib/qmmp/Effect/CMakeLists.txt new file mode 100644 index 000000000..a777010b9 --- /dev/null +++ b/lib/qmmp/Effect/CMakeLists.txt @@ -0,0 +1,8 @@ +SET(USE_SRC TRUE CACHE BOOL "enable/disable SRC plugin") + +IF(USE_SRC) +MESSAGE( STATUS "SRC ON") +add_subdirectory(srconverter) +ELSE(USE_SRC) +MESSAGE( STATUS "SRC OFF") +ENDIF(USE_SRC) diff --git a/lib/qmmp/Effect/Effect.pro b/lib/qmmp/Effect/Effect.pro new file mode 100644 index 000000000..b03c8a598 --- /dev/null +++ b/lib/qmmp/Effect/Effect.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs + +SUBDIRS += srconverter + diff --git a/lib/qmmp/Effect/srconverter/CMakeLists.txt b/lib/qmmp/Effect/srconverter/CMakeLists.txt new file mode 100644 index 000000000..ef95abf79 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/CMakeLists.txt @@ -0,0 +1,76 @@ +project(libsrconverter) + +cmake_minimum_required(VERSION 2.4.0) + + +INCLUDE(UsePkgConfig) +INCLUDE(FindQt4) + +find_package(Qt4 REQUIRED) # find and setup Qt4 for this project +include(${QT_USE_FILE}) + +# qt plugin +ADD_DEFINITIONS( -Wall ) +ADD_DEFINITIONS(${QT_DEFINITIONS}) +ADD_DEFINITIONS(-DQT_PLUGIN) +ADD_DEFINITIONS(-DQT_NO_DEBUG) +ADD_DEFINITIONS(-DQT_SHARED) +ADD_DEFINITIONS(-DQT_THREAD) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +SET(QT_INCLUDES + ${QT_INCLUDES} + ${CMAKE_CURRENT_BINARY_DIR}/../../../ +) + +# libqmmp +include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../) +link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../) + +PKGCONFIG(samplerate SAMPLERATE_INCLUDE_DIR SAMPLERATE_LINK_DIR SAMPLERATE_LINK_FLAGS SAMPLERATE_CFLAGS) + +IF(NOT SAMPLERATE_LINK_FLAGS) + SET(SAMPLERATE_LINK_FLAGS -lsamplerate) +ENDIF(NOT SAMPLERATE_LINK_FLAGS) + +include_directories(${SAMPLERATE_INCLUDE_DIR}) +link_directories(${SAMPLERATE_LINK_DIR}) + +ADD_DEFINITIONS(${SAMPLERATE_CFLAGS}) + +SET(libsrconverter_SRCS + srconverter.cpp + settingsdialog.cpp + effectsrconverterfactory.cpp +) + +SET(libsrconverter_MOC_HDRS + srconverter.h + settingsdialog.h + effectsrconverterfactory.h +) + +#SET(libsrconverter_RCCS translations/translations.qrc) + +#QT4_ADD_RESOURCES(libsrconverter_RCC_SRCS ${libsrconverter_RCCS}) + +QT4_WRAP_CPP(libsrconverter_MOC_SRCS ${libsrconverter_MOC_HDRS}) + +# user interface + + +SET(libsrconverter_UIS + settingsdialog.ui +) + +QT4_WRAP_UI(libsrconverter_UIS_H ${libsrconverter_UIS}) +# Don't forget to include output directory, otherwise +# the UI file won't be wrapped! +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +ADD_LIBRARY(srconverter SHARED ${libsrconverter_SRCS} ${libsrconverter_MOC_SRCS} ${libsrconverter_UIS_H} + ${libsrconverter_RCC_SRCS}) +target_link_libraries(srconverter ${QT_LIBRARIES} -lqmmp ${SAMPLERATE_LINK_FLAGS}) +install(TARGETS srconverter DESTINATION ${LIB_DIR}/qmmp/Effect) + diff --git a/lib/qmmp/Effect/srconverter/effectsrconverterfactory.cpp b/lib/qmmp/Effect/srconverter/effectsrconverterfactory.cpp new file mode 100644 index 000000000..bd4f93c1b --- /dev/null +++ b/lib/qmmp/Effect/srconverter/effectsrconverterfactory.cpp @@ -0,0 +1,57 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QtGui> + +#include "settingsdialog.h" +#include "effectsrconverterfactory.h" +#include "srconverter.h" + +const EffectProperties EffectSRConverterFactory::properties() const +{ + EffectProperties properties; + properties.name = tr("SRC Plugin"); + return properties; +}; + +Effect *EffectSRConverterFactory::create(QObject *parent) +{ + return new SRConverter(parent); +}; + +void EffectSRConverterFactory::showSettings(QWidget *parent) +{ + SettingsDialog *s = new SettingsDialog(parent); + s ->show(); +}; + +void EffectSRConverterFactory::showAbout(QWidget *parent) +{ + QMessageBox::about (parent, tr("About Sample Rate Converter Plugin"), + tr("Qmmp Sample Rate Converter Plugin")+"\n"+ + tr("Writen by: Ilya Kotov <forkotov02@hotmail.ru>")); +}; + +QTranslator *EffectSRConverterFactory::createTranslator(QObject *parent) +{ + return 0; +}; + +Q_EXPORT_PLUGIN(EffectSRConverterFactory) diff --git a/lib/qmmp/Effect/srconverter/effectsrconverterfactory.h b/lib/qmmp/Effect/srconverter/effectsrconverterfactory.h new file mode 100644 index 000000000..4112a3af5 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/effectsrconverterfactory.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef EFFECTSRCONVERTERFACTORY_H +#define EFFECTSRCONVERTERFACTORY_H + + +#include <QObject> + +#include <effectfactory.h> +#include <effect.h> + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class EffectSRConverterFactory : public QObject, public EffectFactory +{ +Q_OBJECT +Q_INTERFACES(EffectFactory); + +public: + const EffectProperties properties() const; + Effect *create(QObject *parent); + void showSettings(QWidget *parent); + void showAbout(QWidget *parent); + QTranslator *createTranslator(QObject *parent); +}; + + +#endif diff --git a/lib/qmmp/Effect/srconverter/settingsdialog.cpp b/lib/qmmp/Effect/srconverter/settingsdialog.cpp new file mode 100644 index 000000000..d4e017bba --- /dev/null +++ b/lib/qmmp/Effect/srconverter/settingsdialog.cpp @@ -0,0 +1,48 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QSettings> +#include <QDir> + +#include "settingsdialog.h" + +SettingsDialog::SettingsDialog(QWidget *parent) + : QDialog(parent) +{ + ui.setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, TRUE); + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + ui.srSpinBox->setValue(settings.value("SRC/sample_rate",48000).toInt()); + ui.engineComboBox->setCurrentIndex(settings.value("SRC/engine", 0).toInt()); + connect (ui.okButton, SIGNAL(clicked()),SLOT(writeSettings())); +} + + +SettingsDialog::~SettingsDialog() +{ +} + +void SettingsDialog::writeSettings() +{ + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + settings.setValue("SRC/sample_rate",ui.srSpinBox->value()); + settings.setValue("SRC/engine", ui.engineComboBox->currentIndex()); + accept(); +} diff --git a/lib/qmmp/Effect/srconverter/settingsdialog.h b/lib/qmmp/Effect/srconverter/settingsdialog.h new file mode 100644 index 000000000..b7c466477 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/settingsdialog.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SETTINGSDIALOG_H +#define SETTINGSDIALOG_H + +#include <QDialog> + +#include "ui_settingsdialog.h" + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ +class SettingsDialog : public QDialog +{ +Q_OBJECT +public: + SettingsDialog(QWidget *parent = 0); + + ~SettingsDialog(); + +private slots: + void writeSettings(); + +private: + Ui::SettingsDialog ui; + +}; + +#endif diff --git a/lib/qmmp/Effect/srconverter/settingsdialog.ui b/lib/qmmp/Effect/srconverter/settingsdialog.ui new file mode 100644 index 000000000..e837c9cf0 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/settingsdialog.ui @@ -0,0 +1,124 @@ +<ui version="4.0" > + <class>SettingsDialog</class> + <widget class="QDialog" name="SettingsDialog" > + <property name="geometry" > + <rect> + <x>0</x> + <y>0</y> + <width>357</width> + <height>107</height> + </rect> + </property> + <property name="windowTitle" > + <string>Sample Rate Converter Plugin Settings</string> + </property> + <layout class="QGridLayout" > + <item row="0" column="0" > + <widget class="QLabel" name="label" > + <property name="text" > + <string>Sample Rate (Hz):</string> + </property> + </widget> + </item> + <item row="0" column="1" > + <widget class="QSpinBox" name="srSpinBox" > + <property name="maximum" > + <number>96000</number> + </property> + <property name="singleStep" > + <number>100</number> + </property> + <property name="value" > + <number>48000</number> + </property> + </widget> + </item> + <item row="1" column="0" > + <widget class="QLabel" name="label_2" > + <property name="text" > + <string>Interpolation Engine:</string> + </property> + </widget> + </item> + <item row="1" column="1" > + <widget class="QComboBox" name="engineComboBox" > + <item> + <property name="text" > + <string>Best Sinc Interpolation</string> + </property> + </item> + <item> + <property name="text" > + <string>Medium Sinc Interpolation</string> + </property> + </item> + <item> + <property name="text" > + <string>Fastest Sinc Interpolation</string> + </property> + </item> + <item> + <property name="text" > + <string>ZOH Interpolation</string> + </property> + </item> + <item> + <property name="text" > + <string>Linear Interpolation</string> + </property> + </item> + </widget> + </item> + <item row="2" column="0" > + <spacer> + <property name="orientation" > + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" > + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1" > + <layout class="QHBoxLayout" > + <item> + <widget class="QPushButton" name="okButton" > + <property name="text" > + <string>&OK</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="cancelButton" > + <property name="text" > + <string>&Cancel</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>cancelButton</sender> + <signal>clicked()</signal> + <receiver>SettingsDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel" > + <x>302</x> + <y>88</y> + </hint> + <hint type="destinationlabel" > + <x>42</x> + <y>69</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/lib/qmmp/Effect/srconverter/srconverter.cpp b/lib/qmmp/Effect/srconverter/srconverter.cpp new file mode 100644 index 000000000..0e733c8c4 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/srconverter.cpp @@ -0,0 +1,125 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <QSettings> +#include <QDir> +#include <math.h> + +#include "srconverter.h" + +SRConverter::SRConverter(QObject* parent) : Effect(parent) +{ + m_isSrcAlloc = FALSE; + int converter_type_array[] = {SRC_SINC_BEST_QUALITY, SRC_SINC_MEDIUM_QUALITY, SRC_SINC_FASTEST, + SRC_ZERO_ORDER_HOLD, SRC_LINEAR}; + m_srcIn = 0; + m_srcOut = 0; + m_src_state = 0; + m_srcError = 0; + QSettings settings(QDir::homePath()+"/.qmmp/qmmprc", QSettings::IniFormat); + m_overSamplingFs = settings.value("SRC/sample_rate",48000).toInt(); + m_converter_type = converter_type_array[settings.value("SRC/engine", 0).toInt()]; +} + +SRConverter::~SRConverter() +{ + src_reset (m_src_state) ; + freeSRC(); + m_src_data.data_in = 0; + m_src_data.data_out = 0; + m_src_data.end_of_input = 0; + m_src_data.input_frames = 0; + m_src_data.output_frames = 0; + if (m_isSrcAlloc) + { + free(m_srcIn); + free(m_srcOut); + free(m_wOut); + m_isSrcAlloc = FALSE; + } +} + +const ulong SRConverter::process(char *in_data, const ulong size, char **out_data) +{ + if (m_isSrcAlloc) + { + free(m_srcIn); + free(m_srcOut); + free(m_wOut); + m_isSrcAlloc = FALSE; + } + ulong wbytes = 0; + + if (m_src_state && size > 0) + { + int lrLength = size/2; + int overLrLength= (int)floor(lrLength*(m_src_data.src_ratio+1)); + m_srcIn = (float*) malloc(sizeof(float)*lrLength); + m_srcOut = (float*) malloc(sizeof(float)*overLrLength); + m_wOut = (short int*) malloc(sizeof(short int)*overLrLength); + src_short_to_float_array((short int*)in_data, m_srcIn, lrLength); + m_isSrcAlloc = TRUE; + m_src_data.data_in = m_srcIn; + m_src_data.data_out = m_srcOut; + m_src_data.end_of_input = 0; + m_src_data.input_frames = lrLength/2; + m_src_data.output_frames = overLrLength/2; + if ((m_srcError = src_process(m_src_state, &m_src_data)) > 0) + { + qWarning("SRConverter: src_process(): %s\n", src_strerror(m_srcError)); + } + else + { + src_float_to_short_array(m_srcOut, m_wOut, m_src_data.output_frames_gen*2); + wbytes = m_src_data.output_frames_gen*4; + *out_data = new char[wbytes]; + memcpy(*out_data, (char*) m_wOut, wbytes); + } + } + return wbytes; +} + +void SRConverter::configure(ulong freq, int chan, int res) +{ + Effect::configure(freq, chan, res); + freeSRC(); + uint rate = freq; + { + m_src_state = src_new(m_converter_type, 2, &m_srcError); + if (m_src_state) + { + m_src_data.src_ratio = (float)m_overSamplingFs/(float)rate; + rate = m_overSamplingFs; + } + else + qDebug("SRConverter: src_new(): %s", src_strerror(m_srcError)); + } +} + +const ulong SRConverter::frequency() +{ + return m_overSamplingFs; +} + +void SRConverter::freeSRC() +{ + if (m_src_state != NULL) + m_src_state = src_delete(m_src_state); +} diff --git a/lib/qmmp/Effect/srconverter/srconverter.h b/lib/qmmp/Effect/srconverter/srconverter.h new file mode 100644 index 000000000..1b3e13416 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/srconverter.h @@ -0,0 +1,60 @@ +/*************************************************************************** + * Copyright (C) 2007 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program 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 General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef SRCONVERTER_H +#define SRCONVERTER_H + +#include <effect.h> + +extern "C" +{ +#include <samplerate.h> +} + +/** + @author Ilya Kotov <forkotov02@hotmail.ru> +*/ + +class SRConverter : public Effect +{ + Q_OBJECT +public: + SRConverter(QObject *parent = 0); + + virtual ~SRConverter(); + + //bool process(char *in_data, char *out_data, const ulong maxsize, ulong &rbytes, ulong &wbytes); + const ulong process(char *in_data, const ulong size, char **out_data); + void configure(ulong freq, int chan, int res); + const ulong frequency(); + +private: + void freeSRC(); + SRC_STATE *m_src_state; + SRC_DATA m_src_data; + int m_overSamplingFs; + int m_srcError; + int m_converter_type; + bool m_isSrcAlloc; + float *m_srcIn, *m_srcOut; + short *m_wOut; + ulong m_freq; +}; + +#endif diff --git a/lib/qmmp/Effect/srconverter/srconverter.pro b/lib/qmmp/Effect/srconverter/srconverter.pro new file mode 100644 index 000000000..820cdbe98 --- /dev/null +++ b/lib/qmmp/Effect/srconverter/srconverter.pro @@ -0,0 +1,33 @@ +HEADERS += srconverter.h \ + effectsrconverterfactory.h \ + settingsdialog.h + +SOURCES += srconverter.cpp \ + effectsrconverterfactory.cpp \ + settingsdialog.cpp + +DESTDIR = ../ +QMAKE_CLEAN = ../libsrconverter.so +INCLUDEPATH += ../../../ +CONFIG += release \ +warn_on \ +plugin \ +link_pkgconfig + +PKGCONFIG += samplerate +TEMPLATE = lib +QMAKE_LIBDIR += ../../../ +LIBS += -lqmmp -L/usr/lib -I/usr/include + +#TRANSLATIONS = translations/ffmpeg_plugin_ru.ts +#RESOURCES = translations/translations.qrc + +isEmpty(LIB_DIR){ + LIB_DIR = /lib +} +target.path = $$LIB_DIR/qmmp/Effect +INSTALLS += target +#FORMS += settingsdialog.ui + +FORMS += settingsdialog.ui + diff --git a/lib/qmmp/Input/ffmpeg/decoder_ffmpeg.cpp b/lib/qmmp/Input/ffmpeg/decoder_ffmpeg.cpp index a23a470a9..095f818e7 100644 --- a/lib/qmmp/Input/ffmpeg/decoder_ffmpeg.cpp +++ b/lib/qmmp/Input/ffmpeg/decoder_ffmpeg.cpp @@ -179,8 +179,7 @@ bool DecoderFFmpeg::initialize() totalTime = ic->duration/AV_TIME_BASE; - if (output()) - output()->configure(c->sample_rate, c->channels, 16, c->bit_rate); + configure(c->sample_rate, c->channels, 16, c->bit_rate); bitrate = c->bit_rate; chan = c->channels; diff --git a/lib/qmmp/Input/flac/decoder_flac.cpp b/lib/qmmp/Input/flac/decoder_flac.cpp index 4a23dc097..b2a895bca 100644 --- a/lib/qmmp/Input/flac/decoder_flac.cpp +++ b/lib/qmmp/Input/flac/decoder_flac.cpp @@ -436,8 +436,7 @@ bool DecoderFLAC::initialize() return FALSE; } chan = data()->channels; - if (output()) - output()->configure(data()->sample_rate, data()->channels, 16, bitrate); + configure(data()->sample_rate, data()->channels, 16, bitrate); totalTime = data()->length; inited = TRUE; diff --git a/lib/qmmp/Input/mad/decoder_mad.cpp b/lib/qmmp/Input/mad/decoder_mad.cpp index 6bb16daab..6b4c2569a 100644 --- a/lib/qmmp/Input/mad/decoder_mad.cpp +++ b/lib/qmmp/Input/mad/decoder_mad.cpp @@ -109,8 +109,7 @@ bool DecoderMAD::initialize() qDebug("DecoderMAD: Cannot find a valid MPEG header."); return FALSE; } - if (output()) - output()->configure(freq, channels, 16, bitrate); + configure(freq, channels, 16, bitrate); inited = TRUE; return TRUE; @@ -308,7 +307,6 @@ void DecoderMAD::flush(bool final) while ((! done && ! finish) && output()->recycler()->full()) { mutex()->unlock(); - output()->recycler()->cond()->wait(output()->recycler()->mutex()); mutex()->lock(); diff --git a/lib/qmmp/Input/mpc/decoder_mpc.cpp b/lib/qmmp/Input/mpc/decoder_mpc.cpp index 49a5c0cc4..10591a384 100644 --- a/lib/qmmp/Input/mpc/decoder_mpc.cpp +++ b/lib/qmmp/Input/mpc/decoder_mpc.cpp @@ -245,8 +245,7 @@ bool DecoderMPC::initialize() if (mpc_streaminfo_read (&m_data->info, &m_data->reader) != ERROR_CODE_OK) return FALSE; chan = data()->info.channels; - if (output()) - output()->configure(data()->info.sample_freq, chan, 16, data()->info.bitrate); + configure(data()->info.sample_freq, chan, 16, data()->info.bitrate); mpc_decoder_setup (&data()->decoder, &data()->reader); diff --git a/lib/qmmp/Input/vorbis/decoder_vorbis.cpp b/lib/qmmp/Input/vorbis/decoder_vorbis.cpp index c37949085..31fb99c6f 100644 --- a/lib/qmmp/Input/vorbis/decoder_vorbis.cpp +++ b/lib/qmmp/Input/vorbis/decoder_vorbis.cpp @@ -226,8 +226,7 @@ bool DecoderVorbis::initialize() chan = ogginfo->channels; } - if (output()) - output()->configure(freq, chan, 16, bitrate); + configure(freq, chan, 16, bitrate); inited = TRUE; return TRUE; diff --git a/lib/qmmp/Output/alsa/outputalsa.cpp b/lib/qmmp/Output/alsa/outputalsa.cpp index 41415d93f..c07a2b7a0 100644 --- a/lib/qmmp/Output/alsa/outputalsa.cpp +++ b/lib/qmmp/Output/alsa/outputalsa.cpp @@ -87,10 +87,6 @@ long OutputALSA::written() void OutputALSA::seek(long pos) { - recycler()->mutex()->lock (); - recycler()->clear(); - recycler()->mutex()->unlock(); - m_totalWritten = (pos * m_bps); m_currentSeconds = -1; } diff --git a/lib/qmmp/qmmp.pro b/lib/qmmp/qmmp.pro index fded51223..6a68558ce 100644 --- a/lib/qmmp/qmmp.pro +++ b/lib/qmmp/qmmp.pro @@ -1,5 +1,6 @@ SUBDIRS += Input \ Output \ - Visual + Visual \ + Effect TEMPLATE = subdirs diff --git a/lib/recycler.cpp b/lib/recycler.cpp index 515652fb0..15d2234a6 100644 --- a/lib/recycler.cpp +++ b/lib/recycler.cpp @@ -10,94 +10,111 @@ Recycler::Recycler ( unsigned int sz ) - : add_index ( 0 ), done_index ( 0 ), current_count ( 0 ) + : add_index ( 0 ), done_index ( 0 ), current_count ( 0 ) { - buffer_count = ( sz / Buffer::size() ); - if ( buffer_count < 1 ) - { - buffer_count = 1; - } - - buffers = new Buffer*[buffer_count]; - - for ( unsigned int i = 0; i < buffer_count; i ++ ) - { - buffers[i] = new Buffer; - } + buffer_count = ( sz / Buffer::size() ); + if ( buffer_count < 1 ) + { + buffer_count = 1; + } + + buffers = new Buffer*[buffer_count]; + + for ( unsigned int i = 0; i < buffer_count; i ++ ) + { + buffers[i] = new Buffer; + } } Recycler::~Recycler() { - for ( unsigned int i = 0; i < buffer_count; i++ ) - { - delete buffers[i]; - buffers[i] = 0; - } + for ( unsigned int i = 0; i < buffer_count; i++ ) + { + delete buffers[i]; + buffers[i] = 0; + } - delete [] buffers; + delete [] buffers; } bool Recycler::full() const { - return current_count == buffer_count; + return current_count == buffer_count; } bool Recycler::empty() const { - return current_count == 0; + return current_count == 0; } int Recycler::available() const { - return buffer_count - current_count; + return buffer_count - current_count; } - int Recycler::used() const { - return current_count; + return current_count; } -Buffer *Recycler::get() +Buffer *Recycler::get(unsigned long size) { - if ( full() ) - return 0; - return buffers[add_index]; + if (full()) + return 0; + if(size > Buffer::size() + buffers[add_index]->exceeding) + { + delete buffers[add_index]->data; + buffers[add_index]->data = new unsigned char[size]; + buffers[add_index]->exceeding = size - Buffer::size(); + //qDebug("new size = %d, index = %d", size, add_index); + } + + return buffers[add_index]; } void Recycler::add() { - add_index = ++add_index % buffer_count; - current_count++; + add_index = ++add_index % buffer_count; + current_count++; } Buffer *Recycler::next() { - return buffers[done_index]; + return buffers[done_index]; } void Recycler::done() { - done_index = ++done_index % buffer_count; - current_count--; + done_index = ++done_index % buffer_count; + current_count--; } void Recycler::clear() { - add_index = done_index = current_count = 0; + add_index = done_index = current_count = 0; + /*for ( unsigned int i = 0; i < buffer_count; i ++ ) + { + if(buffers[i]->exceeding > 0) + { + delete buffers[i]->data; + buffers[i]->data = new unsigned char[Buffer::size()]; + buffers[i]->exceeding = 0; + buffers[i]->nbytes = 0; + } + }*/ } unsigned int Recycler::size() const { - return buffer_count * Buffer::size(); + return buffer_count * Buffer::size(); } diff --git a/lib/recycler.h b/lib/recycler.h index b01742350..6bb80375d 100644 --- a/lib/recycler.h +++ b/lib/recycler.h @@ -26,7 +26,7 @@ public: int used() const; Buffer *next(); // get next in queue - Buffer *get(); // get next in recycle + Buffer *get(unsigned long size); // get next in recycle void add(); // add to queue void done(); // add to recycle diff --git a/lib/soundcore.cpp b/lib/soundcore.cpp index 6c6f058e7..37c28e5f5 100644 --- a/lib/soundcore.cpp +++ b/lib/soundcore.cpp @@ -25,6 +25,7 @@ #include "decoderfactory.h" #include "constants.h" #include "streamreader.h" +#include "effect.h" #include "soundcore.h" @@ -64,6 +65,8 @@ SoundCore::SoundCore(QObject *parent) QList<DecoderFactory*> *decoderFactories = Decoder::decoderFactories(); foreach(DecoderFactory* df, *decoderFactories) qApp->installTranslator(df->createTranslator(this)); + + Effect::effectFactories(); } @@ -234,6 +237,9 @@ void SoundCore::seek(int pos) { if (m_output && m_output->isRunning()) { + m_output->recycler()->mutex()->lock (); + m_output->recycler()->clear (); + m_output->recycler()->mutex()->unlock (); m_output->mutex()->lock (); m_output->seek(pos); m_output->mutex()->unlock(); diff --git a/src/configdialog.cpp b/src/configdialog.cpp index 0005b1847..958453a27 100644 --- a/src/configdialog.cpp +++ b/src/configdialog.cpp @@ -31,6 +31,8 @@ #include <decoderfactory.h> #include <outputfactory.h> #include <visualfactory.h> +#include <effectfactory.h> +#include <effect.h> #include "skin.h" #include "filedialog.h" @@ -72,6 +74,8 @@ ConfigDialog::~ConfigDialog() delete m_outputPluginItems.takeFirst(); while (!m_visualPluginItems.isEmpty()) delete m_visualPluginItems.takeFirst(); + while (!m_effectPluginItems.isEmpty()) + delete m_effectPluginItems.takeFirst(); } void ConfigDialog::readSettings() @@ -259,6 +263,34 @@ void ConfigDialog::loadPluginsInfo() ui.visualPluginTable->resizeColumnToContents ( 1 ); ui.visualPluginTable->resizeRowsToContents (); + /* + load effect plugin information + */ + QList <EffectFactory *> *effects = 0; + effects = Effect::effectFactories(); + files = Effect::effectFiles(); + ui.effectPluginTable->setColumnCount ( 3 ); + ui.effectPluginTable->verticalHeader()->hide(); + ui.effectPluginTable->setHorizontalHeaderLabels ( QStringList() + << tr ( "Enabled" ) << tr ( "Description" ) << tr ( "Filename" ) ); + ui.effectPluginTable->setRowCount ( visuals->count () ); + + for ( int i = 0; i < effects->count (); ++i ) + { + EffectPluginItem *item = new EffectPluginItem(this,effects->at(i),files.at(i)); + m_effectPluginItems.append(item); + QCheckBox* button = new QCheckBox (ui.effectPluginTable); + connect(button, SIGNAL(clicked (bool)), item, SLOT(select(bool))); + button->setChecked (item->isSelected()); + ui.effectPluginTable->setCellWidget ( i, 0, button ); + ui.effectPluginTable->setItem (i,1, + new QTableWidgetItem (item->factory()->properties().name)); + ui.effectPluginTable->setItem (i,2, new QTableWidgetItem (files.at(i))); + } + + ui.effectPluginTable->resizeColumnToContents ( 0 ); + ui.effectPluginTable->resizeColumnToContents ( 1 ); + ui.effectPluginTable->resizeRowsToContents (); } @@ -335,6 +367,14 @@ void ConfigDialog::showPluginSettings() m_visualPluginItems.at(row)->factory()->showSettings ( this ); break; } + case 3: + { + int row = ui.effectPluginTable->currentRow (); + if ( m_effectPluginItems.isEmpty() || row < 0 ) + return; + m_effectPluginItems.at(row)->factory()->showSettings ( this ); + break; + } } } @@ -369,6 +409,14 @@ void ConfigDialog::showPluginInfo() m_visualPluginItems.at(row)->factory()->showAbout ( this ); break; } + case 3: + { + int row = ui.effectPluginTable->currentRow (); + if ( m_effectPluginItems.isEmpty() || row < 0 ) + return; + m_effectPluginItems.at(row)->factory()->showAbout ( this ); + break; + } } } diff --git a/src/configdialog.h b/src/configdialog.h index e694f6a8d..a5c632cc6 100644 --- a/src/configdialog.h +++ b/src/configdialog.h @@ -35,6 +35,7 @@ class Skin; class InputPluginItem; class OutputPluginItem; class VisualPluginItem; +class EffectPluginItem; class ConfigDialog : public QDialog { @@ -71,6 +72,7 @@ private: QList <InputPluginItem*> m_inputPluginItems; QList <OutputPluginItem*> m_outputPluginItems; QList <VisualPluginItem*> m_visualPluginItems; + QList <EffectPluginItem*> m_effectPluginItems; }; #endif diff --git a/src/configdialog.ui b/src/configdialog.ui index 4b68c84c6..1f6f45516 100644 --- a/src/configdialog.ui +++ b/src/configdialog.ui @@ -561,6 +561,20 @@ </item> </layout> </widget> + <widget class="QWidget" name="tab_2" > + <attribute name="title" > + <string>Effects</string> + </attribute> + <layout class="QVBoxLayout" > + <item> + <widget class="QTableWidget" name="effectPluginTable" > + <property name="selectionBehavior" > + <enum>QAbstractItemView::SelectRows</enum> + </property> + </widget> + </item> + </layout> + </widget> <widget class="QWidget" name="fileDialogTab" > <attribute name="title" > <string>File Dialog</string> diff --git a/src/pluginitem.cpp b/src/pluginitem.cpp index 391f75148..fc32f8ab8 100644 --- a/src/pluginitem.cpp +++ b/src/pluginitem.cpp @@ -24,6 +24,8 @@ #include <decoderfactory.h> #include <outputfactory.h> #include <visualfactory.h> +#include <effectfactory.h> +#include <effect.h> #include <soundcore.h> #include "pluginitem.h" @@ -121,3 +123,30 @@ VisualFactory *VisualPluginItem::factory() { return m_factory; } + +/*Effect*/ +EffectPluginItem::EffectPluginItem(QObject *parent, EffectFactory *fact, + const QString &filePath): QObject(parent) +{ + m_fileName = filePath.section('/',-1); + m_factory = fact; +} + + +EffectPluginItem::~EffectPluginItem() +{} + +void EffectPluginItem::select(bool on) +{ + Effect::setEnabled(m_factory, on); +} + +bool EffectPluginItem::isSelected() +{ + return Effect::isEnabled(m_factory); +} + +EffectFactory *EffectPluginItem::factory() +{ + return m_factory; +} diff --git a/src/pluginitem.h b/src/pluginitem.h index 4a54f0e9d..11798ee25 100644 --- a/src/pluginitem.h +++ b/src/pluginitem.h @@ -29,6 +29,7 @@ class DecoderFactory; class OutputFactory; class VisualFactory; +class EffectFactory; class InputPluginItem : public QObject { @@ -89,4 +90,23 @@ private: VisualFactory *m_factory; }; +class EffectPluginItem : public QObject +{ + Q_OBJECT +public: + EffectPluginItem(QObject *parent, EffectFactory *fact, const QString &filePath); + + ~EffectPluginItem(); + + bool isSelected(); + EffectFactory * factory(); + +public slots: + void select(bool); + +private: + QString m_fileName; + EffectFactory *m_factory; +}; + #endif |
