diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/plugins/Input/flac/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/plugins/Input/flac/cueparser.cpp | 219 | ||||
| -rw-r--r-- | src/plugins/Input/flac/cueparser.h | 63 | ||||
| -rw-r--r-- | src/plugins/Input/flac/decoder_flac.cpp | 36 | ||||
| -rw-r--r-- | src/plugins/Input/flac/decoder_flac.h | 4 | ||||
| -rw-r--r-- | src/plugins/Input/flac/decoderflacfactory.cpp | 93 | ||||
| -rw-r--r-- | src/plugins/Input/flac/flac.pro | 2 | ||||
| -rw-r--r-- | src/qmmp/cueparser.cpp | 8 | ||||
| -rw-r--r-- | src/qmmp/cueparser.h | 1 |
9 files changed, 76 insertions, 352 deletions
diff --git a/src/plugins/Input/flac/CMakeLists.txt b/src/plugins/Input/flac/CMakeLists.txt index 6867ba9bb..3b4703db2 100644 --- a/src/plugins/Input/flac/CMakeLists.txt +++ b/src/plugins/Input/flac/CMakeLists.txt @@ -22,12 +22,10 @@ SET(libflac_SRCS decoder_flac.cpp decoderflacfactory.cpp flacmetadatamodel.cpp - cueparser.cpp ) SET(libflac_HDRS decoder_flac.h - cueparser.h ) SET(libflac_RCCS translations/translations.qrc) diff --git a/src/plugins/Input/flac/cueparser.cpp b/src/plugins/Input/flac/cueparser.cpp deleted file mode 100644 index 3b02d1b7e..000000000 --- a/src/plugins/Input/flac/cueparser.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008-2019 by Ilya Kotov * - * forkotov02@ya.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., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#include <QFile> -#include <QDir> -#include <QDirIterator> -#include <QSettings> -#include <QTextStream> -#include <QTextCodec> -#include <qmmp/decoder.h> -#include <qmmp/metadatamanager.h> -#include "cueparser.h" - -CUEParser::CUEParser(const QByteArray &array, const QString &path) -{ - QString album, genre, date, comment; - QTextStream textStream (array); - textStream.setCodec("UTF-8"); - m_filePath = path; - QString artist; - double album_peak = 0.0, album_gain = 0.0; - while (!textStream.atEnd()) - { - QString line = textStream.readLine().trimmed(); - QStringList words = splitLine(line); - if (words.size() < 2) - continue; - - if (words[0] == "PERFORMER") - { - if(m_tracks.isEmpty()) - artist = words[1]; - else - m_tracks.last()->info.setValue(Qmmp::ARTIST, words[1]); - } - else if (words[0] == "TITLE") - { - if(m_tracks.isEmpty()) - album = words[1]; - else - m_tracks.last()->info.setValue(Qmmp::TITLE, words[1]); - } - else if (words[0] == "TRACK") - { - TrackInfo info("flac://" + path + QString("#%1").arg(words[1].toInt())); - info.setValue(Qmmp::TRACK, words[1].toInt()); - info.setValue(Qmmp::ALBUM, album); - info.setValue(Qmmp::GENRE, genre); - info.setValue(Qmmp::YEAR, date); - info.setValue(Qmmp::COMMENT, comment); - info.setValue(Qmmp::ARTIST, artist); - info.setValue(Qmmp::ALBUMARTIST, artist); - info.setValue(Qmmp::REPLAYGAIN_ALBUM_GAIN, album_gain); - info.setValue(Qmmp::REPLAYGAIN_ALBUM_PEAK, album_peak); - - m_tracks << new CUETrack; - m_tracks.last()->info = info; - m_tracks.last()->offset = 0; - } - else if (words[0] == "INDEX" && words[1] == "01") - { - if (m_tracks.isEmpty()) - continue; - m_tracks.last()->offset = getLength(words[2]); - int c = m_tracks.count(); - if(c > 1) - m_tracks[c - 2]->info.setDuration(m_tracks[c - 1]->offset - m_tracks[c - 2]->offset); - } - else if (words[0] == "REM") - { - if (words.size() < 3) - continue; - if (words[1] == "GENRE") - genre = words[2]; - else if (words[1] == "DATE") - date = words[2]; - else if (words[1] == "COMMENT") - comment = words[2]; - else if (words[1] == "REPLAYGAIN_ALBUM_GAIN") - album_gain = words[2].toDouble(); - else if (words[1] == "REPLAYGAIN_ALBUM_PEAK") - album_peak = words[2].toDouble(); - else if (words[1] == "REPLAYGAIN_TRACK_GAIN" && !m_tracks.isEmpty()) - m_tracks.last()->info.setValue(Qmmp::REPLAYGAIN_TRACK_GAIN, words[2].toDouble()); - else if (words[1] == "REPLAYGAIN_TRACK_PEAK" && !m_tracks.isEmpty()) - m_tracks.last()->info.setValue(Qmmp::REPLAYGAIN_TRACK_PEAK, words[2].toDouble()); - } - } - if(m_tracks.isEmpty()) - { - qWarning("CUEParser: invalid cue file"); - return; - } - - QList<TrackInfo *> f_list = MetaDataManager::instance()->createPlayList(m_filePath, TrackInfo::Properties); - if(!f_list.isEmpty()) - { - //calculate last item length - m_tracks.last()->info.setDuration(qMax(0LL, f_list.first()->duration() - m_tracks.last()->offset)); - //add properties - foreach(CUETrack *cueTrack, m_tracks) - cueTrack->info.setValues(f_list.first()->properties()); - qDeleteAll(f_list); - f_list.clear(); - } -} - -CUEParser::~CUEParser() -{ - qDeleteAll(m_tracks); - m_tracks.clear(); -} - -QList<TrackInfo*> CUEParser::createPlayList() -{ - QList<TrackInfo*> list; - foreach(CUETrack *track, m_tracks) - { - list << new TrackInfo(track->info); - } - return list; -} - -const QString CUEParser::filePath() const -{ - return m_filePath; -} - -qint64 CUEParser::offset(int track) const -{ - return m_tracks.at(track - 1)->offset; -} - -qint64 CUEParser::duration(int track) const -{ - return m_tracks.at(track - 1)->info.duration(); -} - -int CUEParser::count() const -{ - return m_tracks.count(); -} - -TrackInfo *CUEParser::info(int track) -{ - return &m_tracks.at(track - 1)->info; -} - -const QString CUEParser::trackURL(int track) const -{ - return m_tracks.at(track - 1)->info.path(); -} - -const QMap<Qmmp::ReplayGainKey, double> CUEParser::replayGain(int track) const -{ - return m_tracks.at(track - 1)->info.replayGainInfo(); -} - -QStringList CUEParser::splitLine(const QString &line) -{ - //qDebug("raw string = %s",qPrintable(line)); - QStringList list; - QString buf = line.trimmed(); - if (buf.isEmpty()) - return list; - while (!buf.isEmpty()) - { - //qDebug(qPrintable(buf)); - if (buf.startsWith('"')) - { - int end = buf.indexOf('"',1); - if(end == -1) //ignore invalid line - { - list.clear(); - qWarning("CUEParser: unable to parse line: %s",qPrintable(line)); - return list; - } - list << buf.mid (1, end - 1); - buf.remove (0, end+1); - } - else - { - int end = buf.indexOf(' ', 0); - if (end < 0) - end = buf.size(); - list << buf.mid (0, end); - buf.remove (0, end); - } - buf = buf.trimmed(); - } - return list; -} - -qint64 CUEParser::getLength(const QString &str) -{ - QStringList list = str.split(":"); - if (list.size() == 2) - return (qint64)list.at(0).toInt()*60000 + list.at(1).toInt()*1000; - else if (list.size() == 3) - return (qint64)list.at(0).toInt()*60000 + list.at(1).toInt()*1000 + list.at(2).toInt()*1000/75; - return 0; -} diff --git a/src/plugins/Input/flac/cueparser.h b/src/plugins/Input/flac/cueparser.h deleted file mode 100644 index 12b2e7893..000000000 --- a/src/plugins/Input/flac/cueparser.h +++ /dev/null @@ -1,63 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008-2019 by Ilya Kotov * - * forkotov02@ya.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., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ -#ifndef CUEPARSER_H -#define CUEPARSER_H - -#include <QList> -#include <QMap> -#include <QString> -#include <QStringList> -#include <QUrl> -#include <qmmp/qmmp.h> -#include <qmmp/trackinfo.h> - - -/** - @author Ilya Kotov <forkotov02@ya.ru> -*/ -class CUEParser -{ -public: - CUEParser(const QByteArray &array, const QString &path); - - ~CUEParser(); - - QList<TrackInfo *> createPlayList(); - const QString filePath() const; - qint64 offset(int track) const; - qint64 duration(int track) const; - int count() const; - TrackInfo *info(int track); - const QString trackURL(int track) const; - const QMap<Qmmp::ReplayGainKey, double> replayGain(int track) const; - -private: - struct CUETrack - { - TrackInfo info; - qint64 offset; - }; - QList <CUETrack *> m_tracks; - QStringList splitLine(const QString &line); - qint64 getLength(const QString &str); - QString m_filePath; -}; - -#endif diff --git a/src/plugins/Input/flac/decoder_flac.cpp b/src/plugins/Input/flac/decoder_flac.cpp index 4f515b080..f45b3148e 100644 --- a/src/plugins/Input/flac/decoder_flac.cpp +++ b/src/plugins/Input/flac/decoder_flac.cpp @@ -29,12 +29,14 @@ #include <taglib/xiphcomment.h> #include <taglib/tmap.h> #include <taglib/id3v2header.h> +#include <taglib/tfilestream.h> +#include <taglib/id3v2framefactory.h> #include <QObject> #include <QFile> #include <QIODevice> #include <FLAC/all.h> #include <stdint.h> -#include "cueparser.h" +#include <qmmp/cueparser.h> #include "decoder_flac.h" #define BITRATE_CALC_TIME_MS 2000 @@ -302,33 +304,35 @@ bool DecoderFLAC::initialize() QString p = m_path; p.remove("flac://"); p.remove(QRegExp("#\\d+$")); - TagLib::FLAC::File fileRef(QStringToFileName(p)); + TagLib::FileStream stream(QStringToFileName(p), true); + TagLib::FLAC::File fileRef(&stream, TagLib::ID3v2::FrameFactory::instance()); //looking for cuesheet comment - TagLib::Ogg::XiphComment *xiph_comment = fileRef.xiphComment(); + TagLib::Ogg::XiphComment *tag = fileRef.xiphComment(); + TagLib::FLAC::Properties *ap = fileRef.audioProperties(); - if (xiph_comment && xiph_comment->fieldListMap().contains("CUESHEET")) + if (ap && tag && tag->fieldListMap().contains("CUESHEET")) { qDebug("DecoderFLAC: using cuesheet xiph comment."); - m_parser = new CUEParser(xiph_comment->fieldListMap()["CUESHEET"].toString() - .toCString(true), p); + m_parser = new CueParser(tag->fieldListMap()["CUESHEET"].toString() .toCString(true)); + m_parser->setDuration(fileRef.audioProperties()->lengthInMilliseconds()); + m_parser->setUrl("flac", p); m_track = m_path.section("#", -1).toInt(); - if(m_track > m_parser->count()) + if(m_track < 1 || m_track > m_parser->count()) { qWarning("DecoderFLAC: invalid cuesheet xiph comment"); return false; } m_data->input = new QFile(p); m_data->input->open(QIODevice::ReadOnly); - if(xiph_comment->contains("DISCNUMBER") && !xiph_comment->fieldListMap()["DISCNUMBER"].isEmpty()) + if(tag->contains("DISCNUMBER") && !tag->fieldListMap()["DISCNUMBER"].isEmpty()) { - TagLib::StringList fld = xiph_comment->fieldListMap()["DISCNUMBER"]; + TagLib::StringList fld = tag->fieldListMap()["DISCNUMBER"]; for(int i = 1; i <= m_parser->count(); i++) { - m_parser->info(i)->setValue(Qmmp::DISCNUMBER, TStringToQString(fld.toString())); + m_parser->setMetaData(i, Qmmp::DISCNUMBER, TStringToQString(fld.toString())); } } - QMap<Qmmp::MetaData, QString> metaData = m_parser->info(m_track)->metaData(); - addMetaData(metaData); //send metadata + addMetaData(m_parser->info(m_track)->metaData()); //send metadata } else { @@ -338,7 +342,7 @@ bool DecoderFLAC::initialize() } else { - qWarning("DecoderFLAC: cannot initialize. No input."); + qWarning("DecoderFLAC: cannot initialize. No input."); return false; } } @@ -456,7 +460,7 @@ bool DecoderFLAC::initialize() m_offset = m_parser->offset(m_track); length_in_bytes = audioParameters().sampleRate() * audioParameters().frameSize() * m_length/1000; - setReplayGainInfo(m_parser->replayGain(m_track)); + setReplayGainInfo(m_parser->info(m_track)->replayGainInfo()); seek(0); } m_totalBytes = 0; @@ -557,7 +561,7 @@ void DecoderFLAC::deinit() const QString DecoderFLAC::nextURL() const { if(m_parser && m_track +1 <= m_parser->count()) - return m_parser->trackURL(m_track + 1); + return m_parser->url(m_track + 1); else return QString(); } @@ -573,7 +577,7 @@ void DecoderFLAC::next() audioParameters().channels() * audioParameters().sampleSize() * m_length/1000; addMetaData(m_parser->info(m_track)->metaData()); - setReplayGainInfo(m_parser->replayGain(m_track)); + setReplayGainInfo(m_parser->info(m_track)->replayGainInfo()); m_totalBytes = 0; } } diff --git a/src/plugins/Input/flac/decoder_flac.h b/src/plugins/Input/flac/decoder_flac.h index b77fa7154..2d31f97a3 100644 --- a/src/plugins/Input/flac/decoder_flac.h +++ b/src/plugins/Input/flac/decoder_flac.h @@ -29,7 +29,7 @@ #define SAMPLES_PER_WRITE 512 #define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * MAX_SUPPORTED_CHANNELS * (32/8)) -class CUEParser; +class CueParser; struct flac_data { @@ -86,7 +86,7 @@ private: qint64 m_offset; qint64 m_length; QString m_path; - CUEParser *m_parser; + CueParser *m_parser; int m_track; char *m_buf; //buffer for remainig data qint64 m_buf_size; diff --git a/src/plugins/Input/flac/decoderflacfactory.cpp b/src/plugins/Input/flac/decoderflacfactory.cpp index 74066316b..05d9c7881 100644 --- a/src/plugins/Input/flac/decoderflacfactory.cpp +++ b/src/plugins/Input/flac/decoderflacfactory.cpp @@ -27,7 +27,7 @@ #include <taglib/tmap.h> #include <taglib/tfilestream.h> #include <taglib/id3v2framefactory.h> -#include "cueparser.h" +#include <qmmp/cueparser.h> #include "decoder_flac.h" #include "flacmetadatamodel.h" #include "decoderflacfactory.h" @@ -67,23 +67,17 @@ Decoder *DecoderFLACFactory::create(const QString &path, QIODevice *i) QList<TrackInfo*> DecoderFLACFactory::createPlayList(const QString &path, TrackInfo::Parts parts, QStringList *ignoredFiles) { - //extract metadata of the one cue track - if(path.contains("://")) + Q_UNUSED(ignoredFiles); + + int track = -1; //cue track + QString filePath = path; + + if(path.contains("://")) //is it cue track? { - QString filePath = path; filePath.remove("flac://"); filePath.remove(QRegExp("#\\d+$")); - int track = filePath.section("#", -1).toInt(); - QList<TrackInfo *> list = createPlayList(filePath, TrackInfo::Properties, ignoredFiles); - if (list.isEmpty() || track <= 0 || track > list.count()) - { - qDeleteAll(list); - list.clear(); - return list; - } - TrackInfo *info = list.takeAt(track - 1); - qDeleteAll(list); - return QList<TrackInfo *>() << info; + track = filePath.section("#", -1).toInt(); + parts = TrackInfo::AllParts; //extract all metadata for single cue track } TrackInfo *info = new TrackInfo(path); @@ -117,12 +111,33 @@ QList<TrackInfo*> DecoderFLACFactory::createPlayList(const QString &path, TrackI return QList<TrackInfo *>(); } + if((parts & TrackInfo::Properties) && ap) + { + info->setValue(Qmmp::BITRATE, ap->bitrate()); + info->setValue(Qmmp::SAMPLERATE, ap->sampleRate()); + info->setValue(Qmmp::CHANNELS, ap->channels()); + info->setValue(Qmmp::BITS_PER_SAMPLE, ap->bitsPerSample()); + info->setValue(Qmmp::FORMAT_NAME, flacFile ? "FLAC" : "Ogg FLAC"); + info->setDuration(ap->lengthInMilliseconds()); + } + + if((parts & TrackInfo::ReplayGainInfo) && tag && !tag->isEmpty()) + { + TagLib::Ogg::FieldListMap items = tag->fieldListMap(); + if (items.contains("REPLAYGAIN_TRACK_GAIN")) + info->setValue(Qmmp::REPLAYGAIN_TRACK_GAIN,TStringToQString(items["REPLAYGAIN_TRACK_GAIN"].front())); + if (items.contains("REPLAYGAIN_TRACK_PEAK")) + info->setValue(Qmmp::REPLAYGAIN_TRACK_PEAK,TStringToQString(items["REPLAYGAIN_TRACK_PEAK"].front())); + if (items.contains("REPLAYGAIN_ALBUM_GAIN")) + info->setValue(Qmmp::REPLAYGAIN_ALBUM_GAIN,TStringToQString(items["REPLAYGAIN_ALBUM_GAIN"].front())); + if (items.contains("REPLAYGAIN_ALBUM_PEAK")) + info->setValue(Qmmp::REPLAYGAIN_ALBUM_PEAK,TStringToQString(items["REPLAYGAIN_ALBUM_PEAK"].front())); + } + if((parts & TrackInfo::MetaData) && tag && !tag->isEmpty()) { - if (tag->fieldListMap().contains("CUESHEET")) + if (tag->fieldListMap().contains("CUESHEET") && ap) { - delete info; - QByteArray data(tag->fieldListMap()["CUESHEET"].toString().toCString(true)); QString diskNumber; @@ -132,19 +147,24 @@ QList<TrackInfo*> DecoderFLACFactory::createPlayList(const QString &path, TrackI diskNumber = TStringToQString(fld.toString()).trimmed(); } - if(flacFile) - delete flacFile; - if(oggFlacFile) - delete oggFlacFile; + CueParser parser(data); - CUEParser parser(data, path); if(!diskNumber.isEmpty()) { for(int i = 1; i <= parser.count(); ++i) - parser.info(i)->setValue(Qmmp::DISCNUMBER, diskNumber); + parser.setMetaData(i, Qmmp::DISCNUMBER, diskNumber); } + parser.setDuration(ap->lengthInMilliseconds()); + parser.setProperties(info->properties()); + parser.setUrl("flac", path); + + if(flacFile) + delete flacFile; + if(oggFlacFile) + delete oggFlacFile; - return parser.createPlayList(); + delete info; + return (track > 0) ? parser.createPlayList(track) : parser.createPlayList(); } info->setValue(Qmmp::ALBUM, TStringToQString(tag->album())); @@ -165,29 +185,6 @@ QList<TrackInfo*> DecoderFLACFactory::createPlayList(const QString &path, TrackI } - if((parts & TrackInfo::Properties) && ap) - { - info->setValue(Qmmp::BITRATE, ap->bitrate()); - info->setValue(Qmmp::SAMPLERATE, ap->sampleRate()); - info->setValue(Qmmp::CHANNELS, ap->channels()); - info->setValue(Qmmp::BITS_PER_SAMPLE, ap->bitsPerSample()); - info->setValue(Qmmp::FORMAT_NAME, flacFile ? "FLAC" : "Ogg FLAC"); - info->setDuration(ap->lengthInMilliseconds()); - } - - if((parts & TrackInfo::ReplayGainInfo) && tag && !tag->isEmpty()) - { - TagLib::Ogg::FieldListMap items = tag->fieldListMap(); - if (items.contains("REPLAYGAIN_TRACK_GAIN")) - info->setValue(Qmmp::REPLAYGAIN_TRACK_GAIN,TStringToQString(items["REPLAYGAIN_TRACK_GAIN"].front())); - if (items.contains("REPLAYGAIN_TRACK_PEAK")) - info->setValue(Qmmp::REPLAYGAIN_TRACK_PEAK,TStringToQString(items["REPLAYGAIN_TRACK_PEAK"].front())); - if (items.contains("REPLAYGAIN_ALBUM_GAIN")) - info->setValue(Qmmp::REPLAYGAIN_ALBUM_GAIN,TStringToQString(items["REPLAYGAIN_ALBUM_GAIN"].front())); - if (items.contains("REPLAYGAIN_ALBUM_PEAK")) - info->setValue(Qmmp::REPLAYGAIN_ALBUM_PEAK,TStringToQString(items["REPLAYGAIN_ALBUM_PEAK"].front())); - } - if(flacFile) delete flacFile; if(oggFlacFile) diff --git a/src/plugins/Input/flac/flac.pro b/src/plugins/Input/flac/flac.pro index 298f03225..ae9ed0aa9 100644 --- a/src/plugins/Input/flac/flac.pro +++ b/src/plugins/Input/flac/flac.pro @@ -4,12 +4,10 @@ TARGET = $$PLUGINS_PREFIX/Input/flac HEADERS += decoderflacfactory.h \ decoder_flac.h \ - cueparser.h \ flacmetadatamodel.h SOURCES += decoder_flac.cpp \ decoderflacfactory.cpp \ - cueparser.cpp \ flacmetadatamodel.cpp RESOURCES = translations/translations.qrc diff --git a/src/qmmp/cueparser.cpp b/src/qmmp/cueparser.cpp index 937485470..3dc42a1d3 100644 --- a/src/qmmp/cueparser.cpp +++ b/src/qmmp/cueparser.cpp @@ -257,6 +257,14 @@ void CueParser::setProperties(const QMap<Qmmp::TrackProperty, QString> &properti track->info.setValues(properties); } +void CueParser::setMetaData(int track, Qmmp::MetaData key, const QVariant &value) +{ + if(track < 1 || track > m_tracks.count()) + qWarning("CueParser: invalid track number: %d", track); + + m_tracks.at(track - 1)->info.setValue(key, value); +} + void CueParser::setUrl(const QString &scheme, const QString &path) { for(int i = 0; i < m_tracks.count(); ++i) diff --git a/src/qmmp/cueparser.h b/src/qmmp/cueparser.h index 2606a4468..a452ed054 100644 --- a/src/qmmp/cueparser.h +++ b/src/qmmp/cueparser.h @@ -50,6 +50,7 @@ public: void setDuration(qint64 duration); void setProperties(const QString &file, const QMap<Qmmp::TrackProperty, QString> &properties); void setProperties(const QMap<Qmmp::TrackProperty, QString> &properties); + void setMetaData(int track, Qmmp::MetaData key, const QVariant &value); void setUrl(const QString &scheme, const QString &path); void clear(); |
