aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/plugins/Input/cue/decoder_cue.cpp6
-rw-r--r--src/plugins/Input/cue/decoder_cue.h2
-rw-r--r--src/plugins/Input/cue/decodercuefactory.cpp7
-rw-r--r--src/plugins/Input/cue/decodercuefactory.h2
-rw-r--r--src/plugins/Input/mad/decoder_mad.h3
-rw-r--r--src/plugins/Input/mad/decodermadfactory.cpp2
-rw-r--r--src/plugins/Input/mad/decodermadfactory.h2
-rw-r--r--src/plugins/Input/mad/translations/mad_plugin_ru.ts26
-rw-r--r--src/qmmp/CMakeLists.txt2
-rw-r--r--src/qmmp/abstractengine.h4
-rw-r--r--src/qmmp/audioparameters.cpp2
-rw-r--r--src/qmmp/decoder.cpp6
-rw-r--r--src/qmmp/decoderfactory.h4
-rw-r--r--src/qmmp/inputsource.cpp72
-rw-r--r--src/qmmp/inputsource.h46
-rw-r--r--src/qmmp/output.cpp6
-rw-r--r--src/qmmp/qmmp.pro6
-rw-r--r--src/qmmp/qmmpaudioengine.cpp242
-rw-r--r--src/qmmp/qmmpaudioengine.h15
-rw-r--r--src/qmmp/soundcore.cpp91
-rw-r--r--src/qmmp/soundcore.h2
-rw-r--r--src/qmmpui/mediaplayer.cpp9
-rw-r--r--src/qmmpui/translations/libqmmpui_ru.ts38
23 files changed, 347 insertions, 248 deletions
diff --git a/src/plugins/Input/cue/decoder_cue.cpp b/src/plugins/Input/cue/decoder_cue.cpp
index 8ee786105..944c9911a 100644
--- a/src/plugins/Input/cue/decoder_cue.cpp
+++ b/src/plugins/Input/cue/decoder_cue.cpp
@@ -32,8 +32,8 @@
#include "decoder_cue.h"
-DecoderCUE::DecoderCUE(const QString &url, QIODevice *input)
- : Decoder(input)
+DecoderCUE::DecoderCUE(const QString &url)
+ : Decoder()
{
m_path = url;
m_decoder = 0;
@@ -73,7 +73,7 @@ bool DecoderCUE::initialize()
m_length = parser.length(track);
m_offset = parser.offset(track);
- m_decoder = df->create(new QFile(m_path), m_path);
+ m_decoder = df->create(m_path, new QFile(m_path));
if(!m_decoder->initialize())
{
qWarning("DecoderCUE: invalid audio file");
diff --git a/src/plugins/Input/cue/decoder_cue.h b/src/plugins/Input/cue/decoder_cue.h
index 1f641574f..ce3bcb4b5 100644
--- a/src/plugins/Input/cue/decoder_cue.h
+++ b/src/plugins/Input/cue/decoder_cue.h
@@ -30,7 +30,7 @@ class QIDevice;
class DecoderCUE : public Decoder
{
public:
- DecoderCUE(const QString &url, QIODevice *input);
+ DecoderCUE(const QString &url);
virtual ~DecoderCUE();
// Standard Decoder API
diff --git a/src/plugins/Input/cue/decodercuefactory.cpp b/src/plugins/Input/cue/decodercuefactory.cpp
index a25e930f7..5b7a9a716 100644
--- a/src/plugins/Input/cue/decodercuefactory.cpp
+++ b/src/plugins/Input/cue/decodercuefactory.cpp
@@ -53,11 +53,10 @@ const DecoderProperties DecoderCUEFactory::properties() const
return properties;
}
-Decoder *DecoderCUEFactory::create(QIODevice *input, const QString &path)
+Decoder *DecoderCUEFactory::create(const QString &path, QIODevice *input)
{
- //Q_UNUSED(input);
- //Q_UNUSED(output);
- return new DecoderCUE(path, input);
+ Q_UNUSED(input);
+ return new DecoderCUE(path);
}
QList<FileInfo *> DecoderCUEFactory::createPlayList(const QString &fileName, bool useMetaData)
diff --git a/src/plugins/Input/cue/decodercuefactory.h b/src/plugins/Input/cue/decodercuefactory.h
index d24108369..451ae5f4f 100644
--- a/src/plugins/Input/cue/decodercuefactory.h
+++ b/src/plugins/Input/cue/decodercuefactory.h
@@ -40,7 +40,7 @@ public:
bool supports(const QString &source) const;
bool canDecode(QIODevice *input) const;
const DecoderProperties properties() const;
- Decoder *create(QIODevice *, const QString &);
+ Decoder *create(const QString &, QIODevice *);
QList<FileInfo *> createPlayList(const QString &fileName, bool useMetaData);
MetaDataModel* createMetaDataModel(const QString &path, QObject *parent = 0);
void showSettings(QWidget *parent);
diff --git a/src/plugins/Input/mad/decoder_mad.h b/src/plugins/Input/mad/decoder_mad.h
index 68fc35538..c78e3f8c8 100644
--- a/src/plugins/Input/mad/decoder_mad.h
+++ b/src/plugins/Input/mad/decoder_mad.h
@@ -29,11 +29,10 @@ public:
bool initialize();
qint64 totalTime();
int bitrate();
-
-private:
qint64 read(char *data, qint64 size);
void seek(qint64);
+private:
// helper functions
qint64 madOutput(char *data, qint64 size);
bool fillBuffer();
diff --git a/src/plugins/Input/mad/decodermadfactory.cpp b/src/plugins/Input/mad/decodermadfactory.cpp
index 47de2e828..11009d617 100644
--- a/src/plugins/Input/mad/decodermadfactory.cpp
+++ b/src/plugins/Input/mad/decodermadfactory.cpp
@@ -94,7 +94,7 @@ const DecoderProperties DecoderMADFactory::properties() const
return properties;
}
-Decoder *DecoderMADFactory::create(QIODevice *input, const QString &)
+Decoder *DecoderMADFactory::create(const QString&, QIODevice *input)
{
return new DecoderMAD(input);
}
diff --git a/src/plugins/Input/mad/decodermadfactory.h b/src/plugins/Input/mad/decodermadfactory.h
index 6107e56f0..a4e18c8f4 100644
--- a/src/plugins/Input/mad/decodermadfactory.h
+++ b/src/plugins/Input/mad/decodermadfactory.h
@@ -43,7 +43,7 @@ public:
bool supports(const QString &source) const;
bool canDecode(QIODevice *input) const;
const DecoderProperties properties() const;
- Decoder *create(QIODevice *, const QString &);
+ Decoder *create(const QString &path, QIODevice *input);
QList<FileInfo *> createPlayList(const QString &fileName, bool useMetaData);
MetaDataModel* createMetaDataModel(const QString &path, QObject *parent = 0);
void showSettings(QWidget *parent);
diff --git a/src/plugins/Input/mad/translations/mad_plugin_ru.ts b/src/plugins/Input/mad/translations/mad_plugin_ru.ts
index 6f337c558..d471fea15 100644
--- a/src/plugins/Input/mad/translations/mad_plugin_ru.ts
+++ b/src/plugins/Input/mad/translations/mad_plugin_ru.ts
@@ -44,27 +44,27 @@
<message>
<location filename="../mpegmetadatamodel.cpp" line="69"/>
<source>Format</source>
- <translation type="unfinished">Формат</translation>
+ <translation>Формат</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="71"/>
<source>Bitrate</source>
- <translation type="unfinished">Битовая частота</translation>
+ <translation>Битовая частота</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="71"/>
<source>kbps</source>
- <translation type="unfinished">Кб/с</translation>
+ <translation>Кб/с</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="73"/>
<source>Samplerate</source>
- <translation type="unfinished">Дискретизация</translation>
+ <translation>Дискретизация</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="73"/>
<source>Hz</source>
- <translation type="unfinished">Гц</translation>
+ <translation>Гц</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="77"/>
@@ -72,49 +72,49 @@
<location filename="../mpegmetadatamodel.cpp" line="83"/>
<location filename="../mpegmetadatamodel.cpp" line="86"/>
<source>Mode</source>
- <translation type="unfinished">Режим</translation>
+ <translation>Режим</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="89"/>
<source>KB</source>
- <translation type="unfinished">Кб</translation>
+ <translation>Кб</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="90"/>
<source>File size</source>
- <translation type="unfinished">Размер файла</translation>
+ <translation>Размер файла</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="92"/>
<location filename="../mpegmetadatamodel.cpp" line="94"/>
<source>Protection</source>
- <translation type="unfinished">Защита</translation>
+ <translation>Защита</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="92"/>
<location filename="../mpegmetadatamodel.cpp" line="96"/>
<location filename="../mpegmetadatamodel.cpp" line="100"/>
<source>Yes</source>
- <translation type="unfinished">Есть</translation>
+ <translation>Да</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="94"/>
<location filename="../mpegmetadatamodel.cpp" line="98"/>
<location filename="../mpegmetadatamodel.cpp" line="102"/>
<source>No</source>
- <translation type="unfinished">Нет</translation>
+ <translation>Нет</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="96"/>
<location filename="../mpegmetadatamodel.cpp" line="98"/>
<source>Copyright</source>
- <translation type="unfinished">Авторские права</translation>
+ <translation>Авторские права</translation>
</message>
<message>
<location filename="../mpegmetadatamodel.cpp" line="100"/>
<location filename="../mpegmetadatamodel.cpp" line="102"/>
<source>Original</source>
- <translation type="unfinished">Оригинальный</translation>
+ <translation>Оригинальный</translation>
</message>
</context>
<context>
diff --git a/src/qmmp/CMakeLists.txt b/src/qmmp/CMakeLists.txt
index b3d6904af..e27326517 100644
--- a/src/qmmp/CMakeLists.txt
+++ b/src/qmmp/CMakeLists.txt
@@ -57,6 +57,7 @@ SET(libqmmp_SRCS
qmmpaudioengine.cpp
abstractengine.cpp
audioparameters.cpp
+ inputsource.cpp
)
SET(libqmmp_MOC_HDRS
@@ -84,6 +85,7 @@ SET(libqmmp_MOC_HDRS
qmmpaudioengine.h
abstractengine.h
audioparameters.h
+ inputsource.h
)
SET(libqmmp_DEVEL_HDRS
diff --git a/src/qmmp/abstractengine.h b/src/qmmp/abstractengine.h
index 75829174f..442e02da7 100644
--- a/src/qmmp/abstractengine.h
+++ b/src/qmmp/abstractengine.h
@@ -27,6 +27,7 @@
#include <QThread>
class QIODevice;
+class InputSource;
/*!
* @author Ilya Kotov <forkotov02@hotmail.ru>
@@ -42,7 +43,8 @@ public:
* Prepares decoder for usage.
* Subclass should reimplement this function.
*/
- virtual bool initialize(const QString &source, QIODevice *input = 0) = 0;
+ //virtual bool initialize(const QString &source, QIODevice *input = 0) = 0;
+ virtual bool enqueue(InputSource *source) = 0;
/*!
* Returns the total time in milliseconds.
* Subclass should reimplement this function.
diff --git a/src/qmmp/audioparameters.cpp b/src/qmmp/audioparameters.cpp
index 0a858a1e4..34ffe98a9 100644
--- a/src/qmmp/audioparameters.cpp
+++ b/src/qmmp/audioparameters.cpp
@@ -35,7 +35,7 @@ bool AudioParameters::operator==(const AudioParameters &p) const
bool AudioParameters::operator!=(const AudioParameters &p) const
{
- return !operator!=(p);
+ return !operator==(p);
}
quint32 AudioParameters::sampleRate() const
diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp
index 73a8816c1..151a1a23a 100644
--- a/src/qmmp/decoder.cpp
+++ b/src/qmmp/decoder.cpp
@@ -31,11 +31,7 @@ Decoder::Decoder(QIODevice *input) : m_input(input)
{}
Decoder::~Decoder()
-{
- if(m_input)
- m_input->deleteLater();
- m_input = 0;
-}
+{}
void Decoder::configure(quint32 srate, int chan, int bps)
{
diff --git a/src/qmmp/decoderfactory.h b/src/qmmp/decoderfactory.h
index 144d3ccd7..f71c5e9af 100644
--- a/src/qmmp/decoderfactory.h
+++ b/src/qmmp/decoderfactory.h
@@ -84,10 +84,10 @@ public:
virtual const DecoderProperties properties() const = 0;
/*!
* Creates decoder object.
- * @param input Input data (if required)
* @param path File path
+ * @param input Input data (if required)
*/
- virtual Decoder *create(QIODevice *input = 0, const QString &path = QString()) = 0;
+ virtual Decoder *create(const QString &path , QIODevice *input = 0) = 0;
/*!
* Extracts metadata and audio information from file \b path and returns a list of FileInfo items.
* One file may contain several playlist items (for example: cda disk or flac with embedded cue)
diff --git a/src/qmmp/inputsource.cpp b/src/qmmp/inputsource.cpp
new file mode 100644
index 000000000..f69912b42
--- /dev/null
+++ b/src/qmmp/inputsource.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2009 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 <QFile>
+#include "streamreader.h"
+#include "inputsource.h"
+
+InputSource::InputSource(const QString &source, QObject *parent) : QObject(parent)
+{
+ m_device = 0;
+ m_isValid = FALSE;
+ m_url = source;
+ QUrl url;
+ if (source.contains("://")) //url
+ url = source;
+ else if (QFile::exists(source))
+ {
+ url = QUrl::fromLocalFile(source);
+ }
+ else
+ {
+ qDebug("InputSource: file doesn't exist");
+ return;
+ }
+ m_url = url;
+ if (url.scheme() == "file")
+ {
+ m_device = new QFile(source, this);
+ /*if (!m_device->open(QIODevice::ReadOnly))
+ {
+ qDebug("InputSource: cannot open input");
+ return FALSE;
+ }*/
+ }
+ if (url.scheme() == "http")
+ {
+ m_device = new StreamReader(source, this);
+ //connect(m_input, SIGNAL(bufferingProgress(int)), SIGNAL(bufferingProgress(int)));
+ connect(m_device, SIGNAL(readyRead()),SIGNAL(readyRead()));
+ qobject_cast<StreamReader *>(m_device)->downloadFile();
+ return;
+ }
+ m_isValid = FALSE;
+}
+
+const QUrl InputSource::url()
+{
+ return m_url;
+}
+
+QIODevice *InputSource::ioDevice()
+{
+ return m_device;
+}
+
diff --git a/src/qmmp/inputsource.h b/src/qmmp/inputsource.h
new file mode 100644
index 000000000..d68ac91b7
--- /dev/null
+++ b/src/qmmp/inputsource.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * Copyright (C) 2009 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 INPUTSOURCE_H
+#define INPUTSOURCE_H
+
+#include <QObject>
+#include <QString>
+#include <QUrl>
+#include <QIODevice>
+
+class InputSource : public QObject
+{
+Q_OBJECT
+public:
+ InputSource(const QString &source, QObject *parent = 0);
+ QIODevice *ioDevice();
+ const QUrl url();
+
+signals:
+ void readyRead();
+
+private:
+ QUrl m_url;
+ QIODevice *m_device;
+ bool m_isValid;
+};
+
+#endif // INPUTSOURCE_H
diff --git a/src/qmmp/output.cpp b/src/qmmp/output.cpp
index 87bce44c8..ca4b73805 100644
--- a/src/qmmp/output.cpp
+++ b/src/qmmp/output.cpp
@@ -33,7 +33,6 @@ Output::Output (QObject* parent) : QThread (parent), m_recycler (stackSize())
void Output::configure(quint32 freq, int chan, int prec)
{
- qDebug("%u -- %d -- %d", freq, chan, prec);
m_frequency = freq;
m_channels = chan;
m_precision = prec;
@@ -164,7 +163,7 @@ void Output::run()
{
mutex()->lock ();
recycler()->mutex()->lock ();
- done = m_userStop;
+ done = m_userStop || (m_finish && recycler()->empty());
while (!done && (recycler()->empty() || m_pause))
{
@@ -172,7 +171,7 @@ void Output::run()
recycler()->cond()->wakeOne();
recycler()->cond()->wait(recycler()->mutex());
mutex()->lock ();
- done = m_userStop;
+ done = m_userStop || m_finish;
}
status();
if (!b)
@@ -181,6 +180,7 @@ void Output::run()
if (b && b->rate)
m_kbps = b->rate;
}
+
recycler()->cond()->wakeOne();
recycler()->mutex()->unlock();
mutex()->unlock();
diff --git a/src/qmmp/qmmp.pro b/src/qmmp/qmmp.pro
index c254399c8..1cbfb1945 100644
--- a/src/qmmp/qmmp.pro
+++ b/src/qmmp/qmmp.pro
@@ -24,7 +24,8 @@ HEADERS += recycler.h \
tagmodel.h \
abstractengine.h \
qmmpaudioengine.h \
- audioparameters.h
+ audioparameters.h \
+ inputsource.h
SOURCES += recycler.cpp \
decoder.cpp \
output.cpp \
@@ -44,7 +45,8 @@ SOURCES += recycler.cpp \
tagmodel.cpp \
abstractengine.cpp \
qmmpaudioengine.cpp \
- audioparameters.cpp
+ audioparameters.cpp \
+ inputsource.cpp
FORMS +=
unix:TARGET = ../../lib/qmmp
win32:TARGET = ../../../bin/qmmp
diff --git a/src/qmmp/qmmpaudioengine.cpp b/src/qmmp/qmmpaudioengine.cpp
index ae2efff89..5ebcee90d 100644
--- a/src/qmmp/qmmpaudioengine.cpp
+++ b/src/qmmp/qmmpaudioengine.cpp
@@ -27,8 +27,10 @@
#include "decoder.h"
#include "output.h"
#include "decoderfactory.h"
+#include "inputsource.h"
#include "qmmpaudioengine.h"
+
extern "C"
{
#include "equ/iir.h"
@@ -47,12 +49,12 @@ QmmpAudioEngine::QmmpAudioEngine(QObject *parent)
m_bks = Buffer::size();
m_decoder = 0;
m_output = 0;
- m_decoder2 = 0;
reset();
}
QmmpAudioEngine::~QmmpAudioEngine()
{
+ stop();
reset();
if(m_output_buf)
delete [] m_output_buf;
@@ -70,68 +72,42 @@ void QmmpAudioEngine::reset()
m_bitrate = 0;
m_chan = 0;
m_bps = 0;
- m_source.clear();
}
-
-bool QmmpAudioEngine::initialize(const QString &source, QIODevice *input)
+bool QmmpAudioEngine::enqueue(InputSource *source)
{
- if(m_decoder && isRunning() && m_output && m_output->isRunning())
- {
- m_factory = Decoder::findByPath(source);
- if(!m_factory)
- m_factory = Decoder::findByURL(QUrl(source));
- m_decoder2 = m_factory->create(input, source);
- if(!m_decoder2->initialize())
- return FALSE;
+ DecoderFactory *factory = Decoder::findByURL(source->url());
- if(m_decoder2->audioParameters() == m_decoder->audioParameters())
- {
- qDebug("accepted!!");
- m_source = source;
- return TRUE;
- }
- delete m_decoder2;
- m_decoder2 = 0;
- }
- else
- m_decoder2 = 0;
- stop();
- m_source = source;
- m_output = Output::create(this);
- m_output->recycler()->clear();
- if (!m_output)
+ if(!factory && source->url().scheme() == "file")
+ factory = Decoder::findByPath(source->url().toLocalFile());
+ if(!factory && source->ioDevice())
+ factory = Decoder::findByContent(source->ioDevice());
+ if(!factory)
{
- qWarning("SoundCore: unable to create output");
- StateHandler::instance()->dispatch(Qmmp::FatalError);
+ qWarning("QmmpAudioEngine: unsupported file format");
return FALSE;
}
- if (!m_output->initialize())
+ if(factory->properties().noInput && source->ioDevice())
+ source->ioDevice()->close();
+ Decoder *decoder = 0;
+ if(source->url().scheme() == "file")
+ decoder = factory->create(source->url().toLocalFile(), source->ioDevice());
+ else
+ decoder = factory->create(source->url().toString(), source->ioDevice());
+ if(!decoder->initialize())
{
- qWarning("SoundCore: unable to initialize output");
- delete m_output;
- m_output = 0;
- StateHandler::instance()->dispatch(Qmmp::FatalError);
+ qWarning("QmmpAudioEngine: invalid file format");
+ delete decoder;
return FALSE;
}
-
- m_factory = Decoder::findByPath(source);
- if(!m_factory)
- m_factory = Decoder::findByURL(QUrl(source));
- m_decoder = m_factory->create(input, source);
- if (!m_decoder)
+ if(!m_output)
{
- qWarning("SoundCore: unsupported fileformat");
- stop();
- StateHandler::instance()->dispatch(Qmmp::NormalError);
- return FALSE;
+ m_output = createOutput(decoder);
+ if(!m_output)
+ return FALSE;
}
- if(!m_decoder->initialize())
- return FALSE;
-
- m_output->configure(m_decoder->audioParameters().sampleRate(),
- m_decoder->audioParameters().channels(),
- m_decoder->audioParameters().bits());
+ m_decoders.enqueue(decoder);
+ m_inputs.insert(decoder, source);
return TRUE;
}
@@ -143,11 +119,6 @@ qint64 QmmpAudioEngine::totalTime()
return 0;
}
-Output *QmmpAudioEngine::output()
-{
- return m_output;
-}
-
void QmmpAudioEngine::setEQ(double bands[10], double preamp)
{
set_preamp(0, 1.0 + 0.0932471 *preamp + 0.00279033 * preamp * preamp);
@@ -203,11 +174,6 @@ void QmmpAudioEngine::seek(qint64 time)
}
}
-int QmmpAudioEngine::bitrate()
-{
- return 0;
-}
-
void QmmpAudioEngine::pause()
{
if (m_output)
@@ -270,13 +236,14 @@ void QmmpAudioEngine::stop()
m_output = 0;
}
- if(m_decoder)
+ while(!m_decoders.isEmpty())
{
- qDebug("delete m_decoder");
- delete m_decoder;
- m_decoder = 0;
+ Decoder *d = m_decoders.dequeue();
+ delete m_inputs.take(d);
+ delete d;
}
reset();
+ m_decoder = 0;
}
qint64 QmmpAudioEngine::produceSound(char *data, qint64 size, quint32 brate, int chan)
@@ -312,7 +279,7 @@ qint64 QmmpAudioEngine::produceSound(char *data, qint64 size, quint32 brate, int
prev_data = out_data;
}
- Buffer *b = output()->recycler()->get(w);
+ Buffer *b = m_output->recycler()->get(w);
memcpy(b->data, out_data, w);
@@ -325,7 +292,7 @@ qint64 QmmpAudioEngine::produceSound(char *data, qint64 size, quint32 brate, int
b->nbytes = w;
b->rate = brate;
- output()->recycler()->add();
+ m_output->recycler()->add();
size -= sz;
memmove(data, data + sz, size);
@@ -334,11 +301,11 @@ qint64 QmmpAudioEngine::produceSound(char *data, qint64 size, quint32 brate, int
void QmmpAudioEngine::finish()
{
- if (output())
+ if (m_output)
{
- output()->mutex()->lock ();
- output()->finish();
- output()->mutex()->unlock();
+ m_output->mutex()->lock ();
+ m_output->finish();
+ m_output->mutex()->unlock();
}
emit playbackFinished();
}
@@ -348,9 +315,15 @@ void QmmpAudioEngine::run()
Q_ASSERT(m_chan == 0);
Q_ASSERT(!m_output_buf);
mutex()->lock ();
- if (m_output)
- m_output->start();
qint64 len = 0;
+ if(m_decoders.isEmpty())
+ {
+ mutex()->unlock ();
+ return;
+ }
+
+ m_decoder = m_decoders.dequeue();
+ m_output->start();
mutex()->unlock();
sendMetaData();
@@ -364,10 +337,10 @@ void QmmpAudioEngine::run()
{
m_decoder->seek(m_seekTime);
m_seekTime = -1;
- output()->recycler()->mutex()->lock ();
- while(output()->recycler()->used() > 1)
- output()->recycler()->done();
- output()->recycler()->mutex()->unlock ();
+ m_output->recycler()->mutex()->lock ();
+ while(m_output->recycler()->used() > 1)
+ m_output->recycler()->done();
+ m_output->recycler()->mutex()->unlock ();
}
len = m_decoder->read((char *)(m_output_buf + m_output_at),
@@ -377,39 +350,64 @@ void QmmpAudioEngine::run()
{
m_bitrate = m_decoder->bitrate();
m_output_at += len;
- if (output())
+ if (m_output)
flush();
}
else if (len == 0)
{
- if(m_decoder2)
+ if(!m_decoders.isEmpty())
{
- qDebug("next decoder");
+ delete m_inputs.take(m_decoder);
delete m_decoder;
- m_decoder = m_decoder2;
- emit playbackFinished();
- StateHandler::instance()->dispatch(Qmmp::Stopped); //fake stop/start cycle
- StateHandler::instance()->dispatch(Qmmp::Buffering);
- StateHandler::instance()->dispatch(Qmmp::Playing);
- m_output->seek(0); //reset counter
- mutex()->unlock();
- sendMetaData();
- continue;
+ m_decoder = m_decoders.dequeue();
+ //use current output if possible
+ if(m_decoder->audioParameters() == m_ap)
+ {
+ emit playbackFinished();
+ StateHandler::instance()->dispatch(Qmmp::Stopped); //fake stop/start cycle
+ StateHandler::instance()->dispatch(Qmmp::Buffering);
+ StateHandler::instance()->dispatch(Qmmp::Playing);
+ m_output->seek(0); //reset counter
+ mutex()->unlock();
+ sendMetaData();
+ continue;
+ }
+ else
+ {
+ flush(TRUE);
+ finish();
+ //wake up waiting threads
+ cond()->wakeAll();
+ mutex()->unlock();
+ m_output->recycler()->mutex()->lock ();
+ m_output->recycler()->cond()->wakeAll();
+ m_output->recycler()->mutex()->unlock();
+
+ m_output->wait();
+ delete m_output;
+ m_output = createOutput(m_decoder);
+ if(m_output)
+ {
+ m_output->start();
+ sendMetaData();
+ continue;
+ }
+ }
}
flush(TRUE);
- if (output())
+ if (m_output)
{
- output()->recycler()->mutex()->lock ();
+ m_output->recycler()->mutex()->lock ();
// end of stream
- while (!output()->recycler()->empty() && !m_user_stop)
+ while (!m_output->recycler()->empty() && !m_user_stop)
{
- output()->recycler()->cond()->wakeOne();
+ m_output->recycler()->cond()->wakeOne();
mutex()->unlock();
- output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ m_output->recycler()->cond()->wait(m_output->recycler()->mutex());
mutex()->lock ();
}
- output()->recycler()->mutex()->unlock();
+ m_output->recycler()->mutex()->unlock();
}
m_done = TRUE;
m_finish = !m_user_stop;
@@ -418,6 +416,12 @@ void QmmpAudioEngine::run()
m_finish = TRUE;
mutex()->unlock();
}
+ if(m_decoder)
+ {
+ delete m_inputs.take(m_decoder);
+ delete m_decoder;
+ m_decoder = 0;
+ }
mutex()->lock ();
if (m_finish)
@@ -431,19 +435,19 @@ void QmmpAudioEngine::flush(bool final)
while ((!m_done && !m_finish) && m_output_at > min)
{
- output()->recycler()->mutex()->lock ();
+ m_output->recycler()->mutex()->lock ();
if(m_seekTime >= 0)
{
- while(output()->recycler()->used() > 1)
- output()->recycler()->done();
- output()->recycler()->mutex()->unlock ();
+ while(m_output->recycler()->used() > 1)
+ m_output->recycler()->done();
+ m_output->recycler()->mutex()->unlock ();
m_output_at = 0;
break;
}
- while ((!m_done && !m_finish) && output()->recycler()->full())
+ while ((!m_done && !m_finish) && m_output->recycler()->full())
{
mutex()->unlock();
- output()->recycler()->cond()->wait(output()->recycler()->mutex());
+ m_output->recycler()->cond()->wait(m_output->recycler()->mutex());
mutex()->lock ();
m_done = m_user_stop;
}
@@ -455,20 +459,23 @@ void QmmpAudioEngine::flush(bool final)
m_output_at -= produceSound((char*)m_output_buf, m_output_at, m_bitrate, m_chan);
}
- if (output()->recycler()->full())
+ if (m_output->recycler()->full())
{
- output()->recycler()->cond()->wakeOne();
+ m_output->recycler()->cond()->wakeOne();
}
- output()->recycler()->mutex()->unlock();
+ m_output->recycler()->mutex()->unlock();
}
}
void QmmpAudioEngine::sendMetaData()
{
- if (QFile::exists(m_source)) //send metadata for local files
+ if(!m_decoder || m_inputs.isEmpty())
+ return;
+ QUrl url = m_inputs.value(m_decoder)->url();
+ if (url.scheme() == "file") //send metadata for local files only
{
- QList <FileInfo *> list = m_factory->createPlayList(m_source, TRUE);
+ QList <FileInfo *> list = Decoder::createPlayList(url.toLocalFile(), TRUE);
if (!list.isEmpty())
{
StateHandler::instance()->dispatch(list[0]->metaData());
@@ -477,3 +484,26 @@ void QmmpAudioEngine::sendMetaData()
}
}
}
+
+Output *QmmpAudioEngine::createOutput(Decoder *d)
+{
+ m_ap = d->audioParameters();
+ Output *output = Output::create(0);
+ if(!output)
+ {
+ qWarning("QmmpAudioEngine: unable to create output");
+ StateHandler::instance()->dispatch(Qmmp::FatalError);
+ return 0;
+ }
+ if (!output->initialize())
+ {
+ qWarning("SoundCore: unable to initialize output");
+ delete output;
+ output = 0;
+ StateHandler::instance()->dispatch(Qmmp::FatalError);
+ return FALSE;
+ }
+ output->configure(m_ap.sampleRate(), m_ap.channels(), m_ap.bits());
+ return output;
+}
+
diff --git a/src/qmmp/qmmpaudioengine.h b/src/qmmp/qmmpaudioengine.h
index 1cfed931b..e16ecef72 100644
--- a/src/qmmp/qmmpaudioengine.h
+++ b/src/qmmp/qmmpaudioengine.h
@@ -21,7 +21,10 @@
#ifndef QMMPAUDIOENGINE_H
#define QMMPAUDIOENGINE_H
+#include <QQueue>
+#include <QHash>
#include "abstractengine.h"
+#include "audioparameters.h"
class QIODevice;
class Output;
@@ -29,6 +32,7 @@ class Effect;
class DecoderFactory;
class StateHandler;
class Decoder;
+class InputSource;
class QmmpAudioEngine : public AbstractEngine
@@ -38,13 +42,11 @@ public:
QmmpAudioEngine(QObject *parent);
~QmmpAudioEngine();
- bool initialize(const QString &source, QIODevice *input = 0);
+ bool enqueue(InputSource *source);
qint64 totalTime();
void seek(qint64 time);
void stop();
- int bitrate();
void pause();
- Output *output();
void setEQ(double bands[10], double preamp);
void setEQEnabled(bool on);
@@ -60,6 +62,7 @@ private:
void flush(bool = FALSE);
qint64 produceSound(char *data, qint64 size, quint32 brate, int chan);
void sendMetaData();
+ Output *createOutput(Decoder *d);
DecoderFactory *m_factory;
QList <Effect*> m_effects;
@@ -75,8 +78,10 @@ private:
int m_bitrate, m_chan, m_bps;
unsigned char *m_output_buf;
Decoder *m_decoder;
- QString m_source;
- Decoder *m_decoder2;
+ QQueue <Decoder*> m_decoders;
+ QHash <Decoder*, InputSource*> m_inputs;
+ AudioParameters m_ap;
+
};
#endif // QMMPAUDIOENGINE_H
diff --git a/src/qmmp/soundcore.cpp b/src/qmmp/soundcore.cpp
index 83d268a88..271711847 100644
--- a/src/qmmp/soundcore.cpp
+++ b/src/qmmp/soundcore.cpp
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2006-2008 by Ilya Kotov *
+ * Copyright (C) 2006-2009 by Ilya Kotov *
* forkotov02@hotmail.ru *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -29,6 +29,7 @@
#include "streamreader.h"
#include "effect.h"
#include "statehandler.h"
+#include "inputsource.h"
#include "volumecontrol.h"
#include "soundcore.h"
@@ -73,67 +74,26 @@ SoundCore::~SoundCore()
stop();
}
-bool SoundCore::play(const QString &source, bool queue)
+bool SoundCore::play(const QString &source, bool queue)
{
if(!queue)
stop();
+
m_source = source;
- /*if (m_handler->state() != Qmmp::Stopped) //clear error state
- m_handler->dispatch(Qmmp::Stopped);
- m_handler->dispatch(Qmmp::Buffering); //buffering state*/
+ m_inputSource = new InputSource(source, this);
- QUrl url;
- if (source.contains("://")) //url
- url = source;
- else if (QFile::exists(source))
- url = QUrl::fromLocalFile(source);
+ if(m_inputSource->ioDevice())
+ connect(m_inputSource->ioDevice(), SIGNAL(readyRead()), SLOT(decode()));
else
- {
- qDebug("SoundCore: file doesn't exist");
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
- }
-
- m_factory = Decoder::findByURL(url);
- m_input = 0;
- if (m_factory)
return decode();
- if (url.scheme() == "file")
- {
- if ((m_factory = Decoder::findByPath(m_source)))
- {
- m_input = new QFile(m_source);
- if (!m_input->open(QIODevice::ReadOnly))
- {
- qDebug("SoundCore: cannot open input");
- stop();
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
- }
- return decode();
- }
- else
- {
- qWarning("SoundCore: unsupported fileformat");
- stop();
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
- }
- }
- if (url.scheme() == "http")
- {
- m_input = new StreamReader(source, this);
- connect(m_input, SIGNAL(bufferingProgress(int)), SIGNAL(bufferingProgress(int)));
- connect(m_input, SIGNAL(readyRead()),SLOT(decode()));
- qobject_cast<StreamReader *>(m_input)->downloadFile();
- return TRUE;
- }
- qWarning("SoundCore: unsupported fileformat");
- stop();
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
+ if(qobject_cast<StreamReader *>(m_inputSource->ioDevice()))
+ qobject_cast<StreamReader *>(m_inputSource->ioDevice())->downloadFile();
+ else
+ m_inputSource->ioDevice()->open(QIODevice::ReadOnly);
+ return decode();
+ return TRUE;
}
void SoundCore::stop()
@@ -271,21 +231,8 @@ QString SoundCore::metaData(Qmmp::MetaData key)
bool SoundCore::decode()
{
- if (!m_factory)
- {
- if (!m_input->open(QIODevice::ReadOnly))
- {
- qDebug("SoundCore:: cannot open input");
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
- }
- if (!(m_factory = Decoder::findByMime(qobject_cast<StreamReader *>(m_input)->contentType())))
- if (!(m_factory = Decoder::findByContent(m_input)))
- {
- m_handler->dispatch(Qmmp::NormalError);
- return FALSE;
- }
- }
+ qDebug("ready");
+ disconnect(m_inputSource->ioDevice(), SIGNAL(readyRead()), this, SLOT(decode()));
if(!m_engine)
{
@@ -293,10 +240,16 @@ bool SoundCore::decode()
connect(m_engine, SIGNAL(playbackFinished()), SIGNAL(finished()));
}
- if(m_engine->initialize(m_source, m_input))
+ if(m_engine->enqueue(m_inputSource))
+ {
+ m_inputSource->setParent(m_engine);
m_engine->start();
+ }
else
+ {
+ delete m_inputSource;
return FALSE;
+ }
setEQ(m_bands, m_preamp);
setEQEnabled(m_useEQ);
diff --git a/src/qmmp/soundcore.h b/src/qmmp/soundcore.h
index b8d103ba9..f35d96656 100644
--- a/src/qmmp/soundcore.h
+++ b/src/qmmp/soundcore.h
@@ -30,6 +30,7 @@
class QIODevice;
class VolumeControl;
class QmmpAudioEngine;
+class InputSource;
/*! \brief The SoundCore class provides a simple interface for audio playback.
* @author Ilya Kotov <forkotov02@hotmail.ru>
@@ -225,6 +226,7 @@ private:
StateHandler *m_handler;
VolumeControl *m_volumeControl;
QmmpAudioEngine *m_engine;
+ InputSource *m_inputSource;
};
#endif
diff --git a/src/qmmpui/mediaplayer.cpp b/src/qmmpui/mediaplayer.cpp
index d0f55ba9e..43038724e 100644
--- a/src/qmmpui/mediaplayer.cpp
+++ b/src/qmmpui/mediaplayer.cpp
@@ -65,7 +65,6 @@ void MediaPlayer::initialize(SoundCore *core, PlayListModel *model)
m_repeat = FALSE;
connect(m_core, SIGNAL(aboutToFinish()), SLOT(updateNextUrl()));
connect(m_core, SIGNAL(finished()), SLOT(next()));
- //connect(m_model, SIGNAL(listChanged()), SLOT(updateNextUrl()));
}
PlayListModel *MediaPlayer::playListModel()
@@ -80,7 +79,6 @@ bool MediaPlayer::isRepeatable() const
void MediaPlayer::play()
{
- //disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
m_model->doCurrentVisibleRequest();
if (m_core->state() == Qmmp::Paused)
{
@@ -139,11 +137,7 @@ void MediaPlayer::play()
}
}
else
- {
m_skips = 0;
- /*updateNextUrl();
- connect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));*/
- }
}
void MediaPlayer::stop()
@@ -154,7 +148,6 @@ void MediaPlayer::stop()
void MediaPlayer::next()
{
- //disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
if (!m_model->isEmptyQueue())
{
m_model->setCurrentToQueued();
@@ -175,7 +168,6 @@ void MediaPlayer::next()
void MediaPlayer::previous()
{
- //disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
if (!m_model->previous())
{
stop();
@@ -204,7 +196,6 @@ void MediaPlayer::setRepeatable(bool r)
}
m_repeat = r;
emit repeatableChanged(r);
- //updateNextUrl();
}
void MediaPlayer::updateNextUrl()
diff --git a/src/qmmpui/translations/libqmmpui_ru.ts b/src/qmmpui/translations/libqmmpui_ru.ts
index f43c9650e..c3040c409 100644
--- a/src/qmmpui/translations/libqmmpui_ru.ts
+++ b/src/qmmpui/translations/libqmmpui_ru.ts
@@ -6,47 +6,47 @@
<message>
<location filename="../detailsdialog.cpp" line="74"/>
<source>Title</source>
- <translation type="unfinished"></translation>
+ <translation>Название</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="75"/>
<source>Artist</source>
- <translation type="unfinished"></translation>
+ <translation>Исполнитель</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="76"/>
<source>Album</source>
- <translation type="unfinished"></translation>
+ <translation>Альбом</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="77"/>
<source>Comment</source>
- <translation type="unfinished"></translation>
+ <translation>Комментарий</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="78"/>
<source>Genre</source>
- <translation type="unfinished"></translation>
+ <translation>Жанр</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="79"/>
<source>Composer</source>
- <translation type="unfinished"></translation>
+ <translation>Композитр</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="81"/>
<source>Year</source>
- <translation type="unfinished"></translation>
+ <translation>Год</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="83"/>
<source>Track</source>
- <translation type="unfinished"></translation>
+ <translation>Дорожка</translation>
</message>
<message>
<location filename="../detailsdialog.cpp" line="85"/>
<source>Disc number</source>
- <translation type="unfinished"></translation>
+ <translation>Номер диска</translation>
</message>
<message>
<location filename="../detailsdialog.ui" line="14"/>
@@ -129,54 +129,54 @@ p, li { white-space: pre-wrap; }
<message>
<location filename="../tageditor.ui" line="38"/>
<source>Title:</source>
- <translation type="unfinished">Название:</translation>
+ <translation>Название:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="64"/>
<source>Artist:</source>
- <translation type="unfinished">Исполнитель:</translation>
+ <translation>Исполнитель:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="90"/>
<source>Album:</source>
- <translation type="unfinished">Альбом:</translation>
+ <translation>Альбом:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="113"/>
<source>Composer:</source>
- <translation type="unfinished">Композитор:</translation>
+ <translation>Композитор:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="133"/>
<source>Genre:</source>
- <translation type="unfinished">Жанр:</translation>
+ <translation>Жанр:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="159"/>
<source>Disc number:</source>
- <translation type="unfinished">Номер диска:</translation>
+ <translation>Номер диска:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="169"/>
<location filename="../tageditor.ui" line="201"/>
<location filename="../tageditor.ui" line="239"/>
<source>?</source>
- <translation type="unfinished"></translation>
+ <translation></translation>
</message>
<message>
<location filename="../tageditor.ui" line="182"/>
<source>Track:</source>
- <translation type="unfinished"></translation>
+ <translation></translation>
</message>
<message>
<location filename="../tageditor.ui" line="220"/>
<source>Year:</source>
- <translation type="unfinished"></translation>
+ <translation></translation>
</message>
<message>
<location filename="../tageditor.ui" line="252"/>
<source>Comment:</source>
- <translation type="unfinished">Комментарий:</translation>
+ <translation>Комментарий:</translation>
</message>
<message>
<location filename="../tageditor.ui" line="274"/>