summaryrefslogtreecommitdiffstats
path: root/src/convert.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 19:09:31 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-03-01 19:09:31 +0000
commitf2cfda2a54780868dfe0af7bd652fcd4906547da (patch)
treec6ac23545528f5701818424f2af5f79ce3665e6c /src/convert.cpp
downloadsoundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.tar.gz
soundkonverter-f2cfda2a54780868dfe0af7bd652fcd4906547da.zip
Added KDE3 version of SoundKonverter
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/soundkonverter@1097614 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'src/convert.cpp')
-rwxr-xr-xsrc/convert.cpp1615
1 files changed, 1615 insertions, 0 deletions
diff --git a/src/convert.cpp b/src/convert.cpp
new file mode 100755
index 0000000..ce435ab
--- /dev/null
+++ b/src/convert.cpp
@@ -0,0 +1,1615 @@
+
+#include "convert.h"
+//#include "conversionoptions.h"
+#include "convertpluginloader.h"
+#include "replaygainpluginloader.h"
+#include "replaygain.h"
+#include "ripperpluginloader.h"
+#include "config.h"
+#include "tagengine.h"
+#include "cdmanager.h"
+#include "logger.h"
+#include "filelist.h"
+#include "replaygainscanner.h"
+
+#include <math.h>
+
+#include <klocale.h>
+#include <kglobal.h>
+//#include <kdebug.h>
+#include <ktempfile.h>
+#include <kio/job.h>
+//#include <kprocess.h>
+#include <kstandarddirs.h>
+
+#include <qfile.h>
+#include <qtimer.h>
+
+ConvertItem::ConvertItem()
+{
+ // create a new item with the file list item pointer set to zero
+ ConvertItem( (FileListItem*)0 );
+}
+
+ConvertItem::ConvertItem( FileListItem* item )
+{
+ fileListItem = item;
+ getTime = getCorrectionTime = ripTime = decodeTime = encodeTime = replaygainTime = 0;
+}
+
+ConvertItem::~ConvertItem()
+{}
+
+
+Convert::Convert( Config* _config, TagEngine* _tagEngine, CDManager* _cdManager, FileList* _fileList, Logger* _logger )
+{
+ config = _config;
+ tagEngine = _tagEngine;
+ cdManager = _cdManager;
+ fileList = _fileList;
+ connect( fileList, SIGNAL(convertItem(FileListItem*)),
+ this, SLOT(add(FileListItem*))
+ );
+ connect( fileList, SIGNAL(stopItem(FileListItem*)),
+ this, SLOT(stop(FileListItem*))
+ );
+ connect( this, SIGNAL(finished(FileListItem*,int)),
+ fileList, SLOT(itemFinished(FileListItem*,int))
+ );
+ connect( this, SIGNAL(rippingFinished(const QString&)),
+ fileList, SLOT(rippingFinished(const QString&))
+ );
+ logger = _logger;
+ connect( this, SIGNAL(finishedProcess(int,int)),
+ logger, SLOT(processCompleted(int,int))
+ );
+
+ tUpdateProgressIndicator = new QTimer( this, "tUpdateProgressIndicator" );
+ connect( tUpdateProgressIndicator, SIGNAL(timeout()),
+ this, SLOT(updateProgressIndicator())
+ );
+}
+
+Convert::~Convert()
+{}
+
+void Convert::cleanUp()
+{
+ // TODO clean up
+}
+
+void Convert::get( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Getting file") );
+ item->state = ConvertItem::get;
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Getting file")+"... 00 %" );
+
+ KURL source( item->fileListItem->options.filePathName.replace("?","%3f") );
+ KURL destination( item->tempInFile->name() );
+
+ if( source.isLocalFile() && destination.isLocalFile() ) {
+ item->convertProcess->clearArguments();
+
+ *(item->convertProcess) << "cp";
+ *(item->convertProcess) << source.path();
+ *(item->convertProcess) << destination.path();
+
+ logger->log( item->logID, "cp \"" + source.path() + "\" \"" + destination.path() + "\"" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+ }
+ else {
+ item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, true, false, false );
+ connect( item->moveJob, SIGNAL(percent(KIO::Job*,unsigned long)),
+ this, SLOT(moveProgress(KIO::Job*,unsigned long))
+ );
+ connect( item->moveJob, SIGNAL(result(KIO::Job*)),
+ this, SLOT(moveFinished(KIO::Job*))
+ );
+ }
+}
+
+void Convert::getCorrection( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Getting correction file") );
+ item->state = ConvertItem::get_correction;
+
+ // calculate the name of the correction input file
+ QFile file( OutputDirectory::changeExtension(item->fileListItem->options.filePathName,item->correctionInputExtension) );
+ if( !file.exists() ) {
+ logger->log( item->logID, " " + i18n("Aborting, file does not exist") + " (" + file.name() + ")" );
+ executeNextStep( item );
+ return;
+ }
+
+ KURL source( file.name() );
+ KURL destination( item->correctionInFile );
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Getting correction file")+"... 00 %" );
+
+ if( source.isLocalFile() && destination.isLocalFile() ) {
+ item->convertProcess->clearArguments();
+
+ *(item->convertProcess) << "cp";
+ *(item->convertProcess) << source.path();
+ *(item->convertProcess) << destination.path();
+
+ logger->log( item->logID, "cp \"" + source.path() + "\" \"" + destination.path() + "\"" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+ }
+ else {
+ item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, true, false, false );
+ connect( item->moveJob, SIGNAL(percent(KIO::Job*,unsigned long)),
+ this, SLOT(moveProgress(KIO::Job*,unsigned long))
+ );
+ connect( item->moveJob, SIGNAL(result(KIO::Job*)),
+ this, SLOT(moveFinished(KIO::Job*))
+ );
+ }
+}
+
+void Convert::rip( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Ripping") );
+ item->state = ConvertItem::rip;
+
+/** kaudiocreator
+ QString wavFile;
+ QString args = job->device;
+ if(!args.isEmpty())
+ args = QString("?device=%1").arg(args);
+ args = args+"&fileNameTemplate=Track %{number}";
+ if(job->track < 10)
+ wavFile = QString("audiocd:/Wav/Track 0%1.wav%2").arg(job->track).arg(args);
+ else
+ wavFile = QString("audiocd:/Wav/Track %1.wav%2").arg(job->track).arg(args);
+*/
+
+ RipperPlugin* plugin = config->getCurrentRipper();
+
+ if( plugin == 0 ) {
+ // NOTE process devices like '/dev/cdrom' - seems to be done
+ // TODO implement process priority (nice level)
+ QString src;
+ if( item->fileListItem->track != 0 ) {
+ // TODO does it work with cds with less than 10 tracks?
+ src.sprintf( "audiocd:/Wav/Track %02i.wav?device=" + item->fileListItem->device + "&fileNameTemplate=Track %%{number}", item->fileListItem->track );
+ }
+ else {
+ // FIXME implement ripping of full cds
+ src = "audiocd:/Full CD/Full CD.wav?device=" + item->fileListItem->device + "&albumTemplate=Full CD";
+ item->tracks = 1;
+ }
+ KURL source( src );
+ KURL dest( item->tempWavFile->name() );
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Ripping")+"... 00 %" );
+ item->fileListItem->ripping = true;
+
+ item->moveJob = new KIO::FileCopyJob( source, dest, -1, false, true, false, false );
+ connect( item->moveJob, SIGNAL(percent(KIO::Job*,unsigned long)),
+ this, SLOT(moveProgress(KIO::Job*,unsigned long))
+ );
+ connect( item->moveJob, SIGNAL(result(KIO::Job*)),
+ this, SLOT(moveFinished(KIO::Job*))
+ );
+ }
+ else {
+ QStringList params;
+ QString param, paramSplinter;
+
+
+ item->convertProcess->clearArguments();
+
+ param = QString::null;
+ if( plugin->rip.param ) param.append( " " + plugin->rip.param );
+ if( plugin->rip.device ) param.append( " " + plugin->rip.device );
+ if( plugin->rip.overwrite ) param.append( " " + plugin->rip.overwrite );
+
+ if( item->fileListItem->track != 0 ) {
+ if( plugin->rip.track ) param.append( " " + plugin->rip.track );
+ }
+ else {
+ if( plugin->rip.full_disc.param ) param.append( " " + plugin->rip.full_disc.param );
+ item->tracks = cdManager->getTrackCount( item->fileListItem->device );
+ item->track = 0;
+ }
+
+// if( plugin->rip.out_file.find("%p") != -1 ) {
+// QString t_str = plugin->rip.out_file;
+// t_str.replace( "%p", param );
+// param = plugin->rip.bin + " " + t_str;
+// }
+// else {
+// param = plugin->rip.bin + param + " " + plugin->rip.out_file;
+// }
+
+ QString t_str = plugin->rip.out_file;
+ t_str.replace( "%p", param );
+ param = config->binaries[plugin->rip.bin] + " " + t_str;
+
+ param.simplifyWhiteSpace();
+
+ params = QStringList::split( ' ', param );
+
+ for( QStringList::Iterator it = params.begin(); it != params.end(); ++it )
+ {
+ paramSplinter = *it;
+ paramSplinter.replace( "%d", item->fileListItem->device );
+ paramSplinter.replace( "%t", QString().sprintf("%i",item->fileListItem->track) );
+ paramSplinter.replace( "%n", QString().sprintf("%i",cdManager->getTrackCount(item->fileListItem->device)) );
+ paramSplinter.replace( "%o", item->tempWavFile->name() );
+ *(item->convertProcess) << paramSplinter;
+ }
+
+ param.replace( "%d", item->fileListItem->device );
+ param.replace( "%t", QString().sprintf("%i",item->fileListItem->track) );
+ param.replace( "%n", QString().sprintf("%i",cdManager->getTrackCount(item->fileListItem->device)) );
+ param.replace( "%o", "\""+item->tempWavFile->name()+"\"" );
+ logger->log( item->logID, param );
+
+ //kdDebug() << " Executing: `" << param << "'" << endl;
+
+ //item->readOutputTimer.start();
+ item->lastOutputTimer.start();
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Ripping")+"... 00 %" );
+ item->fileListItem->ripping = true;
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+ }
+}
+
+void Convert::decode( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Decoding") );
+ item->state = ConvertItem::decode;
+
+ QStringList params;
+ QString param, paramSplinter;
+
+ item->convertProcess->clearArguments();
+
+ ConvertPlugin* plugin = config->decoderForFormat( item->fileListItem->mimeType );
+ if( plugin == 0 ) {
+ logger->log( item->logID, " NULL POINTER: Convert::decode( ... ) / plugin" );
+ return;
+ }
+
+ param = "";
+ if( !plugin->dec.param.isEmpty() ) param.append( " " + plugin->dec.param );
+ if( !plugin->dec.overwrite.isEmpty() ) param.append( " " + plugin->dec.overwrite );
+
+ QString t_str = plugin->dec.in_out_files;
+ t_str.replace( "%p", param );
+ param = config->binaries[plugin->dec.bin] + " " + t_str;
+
+ param = param.simplifyWhiteSpace();
+
+ params = QStringList::split( ' ', param );
+
+ for( QStringList::Iterator it = params.begin(); it != params.end(); ++it )
+ {
+ paramSplinter = *it;
+ paramSplinter.replace( "%i", item->tempInFile->name() );
+ paramSplinter.replace( "%o", item->tempWavFile->name() );
+ *(item->convertProcess) << paramSplinter;
+ }
+
+ param.replace( "%i", "\""+item->tempInFile->name()+"\"" );
+ param.replace( "%o", "\""+item->tempWavFile->name()+"\"" );
+ //item->log = param;
+ logger->log( item->logID, param );
+
+ //kdDebug() << " Executing: `" << param << "'" << endl;
+
+ //item->readOutputTimer.start();
+ item->lastOutputTimer.start();
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Decoding")+"... 00 %" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+}
+
+void Convert::encode( ConvertItem* item )
+{
+ // TODO test quality profiles (never done)
+
+ QString sStrength;
+ QString sBitrate;
+ QString sQuality;
+ QString sMinBitrate;
+ QString sMaxBitrate;
+ QString sSamplingRate;
+
+ int t_int;
+ float t_float;
+
+ logger->log( item->logID, i18n("Encoding") );
+ item->state = ConvertItem::encode;
+
+ QStringList params;
+ QString param, paramSplinter;
+
+ item->convertProcess->clearArguments();
+
+ // NOTE use mimetype
+ FormatItem* formatItem = config->getFormatItem( item->fileListItem->options.encodingOptions.sFormat );
+ if( formatItem == 0 ) {
+ //kdDebug() << "NULL POINTER: `" << "Convert::encode( ... ) / formatItem" << "'" << endl;
+ logger->log( 1000, "NULL POINTER: `Convert::encode( ... ) / formatItem'" );
+ return;
+ }
+ ConvertPlugin* plugin = formatItem->encoder;
+ if( plugin == 0 ) {
+ //kdDebug() << "NULL POINTER: `" << "Convert::encode( ... ) / plugin" << "'" << endl;
+ logger->log( 1000, "NULL POINTER: `Convert::encode( ... ) / plugin'" );
+ return;
+ }
+
+// item->binary = plugin->enc.bin;
+
+ param = "";
+ if( !plugin->enc.param.isEmpty() ) param.append( " " + plugin->enc.param );
+ if( !plugin->enc.overwrite.isEmpty() ) param.append( " " + plugin->enc.overwrite );
+
+ if( plugin->enc.strength.enabled ) {
+ param.append( " " + plugin->enc.strength.param );
+ int compressionLevel = formatItem->compressionLevel;
+
+ if( plugin->enc.strength.profiles.empty() ) {
+ if( plugin->enc.strength.step < 1 ) {
+ if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min )
+ sStrength = QString::number( compressionLevel * plugin->enc.strength.step );
+ else
+ sStrength = QString::number( plugin->enc.strength.range_min - compressionLevel * plugin->enc.strength.step );
+ }
+ else {
+ if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min )
+ sStrength = QString::number( int(compressionLevel * plugin->enc.strength.step) );
+ else
+ sStrength = QString::number( int(plugin->enc.strength.range_min - compressionLevel * plugin->enc.strength.step) );
+ }
+ if( plugin->enc.strength.separator != '.' ) sStrength.replace( QChar('.'), plugin->enc.strength.separator );
+ }
+ else {
+ QStringList::Iterator it = plugin->enc.strength.profiles.at( compressionLevel );
+ sStrength = *it;
+ }
+ }
+
+ if( item->fileListItem->options.encodingOptions.sQualityMode == i18n("Bitrate") ) {
+ if( item->fileListItem->options.encodingOptions.sBitrateMode == "cbr" && plugin->enc.lossy.bitrate.cbr.enabled ) {
+ param.append( " " + plugin->enc.lossy.bitrate.cbr.param );
+ sBitrate = QString::number( item->fileListItem->options.encodingOptions.iQuality );
+ }
+ else if( item->fileListItem->options.encodingOptions.sBitrateMode == "abr" && plugin->enc.lossy.bitrate.abr.enabled ) {
+ param.append( " " + plugin->enc.lossy.bitrate.abr.param );
+ sBitrate = QString::number( item->fileListItem->options.encodingOptions.iQuality );
+ if( item->fileListItem->options.encodingOptions.bBitrateRange && plugin->enc.lossy.bitrate.abr.bitrate_range.enabled ) {
+ param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_min );
+ sMinBitrate = QString::number( item->fileListItem->options.encodingOptions.iMinBitrate );
+ param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_max );
+ sMaxBitrate = QString::number( item->fileListItem->options.encodingOptions.iMaxBitrate );
+ }
+ }
+ }
+ else if( item->fileListItem->options.encodingOptions.sQualityMode == i18n("Quality") && plugin->enc.lossy.quality.enabled ) {
+ param.append( " " + plugin->enc.lossy.quality.param );
+ if( plugin->enc.lossy.quality.profiles.empty() ) {
+ if( plugin->enc.lossy.quality.step < 1 ) {
+ if( plugin->enc.lossy.quality.range_max >= plugin->enc.lossy.quality.range_min)
+ t_float = ( (float)item->fileListItem->options.encodingOptions.iQuality * ( plugin->enc.lossy.quality.range_max - plugin->enc.lossy.quality.range_min ) / 100 ) + plugin->enc.lossy.quality.range_min;
+ else
+ t_float = ( (100.0f - (float)item->fileListItem->options.encodingOptions.iQuality) * ( plugin->enc.lossy.quality.range_min - plugin->enc.lossy.quality.range_max ) / 100 ) + plugin->enc.lossy.quality.range_max;
+ //t_float -= t_float%plugin->enc.quality.step;
+ //sQuality = QString().sprintf( "%.2f", t_float );
+ sQuality = QString::number( t_float );
+ }
+ else {
+ if( plugin->enc.lossy.quality.range_max >= plugin->enc.lossy.quality.range_min)
+ t_int = ( item->fileListItem->options.encodingOptions.iQuality * (int)( plugin->enc.lossy.quality.range_max - plugin->enc.lossy.quality.range_min ) / 100) + (int)plugin->enc.lossy.quality.range_min;
+ else
+ t_int = ( (100 - item->fileListItem->options.encodingOptions.iQuality) * (int)( plugin->enc.lossy.quality.range_min - plugin->enc.lossy.quality.range_max ) / 100) + (int)plugin->enc.lossy.quality.range_max;
+ //t_int -= t_int%plugin->enc.quality.step;
+ sQuality = QString::number( t_int );
+ }
+ if( plugin->enc.bin == "oggenc" ) sQuality.replace(QChar('.'),KGlobal::locale()->decimalSymbol()); // HACK make oggenc usable with all langauges
+ else if( plugin->enc.lossy.quality.separator != '.' ) sQuality.replace(QChar('.'),plugin->enc.lossy.quality.separator);
+ }
+ else {
+ QStringList::Iterator it = plugin->enc.lossy.quality.profiles.at( rint(item->fileListItem->options.encodingOptions.iQuality*plugin->enc.lossy.quality.range_max/100) );
+ sQuality = *it;
+ }
+ }
+ else if( item->fileListItem->options.encodingOptions.sQualityMode == i18n("Lossless") && plugin->enc.lossless.enabled ) {
+ param.append( " " + plugin->enc.lossless.param );
+ }
+ else if( item->fileListItem->options.encodingOptions.sQualityMode == i18n("Hybrid") && plugin->enc.hybrid.enabled ) {
+ param.append( " " + plugin->enc.hybrid.param );
+ sBitrate = QString::number( item->fileListItem->options.encodingOptions.iQuality );
+ }
+
+ if( item->fileListItem->options.encodingOptions.samplingRate.bEnabled && plugin->enc.lossy.samplingrate.enabled ) {
+ param.append( " " + plugin->enc.lossy.samplingrate.param );
+ if( plugin->enc.lossy.samplingrate.unit == PluginLoaderBase::Hz ) {
+ sSamplingRate = QString::number( item->fileListItem->options.encodingOptions.samplingRate.iSamplingRate );
+ }
+ else {
+ sSamplingRate = QString::number( (float)item->fileListItem->options.encodingOptions.samplingRate.iSamplingRate/1000 );
+ }
+ }
+
+ if( item->fileListItem->options.encodingOptions.channels.bEnabled ) {
+ if( item->fileListItem->options.encodingOptions.channels.sChannels == i18n("Mono") && plugin->enc.lossy.channels.mono_enabled ) {
+ param.append( " " + plugin->enc.lossy.channels.mono_param );
+ }
+ else if( item->fileListItem->options.encodingOptions.channels.sChannels == i18n("Stereo") && plugin->enc.lossy.channels.stereo_enabled ) {
+ param.append( " " + plugin->enc.lossy.channels.stereo_param );
+ }
+ else if( item->fileListItem->options.encodingOptions.channels.sChannels == i18n("Joint-Stereo") && plugin->enc.lossy.channels.joint_stereo_enabled ) {
+ param.append( " " + plugin->enc.lossy.channels.joint_stereo_param );
+ }
+ else if( item->fileListItem->options.encodingOptions.channels.sChannels == i18n("Forced Joint-Stereo") && plugin->enc.lossy.channels.forced_joint_stereo_enabled ) {
+ param.append( " " + plugin->enc.lossy.channels.forced_joint_stereo_param );
+ }
+ else if( item->fileListItem->options.encodingOptions.channels.sChannels == i18n("Dual Channels") && plugin->enc.lossy.channels.dual_channels_enabled ) {
+ param.append( " " + plugin->enc.lossy.channels.dual_channels_param );
+ }
+ }
+
+ if( item->fileListItem->options.encodingOptions.replaygain.bEnabled && plugin->enc.replaygain.enabled && plugin->enc.replaygain.use && formatItem->internalReplayGain ) {
+ param.append( " " + plugin->enc.replaygain.use );
+ }
+ else if( plugin->enc.replaygain.enabled && plugin->enc.replaygain.avoid ) {
+ param.append( " " + plugin->enc.replaygain.avoid );
+ }
+
+// if( !tagEngine->canWrite(item->fileListItem->options.encodingOptions.sFormat) && item->fileListItem->tags && plugin->enc.tag.enabled ) {
+ if( item->fileListItem->tags && plugin->enc.tag.enabled && item->fileListItem->options.encodingOptions.sFormat != "aac" ) { // HACK don't write metadata to aac
+ if( !plugin->enc.tag.param.isEmpty() ) param.append( " " + plugin->enc.tag.param );
+ if( !plugin->enc.tag.artist.isEmpty() && !item->fileListItem->tags->artist.isEmpty() ) param.append( " " + plugin->enc.tag.artist );
+ if( !plugin->enc.tag.album.isEmpty() && !item->fileListItem->tags->album.isEmpty() ) param.append( " " + plugin->enc.tag.album );
+ if( !plugin->enc.tag.comment.isEmpty() && !item->fileListItem->tags->comment.isEmpty() ) param.append( " " + plugin->enc.tag.comment );
+ if( !plugin->enc.tag.disc.isEmpty() && item->fileListItem->tags->disc != 0 ) param.append( " " + plugin->enc.tag.disc );
+ if( !plugin->enc.tag.genre.isEmpty() && !item->fileListItem->tags->genre.isEmpty() ) param.append( " " + plugin->enc.tag.genre );
+ if( !plugin->enc.tag.track.isEmpty() && item->fileListItem->tags->track != 0 ) param.append( " " + plugin->enc.tag.track );
+ if( !plugin->enc.tag.composer.isEmpty() && !item->fileListItem->tags->composer.isEmpty() ) param.append( " " + plugin->enc.tag.composer );
+ if( !plugin->enc.tag.title.isEmpty() && !item->fileListItem->tags->title.isEmpty() ) param.append( " " + plugin->enc.tag.title );
+ if( !plugin->enc.tag.year.isEmpty() && item->fileListItem->tags->year != 0 ) param.append( " " + plugin->enc.tag.year );
+ }
+
+ QString sInOutFiles = item->fileListItem->options.encodingOptions.sInOutFiles;
+ param = sInOutFiles.replace( "%p", param );
+
+ // cosmetic surgery
+ param = param.simplifyWhiteSpace();
+
+ params = QStringList::split( ' ', param );
+
+ QString inputFile;
+ if( item->mode & ConvertItem::decode || item->mode & ConvertItem::rip ) inputFile = item->tempWavFile->name();
+ else inputFile = item->tempInFile->name();
+
+ for( QStringList::Iterator it = params.begin(); it != params.end(); ++it )
+ {
+ paramSplinter = *it;
+ paramSplinter.replace( "%i", inputFile );
+ paramSplinter.replace( "%o", item->tempOutFile->name() );
+ paramSplinter.replace( "%c", sStrength );
+ paramSplinter.replace( "%b", sBitrate );
+ paramSplinter.replace( "%q", sQuality );
+ paramSplinter.replace( "%m", sMinBitrate );
+ paramSplinter.replace( "%M", sMaxBitrate );
+ paramSplinter.replace( "%s", sSamplingRate );
+
+ if( item->fileListItem->tags ) {
+ paramSplinter.replace( "%ta", ( item->fileListItem->tags->artist != "" ) ? item->fileListItem->tags->artist : i18n("Unknown") );
+ paramSplinter.replace( "%tb", ( item->fileListItem->tags->album != "" ) ? item->fileListItem->tags->album : i18n("Unknown") );
+ paramSplinter.replace( "%tc", ( item->fileListItem->tags->comment != "" ) ? item->fileListItem->tags->comment : i18n("Unknown") );
+ paramSplinter.replace( "%td", ( QString::number(item->fileListItem->tags->disc) != "" ) ? QString::number(item->fileListItem->tags->disc) : "0" );
+ paramSplinter.replace( "%tg", ( item->fileListItem->tags->genre != "" ) ? item->fileListItem->tags->genre : i18n("Unknown") );
+ paramSplinter.replace( "%tn", ( QString::number(item->fileListItem->tags->track) != "" ) ? QString::number(item->fileListItem->tags->track) : "0" );
+ paramSplinter.replace( "%tp", ( item->fileListItem->tags->composer != "" ) ? item->fileListItem->tags->composer : i18n("Unknown") );
+ paramSplinter.replace( "%tt", ( item->fileListItem->tags->title != "" ) ? item->fileListItem->tags->title : i18n("Unknown") );
+ paramSplinter.replace( "%ty", ( QString::number(item->fileListItem->tags->year) != "" ) ? QString::number(item->fileListItem->tags->year) : "0" );
+ }
+
+ if( paramSplinter != "" && paramSplinter != " " ) *(item->convertProcess) << paramSplinter; // NOTE fixes wavpack encoding
+ }
+
+ param.replace( "%i", "\""+inputFile+"\"" );
+ param.replace( "%o", "\""+item->tempOutFile->name()+"\"" );
+ param.replace( "%c", sStrength );
+ param.replace( "%b", sBitrate );
+ param.replace( "%q", sQuality );
+ param.replace( "%m", sMinBitrate );
+ param.replace( "%M", sMaxBitrate );
+ param.replace( "%s", sSamplingRate );
+
+ if( item->fileListItem->tags ) {
+ param.replace( "%ta", "\""+item->fileListItem->tags->artist+"\"" );
+ param.replace( "%tb", "\""+item->fileListItem->tags->album+"\"" );
+ param.replace( "%tc", "\""+item->fileListItem->tags->comment+"\"" );
+ param.replace( "%td", QString::number(item->fileListItem->tags->disc) );
+ param.replace( "%tg", "\""+item->fileListItem->tags->genre+"\"" );
+ param.replace( "%tn", QString::number(item->fileListItem->tags->track) );
+ param.replace( "%tp", "\""+item->fileListItem->tags->composer+"\"" );
+ param.replace( "%tt", "\""+item->fileListItem->tags->title+"\"" );
+ param.replace( "%ty", QString::number(item->fileListItem->tags->year) );
+ }
+
+ logger->log( item->logID, param );
+
+ //kdDebug() << " Executing: `" << param << "'" << endl;
+
+ //item->readOutputTimer.start();
+ item->lastOutputTimer.start();
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Encoding")+"... 00 %" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+}
+
+void Convert::replaygain( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Applying Replay Gain") );
+ item->state = ConvertItem::replaygain;
+
+ FormatItem* formatItem = config->getFormatItem( item->fileListItem->options.encodingOptions.sFormat );
+ if( formatItem == 0 ) {
+ logger->log( item->logID, " NULL POINTER: Convert::replaygain( ... ) / formatItem" );
+ return;
+ }
+ ConvertPlugin* plugin = formatItem->encoder;
+ if( plugin == 0 ) {
+ logger->log( item->logID, " NULL POINTER: Convert::replaygain( ... ) / plugin" );
+ return;
+ }
+
+ if( plugin->enc.replaygain.enabled && formatItem->internalReplayGain ) {
+ executeNextStep( item );
+ return;
+ }
+
+ item->replayGain = new ReplayGain( config, logger );
+ bool ret = item->replayGain->apply( item->tempOutFile->name(), item->fileListItem->options.encodingOptions.sFormat, item->convertProcess, item->logID );
+
+ if( !ret ) {
+ executeNextStep( item );
+ return;
+ }
+
+ //item->readOutputTimer.start();
+ item->lastOutputTimer.start();
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Replay Gain")+"... 00 %" );
+}
+
+void Convert::writeTags( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Writing tags") );
+ item->state = ConvertItem::write_tags;
+
+ if( item->mode & ConvertItem::encode ) {
+ tagEngine->writeTags( item->tempOutFile->name(), item->fileListItem->tags );
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Writing tags")+"... 00 %" );
+ }
+
+ executeNextStep( item );
+}
+
+void Convert::put( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Moving file") );
+ item->state = ConvertItem::put;
+
+ QString src;
+ if( item->mode & ConvertItem::encode ) src = item->tempOutFile->name();
+ else src = item->tempWavFile->name();
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Moving file")+"... 00 %" );
+
+ item->outputFilePathName = OutputDirectory::makePath( OutputDirectory::uniqueFileName(OutputDirectory::calcPath(item->fileListItem,config)) ).replace("%2f","%252f");
+
+ KURL source( src );
+ KURL destination( item->outputFilePathName );
+
+ if( source.isLocalFile() && destination.isLocalFile() ) {
+ item->convertProcess->clearArguments();
+
+ *(item->convertProcess) << "cp";
+ *(item->convertProcess) << source.path();
+ *(item->convertProcess) << destination.path();
+
+ logger->log( item->logID, "cp \"" + source.path() + "\" \"" + destination.path() + "\"" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+ }
+ else {
+ item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, false, false, false );
+ connect( item->moveJob, SIGNAL(percent(KIO::Job*,unsigned long)),
+ this, SLOT(moveProgress(KIO::Job*,unsigned long))
+ );
+ connect( item->moveJob, SIGNAL(result(KIO::Job*)),
+ this, SLOT(moveFinished(KIO::Job*))
+ );
+ }
+}
+
+void Convert::putCorrection( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Moving correction file") );
+ item->state = ConvertItem::put_correction;
+
+ QString src = item->correctionOutFile;
+
+ QString dest = OutputDirectory::makePath( OutputDirectory::calcPath(item->fileListItem,config,item->correctionOutputExtension) ).replace("%2f","%252f");
+
+ KURL source( src );
+// KURL destination( dest );
+ KURL destination;
+ destination.setPath( dest );
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Moving correction file")+"... 00 %" );
+
+ if( source.isLocalFile() && destination.isLocalFile() ) {
+ item->convertProcess->clearArguments();
+
+ *(item->convertProcess) << "cp";
+ *(item->convertProcess) << source.path();
+ *(item->convertProcess) << destination.path();
+
+ logger->log( item->logID, "cp \"" + source.path() + "\" \"" + destination.path() + "\"" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+ }
+ else {
+ item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, false, false, false );
+ connect( item->moveJob, SIGNAL(percent(KIO::Job*,unsigned long)),
+ this, SLOT(moveProgress(KIO::Job*,unsigned long))
+ );
+ connect( item->moveJob, SIGNAL(result(KIO::Job*)),
+ this, SLOT(moveFinished(KIO::Job*))
+ );
+ }
+}
+
+void Convert::executeUserScript( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Running user script") );
+ item->state = ConvertItem::execute_userscript;
+
+ KURL source( item->fileListItem->options.filePathName );
+ KURL destination( item->outputFilePathName );
+
+ item->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Running user script")+"... 00 %" );
+
+ item->convertProcess->clearArguments();
+
+ QString userscript = locate( "data", "soundkonverter/userscript.sh" );
+ if( userscript == "" ) executeNextStep( item );
+
+ *(item->convertProcess) << userscript;
+ *(item->convertProcess) << source.path();
+ *(item->convertProcess) << destination.path();
+
+ logger->log( item->logID, userscript + " \"" + source.path() + "\" \"" + destination.path() + "\"" );
+
+ item->convertProcess->setPriority( config->data.general.priority );
+ item->convertProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput );
+}
+
+void Convert::executeNextStep( ConvertItem* item )
+{
+ logger->log( item->logID, i18n("Executing next step") );
+
+ item->percent = 0;
+ item->lastPercent = 0; // used for ripping a whole cd to one file
+
+ switch( item->state )
+ {
+ case ConvertItem::get:
+ {
+ if( item->mode & ConvertItem::get_correction ) getCorrection( item );
+ else if( item->mode & ConvertItem::rip ) rip( item );
+ else if( item->mode & ConvertItem::decode ) decode( item );
+ else if( item->mode & ConvertItem::encode ) encode( item );
+ else if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::get_correction:
+ {
+ if( item->mode & ConvertItem::rip ) rip( item );
+ else if( item->mode & ConvertItem::decode ) decode( item );
+ else if( item->mode & ConvertItem::encode ) encode( item );
+ else if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::rip:
+ {
+ if( item->mode & ConvertItem::decode ) decode( item );
+ else if( item->mode & ConvertItem::encode ) encode( item );
+ else if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::decode:
+ {
+ if( item->mode & ConvertItem::encode ) encode( item );
+ else if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::encode:
+ {
+ if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::replaygain:
+ {
+ if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::write_tags:
+ {
+ if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::put:
+ {
+ if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::put_correction:
+ {
+ if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ case ConvertItem::execute_userscript:
+ {
+ remove( item );
+ break;
+ }
+ default: // case (ConvertItem::Mode)0x0000:
+ {
+ if( item->mode & ConvertItem::get ) get( item );
+ else if( item->mode & ConvertItem::get_correction ) getCorrection( item );
+ else if( item->mode & ConvertItem::rip ) rip( item );
+ else if( item->mode & ConvertItem::decode ) decode( item );
+ else if( item->mode & ConvertItem::encode ) encode( item );
+ else if( item->mode & ConvertItem::replaygain ) replaygain( item );
+ else if( item->mode & ConvertItem::write_tags ) writeTags( item );
+ else if( item->mode & ConvertItem::put ) put( item );
+ else if( item->mode & ConvertItem::put_correction ) putCorrection( item );
+ else if( config->data.general.executeUserScript ) executeUserScript( item );
+ else remove( item );
+ break;
+ }
+ }
+}
+
+void Convert::moveProgress( KIO::Job* job, unsigned long percent )
+{
+ // search the item list for our item
+ for( QValueList<ConvertItem*>::Iterator item = items.begin(); item != items.end(); item++ ) {
+ if( (*item)->moveJob == job ) {
+ (*item)->percent = percent;
+ }
+ }
+}
+
+void Convert::moveFinished( KIO::Job* job )
+{
+ // search the item list for our item
+ for( QValueList<ConvertItem*>::Iterator item = items.begin(); item != items.end(); item++ ) {
+ if( (*item)->moveJob == job ) {
+
+ (*item)->percent = 0;
+ if( (*item)->state == ConvertItem::get ) {
+ if( job->error() != 0 ) {
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+
+ logger->log( (*item)->logID, " " + i18n("Got file") );
+
+ // if file is remote or the tag reding failed previously, read the tags now
+ if( (*item)->fileListItem->tags == 0 ) {
+ (*item)->fileListItem->tags = tagEngine->readTags( (*item)->tempInFile->name() );
+ }
+
+ emit countTime( (*item)->getTime );
+ }
+ else if( (*item)->state == ConvertItem::get_correction ) {
+ if( job->error() != 0 ) {
+ emit uncountTime( (*item)->getTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+
+ logger->log( (*item)->logID, " " + i18n("Got file") );
+ emit countTime( (*item)->getCorrectionTime );
+ }
+ else if( (*item)->state == ConvertItem::rip ) {
+ if( job->error() != 0 ) {
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+
+ //logger->log( (*item)->logID, " " + i18n("Ripped track") );
+ (*item)->fileListItem->ripping = false;
+ emit countTime( (*item)->ripTime );
+ emit rippingFinished( (*item)->fileListItem->device );
+ }
+ else if( (*item)->state == ConvertItem::put ) {
+ if( job->error() != 0 ) {
+ logger->log( (*item)->logID, i18n("Could not write to file: `%1'").arg(OutputDirectory::calcPath((*item)->fileListItem,config)) );
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+
+ logger->log( (*item)->logID, " " + i18n("File moved") );
+ }
+ else if( (*item)->state == ConvertItem::put_correction ) {
+ if( job->error() != 0 ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+
+ logger->log( (*item)->logID, " " + i18n("File moved") );
+ }
+
+ executeNextStep( *item );
+ return;
+ }
+ }
+}
+
+void Convert::processOutput( KProcess* proc, char* data, int )
+{
+ int iPercent = 0, iTime = 0, iPos = 0, iNum = 0;
+
+ // search the item list for our item
+ for( QValueList<ConvertItem*>::Iterator item = items.begin(); item != items.end(); item++ )
+ {
+ if( (*item)->convertProcess == proc )
+ {
+ QString log_data = data;
+/* log_data.replace("\n","\\n");
+ log_data.replace("\t","\\t");
+ log_data.replace("\r","\\r");
+ log_data.replace("\b","\\b");*/
+ logger->log( (*item)->logID, " " + i18n("Output") + ": " + log_data );
+
+ //if( (*item)->readOutputTimer.elapsed() < /*config->pauseTime*/ 100 ) return; // TODO use config value
+ //(*item)->readOutputTimer.start();
+
+ if( (*item)->state == ConvertItem::decode )
+ {
+ if( (*item)->fileListItem == 0 ) return;
+
+ ConvertPlugin* plugin = config->decoderForFormat( (*item)->fileListItem->mimeType );
+ // TODO null pointer check
+
+ QString outputPattern = plugin->dec.output;
+ //outputPattern.replace( "%i", "%p" ); // for compatibility with old plugins
+
+ if( outputPattern.find("%p") != -1 ) {
+ outputPattern.replace( "%p", "%i" );
+ sscanf( data, outputPattern, &iPercent );
+ }
+ else if( outputPattern.find("%t") != -1 ) {
+ outputPattern.replace( "%t", "%i" );
+ sscanf( data, outputPattern, &iTime );
+ iPercent = iTime * 100 / (*item)->fileListItem->time;
+ }
+ else if( outputPattern.find("%0") != -1 && outputPattern.find("%1") != -1 ) {
+ if( outputPattern.find("%0") < outputPattern.find("%1") ) {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iPos, &iNum );
+ }
+ else {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iNum, &iPos );
+ }
+ if( iPos != 0 && iNum != 0 ) iPercent = iPos * 100 / iNum;
+ }
+
+ if( iPercent > 0 && iPercent <= 100 )
+ {
+ // TODO guess progress, when no signal is received
+ (*item)->lastOutputTimer.start();
+ (*item)->percent = iPercent;
+ }
+ }
+ else if( (*item)->state == ConvertItem::encode )
+ {
+ if( (*item)->fileListItem == 0 ) return;
+
+ // NOTE use mimetype
+ ConvertPlugin* plugin = config->encoderForFormat( (*item)->fileListItem->options.encodingOptions.sFormat );
+ // TODO null pointer check
+
+ QString outputPattern;
+ if( (*item)->fileListItem->options.encodingOptions.sQualityMode == i18n("Quality") ) outputPattern = plugin->enc.lossy.quality.output;
+ else if( (*item)->fileListItem->options.encodingOptions.sQualityMode == i18n("Bitrate") && (*item)->fileListItem->options.encodingOptions.sBitrateMode == "cbr" ) outputPattern = plugin->enc.lossy.bitrate.cbr.output;
+ else if( (*item)->fileListItem->options.encodingOptions.sQualityMode == i18n("Bitrate") && (*item)->fileListItem->options.encodingOptions.sBitrateMode == "abr" ) outputPattern = plugin->enc.lossy.bitrate.abr.output;
+
+ //outputPattern.replace( "%i", "%p" ); // for compatibility with old plugins
+
+ if( outputPattern.find("%p") != -1 ) {
+ outputPattern.replace( "%p", "%i" );
+ sscanf( data, outputPattern, &iPercent );
+ }
+ else if( outputPattern.find("%t") != -1 ) {
+ outputPattern.replace( "%t", "%i" );
+ sscanf( data, outputPattern, &iTime );
+ iPercent = iTime * 100 / (*item)->fileListItem->time;
+ }
+ else if( outputPattern.find("%0") != -1 && outputPattern.find("%1") != -1 ) {
+ if( outputPattern.find("%0") < outputPattern.find("%1") ) {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iPos, &iNum );
+ }
+ else {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iNum, &iPos );
+ }
+ if( iPos != 0 && iNum != 0 ) iPercent = iPos * 100 / iNum;
+ }
+
+ if( iPercent > 0 && iPercent <= 100 )
+ {
+ // TODO guess progress, when no signal is received
+ (*item)->lastOutputTimer.start();
+ (*item)->percent = iPercent;
+ }
+ }
+ else if( (*item)->state == ConvertItem::rip ) // ### soundkonverter 0.4 make the progress dependent on the track length
+ {
+ if( (*item)->fileListItem == 0 ) return;
+
+ RipperPlugin* plugin = config->getCurrentRipper();
+ // TODO null pointer check
+
+ QString outputPattern;
+ if( (*item)->fileListItem->track != 0 ) outputPattern = plugin->rip.output;
+ else outputPattern = plugin->rip.full_disc.output;
+ //outputPattern.replace( "%i", "%p" ); // for compatibility with old plugins
+
+ if( outputPattern.find("%p") != -1 || outputPattern.find("%a") != -1 ) {
+ outputPattern.replace( "%p", "%i" );
+ outputPattern.replace( "%a", "%i" );
+ sscanf( data, outputPattern, &iPercent );
+ }
+ else if( outputPattern.find("%t") != -1 ) {
+ outputPattern.replace( "%t", "%i" );
+ sscanf( data, outputPattern, &iTime );
+ iPercent = iTime * 100 / (*item)->fileListItem->time;
+ }
+ else if( outputPattern.find("%0") != -1 && outputPattern.find("%1") != -1 ) {
+ if( outputPattern.find("%0") < outputPattern.find("%1") ) {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iPos, &iNum );
+ }
+ else {
+ outputPattern.replace( "%0", "%i" );
+ outputPattern.replace( "%1", "%i" );
+ sscanf( data, outputPattern, &iNum, &iPos );
+ }
+ if( iPos != 0 && iNum != 0 ) iPercent = iPos * 100 / iNum;
+ }
+
+ if( iPercent > 0 && iPercent <= 100 )
+ {
+ // TODO guess progress, when no signal is received
+ (*item)->lastOutputTimer.start();
+ if( (*item)->fileListItem->track == 0 && plugin->rip.full_disc.output.find("%a") != -1 ) {
+ if( iPercent < (*item)->lastPercent ) (*item)->track++;
+ (*item)->lastPercent = iPercent;
+ (*item)->percent = (*item)->track * 100 / (*item)->tracks + iPercent / (*item)->tracks;
+ }
+ else {
+ (*item)->percent = iPercent;
+ }
+ }
+ }
+ return;
+ }
+ }
+}
+
+void Convert::processExit( KProcess* proc )
+{
+ // search the item list for our item
+ for( QValueList<ConvertItem*>::Iterator item = items.begin(); item != items.end(); item++ ) {
+// if( (*item)->convertProcess == proc && (*item)->fileListItem != 0 ) {
+ if( (*item)->convertProcess == proc ) {
+
+ (*item)->percent = 0;
+ if( (*item)->state == ConvertItem::rip ) {
+ if( proc->signalled() ) { // FIXME does only check, whether the process has been killed
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ (*item)->fileListItem->ripping = false;
+ emit countTime( (*item)->ripTime );
+ emit rippingFinished( (*item)->fileListItem->device );
+ }
+ }
+ if( (*item)->state == ConvertItem::get ) {
+ if( proc->signalled() ) {
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ logger->log( (*item)->logID, " " + i18n("Got file") );
+
+ // if file is remote or the tag reding failed previously, read the tags now
+ if( (*item)->fileListItem->tags == 0 ) {
+ (*item)->fileListItem->tags = tagEngine->readTags( (*item)->tempInFile->name() );
+ }
+
+ emit countTime( (*item)->getTime );
+ }
+ }
+ if( (*item)->state == ConvertItem::get_correction ) {
+ if( proc->signalled() ) {
+ emit uncountTime( (*item)->getTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ emit uncountTime( (*item)->getTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ logger->log( (*item)->logID, " " + i18n("Got file") );
+ emit countTime( (*item)->getCorrectionTime );
+ }
+ }
+ if( (*item)->state == ConvertItem::decode ) {
+ if( proc->signalled() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ emit countTime( (*item)->decodeTime );
+ }
+ }
+ if( (*item)->state == ConvertItem::encode ) {
+ if( proc->signalled() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+/* if( (*item)->binary == "faac" ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }*/
+ emit countTime( (*item)->encodeTime );
+ }
+ }
+ if( (*item)->state == ConvertItem::put ) {
+ if( proc->signalled() ) {
+ logger->log( (*item)->logID, i18n("Could not write to file: `%1'").arg(OutputDirectory::calcPath((*item)->fileListItem,config)) );
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ if( !proc->normalExit() ) {
+ logger->log( (*item)->logID, i18n("Could not write to file: `%1'").arg(OutputDirectory::calcPath((*item)->fileListItem,config)) );
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ logger->log( (*item)->logID, " " + i18n("File moved") );
+ }
+ }
+ if( (*item)->state == ConvertItem::put_correction ) {
+ if( proc->signalled() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ if( !proc->normalExit() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ emit uncountTime( (*item)->replaygainTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ logger->log( (*item)->logID, " " + i18n("File moved") );
+ }
+ }
+ if( (*item)->state == ConvertItem::replaygain ) {
+ if( proc->signalled() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ remove( *item, 1 );
+ updateProgressIndicator();
+ return;
+ }
+ else if( !proc->normalExit() ) {
+ emit uncountTime( (*item)->getTime );
+ emit uncountTime( (*item)->getCorrectionTime );
+ emit uncountTime( (*item)->ripTime );
+ emit uncountTime( (*item)->decodeTime );
+ emit uncountTime( (*item)->encodeTime );
+ remove( *item, -1 );
+ updateProgressIndicator();
+ return;
+ }
+ else {
+ emit countTime( (*item)->replaygainTime );
+ }
+ }
+ // TODO did we get errors? (complete)
+ executeNextStep( *item );
+ return;
+ }
+ }
+}
+
+void Convert::add( FileListItem* item )
+{
+ logger->log( 1000, i18n("Adding new item to conversion list: `%1'").arg(item->options.filePathName) );
+
+ // append the item to the item list and store the iterator
+ QValueList<ConvertItem*>::Iterator newItem = items.append( new ConvertItem( item ) );
+
+ // register at the logger
+ (*newItem)->logID = logger->registerProcess( item->options.filePathName );
+ logger->log( 1000, " " + i18n("Got log ID: %1").arg((*newItem)->logID) );
+
+ logger->log( (*newItem)->logID, "Mime Type: " + (*newItem)->fileListItem->mimeType );
+ if( (*newItem)->fileListItem->tags ) logger->log( (*newItem)->logID, i18n("Tags successfully read") );
+ else logger->log( (*newItem)->logID, i18n("Reading tags failed") );
+
+ // set some variables to default values
+ (*newItem)->mode = (ConvertItem::Mode)0x0000;
+ (*newItem)->state = (ConvertItem::Mode)0x0000;
+ (*newItem)->convertProcess = 0;
+ (*newItem)->moveJob = 0;
+ (*newItem)->replayGain = 0;
+
+ /* seems to be unnecessary
+ (*newItem)->correctionInFile = QString::null();
+ (*newItem)->correctionOutFile = QString::null();
+ (*newItem)->correctionInputExtension = QString::null();
+ (*newItem)->correctionOutputExtension = QString::null();*/
+
+ // connect convertProcess of our new item with the slots of Convert
+ (*newItem)->convertProcess = new KProcess();
+ connect( (*newItem)->convertProcess, SIGNAL(receivedStdout(KProcess*,char*,int)),
+ this, SLOT(processOutput(KProcess*,char*,int))
+ );
+ connect( (*newItem)->convertProcess, SIGNAL(receivedStderr(KProcess*,char*,int)),
+ this, SLOT(processOutput(KProcess*,char*,int))
+ );
+ connect( (*newItem)->convertProcess, SIGNAL(processExited(KProcess*)),
+ this, SLOT(processExit(KProcess*))
+ );
+
+ // NOTE the tempInFile is also created if the file is a audio cd track
+
+ // set up the names of our temp files
+ (*newItem)->tempInFile = new KTempFile( QString::null, "." + item->fileFormat );
+ (*newItem)->tempInFile->setAutoDelete( true );
+ (*newItem)->tempInFile->close();
+
+ (*newItem)->tempWavFile = new KTempFile( QString::null, ".wav" );
+ (*newItem)->tempWavFile->setAutoDelete( true );
+ (*newItem)->tempWavFile->close();
+
+ (*newItem)->tempOutFile = new KTempFile( QString::null, "." + item->options.encodingOptions.sFormat );
+ (*newItem)->tempOutFile->setAutoDelete( true );
+ (*newItem)->tempOutFile->close();
+
+ if( item->track >= 0 ) // it's an audio cd track
+ {
+ (*newItem)->mode = ConvertItem::Mode( ConvertItem::rip );
+ }
+ else // it's a file
+ {
+ (*newItem)->mode = ConvertItem::Mode( ConvertItem::get );
+ if( item->fileFormat != "wav" )
+ {
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::decode );
+ }
+ }
+
+ if( item->options.encodingOptions.sFormat != "wav" )
+ {
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::encode );
+ }
+ if( item->options.encodingOptions.replaygain.bEnabled )
+ {
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::replaygain );
+ }
+
+ QString extension;
+
+ extension = config->getCorrectionExtension( item->mimeType );
+ if( !extension.isEmpty() ) {
+ (*newItem)->correctionInputExtension = extension;
+ (*newItem)->correctionInFile = OutputDirectory::changeExtension( (*newItem)->tempInFile->name(), extension );
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::get_correction );
+ logger->log( (*newItem)->logID, " correctionInFile: `" + (*newItem)->correctionInFile + "'" );
+ }
+
+ extension = config->getCorrectionExtension( item->options.encodingOptions.sFormat );
+ if( !extension.isEmpty() && item->options.encodingOptions.sQualityMode == i18n("Hybrid") ) {
+ (*newItem)->correctionOutputExtension = extension;
+ (*newItem)->correctionOutFile = OutputDirectory::changeExtension( (*newItem)->tempOutFile->name(), extension );
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::put_correction );
+ logger->log( (*newItem)->logID, " correctionOutFile: `" + (*newItem)->correctionOutFile + "'" );
+ }
+
+ (*newItem)->mode = ConvertItem::Mode( (*newItem)->mode | ConvertItem::write_tags | ConvertItem::put );
+
+ // TODO use the values from the format info files !!!
+
+ if( (*newItem)->mode & ConvertItem::get ) {
+ if( !item->local ) {
+ (*newItem)->getTime = 0.8; // TODO use the file size from the format info files
+ }
+ }
+ if( (*newItem)->mode & ConvertItem::get_correction ) {
+ if( !item->local ) {
+ (*newItem)->getCorrectionTime = 2.0; // TODO use the file size from the format info files
+ }
+ }
+ if( (*newItem)->mode & ConvertItem::rip ) {
+ (*newItem)->ripTime = 1.0;
+ }
+ if( (*newItem)->mode & ConvertItem::decode ) {
+ (*newItem)->decodeTime = 0.4;
+ }
+ if( (*newItem)->mode & ConvertItem::encode ) {
+ (*newItem)->encodeTime = 1.0;
+ }
+ if( (*newItem)->mode & ConvertItem::replaygain ) {
+ (*newItem)->replaygainTime = 0.2;
+ }
+
+ float sum = ( (*newItem)->getTime + (*newItem)->getCorrectionTime + (*newItem)->ripTime + (*newItem)->decodeTime + (*newItem)->encodeTime + (*newItem)->replaygainTime ) / item->time;
+
+ (*newItem)->getTime /= sum;
+ (*newItem)->getCorrectionTime /= sum;
+ (*newItem)->ripTime /= sum;
+ (*newItem)->decodeTime /= sum;
+ (*newItem)->encodeTime /= sum;
+ (*newItem)->replaygainTime /= sum;
+
+ // visual feedback
+ item->converting = true;
+
+ if( !tUpdateProgressIndicator->isActive() ) {
+ tUpdateProgressIndicator->start( config->data.general.updateDelay );
+ }
+
+ // and start
+ executeNextStep( *newItem );
+}
+
+void Convert::stop( FileListItem* item )
+{
+ // search the item list for our item to stop
+ for( QValueList<ConvertItem*>::Iterator stopItem = items.begin(); stopItem != items.end(); stopItem++ ) {
+ // is fileListItem pointing at the same address, as item
+ if( (*stopItem)->fileListItem == item ) {
+
+ if( (*stopItem)->convertProcess->isRunning() ) {
+ bool ret = (*stopItem)->convertProcess->kill( SIGKILL );
+ //kdDebug() << "Killing process... (" << ret << ")" << endl;
+ if( ret ) {
+ logger->log( (*stopItem)->logID, i18n("Killing process ...") );
+ }
+ else {
+ logger->log( (*stopItem)->logID, i18n("Killing process failed. Stopping after files are completed ...") );
+ }
+ }
+ else if( (*stopItem)->moveJob != 0 ) {
+ //kdDebug() << "Killing file copy..." << endl;
+ // FIXME crashes sometimes - should be fixed by SIGKILL
+ // FIXME crash if file_copy was stealthed
+ logger->log( (*stopItem)->logID, i18n("Killing process ...") );
+ (*stopItem)->moveJob->kill( false );
+ }
+
+ return;
+ }
+ }
+}
+
+void Convert::remove( ConvertItem* item, int state )
+{
+ // TODO "remove" (re-add) the times to the progress indicator
+ //emit uncountTime( item->getTime + item->getCorrectionTime + item->ripTime +
+ // item->decodeTime + item->encodeTime + item->replaygainTime );
+
+ logger->log( item->logID, i18n("Removing file from conversion list. Exit code %1").arg(state) );
+
+ if( item->fileListItem->notify != "" ) {
+ QString command = item->fileListItem->notify;
+ command.replace( "%u", item->fileListItem->url );
+ command.replace( "%i", item->fileListItem->options.filePathName.replace(" ","%20") );
+ command.replace( "%o", item->outputFilePathName.replace(" ","%20") );
+ logger->log( item->logID, " "+i18n("Executing command: \"%1\"").arg(command) );
+ notify.clearArguments();
+ QString paramSplinter;
+ // FIXME split correct (strings with spaces are splited by mistake)
+ // FIXME only one command can be executed at once!?
+ QStringList params = QStringList::split( ' ', item->fileListItem->notify );
+ for( QStringList::Iterator it = params.begin(); it != params.end(); ++it )
+ {
+ paramSplinter = *it;
+ paramSplinter.replace( "%u", item->fileListItem->url );
+ paramSplinter.replace( "%i", item->fileListItem->options.filePathName );
+ paramSplinter.replace( "%o", item->outputFilePathName );
+ notify << paramSplinter;
+ }
+ notify.start( KProcess::DontCare );
+ }
+
+ item->fileListItem->converting = false;
+ emit finished( item->fileListItem, state ); // send signal to FileList
+ emit finishedProcess( item->logID, state ); // send signal to Logger
+
+ item->fileListItem = 0;
+ if( item->convertProcess != 0 ) delete item->convertProcess;
+ item->convertProcess = 0;
+ //if( item->moveJob != 0 ) delete item->moveJob; // NOTE makes soundkonverter crash
+ //item->moveJob = 0;
+ if( item->replayGain != 0 ) delete item->replayGain;
+ item->replayGain = 0;
+
+ if( item->tempInFile != 0 ) delete item->tempInFile;
+ item->tempInFile = 0;
+ if( item->tempWavFile != 0 ) delete item->tempWavFile;
+ item->tempWavFile = 0;
+ if( item->tempOutFile != 0 ) delete item->tempOutFile;
+ item->tempOutFile = 0;
+ QFile file;
+ file.setName( item->correctionInFile );
+ if( file.exists() ) file.remove();
+ file.setName( item->correctionOutFile );
+ if( file.exists() ) file.remove();
+
+ for( QValueList<ConvertItem*>::Iterator it = items.begin(); it != items.end(); it++ ) {
+ if( (*it) == item ) {
+ items.remove( it );
+ break;
+ }
+ }
+
+ delete item;
+ item = 0;
+
+ if( items.count() == 0 ) {
+ tUpdateProgressIndicator->stop();
+ }
+}
+
+void Convert::updateProgressIndicator()
+{
+ float time = 0;
+
+ for( QValueList<ConvertItem*>::Iterator it = items.begin(); it != items.end(); it++ ) {
+ if( (*it)->state == ConvertItem::get ) {
+ time += (*it)->getTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Getting file")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ else if( (*it)->state == ConvertItem::get_correction ) {
+ time += (*it)->getCorrectionTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Getting correction file")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ else if( (*it)->state == ConvertItem::rip ) {
+ RipperPlugin* plugin = config->getCurrentRipper();
+ if( plugin != 0 && plugin->rip.output.isEmpty() ) {
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Ripping")+"... "+i18n("State")+": "+i18n("Unknown") );
+ }
+ else {
+ time += (*it)->ripTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Ripping")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ }
+ else if( (*it)->state == ConvertItem::decode ) {
+ ConvertPlugin* plugin = config->decoderForFormat( (*it)->fileListItem->mimeType );
+ if( plugin == 0 || plugin->dec.output.isEmpty() ) {
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Decoding")+"... "+i18n("State")+": "+i18n("Unknown") );
+ }
+ else {
+ time += (*it)->decodeTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Decoding")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ }
+ else if( (*it)->state == ConvertItem::encode ) {
+ ConvertPlugin* plugin = config->encoderForFormat( (*it)->fileListItem->options.encodingOptions.sFormat );
+ QString outputPattern;
+ if( plugin != 0 && (*it)->fileListItem->options.encodingOptions.sQualityMode == i18n("Quality") ) outputPattern = plugin->enc.lossy.quality.output;
+ else if( plugin != 0 && (*it)->fileListItem->options.encodingOptions.sQualityMode == i18n("Bitrate") && (*it)->fileListItem->options.encodingOptions.sBitrateMode == "cbr" ) outputPattern = plugin->enc.lossy.bitrate.cbr.output;
+ else if( plugin != 0 && (*it)->fileListItem->options.encodingOptions.sQualityMode == i18n("Bitrate") && (*it)->fileListItem->options.encodingOptions.sBitrateMode == "abr" ) outputPattern = plugin->enc.lossy.bitrate.abr.output;
+ if( outputPattern.isEmpty() ) {
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Encoding")+"... "+i18n("State")+": "+i18n("Unknown") );
+ }
+ else {
+ time += (*it)->encodeTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Encoding")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ }
+ else if( (*it)->state == ConvertItem::replaygain ) {
+ time += (*it)->replaygainTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Replay Gain")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ else if( (*it)->state == ConvertItem::put ) {
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Moving file")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ else if( (*it)->state == ConvertItem::put_correction ) {
+ time += (*it)->getCorrectionTime * (*it)->percent / 100;
+ (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Moving correction file")+"... "+QString().sprintf("%02i %%",(*it)->percent) );
+ }
+ }
+ emit update( time );
+}
+
+// void Convert::priorityChanged( int priority )
+// { // FIXME setting a higher priority does not work
+// KProcess pChangePriority;
+//
+// for( QValueList<ConvertItem*>::Iterator it = items.begin(); it != items.end(); it++ ) {
+// if( (*it)->convertProcess->isRunning() ) {
+// //(*it)->convertProcess->setPriority( priority );
+// pChangePriority.clearArguments();
+// pChangePriority << "renice";
+// QString prio;
+// prio.sprintf( "%i", priority );
+// pChangePriority << prio;
+// QString pid;
+// pid.sprintf( "%i", (*it)->convertProcess->pid() );
+// pChangePriority << pid;
+// //QString cmd;
+// //cmd.sprintf( "renice %i %i", );
+// pChangePriority.start( KProcess::Block );
+// }
+// }
+// }
+
+