aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xclear_cmake.sh8
-rw-r--r--lib/CMakeLists.txt3
-rw-r--r--lib/buffer.h25
-rw-r--r--lib/decoder.cpp82
-rw-r--r--lib/decoder.h12
-rw-r--r--lib/effect.cpp148
-rw-r--r--lib/effect.h87
-rw-r--r--lib/effectfactory.h53
-rw-r--r--lib/iir.c85
-rw-r--r--lib/iir.h84
-rw-r--r--lib/iir_cfs.c235
-rw-r--r--lib/iir_cfs.h41
-rw-r--r--lib/iir_fpu.c210
-rw-r--r--lib/iir_fpu.h39
-rw-r--r--lib/lib.pro7
-rw-r--r--lib/qmmp/CMakeLists.txt1
-rw-r--r--lib/qmmp/Effect/CMakeLists.txt8
-rw-r--r--lib/qmmp/Effect/Effect.pro4
-rw-r--r--lib/qmmp/Effect/srconverter/CMakeLists.txt76
-rw-r--r--lib/qmmp/Effect/srconverter/effectsrconverterfactory.cpp57
-rw-r--r--lib/qmmp/Effect/srconverter/effectsrconverterfactory.h46
-rw-r--r--lib/qmmp/Effect/srconverter/settingsdialog.cpp48
-rw-r--r--lib/qmmp/Effect/srconverter/settingsdialog.h46
-rw-r--r--lib/qmmp/Effect/srconverter/settingsdialog.ui124
-rw-r--r--lib/qmmp/Effect/srconverter/srconverter.cpp125
-rw-r--r--lib/qmmp/Effect/srconverter/srconverter.h60
-rw-r--r--lib/qmmp/Effect/srconverter/srconverter.pro33
-rw-r--r--lib/qmmp/Input/ffmpeg/decoder_ffmpeg.cpp3
-rw-r--r--lib/qmmp/Input/flac/decoder_flac.cpp3
-rw-r--r--lib/qmmp/Input/mad/decoder_mad.cpp4
-rw-r--r--lib/qmmp/Input/mpc/decoder_mpc.cpp3
-rw-r--r--lib/qmmp/Input/vorbis/decoder_vorbis.cpp3
-rw-r--r--lib/qmmp/Output/alsa/outputalsa.cpp4
-rw-r--r--lib/qmmp/qmmp.pro3
-rw-r--r--lib/recycler.cpp87
-rw-r--r--lib/recycler.h2
-rw-r--r--lib/soundcore.cpp6
-rw-r--r--src/configdialog.cpp48
-rw-r--r--src/configdialog.h2
-rw-r--r--src/configdialog.ui14
-rw-r--r--src/pluginitem.cpp29
-rw-r--r--src/pluginitem.h20
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>&amp;OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>&amp;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