You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
soundkonverter/src/convert.cpp

1616 lines
72 KiB

#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 <tqfile.h>
#include <tqtimer.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, TQT_SIGNAL(convertItem(FileListItem*)),
this, TQT_SLOT(add(FileListItem*))
);
connect( fileList, TQT_SIGNAL(stopItem(FileListItem*)),
this, TQT_SLOT(stop(FileListItem*))
);
connect( this, TQT_SIGNAL(finished(FileListItem*,int)),
fileList, TQT_SLOT(itemFinished(FileListItem*,int))
);
connect( this, TQT_SIGNAL(rippingFinished(const TQString&)),
fileList, TQT_SLOT(rippingFinished(const TQString&))
);
logger = _logger;
connect( this, TQT_SIGNAL(finishedProcess(int,int)),
logger, TQT_SLOT(processCompleted(int,int))
);
tUpdateProgressIndicator = new TQTimer( this, "tUpdateProgressIndicator" );
connect( tUpdateProgressIndicator, TQT_SIGNAL(timeout()),
this, TQT_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, TQT_SIGNAL(percent(KIO::Job*,unsigned long)),
this, TQT_SLOT(moveProgress(KIO::Job*,unsigned long))
);
connect( item->moveJob, TQT_SIGNAL(result(KIO::Job*)),
this, TQT_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
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( KProcess::NotifyOnExit, KProcess::AllOutput );
}
else {
item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, true, false, false );
connect( item->moveJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)),
this, TQT_SLOT(moveProgress(KIO::Job*,unsigned long))
);
connect( item->moveJob, TQT_SIGNAL(result(KIO::Job*)),
this, TQT_SLOT(moveFinished(KIO::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.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, TQT_SIGNAL(percent(KIO::Job*,unsigned long)),
this, TQT_SLOT(moveProgress(KIO::Job*,unsigned long))
);
connect( item->moveJob, TQT_SIGNAL(result(KIO::Job*)),
this, TQT_SLOT(moveFinished(KIO::Job*))
);
}
else {
TQStringList params;
TQString param, paramSplinter;
item->convertProcess->clearArguments();
param = TQString();
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 ) {
// 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( KProcess::NotifyOnExit, KProcess::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( KProcess::NotifyOnExit, KProcess::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('.'),KGlobal::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 && 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 );
}
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( 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;
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( KProcess::NotifyOnExit, KProcess::AllOutput );
}
else {
item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, false, false, false );
connect( item->moveJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)),
this, TQT_SLOT(moveProgress(KIO::Job*,unsigned long))
);
connect( item->moveJob, TQT_SIGNAL(result(KIO::Job*)),
this, TQT_SLOT(moveFinished(KIO::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( KProcess::NotifyOnExit, KProcess::AllOutput );
}
else {
item->moveJob = new KIO::FileCopyJob( source, destination, -1, false, false, false, false );
connect( item->moveJob, TQT_SIGNAL(percent(KIO::Job*,unsigned long)),
this, TQT_SLOT(moveProgress(KIO::Job*,unsigned long))
);
connect( item->moveJob, TQT_SIGNAL(result(KIO::Job*)),
this, TQT_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();
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( 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( TQValueList<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( TQValueList<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( TQValueList<ConvertItem*>::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, &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
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, &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
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, &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( TQValueList<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
TQValueList<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 = TQString()();
(*newItem)->correctionOutFile = TQString()();
(*newItem)->correctionInputExtension = TQString()();
(*newItem)->correctionOutputExtension = TQString()();*/
// connect convertProcess of our new item with the slots of Convert
(*newItem)->convertProcess = new KProcess();
connect( (*newItem)->convertProcess, TQT_SIGNAL(receivedStdout(KProcess*,char*,int)),
this, TQT_SLOT(processOutput(KProcess*,char*,int))
);
connect( (*newItem)->convertProcess, TQT_SIGNAL(receivedStderr(KProcess*,char*,int)),
this, TQT_SLOT(processOutput(KProcess*,char*,int))
);
connect( (*newItem)->convertProcess, TQT_SIGNAL(processExited(KProcess*)),
this, TQT_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( 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<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 != "" ) {
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( 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;
TQFile file;
file.setName( item->correctionInFile );
if( file.exists() ) file.remove();
file.setName( item->correctionOutFile );
if( file.exists() ) file.remove();
for( TQValueList<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( TQValueList<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")+"... "+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
// KProcess pChangePriority;
//
// for( TQValueList<ConvertItem*>::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( KProcess::Block );
// }
// }
// }