The Cue Sheet splitter will now also handle input files that are not PCM/Wave.

This commit is contained in:
LoRd_MuldeR 2011-05-15 18:53:44 +02:00
parent 9296fc32b6
commit f8f792f23f
21 changed files with 259 additions and 38 deletions

View File

@ -19,7 +19,7 @@ a:visited { color: #0000EE; }
<a name="4.02"></a>Changes between v4.01 and v4.02:<br><ul> <a name="4.02"></a>Changes between v4.01 and v4.02:<br><ul>
<li>Upgraded build environment to Microsoft Visual Studio 2010 <li>Upgraded build environment to Microsoft Visual Studio 2010
<li>Dropping support for Windows 2000 and for Windows XP RTM/SP1, Windows XP needs SP2 or SP3 now! <li>Dropping support for Windows 2000 and for Windows XP RTM/SP1, Windows XP needs SP2 or SP3 now!
<li>Added Cue Sheet import wizard, only uncompressed Wave/PCM files are suppported at the moment <li>Added Cue Sheet import wizard, which allows splitting and importing tracks from Cue Sheet images
<li>Added ATSC A/52 (AC-3) encoding support, based on Aften encoder v0.0.8+ (Git Master) <li>Added ATSC A/52 (AC-3) encoding support, based on Aften encoder v0.0.8+ (Git Master)
<li>Added one new translation: Korean <li>Added one new translation: Korean
<li>Added a method to use custom tools instead of the "built-in" ones (see <a href="FAQ.html#3d6684e9" target="_blank">FAQ doc</a> for details) <li>Added a method to use custom tools instead of the "built-in" ones (see <a href="FAQ.html#3d6684e9" target="_blank">FAQ doc</a> for details)

View File

@ -321,6 +321,22 @@
<source>Analyzing file(s), please wait...</source> <source>Analyzing file(s), please wait...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>Splitting file(s), please wait...</source> <source>Splitting file(s), please wait...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>

View File

@ -331,12 +331,28 @@
</message> </message>
<message> <message>
<source>Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).</source> <source>Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).</source>
<translation>%1 Datei(ein) wurden aus dem Cuesheet importiert und %2 Datei(en) übersprungen.</translation> <translation>%1 Datei(ein) wurden aus dem Cuesheet importiert, %2 Datei(en) übersprungen.</translation>
</message> </message>
<message> <message>
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation>Cuesheet Abgeschlossen</translation> <translation>Cuesheet Abgeschlossen</translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation>Analyse fehlgeschlagen</translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation>Achtung: Das Dateiformat einiger Dateien konnte nicht festgestellt werden!</translation>
</message>
<message>
<source>Continue Anyway</source>
<translation>Trotzdem fortfahren</translation>
</message>
<message>
<source>Abort</source>
<translation>Abbrechen</translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished">Cancelar</translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -341,6 +341,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished">Abandonner</translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished">Ferma</translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished">Отмена</translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source> <source>Cue Sheet Completed</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Analysis Failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Warning: The format of some of the input files could not be determined!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Continue Anyway</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Abort</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>CueSheetImport</name> <name>CueSheetImport</name>

View File

@ -186,6 +186,15 @@
<property name="selectionBehavior"> <property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum> <enum>QAbstractItemView::SelectRows</enum>
</property> </property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget> </widget>
</item> </item>
<item> <item>
@ -616,6 +625,7 @@
<include location="../res/Images.qrc"/> <include location="../res/Images.qrc"/>
<include location="../res/Images.qrc"/> <include location="../res/Images.qrc"/>
<include location="../res/Images.qrc"/> <include location="../res/Images.qrc"/>
<include location="../res/Images.qrc"/>
</resources> </resources>
<connections> <connections>
<connection> <connection>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -230,11 +230,13 @@ void CueImportDialog::importCueSheet(void)
files << temp; files << temp;
} }
//Analyze all source files //Analyze all source files first
analyzeFiles(files); if(analyzeFiles(files))
{
//Now split files according to Cue Sheet
splitFiles();
}
//Now split files according to Cue Sheet
splitFiles();
//Release locks //Release locks
while(!m_locks.isEmpty()) while(!m_locks.isEmpty())
@ -243,9 +245,10 @@ void CueImportDialog::importCueSheet(void)
} }
} }
void CueImportDialog::analyzeFiles(QStringList &files) bool CueImportDialog::analyzeFiles(QStringList &files)
{ {
m_fileInfo.clear(); m_fileInfo.clear();
bool bSuccess = true;
WorkingBanner *progress = new WorkingBanner(this); WorkingBanner *progress = new WorkingBanner(this);
FileAnalyzer *analyzer = new FileAnalyzer(files); FileAnalyzer *analyzer = new FileAnalyzer(files);
@ -255,7 +258,19 @@ void CueImportDialog::analyzeFiles(QStringList &files)
progress->show(tr("Analyzing file(s), please wait..."), analyzer); progress->show(tr("Analyzing file(s), please wait..."), analyzer);
progress->close(); progress->close();
if(analyzer->filesAccepted() < files.count())
{
if(QMessageBox::warning(this, tr("Analysis Failed"), tr("Warning: The format of some of the input files could not be determined!"), tr("Continue Anyway"), tr("Abort")) == 1)
{
bSuccess = false;
}
}
LAMEXP_DELETE(progress); LAMEXP_DELETE(progress);
LAMEXP_DELETE(analyzer);
return bSuccess;
} }
void CueImportDialog::splitFiles(void) void CueImportDialog::splitFiles(void)
@ -308,7 +323,7 @@ void CueImportDialog::splitFiles(void)
} }
else else
{ {
QString text = tr("Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).").arg(QString::number(splitter->getTracksSuccess()), QString::number(splitter->getTracksSkipped() + nTracksSkipped)); QString text = QString("<nobr>%1</nobr>").arg(tr("Imported %1 track(s) from the Cue Sheet and skipped %2 track(s).").arg(QString::number(splitter->getTracksSuccess()), QString::number(splitter->getTracksSkipped() + nTracksSkipped)));
QMessageBox::information(this, tr("Cue Sheet Completed"), text); QMessageBox::information(this, tr("Cue Sheet Completed"), text);
} }

View File

@ -51,8 +51,8 @@ private slots:
private: private:
void importCueSheet(void); void importCueSheet(void);
void analyzeFiles(QStringList &files); bool analyzeFiles(QStringList &files);
void CueImportDialog::splitFiles(void); void splitFiles(void);
CueSheetModel *m_model; CueSheetModel *m_model;
FileListModel *m_fileList; FileListModel *m_fileList;

View File

@ -129,13 +129,13 @@ QModelIndex CueSheetModel::index(int row, int column, const QModelIndex &parent)
{ {
if(!parent.isValid()) if(!parent.isValid())
{ {
return createIndex(row, column, m_files.at(row)); return (row < m_files.count()) ? createIndex(row, column, m_files.at(row)) : QModelIndex();
} }
CueSheetItem *parentItem = static_cast<CueSheetItem*>(parent.internalPointer()); CueSheetItem *parentItem = static_cast<CueSheetItem*>(parent.internalPointer());
if(CueSheetFile *filePtr = dynamic_cast<CueSheetFile*>(parentItem)) if(CueSheetFile *filePtr = dynamic_cast<CueSheetFile*>(parentItem))
{ {
return createIndex(row, column, filePtr->track(row)); return (row < filePtr->trackCount()) ? createIndex(row, column, filePtr->track(row)) : QModelIndex();
} }
return QModelIndex(); return QModelIndex();

View File

@ -25,6 +25,8 @@
#include "LockedFile.h" #include "LockedFile.h"
#include "Model_AudioFile.h" #include "Model_AudioFile.h"
#include "PlaylistImporter.h" #include "PlaylistImporter.h"
#include "Registry_Decoder.h"
#include "Decoder_Abstract.h"
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
@ -52,6 +54,8 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
m_albumPerformer.clear(); m_albumPerformer.clear();
m_albumTitle.clear(); m_albumTitle.clear();
m_decompressedFiles.clear();
m_tempFiles.clear();
qDebug("\n[CueSplitter::CueSplitter]"); qDebug("\n[CueSplitter::CueSplitter]");
@ -59,13 +63,21 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
for(int i = 0; i < nInputFiles; i++) for(int i = 0; i < nInputFiles; i++)
{ {
m_inputFiles.insert(inputFiles[i].filePath(), inputFiles[i]); m_inputFiles.insert(inputFiles[i].filePath(), inputFiles[i]);
qDebug("%02d <%s>", i, inputFiles[i].filePath()); qDebug("%02d <%s>", i, inputFiles[i].filePath().toUtf8().constData());
} }
qDebug("All input files added."); qDebug("All input files added.");
m_bSuccess = false; m_bSuccess = false;
} }
CueSplitter::~CueSplitter(void)
{
while(!m_tempFiles.isEmpty())
{
lamexp_remove_file(m_tempFiles.takeFirst());
}
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Thread Main // Thread Main
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -73,11 +85,11 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
void CueSplitter::run() void CueSplitter::run()
{ {
m_bSuccess = false; m_bSuccess = false;
m_abortFlag = false;
m_nTracksSuccess = 0; m_nTracksSuccess = 0;
m_nTracksSkipped = 0; m_nTracksSkipped = 0;
m_abortFlag = false; m_decompressedFiles.clear();
m_activeFile.clear();
int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count());
if(!QDir(m_outputDir).exists()) if(!QDir(m_outputDir).exists())
{ {
@ -85,6 +97,49 @@ void CueSplitter::run()
return; return;
} }
QStringList inputFileList = m_inputFiles.keys();
int nInputFiles = inputFileList.count();
//Decompress all input files
for(int i = 0; i < nInputFiles; i++)
{
AudioFileModel &inputFileInfo = m_inputFiles[inputFileList.at(i)];
if(inputFileInfo.formatContainerType().compare("Wave", Qt::CaseInsensitive) || inputFileInfo.formatAudioType().compare("PCM", Qt::CaseInsensitive))
{
AbstractDecoder *decoder = DecoderRegistry::lookup(inputFileInfo.formatContainerType(), inputFileInfo.formatContainerProfile(), inputFileInfo.formatAudioType(), inputFileInfo.formatAudioProfile(), inputFileInfo.formatAudioVersion());
if(decoder)
{
m_activeFile = QFileInfo(inputFileList.at(i)).fileName().left(54).trimmed();
emit fileSelected(m_activeFile);
QString tempFile = QString("%1/~%2.wav").arg(m_outputDir, lamexp_rand_str());
connect(decoder, SIGNAL(statusUpdated(int)), this, SLOT(handleUpdate(int)), Qt::DirectConnection);
if(decoder->decode(inputFileList.at(i), tempFile, &m_abortFlag))
{
m_decompressedFiles.insert(inputFileList.at(i), tempFile);
m_tempFiles.append(tempFile);
}
else
{
qWarning("Failed to decompress file: <%s>", inputFileList.at(i).toLatin1().constData());
lamexp_remove_file(tempFile);
}
m_activeFile.clear();
LAMEXP_DELETE(decoder);
}
else
{
qWarning("Unsupported input file: <%s>", inputFileList.at(i).toLatin1().constData());
}
}
else
{
m_decompressedFiles.insert(inputFileList.at(i), inputFileList.at(i));
}
}
int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count());
//Now split all tracks
for(int i = 0; i < nTracks; i++) for(int i = 0; i < nTracks; i++)
{ {
QString outputFile = QString("%1/%2 - Track %3.wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", m_trackNo.at(i))); QString outputFile = QString("%1/%2 - Track %3.wav").arg(m_outputDir, m_baseName, QString().sprintf("%02d", m_trackNo.at(i)));
@ -114,7 +169,7 @@ void CueSplitter::addTrack(const int trackNo, const QString &file, const double
} }
else else
{ {
throw "Unknown input file!"; throw "The input file is unknown/missing!";
} }
} }
@ -124,40 +179,43 @@ void CueSplitter::setAlbumInfo(const QString &performer, const QString &title)
if(!title.isEmpty()) m_albumTitle = title; if(!title.isEmpty()) m_albumTitle = title;
} }
////////////////////////////////////////////////////////////
// Slots
////////////////////////////////////////////////////////////
void CueSplitter::handleUpdate(int progress)
{
emit fileSelected(QString("%1 [%2%]").arg(m_activeFile, QString::number(progress)));
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Privtae Functions // Privtae Functions
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void CueSplitter::splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo) void CueSplitter::splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo)
{ {
qDebug("\n[Track %02d]", trackNo); qDebug("[Track %02d]", trackNo);
qDebug("File: <%s>", file.toUtf8().constData()); qDebug("File: <%s>", file.toUtf8().constData());
qDebug("Offset: %f", offset); qDebug("Offset: %f", offset);
qDebug("Length: %f", length); qDebug("Length: %f", length);
qDebug("Artist: <%s>", metaInfo.fileArtist().toUtf8().constData()); qDebug("Artist: <%s>", metaInfo.fileArtist().toUtf8().constData());
qDebug("Title: <%s>", metaInfo.fileName().toUtf8().constData()); qDebug("Title: <%s>", metaInfo.fileName().toUtf8().constData());
if(!m_decompressedFiles.contains(file))
{
qWarning("Unknown or unsupported input file, skipping!");
m_nTracksSkipped++;
return;
}
QString baseName = QFileInfo(output).fileName(); QString baseName = QFileInfo(output).fileName();
QString decompressedInput = m_decompressedFiles[file];
if(!m_inputFiles.contains(file)) qDebug("Input: <%s>", decompressedInput.toUtf8().constData());
{
qWarning("Unknown input file, skipping!");
m_nTracksSkipped++;
return;
}
AudioFileModel &inputFileInfo = m_inputFiles[file];
if(inputFileInfo.formatContainerType().compare("Wave", Qt::CaseInsensitive) || inputFileInfo.formatAudioType().compare("PCM", Qt::CaseInsensitive))
{
qWarning("Sorry, only Wave/PCM files are supported at this time!");
m_nTracksSkipped++;
return;
}
AudioFileModel outFileInfo(metaInfo); AudioFileModel outFileInfo(metaInfo);
outFileInfo.setFilePath(output); outFileInfo.setFilePath(output);
outFileInfo.setFormatContainerType(inputFileInfo.formatContainerType()); outFileInfo.setFormatContainerType("Wave");
outFileInfo.setFormatAudioType(inputFileInfo.formatAudioType()); outFileInfo.setFormatAudioType("PCM");
if(length != std::numeric_limits<double>::infinity()) if(length != std::numeric_limits<double>::infinity())
{ {
@ -175,9 +233,10 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
QStringList args; QStringList args;
args << "-S" << "-V3"; args << "-S" << "-V3";
args << "--guard" << "--temp" << "."; args << "--guard" << "--temp" << ".";
args << QDir::toNativeSeparators(file); args << QDir::toNativeSeparators(decompressedInput);
args << QDir::toNativeSeparators(output); args << QDir::toNativeSeparators(output);
//Add trim parameters, if needed
if(offset != 0.0 || length != std::numeric_limits<double>::infinity()) if(offset != 0.0 || length != std::numeric_limits<double>::infinity())
{ {
args << "trim"; args << "trim";
@ -268,7 +327,9 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
if(length == std::numeric_limits<double>::infinity()) if(length == std::numeric_limits<double>::infinity())
{ {
qDebug("Duration updated from SoX info!"); qDebug("Duration updated from SoX info!");
outFileInfo.setFileDuration(max(0, intputLen - static_cast<unsigned int>(floor(offset + 0.5)))); int duration = intputLen - static_cast<int>(floor(offset + 0.5));
if(duration < 0) qWarning("Track is out of bounds: Track offset exceeds input file duration!");
outFileInfo.setFileDuration(max(0, duration));
} }
else else
{ {

View File

@ -40,6 +40,7 @@ class CueSplitter: public QThread
public: public:
CueSplitter(const QString &outputDir, const QString &baseName, const QList<AudioFileModel> &inputFiles); CueSplitter(const QString &outputDir, const QString &baseName, const QList<AudioFileModel> &inputFiles);
~CueSplitter(void);
void run(); void run();
bool getSuccess(void) { return !isRunning() && m_bSuccess; } bool getSuccess(void) { return !isRunning() && m_bSuccess; }
unsigned int getTracksSuccess(void) { return m_nTracksSuccess; } unsigned int getTracksSuccess(void) { return m_nTracksSuccess; }
@ -51,6 +52,9 @@ signals:
void fileSelected(const QString &fileName); void fileSelected(const QString &fileName);
void fileSplit(const AudioFileModel &file); void fileSplit(const AudioFileModel &file);
private slots:
void handleUpdate(int progress);
private: private:
void splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo); void splitFile(const QString &output, const int trackNo, const QString &file, const double offset, const double length, const AudioFileModel &metaInfo);
QString indexToString(const double index) const; QString indexToString(const double index) const;
@ -65,7 +69,10 @@ private:
QString m_albumTitle; QString m_albumTitle;
QString m_albumPerformer; QString m_albumPerformer;
QString m_activeFile;
QMap<QString,AudioFileModel> m_inputFiles; QMap<QString,AudioFileModel> m_inputFiles;
QMap<QString,QString> m_decompressedFiles;
QStringList m_tempFiles;
QList<QString> m_trackFile; QList<QString> m_trackFile;
QList<int> m_trackNo; QList<int> m_trackNo;
QList<double> m_trackOffset; QList<double> m_trackOffset;