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>
<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>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 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)

View File

@ -321,6 +321,22 @@
<source>Analyzing file(s), please wait...</source>
<translation type="unfinished"></translation>
</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>
<source>Splitting file(s), please wait...</source>
<translation type="unfinished"></translation>

View File

@ -331,12 +331,28 @@
</message>
<message>
<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>
<source>Cue Sheet Completed</source>
<translation>Cuesheet Abgeschlossen</translation>
</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>
<name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -341,6 +341,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -337,6 +337,22 @@
<source>Cue Sheet Completed</source>
<translation type="unfinished"></translation>
</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>
<name>CueSheetImport</name>

View File

@ -186,6 +186,15 @@
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus">
<bool>true</bool>
</property>
<attribute name="headerStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</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"/>
</resources>
<connections>
<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;
}
//Analyze all source files
analyzeFiles(files);
//Analyze all source files first
if(analyzeFiles(files))
{
//Now split files according to Cue Sheet
splitFiles();
}
//Now split files according to Cue Sheet
splitFiles();
//Release locks
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();
bool bSuccess = true;
WorkingBanner *progress = new WorkingBanner(this);
FileAnalyzer *analyzer = new FileAnalyzer(files);
@ -255,7 +258,19 @@ void CueImportDialog::analyzeFiles(QStringList &files)
progress->show(tr("Analyzing file(s), please wait..."), analyzer);
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(analyzer);
return bSuccess;
}
void CueImportDialog::splitFiles(void)
@ -308,7 +323,7 @@ void CueImportDialog::splitFiles(void)
}
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);
}

View File

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

View File

@ -129,13 +129,13 @@ QModelIndex CueSheetModel::index(int row, int column, const QModelIndex &parent)
{
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());
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();

View File

@ -25,6 +25,8 @@
#include "LockedFile.h"
#include "Model_AudioFile.h"
#include "PlaylistImporter.h"
#include "Registry_Decoder.h"
#include "Decoder_Abstract.h"
#include <QDir>
#include <QFileInfo>
@ -52,6 +54,8 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
m_albumPerformer.clear();
m_albumTitle.clear();
m_decompressedFiles.clear();
m_tempFiles.clear();
qDebug("\n[CueSplitter::CueSplitter]");
@ -59,13 +63,21 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
for(int i = 0; i < nInputFiles; 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.");
m_bSuccess = false;
}
CueSplitter::~CueSplitter(void)
{
while(!m_tempFiles.isEmpty())
{
lamexp_remove_file(m_tempFiles.takeFirst());
}
}
////////////////////////////////////////////////////////////
// Thread Main
////////////////////////////////////////////////////////////
@ -73,18 +85,61 @@ CueSplitter::CueSplitter(const QString &outputDir, const QString &baseName, cons
void CueSplitter::run()
{
m_bSuccess = false;
m_abortFlag = false;
m_nTracksSuccess = 0;
m_nTracksSkipped = 0;
m_abortFlag = false;
int nTracks = min(min(min(m_trackFile.count(), m_trackNo.count()), min(m_trackOffset.count(), m_trackLength.count())), m_trackMetaInfo.count());
m_decompressedFiles.clear();
m_activeFile.clear();
if(!QDir(m_outputDir).exists())
{
qWarning("Output directory \"%s\" does not exist!", m_outputDir.toUtf8().constData());
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++)
{
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
{
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;
}
////////////////////////////////////////////////////////////
// Slots
////////////////////////////////////////////////////////////
void CueSplitter::handleUpdate(int progress)
{
emit fileSelected(QString("%1 [%2%]").arg(m_activeFile, QString::number(progress)));
}
////////////////////////////////////////////////////////////
// Privtae Functions
////////////////////////////////////////////////////////////
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("Offset: %f", offset);
qDebug("Length: %f", length);
qDebug("Artist: <%s>", metaInfo.fileArtist().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();
if(!m_inputFiles.contains(file))
{
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;
}
QString decompressedInput = m_decompressedFiles[file];
qDebug("Input: <%s>", decompressedInput.toUtf8().constData());
AudioFileModel outFileInfo(metaInfo);
outFileInfo.setFilePath(output);
outFileInfo.setFormatContainerType(inputFileInfo.formatContainerType());
outFileInfo.setFormatAudioType(inputFileInfo.formatAudioType());
outFileInfo.setFormatContainerType("Wave");
outFileInfo.setFormatAudioType("PCM");
if(length != std::numeric_limits<double>::infinity())
{
@ -175,9 +233,10 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
QStringList args;
args << "-S" << "-V3";
args << "--guard" << "--temp" << ".";
args << QDir::toNativeSeparators(file);
args << QDir::toNativeSeparators(decompressedInput);
args << QDir::toNativeSeparators(output);
//Add trim parameters, if needed
if(offset != 0.0 || length != std::numeric_limits<double>::infinity())
{
args << "trim";
@ -268,7 +327,9 @@ void CueSplitter::splitFile(const QString &output, const int trackNo, const QStr
if(length == std::numeric_limits<double>::infinity())
{
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
{

View File

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