#include "convert.h" //#include "conversionoptions.h" #include "convertpluginloader.h" #include "replaygainpluginloader.h" #include "replaygain.h" #include "ripperpluginloader.h" #include "configuration.h" #include "tagengine.h" #include "cdmanager.h" #include "logger.h" #include "filelist.h" #include "replaygainscanner.h" #include #include #include //#include #include #include //#include #include #include #include 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, TQ_SIGNAL(convertItem(FileListItem*)), this, TQ_SLOT(add(FileListItem*)) ); connect( fileList, TQ_SIGNAL(stopItem(FileListItem*)), this, TQ_SLOT(stop(FileListItem*)) ); connect( this, TQ_SIGNAL(finished(FileListItem*,int)), fileList, TQ_SLOT(itemFinished(FileListItem*,int)) ); connect( this, TQ_SIGNAL(rippingFinished(const TQString&)), fileList, TQ_SLOT(rippingFinished(const TQString&)) ); logger = _logger; connect( this, TQ_SIGNAL(finishedProcess(int,int)), logger, TQ_SLOT(processCompleted(int,int)) ); tUpdateProgressIndicator = new TQTimer( this, "tUpdateProgressIndicator" ); connect( tUpdateProgressIndicator, TQ_SIGNAL(timeout()), this, TQ_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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } else { item->moveJob = new TDEIO::FileCopyJob( source, destination, -1, false, true, false, false ); connect( item->moveJob, TQ_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQ_SLOT(moveProgress(TDEIO::Job*,unsigned long)) ); connect( item->moveJob, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(moveFinished(TDEIO::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 TQFile 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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } else { item->moveJob = new TDEIO::FileCopyJob( source, destination, -1, false, true, false, false ); connect( item->moveJob, TQ_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQ_SLOT(moveProgress(TDEIO::Job*,unsigned long)) ); connect( item->moveJob, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(moveFinished(TDEIO::Job*)) ); } } void Convert::rip( ConvertItem* item ) { logger->log( item->logID, i18n("Ripping") ); item->state = ConvertItem::rip; /** kaudiocreator TQString wavFile; TQString args = job->device; if(!args.isEmpty()) args = TQString("?device=%1").arg(args); args = args+"&fileNameTemplate=Track %{number}"; if(job->track < 10) wavFile = TQString("audiocd:/Wav/Track 0%1.wav%2").arg(job->track).arg(args); else wavFile = TQString("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) TQString src; if( item->fileListItem->track != 0 ) { // TODO does it work with cds with less than 10 tracks? src = TQString("audiocd:/Wav/Track %1.wav?device=%2&fileNameTemplate=Track %%{number}"). arg(TQString::number(item->fileListItem->track).rightJustify(2, '0')). arg(item->fileListItem->device); } else { // FIXME implement ripping of full cds src = TQString("audiocd:/Full CD/Full CD.wav?device=%1&albumTemplate=Full CD").arg(item->fileListItem->device); 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 TDEIO::FileCopyJob( source, dest, -1, false, true, false, false ); connect( item->moveJob, TQ_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQ_SLOT(moveProgress(TDEIO::Job*,unsigned long)) ); connect( item->moveJob, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(moveFinished(TDEIO::Job*)) ); } else { TQStringList params; TQString param, paramSplinter; item->convertProcess->clearArguments(); param = TQString(); if( !plugin->rip.param.isEmpty() ) param.append( " " + plugin->rip.param ); if( !plugin->rip.device.isEmpty() ) param.append( " " + plugin->rip.device ); if( !plugin->rip.overwrite.isEmpty() ) param.append( " " + plugin->rip.overwrite ); if( item->fileListItem->track != 0 ) { if( !plugin->rip.track.isEmpty() ) param.append( " " + plugin->rip.track ); } else { if( !plugin->rip.full_disc.param.isEmpty() ) 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 ) { // TQString 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; // } TQString t_str = plugin->rip.out_file; t_str.replace( "%p", param ); param = config->binaries[plugin->rip.bin] + " " + t_str; param.simplifyWhiteSpace(); params = TQStringList::split( ' ', param ); for( TQStringList::Iterator it = params.begin(); it != params.end(); ++it ) { paramSplinter = *it; paramSplinter.replace( "%d", item->fileListItem->device ); paramSplinter.replace( "%t", TQString().sprintf("%i",item->fileListItem->track) ); paramSplinter.replace( "%n", TQString().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", TQString().sprintf("%i",item->fileListItem->track) ); param.replace( "%n", TQString().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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } } void Convert::decode( ConvertItem* item ) { logger->log( item->logID, i18n("Decoding") ); item->state = ConvertItem::decode; TQStringList params; TQString 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 ); TQString t_str = plugin->dec.in_out_files; t_str.replace( "%p", param ); param = config->binaries[plugin->dec.bin] + " " + t_str; param = param.simplifyWhiteSpace(); params = TQStringList::split( ' ', param ); for( TQStringList::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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } void Convert::encode( ConvertItem* item ) { // TODO test quality profiles (never done) TQString sStrength; TQString sBitrate; TQString sQuality; TQString sMinBitrate; TQString sMaxBitrate; TQString sSamplingRate; int t_int; float t_float; logger->log( item->logID, i18n("Encoding") ); item->state = ConvertItem::encode; TQStringList params; TQString 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 = TQString::number( compressionLevel * plugin->enc.strength.step ); else sStrength = TQString::number( plugin->enc.strength.range_min - compressionLevel * plugin->enc.strength.step ); } else { if( plugin->enc.strength.range_max >= plugin->enc.strength.range_min ) sStrength = TQString::number( int(compressionLevel * plugin->enc.strength.step) ); else sStrength = TQString::number( int(plugin->enc.strength.range_min - compressionLevel * plugin->enc.strength.step) ); } if( plugin->enc.strength.separator != '.' ) sStrength.replace( TQChar('.'), plugin->enc.strength.separator ); } else { TQStringList::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 = TQString::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 = TQString::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 = TQString::number( item->fileListItem->options.encodingOptions.iMinBitrate ); param.append( " " + plugin->enc.lossy.bitrate.abr.bitrate_range.param_max ); sMaxBitrate = TQString::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 = TQString().sprintf( "%.2f", t_float ); sQuality = TQString::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 = TQString::number( t_int ); } if( plugin->enc.bin == "oggenc" ) sQuality.replace(TQChar('.'),TDEGlobal::locale()->decimalSymbol()); // HACK make oggenc usable with all langauges else if( plugin->enc.lossy.quality.separator != '.' ) sQuality.replace(TQChar('.'),plugin->enc.lossy.quality.separator); } else { TQStringList::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 = TQString::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 = TQString::number( item->fileListItem->options.encodingOptions.samplingRate.iSamplingRate ); } else { sSamplingRate = TQString::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.isEmpty() && formatItem->internalReplayGain ) { param.append( " " + plugin->enc.replaygain.use ); } else if( plugin->enc.replaygain.enabled && !plugin->enc.replaygain.avoid.isEmpty() ) { 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 ); } TQString sInOutFiles = item->fileListItem->options.encodingOptions.sInOutFiles; param = sInOutFiles.replace( "%p", param ); // cosmetic surgery param = param.simplifyWhiteSpace(); params = TQStringList::split( ' ', param ); TQString inputFile; if( item->mode & ConvertItem::decode || item->mode & ConvertItem::rip ) inputFile = item->tempWavFile->name(); else inputFile = item->tempInFile->name(); for( TQStringList::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", ( TQString::number(item->fileListItem->tags->disc) != "" ) ? TQString::number(item->fileListItem->tags->disc) : "0" ); paramSplinter.replace( "%tg", ( item->fileListItem->tags->genre != "" ) ? item->fileListItem->tags->genre : i18n("Unknown") ); paramSplinter.replace( "%tn", ( TQString::number(item->fileListItem->tags->track) != "" ) ? TQString::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", ( TQString::number(item->fileListItem->tags->year) != "" ) ? TQString::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", TQString::number(item->fileListItem->tags->disc) ); param.replace( "%tg", "\""+item->fileListItem->tags->genre+"\"" ); param.replace( "%tn", TQString::number(item->fileListItem->tags->track) ); param.replace( "%tp", "\""+item->fileListItem->tags->composer+"\"" ); param.replace( "%tt", "\""+item->fileListItem->tags->title+"\"" ); param.replace( "%ty", TQString::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( TDEProcess::NotifyOnExit, TDEProcess::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; TQString 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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } else { item->moveJob = new TDEIO::FileCopyJob( source, destination, -1, false, false, false, false ); connect( item->moveJob, TQ_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQ_SLOT(moveProgress(TDEIO::Job*,unsigned long)) ); connect( item->moveJob, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(moveFinished(TDEIO::Job*)) ); } } void Convert::putCorrection( ConvertItem* item ) { logger->log( item->logID, i18n("Moving correction file") ); item->state = ConvertItem::put_correction; TQString src = item->correctionOutFile; TQString 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( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ); } else { item->moveJob = new TDEIO::FileCopyJob( source, destination, -1, false, false, false, false ); connect( item->moveJob, TQ_SIGNAL(percent(TDEIO::Job*,unsigned long)), this, TQ_SLOT(moveProgress(TDEIO::Job*,unsigned long)) ); connect( item->moveJob, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(moveFinished(TDEIO::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(); TQString 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( TDEProcess::NotifyOnExit, TDEProcess::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( TDEIO::Job* job, unsigned long percent ) { // search the item list for our item for( TQValueList::Iterator item = items.begin(); item != items.end(); item++ ) { if( (*item)->moveJob == job ) { (*item)->percent = percent; } } } void Convert::moveFinished( TDEIO::Job* job ) { // search the item list for our item for( TQValueList::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( TDEProcess* proc, char* data, int ) { int iPercent = 0, iTime = 0, iPos = 0, iNum = 0; // search the item list for our item for( TQValueList::Iterator item = items.begin(); item != items.end(); item++ ) { if( (*item)->convertProcess == proc ) { TQString 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 TQString 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.local8Bit().data(), &iPercent ); } else if( outputPattern.find("%t") != -1 ) { outputPattern.replace( "%t", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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.local8Bit().data(), &iPos, &iNum ); } else { outputPattern.replace( "%0", "%i" ); outputPattern.replace( "%1", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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 TQString 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.local8Bit().data(), &iPercent ); } else if( outputPattern.find("%t") != -1 ) { outputPattern.replace( "%t", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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.local8Bit().data(), &iPos, &iNum ); } else { outputPattern.replace( "%0", "%i" ); outputPattern.replace( "%1", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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 TQString 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.local8Bit().data(), &iPercent ); } else if( outputPattern.find("%t") != -1 ) { outputPattern.replace( "%t", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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.local8Bit().data(), &iPos, &iNum ); } else { outputPattern.replace( "%0", "%i" ); outputPattern.replace( "%1", "%i" ); sscanf( data, outputPattern.local8Bit().data(), &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( TDEProcess* proc ) { // search the item list for our item for( TQValueList::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 TQValueList::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 = TQString()(); (*newItem)->correctionOutFile = TQString()(); (*newItem)->correctionInputExtension = TQString()(); (*newItem)->correctionOutputExtension = TQString()();*/ // connect convertProcess of our new item with the slots of Convert (*newItem)->convertProcess = new TDEProcess(); connect( (*newItem)->convertProcess, TQ_SIGNAL(receivedStdout(TDEProcess*,char*,int)), this, TQ_SLOT(processOutput(TDEProcess*,char*,int)) ); connect( (*newItem)->convertProcess, TQ_SIGNAL(receivedStderr(TDEProcess*,char*,int)), this, TQ_SLOT(processOutput(TDEProcess*,char*,int)) ); connect( (*newItem)->convertProcess, TQ_SIGNAL(processExited(TDEProcess*)), this, TQ_SLOT(processExit(TDEProcess*)) ); // 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( TQString(), "." + item->fileFormat ); (*newItem)->tempInFile->setAutoDelete( true ); (*newItem)->tempInFile->close(); (*newItem)->tempWavFile = new KTempFile( TQString(), ".wav" ); (*newItem)->tempWavFile->setAutoDelete( true ); (*newItem)->tempWavFile->close(); (*newItem)->tempOutFile = new KTempFile( TQString(), "." + 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 ); } TQString 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( TQValueList::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 != "" ) { TQString 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(); TQString paramSplinter; // FIXME split correct (strings with spaces are splited by mistake) // FIXME only one command can be executed at once!? TQStringList params = TQStringList::split( ' ', item->fileListItem->notify ); for( TQStringList::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( TDEProcess::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; TQFile file; file.setName( item->correctionInFile ); if( file.exists() ) file.remove(); file.setName( item->correctionOutFile ); if( file.exists() ) file.remove(); for( TQValueList::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( TQValueList::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")+"... "+TQString().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")+"... "+TQString().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")+"... "+TQString().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")+"... "+TQString().sprintf("%02i %%",(*it)->percent) ); } } else if( (*it)->state == ConvertItem::encode ) { ConvertPlugin* plugin = config->encoderForFormat( (*it)->fileListItem->options.encodingOptions.sFormat ); TQString 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")+"... "+TQString().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")+"... "+TQString().sprintf("%02i %%",(*it)->percent) ); } else if( (*it)->state == ConvertItem::put ) { (*it)->fileListItem->setText( fileList->columnByName(i18n("State")), i18n("Moving file")+"... "+TQString().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")+"... "+TQString().sprintf("%02i %%",(*it)->percent) ); } } emit update( time ); } // void Convert::priorityChanged( int priority ) // { // FIXME setting a higher priority does not work // TDEProcess pChangePriority; // // for( TQValueList::Iterator it = items.begin(); it != items.end(); it++ ) { // if( (*it)->convertProcess->isRunning() ) { // //(*it)->convertProcess->setPriority( priority ); // pChangePriority.clearArguments(); // pChangePriority << "renice"; // TQString prio; // prio.sprintf( "%i", priority ); // pChangePriority << prio; // TQString pid; // pid.sprintf( "%i", (*it)->convertProcess->pid() ); // pChangePriority << pid; // //TQString cmd; // //cmd.sprintf( "renice %i %i", ); // pChangePriority.start( TDEProcess::Block ); // } // } // } #include "convert.moc"