aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2009-07-15 14:39:35 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2009-07-15 14:39:35 +0000
commitdb0834220d3c3e11c77d24de356cdd975343442d (patch)
tree483750c572af6d8c74852f9be37adb0c1c606c02
parentd69b825c74552cbaa7027297782e3c2bd89901a7 (diff)
downloadqmmp-db0834220d3c3e11c77d24de356cdd975343442d.tar.gz
qmmp-db0834220d3c3e11c77d24de356cdd975343442d.tar.bz2
qmmp-db0834220d3c3e11c77d24de356cdd975343442d.zip
fixed cue support
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@1037 90c681e8-e032-0410-971d-27865f9a5e38
-rw-r--r--src/plugins/Input/cue/decoder_cue.cpp27
-rw-r--r--src/qmmp/decoder.cpp25
-rw-r--r--src/qmmp/decoder.h57
-rw-r--r--src/qmmp/soundcore.cpp20
-rw-r--r--src/qmmp/soundcore.h18
-rw-r--r--src/qmmp/statehandler.cpp2
-rw-r--r--src/qmmp/statehandler.h2
-rw-r--r--src/qmmpui/mediaplayer.cpp41
-rw-r--r--src/qmmpui/mediaplayer.h2
9 files changed, 118 insertions, 76 deletions
diff --git a/src/plugins/Input/cue/decoder_cue.cpp b/src/plugins/Input/cue/decoder_cue.cpp
index f65e17f79..6064025e6 100644
--- a/src/plugins/Input/cue/decoder_cue.cpp
+++ b/src/plugins/Input/cue/decoder_cue.cpp
@@ -122,6 +122,7 @@ bool DecoderCUE::initialize()
connect(stateHandler(), SIGNAL(aboutToFinish()), SLOT(proccessFinish()));
//prepare decoder and ouput objects
m_decoder->initialize();
+ qDebug("%lld == %lld", m_offset, m_length);
m_decoder->setFragment(m_offset, m_length);
//send metadata
QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData();
@@ -257,34 +258,23 @@ void DecoderCUE::run()
void DecoderCUE::proccessFinish()
{
- qDebug("==>%s", qPrintable(SoundCore::instance()->nextUrl()));
- qDebug("==>%s", qPrintable(m_nextUrl));
- if(!SoundCore::instance()->nextUrl().isEmpty()
- && !m_nextUrl.isEmpty()
- && SoundCore::instance()->nextUrl() == m_nextUrl)
+ if(nextUrlRequest(m_nextUrl))
{
- qDebug("prefinish");
- qDebug("next url: %s", qPrintable(m_nextUrl));
+ qDebug("DecoderCUE: using next url");
int track = m_nextUrl.section("#", -1).toInt();
+ qDebug("==%d", track);
QString p = QUrl(m_nextUrl).path();
p.replace(QString(QUrl::toPercentEncoding("#")), "#");
p.replace(QString(QUrl::toPercentEncoding("%")), "%");
-
+ //update decoder's fragment
CUEParser parser(p);
m_length = parser.length(track);
m_offset = parser.offset(track);
m_decoder->mutex()->lock();
+ qDebug("%lld == %lld", m_offset, m_length);
m_decoder->setFragment(m_offset, m_length);
m_output2->seek(0);
m_decoder->mutex()->unlock();
-
- //stateHandler()->dispatch(Qmmp::Stopped);
- //stateHandler()->dispatch(Qmmp::Buffering);
- //stateHandler()->dispatch(Qmmp::Playing);
- //m_decoder->mutex()->lock();
- //m_output2->seek(0);
- //m_decoder->mutex()->unlock();
-
// find next track
if(track <= parser.count() - 1)
m_nextUrl = parser.info(track + 1)->path();
@@ -293,10 +283,11 @@ void DecoderCUE::proccessFinish()
//is it track of another file?
if(QUrl(m_nextUrl).path() != p)
m_nextUrl.clear();
+ //change track
emit playbackFinished();
+ QMap<Qmmp::MetaData, QString> metaData = parser.info(track)->metaData();
+ stateHandler()->dispatch(metaData);
}
- else
- Decoder::stop();
}
CUEStateHandler::CUEStateHandler(QObject *parent): StateHandler(parent){}
diff --git a/src/qmmp/decoder.cpp b/src/qmmp/decoder.cpp
index ebbd2528b..f6a9b95f9 100644
--- a/src/qmmp/decoder.cpp
+++ b/src/qmmp/decoder.cpp
@@ -95,6 +95,7 @@ void Decoder::init()
_m_length_in_bytes = 0;
_m_offset = 0;
_m_totalBytes = 0;
+ _m_useNextUrl = FALSE;
}
DecoderFactory *Decoder::factory() const
@@ -193,9 +194,26 @@ void Decoder::setFragment(qint64 offset, qint64 length)
void Decoder::stop()
{
+ _m_nextUrl.clear();
_m_user_stop = TRUE;
}
+void Decoder::setNextUrl(const QString &url)
+{
+ _m_nextUrl = url;
+}
+
+void Decoder::clearNextUrl()
+{
+ _m_nextUrl.clear();
+ _m_useNextUrl = FALSE;
+}
+
+bool Decoder::nextUrlAccepted()
+{
+ return _m_useNextUrl;
+}
+
qint64 Decoder::produceSound(char *data, qint64 size, quint32 brate, int chan)
{
ulong sz = size < _blksize ? size : _blksize;
@@ -310,7 +328,6 @@ void Decoder::run()
else if (len == 0)
{
flush(TRUE);
-
if (output())
{
output()->recycler()->mutex()->lock ();
@@ -370,6 +387,12 @@ void Decoder::flush(bool final)
}
}
+bool Decoder::nextUrlRequest(const QString &url)
+{
+ _m_useNextUrl = !_m_nextUrl.isEmpty() && (_m_nextUrl == url);
+ return _m_useNextUrl;
+}
+
// static methods
QList<DecoderFactory*> *Decoder::m_factories = 0;
DecoderFactory *Decoder::m_lastFactory = 0;
diff --git a/src/qmmp/decoder.h b/src/qmmp/decoder.h
index a0a311da9..73506a3ad 100644
--- a/src/qmmp/decoder.h
+++ b/src/qmmp/decoder.h
@@ -67,26 +67,42 @@ public:
virtual qint64 totalTime() = 0;
/*!
* Requests a seek to the time \b time indicated, specified in milliseconds.
- * Subclass should reimplement this function.
*/
virtual void seek(qint64 time);
/*!
* Requests playback to stop
- * Subclass should reimplement this function.
*/
virtual void stop();
-
+ /*!
+ * Returns current bitrate (in kbps).
+ * Subclass should reimplement this function.
+ */
virtual int bitrate();
-
/*!
* Requests playback to pause. If it was paused already, playback should resume.
* Subclass with own output should reimplement this function.
*/
virtual void pause();
-
-
+ /*!
+ * Tells decoder about next track. It may be useful for gapless playback.
+ * @param url Url of the next item in the playlist
+ */
+ void setNextUrl(const QString &url);
+ /*!
+ * Removes information about next url
+ */
+ void clearNextUrl();
+ /*!
+ * Return \b true if the decoder can play next url without reinitialization;
+ * otherwise returns \b false
+ */
+ bool nextUrlAccepted();
+ /*!
+ * Setups fragment for playback.
+ * @param offset Fragment offset in milliseconds
+ * @param length Fragment duration in milliseconds
+ */
void setFragment(qint64 offset, qint64 length);
-
/*!
* Returns decoder's factory object.
*/
@@ -182,8 +198,6 @@ public:
*/
static bool isEnabled(DecoderFactory* factory);
- bool isFinished(){return _m_user_stop;}
-
signals:
/*!
* Emitted when the decoder has finished playback.
@@ -191,10 +205,21 @@ signals:
void playbackFinished();
protected:
+ /*!
+ * Reads up to \b maxSize bytes of decoded audio to \b data
+ * Returns the number of bytes read, or -1 if an error occurred.
+ * In most cases subclass should reimplement this function.
+ */
virtual qint64 readAudio(char *data, qint64 maxSize);
-
+ /*!
+ * Sets current playback position.
+ * In most cases subclass should reimplement this function.
+ * @param time New position for playback in milliseconds
+ */
virtual void seekAudio(qint64 time);
-
+ /*!
+ * The starting point for the decoding thread.
+ */
virtual void run();
/*!
* Use this function inside initialize() reimplementation to tell other plugins about audio parameters.
@@ -211,8 +236,11 @@ protected:
* @param chan Number of channels.
*/
qint64 produceSound(char *data, qint64 size, quint32 brate, int chan);
-
-
+ /*!
+ * Use this function to check next url.
+ * Returns \b true if url of the next playlist item same as \b url; otherwise returns \b false
+ */
+ bool nextUrlRequest(const QString &url);
protected slots:
/*!
@@ -237,6 +265,9 @@ private:
bool _m_eqInited;
bool _m_useEQ;
bool _m_done, _m_finish, _m_user_stop;
+ bool _m_useNextUrl;
+
+ QString _m_nextUrl;
ulong _m_bks;
qint64 _m_totalTime, _m_seekTime, _m_totalBytes;
diff --git a/src/qmmp/soundcore.cpp b/src/qmmp/soundcore.cpp
index e335d1580..0684fec42 100644
--- a/src/qmmp/soundcore.cpp
+++ b/src/qmmp/soundcore.cpp
@@ -73,18 +73,18 @@ SoundCore::~SoundCore()
bool SoundCore::play(const QString &source)
{
- qDebug("==%s", qPrintable(source));
- qDebug("==%s",qPrintable(m_next));
- if((m_next == source) && m_decoder && !m_decoder->isFinished()
- && m_decoder->factory()->properties().noOutput)
+ if(m_decoder && m_decoder->nextUrlAccepted()) //decoder can play next url
{
+ //fake stop/start cycle
m_handler->dispatch(Qmmp::Stopped);
m_handler->dispatch(Qmmp::Playing);
m_handler->dispatch(Qmmp::Buffering);
m_handler->dispatch(Qmmp::Playing);
m_source = source;
+ m_decoder->clearNextUrl();
return TRUE;
}
+ qDebug("stop!");
stop();
m_source = source;
@@ -145,15 +145,21 @@ bool SoundCore::play(const QString &source)
return FALSE;
}
-void SoundCore::setNext(const QString &source)
+void SoundCore::setNextUrl(const QString &source)
{
- m_next = source;
+ if(m_decoder)
+ m_decoder->setNextUrl(source);
+}
+
+void SoundCore::clearNextUrl()
+{
+ if(m_decoder)
+ m_decoder->clearNextUrl();
}
void SoundCore::stop()
{
m_factory = 0;
- //m_next.clear();
m_source.clear();
if (m_decoder /*&& m_decoder->isRunning()*/)
{
diff --git a/src/qmmp/soundcore.h b/src/qmmp/soundcore.h
index b39fab1d2..f099318e3 100644
--- a/src/qmmp/soundcore.h
+++ b/src/qmmp/soundcore.h
@@ -127,8 +127,15 @@ public slots:
* otherwise returns \b false. Useful for invalid files skipping.
*/
bool play(const QString &source);
-
- void setNext(const QString &source);
+ /*!
+ * Tells decoder about next track. It may be useful for gapless playback.
+ * @param source Url of the next item in the playlist
+ */
+ void setNextUrl(const QString &source);
+ /*!
+ * Removes information about next url
+ */
+ void clearNextUrl();
/*!
* Stops playback
*/
@@ -146,8 +153,6 @@ public slots:
*/
const QString url();
- const QString nextUrl(){return m_next;}
-
signals:
/*!
* This signal is emitted when the stream reader fills it's buffer.
@@ -198,8 +203,7 @@ signals:
*/
void volumeChanged(int left, int right);
/*!
- * Emitted before the playback ends. Use this signal to tell decoder about next track.
- * This may be useful for multitrack formats like CDA or cue sheets.
+ * Emitted before the playback ends.
*/
void aboutToFinish();
@@ -209,8 +213,6 @@ private slots:
private:
Decoder* m_decoder;
DecoderFactory* m_factory;
- //QUrl m_url;
- QString m_next;
QString m_source;
Output* m_output;
QIODevice* m_input;
diff --git a/src/qmmp/statehandler.cpp b/src/qmmp/statehandler.cpp
index 1086e477b..8ccd46e82 100644
--- a/src/qmmp/statehandler.cpp
+++ b/src/qmmp/statehandler.cpp
@@ -24,7 +24,7 @@
#include "statehandler.h"
#define TICK_INTERVAL 250
-#define PREFINISH_TIME 5000
+#define PREFINISH_TIME 2000
StateHandler* StateHandler::m_instance = 0;
diff --git a/src/qmmp/statehandler.h b/src/qmmp/statehandler.h
index 0e64b0a7e..3eb3c2036 100644
--- a/src/qmmp/statehandler.h
+++ b/src/qmmp/statehandler.h
@@ -139,7 +139,7 @@ signals:
*/
void finished();
/*!
- * Emitted before the playback ends. Use this signal to tell decoder about next track.
+ * Emitted before the playback ends. Use this signal inside decoder to check next url.
* This may be useful for multitrack formats like CDA or cue sheets.
*/
void aboutToFinish();
diff --git a/src/qmmpui/mediaplayer.cpp b/src/qmmpui/mediaplayer.cpp
index 3f7545091..42a0cf6b8 100644
--- a/src/qmmpui/mediaplayer.cpp
+++ b/src/qmmpui/mediaplayer.cpp
@@ -64,7 +64,7 @@ void MediaPlayer::initialize(SoundCore *core, PlayListModel *model)
m_model = model;
m_repeat = FALSE;
connect(m_core, SIGNAL(finished()), SLOT(next()));
- connect(m_core, SIGNAL(aboutToFinish()), SLOT(sendNext()));
+ //connect(m_model, SIGNAL(listChanged()), SLOT(updateNextUrl()));
}
PlayListModel *MediaPlayer::playListModel()
@@ -79,9 +79,8 @@ bool MediaPlayer::isRepeatable() const
void MediaPlayer::play()
{
- qDebug("+1");
+ disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
m_model->doCurrentVisibleRequest();
- qDebug("+2");
if (m_core->state() == Qmmp::Paused)
{
m_core->pause();
@@ -90,15 +89,13 @@ void MediaPlayer::play()
if (m_model->count() == 0)
return;
- qDebug("+3");
+
QString s = m_model->currentItem()->url();
if (s.isEmpty())
return;
- qDebug("+4");
- //m_core->setNext (m_model->nextItem()->url());
+
if (!m_core->play(s))
{
- qDebug("+5");
//find out the reason why playback failed
switch ((int) m_core->state())
{
@@ -134,17 +131,9 @@ void MediaPlayer::play()
}
else
{
- qDebug("1");
m_skips = 0;
- qDebug("2");
- if(m_model->nextItem())
- {
- qDebug("3");
- m_core->setNext (m_model->nextItem()->url());
- qDebug("MediaPlayer: current item: %s",qPrintable(m_core->url()));
- qDebug("MediaPlayer: next item: %s",qPrintable(m_core->nextUrl()));
- qDebug("4");
- }
+ updateNextUrl();
+ connect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
}
}
@@ -155,6 +144,7 @@ void MediaPlayer::stop()
void MediaPlayer::next()
{
+ disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
if (!m_model->isEmptyQueue())
{
m_model->setCurrentToQueued();
@@ -164,7 +154,7 @@ void MediaPlayer::next()
stop();
return;
}
- //m_playlist->update();
+
if (m_core->state() != Qmmp::Stopped)
{
if (m_core->state() == Qmmp::Paused)
@@ -175,22 +165,19 @@ void MediaPlayer::next()
void MediaPlayer::previous()
{
+ disconnect(m_model, SIGNAL(listChanged()), this, SLOT(updateNextUrl()));
if (!m_model->previous())
{
stop();
- //display->hideTimeDisplay();
return;
}
- //m_playlist->update();
if (m_core->state() != Qmmp::Stopped)
{
if (m_core->state() == Qmmp::Paused)
stop();
play();
}
- /*else
- display->hideTimeDisplay();*/
}
void MediaPlayer::setRepeatable(bool r)
@@ -207,11 +194,13 @@ void MediaPlayer::setRepeatable(bool r)
}
m_repeat = r;
emit repeatableChanged(r);
+ updateNextUrl();
}
-void MediaPlayer::sendNext()
+void MediaPlayer::updateNextUrl()
{
- /*if(m_model->nextItem())
- qDebug("MediaPlayer: next item: %s",qPrintable(m_model->nextItem()->url()));*/
+ if(m_model->nextItem() && !isRepeatable())
+ m_core->setNextUrl(m_model->nextItem()->url());
+ else
+ m_core->clearNextUrl();
}
-
diff --git a/src/qmmpui/mediaplayer.h b/src/qmmpui/mediaplayer.h
index c4f5d5bdd..327b9c980 100644
--- a/src/qmmpui/mediaplayer.h
+++ b/src/qmmpui/mediaplayer.h
@@ -91,7 +91,7 @@ signals:
void repeatableChanged(bool enabled);
private slots:
- void sendNext();
+ void updateNextUrl();
private:
PlayListModel *m_model;