File indexing completed on 2024-06-16 07:42:02

0001 /*
0002     SPDX-FileCopyrightText: 2005-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2011 Michal Malek <michalm@jabster.pl>
0004     SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "k3baudiocuefilewritingjob.h"
0010 #include "k3baudiofileanalyzerjob.h"
0011 
0012 #include "k3baudiodoc.h"
0013 #include "k3baudiojob.h"
0014 #include "k3bdevice.h"
0015 #include "k3baudiodecoder.h"
0016 #include "k3baudiotrack.h"
0017 #include "k3baudiofile.h"
0018 #include "k3bcuefileparser.h"
0019 #include "k3bthread.h"
0020 #include "k3bthreadjob.h"
0021 #include "k3b_i18n.h"
0022 
0023 #include <QDebug>
0024 
0025 
0026 class K3b::AudioCueFileWritingJob::Private
0027 {
0028 public:
0029     Private()
0030         : device( 0 ),
0031           audioDoc( 0 ),
0032           audioJob( 0 ),
0033           decoder( 0 ),
0034           analyserJob( 0 ) {
0035     }
0036 
0037     K3b::Device::Device* device;
0038 
0039     QString cueFile;
0040     K3b::AudioDoc* audioDoc;
0041     K3b::AudioJob* audioJob;
0042     K3b::AudioDecoder* decoder;
0043 
0044     K3b::AudioFileAnalyzerJob* analyserJob;
0045 
0046     bool audioJobRunning;
0047     bool canceled;
0048 };
0049 
0050 
0051 
0052 K3b::AudioCueFileWritingJob::AudioCueFileWritingJob( K3b::JobHandler* jh, QObject* parent )
0053     : K3b::BurnJob( jh, parent ),
0054       d( new Private() )
0055 {
0056     d->analyserJob = new K3b::AudioFileAnalyzerJob( this, this );
0057     connect( d->analyserJob, SIGNAL(finished(bool)),
0058              this, SLOT(slotAnalyserJobFinished(bool)) );
0059 
0060     d->audioDoc = new K3b::AudioDoc( this );
0061     d->audioDoc->newDocument();
0062     d->audioJob = new K3b::AudioJob( d->audioDoc, this, this );
0063 
0064     // just loop all through
0065     connect( d->audioJob, SIGNAL(newTask(QString)), this, SIGNAL(newTask(QString)) );
0066     connect( d->audioJob, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) );
0067     connect( d->audioJob, SIGNAL(debuggingOutput(QString,QString)),
0068              this, SIGNAL(debuggingOutput(QString,QString)) );
0069     connect( d->audioJob, SIGNAL(infoMessage(QString,int)),
0070              this, SIGNAL(infoMessage(QString,int)) );
0071     connect( d->audioJob, SIGNAL(finished(bool)), this, SIGNAL(finished(bool)) );
0072     connect( d->audioJob, SIGNAL(canceled()), this, SIGNAL(canceled()) );
0073     connect( d->audioJob, SIGNAL(percent(int)), this, SIGNAL(percent(int)) );
0074     connect( d->audioJob, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) );
0075     connect( d->audioJob, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSubSize(int,int)) );
0076     connect( d->audioJob, SIGNAL(processedSubSize(int,int)), this, SIGNAL(processedSubSize(int,int)) );
0077     connect( d->audioJob, SIGNAL(burning(bool)), this, SIGNAL(burning(bool)) );
0078     connect( d->audioJob, SIGNAL(bufferStatus(int)), this, SIGNAL(bufferStatus(int)) );
0079     connect( d->audioJob, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) );
0080     connect( d->audioJob, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) );
0081 
0082     d->canceled = false;
0083     d->audioJobRunning = false;
0084 }
0085 
0086 
0087 K3b::AudioCueFileWritingJob::~AudioCueFileWritingJob()
0088 {
0089     delete d;
0090 }
0091 
0092 
0093 K3b::Device::Device* K3b::AudioCueFileWritingJob::writer() const
0094 {
0095     return d->audioDoc->burner();
0096 }
0097 
0098 
0099 QString K3b::AudioCueFileWritingJob::cueFile() const
0100 {
0101     return d->cueFile;
0102 }
0103 
0104 
0105 QString K3b::AudioCueFileWritingJob::jobDescription() const
0106 {
0107     return i18n("Writing Audio Cue File");
0108 }
0109 
0110 
0111 QString K3b::AudioCueFileWritingJob::jobDetails() const
0112 {
0113     return d->cueFile.section( '/', -1 );
0114 }
0115 
0116 
0117 QString K3b::AudioCueFileWritingJob::jobSource() const
0118 {
0119     return d->cueFile;
0120 }
0121 
0122 
0123 QString K3b::AudioCueFileWritingJob::jobTarget() const
0124 {
0125     if( Device::Device* device = writer() )
0126         return device->vendor() + ' ' + device->description();
0127     else
0128         return QString();
0129 }
0130 
0131 
0132 void K3b::AudioCueFileWritingJob::start()
0133 {
0134     // FIXME: here we trust that a job won't be started twice :(
0135     jobStarted();
0136     d->canceled = false;
0137     d->audioJobRunning = false;
0138     importCueInProject();
0139 }
0140 
0141 
0142 void K3b::AudioCueFileWritingJob::cancel()
0143 {
0144     d->canceled = true;
0145 
0146     // the AudioJob cancel method is very stupid. It emits the canceled signal even if it was never running :(
0147     if( d->audioJobRunning )
0148         d->audioJob->cancel();
0149     d->analyserJob->cancel();
0150 }
0151 
0152 
0153 void K3b::AudioCueFileWritingJob::setCueFile( const QString& s )
0154 {
0155     d->cueFile = s;
0156 }
0157 
0158 
0159 void K3b::AudioCueFileWritingJob::setOnTheFly( bool b )
0160 {
0161     d->audioDoc->setOnTheFly( b );
0162 }
0163 
0164 
0165 void K3b::AudioCueFileWritingJob::setSpeed( int s )
0166 {
0167     d->audioDoc->setSpeed( s );
0168 }
0169 
0170 
0171 void K3b::AudioCueFileWritingJob::setBurnDevice( K3b::Device::Device* dev )
0172 {
0173     d->audioDoc->setBurner( dev );
0174 }
0175 
0176 
0177 void K3b::AudioCueFileWritingJob::setWritingMode( K3b::WritingMode mode )
0178 {
0179     d->audioDoc->setWritingMode( mode );
0180 }
0181 
0182 
0183 void K3b::AudioCueFileWritingJob::setSimulate( bool b )
0184 {
0185     d->audioDoc->setDummy( b );
0186 }
0187 
0188 
0189 void K3b::AudioCueFileWritingJob::setCopies( int c )
0190 {
0191     d->audioDoc->setCopies( c );
0192 }
0193 
0194 
0195 void K3b::AudioCueFileWritingJob::setTempDir( const QString& s )
0196 {
0197     d->audioDoc->setTempDir( s );
0198 }
0199 
0200 
0201 void K3b::AudioCueFileWritingJob::slotAnalyserJobFinished( bool )
0202 {
0203     if( !d->canceled ) {
0204         if( d->audioDoc->lastTrack()->length() == 0 ) {
0205             emit infoMessage( i18n("Analysing the audio file failed. Corrupt file?"), MessageError );
0206             jobFinished(false);
0207         }
0208         else {
0209             // FIXME: d->audioJobRunning is never reset
0210             d->audioJobRunning = true;
0211             d->audioJob->start(); // from here on the audio job takes over completely
0212         }
0213     }
0214     else {
0215         emit canceled();
0216         jobFinished(false);
0217     }
0218 }
0219 
0220 
0221 void K3b::AudioCueFileWritingJob::importCueInProject()
0222 {
0223     // cleanup the project (this wil also delete the decoder)
0224     // we do not use newDocument as that would overwrite the settings already made
0225     while( d->audioDoc->firstTrack() )
0226         delete d->audioDoc->firstTrack()->take();
0227 
0228     d->decoder = 0;
0229 
0230     K3b::CueFileParser parser( d->cueFile );
0231     if( parser.isValid() && parser.toc().contentType() == K3b::Device::AUDIO ) {
0232 
0233         qDebug() << "(K3b::AudioCueFileWritingJob::importCueFile) parsed with image: " << parser.imageFilename();
0234 
0235         // global cd-text
0236         d->audioDoc->setTitle( parser.cdText().title() );
0237         d->audioDoc->setPerformer( parser.cdText().performer() );
0238         d->audioDoc->writeCdText( !parser.cdText().title().isEmpty() );
0239 
0240         d->decoder = K3b::AudioDecoderFactory::createDecoder( QUrl::fromLocalFile(parser.imageFilename()) );
0241         if( d->decoder ) {
0242             d->decoder->setFilename( parser.imageFilename() );
0243 
0244             K3b::AudioTrack* after = 0;
0245             K3b::AudioFile* newFile = 0;
0246             unsigned int i = 0;
0247             for( K3b::Device::Toc::const_iterator it = parser.toc().constBegin();
0248                  it != parser.toc().constEnd(); ++it ) {
0249                 const K3b::Device::Track& track = *it;
0250 
0251                 newFile = new K3b::AudioFile( d->decoder, d->audioDoc );
0252                 newFile->setStartOffset( track.firstSector() );
0253                 newFile->setEndOffset( track.lastSector()+1 );
0254 
0255                 K3b::AudioTrack* newTrack = new K3b::AudioTrack( d->audioDoc );
0256                 newTrack->addSource( newFile );
0257                 newTrack->moveAfter( after );
0258 
0259                 // cd-text
0260                 newTrack->setTitle( parser.cdText()[i].title() );
0261                 newTrack->setPerformer( parser.cdText()[i].performer() );
0262 
0263                 // add the next track after this one
0264                 after = newTrack;
0265                 ++i;
0266             }
0267 
0268             // let the last source use the data up to the end of the file
0269             if( newFile )
0270                 newFile->setEndOffset(0);
0271 
0272             // now analyze the source
0273             emit newTask( i18n("Analysing the audio file") );
0274             emit newSubTask( i18n("Analysing %1", parser.imageFilename() ) );
0275 
0276             // start the analyser job
0277             d->analyserJob->setDecoder( d->decoder );
0278             d->analyserJob->start();
0279         }
0280         else {
0281             emit infoMessage( i18n("Unable to handle '%1' due to an unsupported format.", d->cueFile ), MessageError );
0282             jobFinished(false);
0283         }
0284     }
0285     else {
0286         emit infoMessage( i18n("No valid audio cue file: '%1'", d->cueFile ), MessageError );
0287         jobFinished(false);
0288     }
0289 }
0290 
0291 #include "moc_k3baudiocuefilewritingjob.cpp"