File indexing completed on 2024-05-12 04:51:07
0001 /* 0002 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 #include "k3bmixedjob.h" 0006 #include "k3bmixeddoc.h" 0007 #include "k3bactivepipe.h" 0008 #include "k3bfilesplitter.h" 0009 0010 #include "k3bdatadoc.h" 0011 #include "k3bisoimager.h" 0012 #include "k3bisooptions.h" 0013 #include "k3bmsinfofetcher.h" 0014 #include "k3baudioimager.h" 0015 #include "k3baudiodoc.h" 0016 #include "k3baudiotrack.h" 0017 #include "k3baudionormalizejob.h" 0018 #include "k3baudiojobtempdata.h" 0019 #include "k3baudiomaxspeedjob.h" 0020 #include "k3bdevicemanager.h" 0021 #include "k3bdevice.h" 0022 #include "k3bdevicehandler.h" 0023 #include "k3bmsf.h" 0024 #include "k3bglobals.h" 0025 #include "k3bexternalbinmanager.h" 0026 #include "k3bversion.h" 0027 #include "k3bcore.h" 0028 #include "k3bcdrecordwriter.h" 0029 #include "k3bcdrdaowriter.h" 0030 #include "k3btocfilewriter.h" 0031 #include "k3binffilewriter.h" 0032 #include "k3bglobalsettings.h" 0033 #include "k3baudiofile.h" 0034 #include "k3b_i18n.h" 0035 0036 #include <KStringHandler> 0037 #include <KIO/CopyJob> 0038 #include <KIO/DeleteJob> 0039 #include <KIO/Global> 0040 0041 #include <QDataStream> 0042 #include <QDebug> 0043 #include <QFile> 0044 #include <QTemporaryFile> 0045 0046 0047 static QString createNonExistingFilesString( const QList<K3b::AudioFile*>& items, int max ) 0048 { 0049 QString s; 0050 int cnt = 0; 0051 for( QList<K3b::AudioFile*>::const_iterator it = items.begin(); 0052 it != items.end(); ++it ) { 0053 0054 s += KStringHandler::csqueeze( (*it)->filename(), 60 ); 0055 0056 ++cnt; 0057 if( cnt >= max || it == items.end() ) 0058 break; 0059 0060 s += "<br>"; 0061 } 0062 0063 if( items.count() > max ) 0064 s += "..."; 0065 0066 return s; 0067 } 0068 0069 0070 0071 class K3b::MixedJob::Private 0072 { 0073 public: 0074 Private() 0075 : maxSpeedJob(0) { 0076 } 0077 0078 0079 int copies; 0080 int copiesDone; 0081 0082 K3b::AudioMaxSpeedJob* maxSpeedJob; 0083 bool maxSpeed; 0084 0085 ActivePipe pipe; 0086 0087 FileSplitter dataImageFile; 0088 }; 0089 0090 0091 K3b::MixedJob::MixedJob( K3b::MixedDoc* doc, K3b::JobHandler* hdl, QObject* parent ) 0092 : K3b::BurnJob( hdl, parent ), 0093 m_doc( doc ), 0094 m_normalizeJob(0) 0095 { 0096 d = new Private; 0097 0098 m_isoImager = new K3b::IsoImager( doc->dataDoc(), this, this ); 0099 connect( m_isoImager, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0100 connect( m_isoImager, SIGNAL(percent(int)), this, SLOT(slotIsoImagerPercent(int)) ); 0101 connect( m_isoImager, SIGNAL(finished(bool)), this, SLOT(slotIsoImagerFinished(bool)) ); 0102 connect( m_isoImager, SIGNAL(debuggingOutput(QString,QString)), 0103 this, SIGNAL(debuggingOutput(QString,QString)) ); 0104 0105 m_tempData = new K3b::AudioJobTempData( m_doc->audioDoc(), this ); 0106 m_audioImager = new K3b::AudioImager( doc->audioDoc(), m_tempData, this, this ); 0107 connect( m_audioImager, SIGNAL(infoMessage(QString,int)), 0108 this, SIGNAL(infoMessage(QString,int)) ); 0109 connect( m_audioImager, SIGNAL(percent(int)), this, SLOT(slotAudioDecoderPercent(int)) ); 0110 connect( m_audioImager, SIGNAL(subPercent(int)), this, SLOT(slotAudioDecoderSubPercent(int)) ); 0111 connect( m_audioImager, SIGNAL(finished(bool)), this, SLOT(slotAudioDecoderFinished(bool)) ); 0112 connect( m_audioImager, SIGNAL(nextTrack(int,int)), this, SLOT(slotAudioDecoderNextTrack(int,int)) ); 0113 0114 m_msInfoFetcher = new K3b::MsInfoFetcher( this, this ); 0115 connect( m_msInfoFetcher, SIGNAL(finished(bool)), this, SLOT(slotMsInfoFetched(bool)) ); 0116 connect( m_msInfoFetcher, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0117 0118 m_writer = 0; 0119 m_tocFile = 0; 0120 } 0121 0122 0123 K3b::MixedJob::~MixedJob() 0124 { 0125 delete m_tocFile; 0126 delete d; 0127 } 0128 0129 0130 K3b::Device::Device* K3b::MixedJob::writer() const 0131 { 0132 if( m_doc->onlyCreateImages() ) 0133 return 0; 0134 else 0135 return m_doc->burner(); 0136 } 0137 0138 0139 K3b::Doc* K3b::MixedJob::doc() const 0140 { 0141 return m_doc; 0142 } 0143 0144 0145 void K3b::MixedJob::start() 0146 { 0147 jobStarted(); 0148 0149 m_canceled = false; 0150 m_errorOccuredAndAlreadyReported = false; 0151 d->copiesDone = 0; 0152 d->copies = m_doc->copies(); 0153 m_currentAction = PREPARING_DATA; 0154 d->maxSpeed = false; 0155 0156 if( m_doc->dummy() ) 0157 d->copies = 1; 0158 0159 prepareProgressInformation(); 0160 0161 // 0162 // Check if all files exist 0163 // 0164 QList<K3b::AudioFile*> nonExistingFiles; 0165 K3b::AudioTrack* track = m_doc->audioDoc()->firstTrack(); 0166 while( track ) { 0167 K3b::AudioDataSource* source = track->firstSource(); 0168 while( source ) { 0169 if( K3b::AudioFile* file = dynamic_cast<K3b::AudioFile*>( source ) ) { 0170 if( !QFile::exists( file->filename() ) ) 0171 nonExistingFiles.append( file ); 0172 } 0173 source = source->next(); 0174 } 0175 track = track->next(); 0176 } 0177 if( !nonExistingFiles.isEmpty() ) { 0178 if( questionYesNo( "<p>" + i18n("The following files could not be found. Do you want to remove them from the " 0179 "project and continue without adding them to the image?") + 0180 "<p>" + createNonExistingFilesString( nonExistingFiles, 10 ), 0181 i18n("Warning"), 0182 KGuiItem( i18n("Remove missing files and continue") ), 0183 KGuiItem( i18n("Cancel and go back") ) ) ) { 0184 for( QList<K3b::AudioFile*>::const_iterator it = nonExistingFiles.constBegin(); 0185 it != nonExistingFiles.constEnd(); ++it ) { 0186 delete *it; 0187 } 0188 } 0189 else { 0190 m_canceled = true; 0191 emit canceled(); 0192 jobFinished(false); 0193 return; 0194 } 0195 } 0196 0197 // 0198 // Make sure the project is not empty 0199 // 0200 if( m_doc->audioDoc()->numOfTracks() == 0 ) { 0201 emit infoMessage( i18n("Please add files to your project first."), MessageError ); 0202 jobFinished(false); 0203 return; 0204 } 0205 0206 0207 // set some flags that are needed 0208 m_doc->audioDoc()->setOnTheFly( m_doc->onTheFly() ); // for the toc writer 0209 m_doc->audioDoc()->setHideFirstTrack( false ); // unsupported 0210 m_doc->dataDoc()->setBurner( m_doc->burner() ); // so the isoImager can read ms data 0211 0212 emit newTask( i18n("Preparing data") ); 0213 0214 determineWritingMode(); 0215 0216 // 0217 // First we make sure the data portion is valid 0218 // 0219 0220 // we do not have msinfo yet 0221 m_currentAction = INITIALIZING_IMAGER; 0222 m_isoImager->setMultiSessionInfo( QString() ); 0223 m_isoImager->init(); 0224 } 0225 0226 0227 void K3b::MixedJob::startFirstCopy() 0228 { 0229 // 0230 // if not onthefly create the iso image and then the wavs 0231 // and write then 0232 // if onthefly calculate the iso size 0233 // 0234 if( m_doc->onTheFly() ) { 0235 if( m_doc->speed() == 0 ) { 0236 emit newSubTask( i18n("Determining maximum writing speed") ); 0237 0238 // 0239 // try to determine the max possible speed 0240 // no need to check the data track's max speed. Most current systems are able 0241 // to handle the maximum possible 0242 // 0243 if( !d->maxSpeedJob ) { 0244 // the maxspeed job gets the device from the doc: 0245 m_doc->audioDoc()->setBurner( m_doc->burner() ); 0246 d->maxSpeedJob = new K3b::AudioMaxSpeedJob( m_doc->audioDoc(), this, this ); 0247 connect( d->maxSpeedJob, SIGNAL(percent(int)), 0248 this, SIGNAL(subPercent(int)) ); 0249 connect( d->maxSpeedJob, SIGNAL(finished(bool)), 0250 this, SLOT(slotMaxSpeedJobFinished(bool)) ); 0251 } 0252 d->maxSpeedJob->start(); 0253 } 0254 else if( m_doc->mixedType() != K3b::MixedDoc::DATA_SECOND_SESSION ) { 0255 m_currentAction = PREPARING_DATA; 0256 m_isoImager->calculateSize(); 0257 } 0258 else { 0259 // we cannot calculate the size since we don't have the msinfo yet 0260 // so first write the audio session 0261 writeNextCopy(); 0262 } 0263 } 0264 else { 0265 emit burning(false); 0266 0267 emit infoMessage( i18n("Creating audio image files in %1",m_doc->tempDir()), MessageInfo ); 0268 0269 m_tempFilePrefix = K3b::findUniqueFilePrefix( ( !m_doc->audioDoc()->title().isEmpty() 0270 ? m_doc->audioDoc()->title() 0271 : m_doc->dataDoc()->isoOptions().volumeID() ), 0272 m_doc->tempDir() ); 0273 0274 m_tempData->prepareTempFileNames( m_doc->tempDir() ); 0275 0276 if( m_doc->mixedType() != K3b::MixedDoc::DATA_SECOND_SESSION ) { 0277 createIsoImage(); 0278 } 0279 else { 0280 emit newTask( i18n("Creating audio image files") ); 0281 m_currentAction = CREATING_AUDIO_IMAGE; 0282 m_audioImager->start(); 0283 } 0284 } 0285 } 0286 0287 0288 void K3b::MixedJob::startSecondSession() 0289 { 0290 // start the next session 0291 m_currentAction = WRITING_ISO_IMAGE; 0292 if( d->copiesDone > 0 ) { 0293 // we only create the image once. This should not be a problem??? 0294 if( !prepareWriter() || !startWriting() ) { 0295 cleanupAfterError(); 0296 jobFinished(false); 0297 } 0298 } 0299 else if( m_doc->dummy() ) { 0300 // do not try to get ms info in simulation mode since the cd is empty! 0301 if( m_doc->onTheFly() ) { 0302 m_currentAction = PREPARING_DATA; 0303 m_isoImager->calculateSize(); 0304 } 0305 else 0306 createIsoImage(); 0307 } 0308 else { 0309 m_currentAction = FETCHING_MSMessageInfo; 0310 m_msInfoFetcher->setDevice( m_doc->burner() ); 0311 m_msInfoFetcher->start(); 0312 } 0313 } 0314 0315 0316 void K3b::MixedJob::slotMaxSpeedJobFinished( bool success ) 0317 { 0318 d->maxSpeed = success; 0319 if( !success ) 0320 emit infoMessage( i18n("Unable to determine maximum speed for some reason. Ignoring."), MessageWarning ); 0321 0322 if( m_doc->mixedType() != K3b::MixedDoc::DATA_SECOND_SESSION ) { 0323 m_currentAction = PREPARING_DATA; 0324 m_isoImager->calculateSize(); 0325 } 0326 else { 0327 // we cannot calculate the size since we don't have the msinfo yet 0328 // so first write the audio session 0329 writeNextCopy(); 0330 } 0331 } 0332 0333 0334 void K3b::MixedJob::writeNextCopy() 0335 { 0336 // the prepareWriter method needs the action to be set 0337 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 0338 m_currentAction = WRITING_ISO_IMAGE; 0339 else 0340 m_currentAction = WRITING_AUDIO_IMAGE; 0341 0342 if( !prepareWriter() || !startWriting() ) { 0343 cleanupAfterError(); 0344 jobFinished(false); 0345 } 0346 } 0347 0348 0349 void K3b::MixedJob::cancel() 0350 { 0351 m_canceled = true; 0352 0353 if( d->maxSpeedJob ) 0354 d->maxSpeedJob->cancel(); 0355 0356 if( m_writer && m_writer->active() ) 0357 m_writer->cancel(); 0358 if ( m_isoImager->active() ) 0359 m_isoImager->cancel(); 0360 if ( m_audioImager->active() ) 0361 m_audioImager->cancel(); 0362 if ( m_msInfoFetcher->active() ) 0363 m_msInfoFetcher->cancel(); 0364 0365 #ifdef __GNUC__ 0366 #warning FIXME: wait for subjobs to finish after cancellation 0367 #endif 0368 0369 emit infoMessage( i18n("Writing canceled."), K3b::Job::MessageError ); 0370 removeBufferFiles(); 0371 emit canceled(); 0372 jobFinished(false); 0373 } 0374 0375 0376 void K3b::MixedJob::slotMsInfoFetched( bool success ) 0377 { 0378 if( m_canceled || m_errorOccuredAndAlreadyReported ) 0379 return; 0380 0381 if( success ) { 0382 if( m_usedDataWritingApp == K3b::WritingAppCdrecord ) 0383 m_isoImager->setMultiSessionInfo( m_msInfoFetcher->msInfo() ); 0384 else // cdrdao seems to write a 150 blocks pregap that is not used by cdrecord 0385 m_isoImager->setMultiSessionInfo( QString("%1,%2") 0386 .arg(m_msInfoFetcher->lastSessionStart()) 0387 .arg(m_msInfoFetcher->nextSessionStart()+150) ); 0388 0389 if( m_doc->onTheFly() ) { 0390 m_currentAction = PREPARING_DATA; 0391 m_isoImager->calculateSize(); 0392 } 0393 else { 0394 createIsoImage(); 0395 } 0396 } 0397 else { 0398 // the MsInfoFetcher already emitted failure info 0399 cleanupAfterError(); 0400 jobFinished(false); 0401 } 0402 } 0403 0404 0405 void K3b::MixedJob::slotIsoImagerFinished( bool success ) 0406 { 0407 if( m_canceled || m_errorOccuredAndAlreadyReported ) 0408 return; 0409 0410 // 0411 // Initializing imager before the first copy 0412 // 0413 if( m_currentAction == INITIALIZING_IMAGER ) { 0414 if( success ) { 0415 m_currentAction = PREPARING_DATA; 0416 0417 // check the size 0418 m_projectSize = m_isoImager->size() + m_doc->audioDoc()->length(); 0419 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) 0420 m_projectSize += 11400; // the session gap 0421 0422 startFirstCopy(); 0423 } 0424 else { 0425 cleanupAfterError(); 0426 jobFinished( false ); 0427 } 0428 } 0429 0430 // 0431 // Recalculated iso image size 0432 // 0433 else if( m_currentAction == PREPARING_DATA ) { 0434 if( success ) { 0435 // 1. data in first track: 0436 // start isoimager and writer 0437 // when isoimager finishes start audiodecoder 0438 0439 // 2. data in last track 0440 // start audiodecoder and writer 0441 // when audiodecoder finishes start isoimager 0442 0443 // 3. data in second session 0444 // start audiodecoder and writer 0445 // start isoimager and writer 0446 0447 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0448 m_currentAction = WRITING_ISO_IMAGE; 0449 if( !prepareWriter() || !startWriting() ) { 0450 cleanupAfterError(); 0451 jobFinished(false); 0452 } 0453 } 0454 else 0455 writeNextCopy(); 0456 } 0457 else { 0458 cleanupAfterError(); 0459 jobFinished( false ); 0460 } 0461 } 0462 0463 // 0464 // Image creation finished 0465 // 0466 else { 0467 if( !success ) { 0468 emit infoMessage( i18n("Error while creating ISO image."), MessageError ); 0469 cleanupAfterError(); 0470 0471 jobFinished( false ); 0472 return; 0473 } 0474 0475 if( m_doc->onTheFly() ) { 0476 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) { 0477 m_currentAction = WRITING_AUDIO_IMAGE; 0478 m_audioImager->writeTo( m_writer->ioDevice() ); 0479 m_audioImager->start(); 0480 } 0481 } 0482 else { 0483 emit infoMessage( i18n("ISO image successfully created."), MessageSuccess ); 0484 0485 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0486 m_currentAction = WRITING_ISO_IMAGE; 0487 0488 if( !prepareWriter() || !startWriting() ) { 0489 cleanupAfterError(); 0490 jobFinished(false); 0491 } 0492 } 0493 else { 0494 emit newTask( i18n("Creating audio image files") ); 0495 m_currentAction = CREATING_AUDIO_IMAGE; 0496 m_audioImager->start(); 0497 } 0498 } 0499 } 0500 } 0501 0502 0503 void K3b::MixedJob::slotWriterFinished( bool success ) 0504 { 0505 if( m_canceled || m_errorOccuredAndAlreadyReported ) 0506 return; 0507 0508 if( !success ) { 0509 cleanupAfterError(); 0510 jobFinished(false); 0511 return; 0512 } 0513 0514 emit burning(false); 0515 0516 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION && m_currentAction == WRITING_AUDIO_IMAGE ) { 0517 // many drives need to reload the medium to return to a proper state 0518 if ( ( int )m_doc->burner()->readToc().count() < m_doc->numOfTracks()-1 ) { 0519 emit infoMessage( i18n( "Need to reload medium to return to proper state." ), MessageInfo ); 0520 connect( K3b::Device::reload( m_doc->burner() ), 0521 SIGNAL(finished(K3b::Device::DeviceHandler*)), 0522 this, 0523 SLOT(slotMediaReloadedForSecondSession(K3b::Device::DeviceHandler*)) ); 0524 } 0525 else { 0526 startSecondSession(); 0527 } 0528 } 0529 else { 0530 d->copiesDone++; 0531 if( d->copiesDone < d->copies ) { 0532 if( !K3b::eject( m_doc->burner() ) ) { 0533 blockingInformation( i18n("K3b was unable to eject the written disk. Please do so manually.") ); 0534 } 0535 writeNextCopy(); 0536 } 0537 else { 0538 if( !m_doc->onTheFly() && m_doc->removeImages() ) 0539 removeBufferFiles(); 0540 0541 if ( k3bcore->globalSettings()->ejectMedia() ) { 0542 K3b::Device::eject( m_doc->burner() ); 0543 } 0544 0545 jobFinished(true); 0546 } 0547 } 0548 } 0549 0550 0551 void K3b::MixedJob::slotMediaReloadedForSecondSession( K3b::Device::DeviceHandler* dh ) 0552 { 0553 if( !dh->success() ) { 0554 blockingInformation( i18n("Please reload the medium and press 'OK'"), 0555 i18n("Unable to close the tray") ); 0556 } 0557 0558 startSecondSession(); 0559 } 0560 0561 0562 void K3b::MixedJob::slotAudioDecoderFinished( bool success ) 0563 { 0564 if( m_canceled || m_errorOccuredAndAlreadyReported ) 0565 return; 0566 0567 if( !success ) { 0568 emit infoMessage( i18n("Error while decoding audio tracks."), MessageError ); 0569 cleanupAfterError(); 0570 jobFinished(false); 0571 return; 0572 } 0573 0574 if( m_doc->onTheFly() ) { 0575 if( m_doc->mixedType() == K3b::MixedDoc::DATA_LAST_TRACK ) { 0576 m_currentAction = WRITING_ISO_IMAGE; 0577 m_isoImager->start(); 0578 d->pipe.readFrom( m_isoImager->ioDevice() ); 0579 d->pipe.writeTo( m_writer->ioDevice() ); 0580 d->pipe.open(); 0581 } 0582 } 0583 else { 0584 emit infoMessage( i18n("Audio images successfully created."), MessageSuccess ); 0585 0586 if( m_doc->audioDoc()->normalize() ) { 0587 normalizeFiles(); 0588 } 0589 else { 0590 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 0591 m_currentAction = WRITING_ISO_IMAGE; 0592 else 0593 m_currentAction = WRITING_AUDIO_IMAGE; 0594 0595 if( !prepareWriter() || !startWriting() ) { 0596 cleanupAfterError(); 0597 jobFinished(false); 0598 } 0599 } 0600 } 0601 } 0602 0603 0604 void K3b::MixedJob::slotAudioDecoderNextTrack( int t, int tt ) 0605 { 0606 if( m_doc->onlyCreateImages() || !m_doc->onTheFly() ) { 0607 K3b::AudioTrack* track = m_doc->audioDoc()->getTrack(t); 0608 emit newSubTask( i18n("Decoding audio track %1 of %2%3", 0609 t, 0610 tt, 0611 ( track->title().isEmpty() || track->artist().isEmpty() 0612 ? QString() 0613 : " (" + track->artist() + " - " + track->title() + ')' ) ) ); 0614 } 0615 } 0616 0617 0618 bool K3b::MixedJob::prepareWriter() 0619 { 0620 delete m_writer; 0621 m_writer = 0; 0622 0623 if( ( m_currentAction == WRITING_ISO_IMAGE && m_usedDataWritingApp == K3b::WritingAppCdrecord ) || 0624 ( m_currentAction == WRITING_AUDIO_IMAGE && m_usedAudioWritingApp == K3b::WritingAppCdrecord ) ) { 0625 0626 if( !writeInfFiles() ) { 0627 qDebug() << "(K3b::MixedJob) could not write inf-files."; 0628 emit infoMessage( i18n("I/O Error"), MessageError ); 0629 0630 return false; 0631 } 0632 0633 K3b::CdrecordWriter* writer = new K3b::CdrecordWriter( m_doc->burner(), this, this ); 0634 0635 // only write the audio tracks in DAO mode 0636 if( m_currentAction == WRITING_ISO_IMAGE ) 0637 writer->setWritingMode( m_usedDataWritingMode ); 0638 else 0639 writer->setWritingMode( m_usedAudioWritingMode ); 0640 0641 writer->setSimulate( m_doc->dummy() ); 0642 writer->setBurnSpeed( m_doc->speed() ); 0643 0644 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0645 if( m_currentAction == WRITING_ISO_IMAGE ) { 0646 if( m_doc->onTheFly() ) 0647 writer->addArgument("-waiti"); 0648 0649 addDataTrack( writer ); 0650 } 0651 else { 0652 writer->setMulti( true ); 0653 addAudioTracks( writer ); 0654 } 0655 } 0656 else { 0657 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 0658 addDataTrack( writer ); 0659 addAudioTracks( writer ); 0660 if( m_doc->mixedType() == K3b::MixedDoc::DATA_LAST_TRACK ) 0661 addDataTrack( writer ); 0662 } 0663 0664 m_writer = writer; 0665 } 0666 else { 0667 if( !writeTocFile() ) { 0668 qDebug() << "(K3b::DataJob) could not write tocfile."; 0669 emit infoMessage( i18n("I/O Error"), MessageError ); 0670 0671 return false; 0672 } 0673 0674 // create the writer 0675 // create cdrdao job 0676 K3b::CdrdaoWriter* writer = new K3b::CdrdaoWriter( m_doc->burner(), this, this ); 0677 writer->setSimulate( m_doc->dummy() ); 0678 writer->setBurnSpeed( m_doc->speed() ); 0679 0680 // multisession only for the first session 0681 writer->setMulti( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION 0682 && m_currentAction == WRITING_AUDIO_IMAGE ); 0683 0684 writer->setTocFile( m_tocFile->fileName() ); 0685 0686 m_writer = writer; 0687 } 0688 0689 connect( m_writer, SIGNAL(infoMessage(QString,int)), this, SIGNAL(infoMessage(QString,int)) ); 0690 connect( m_writer, SIGNAL(percent(int)), this, SLOT(slotWriterJobPercent(int)) ); 0691 connect( m_writer, SIGNAL(processedSize(int,int)), this, SIGNAL(processedSize(int,int)) ); 0692 connect( m_writer, SIGNAL(subPercent(int)), this, SIGNAL(subPercent(int)) ); 0693 connect( m_writer, SIGNAL(processedSubSize(int,int)), this, SIGNAL(processedSubSize(int,int)) ); 0694 connect( m_writer, SIGNAL(nextTrack(int,int)), this, SLOT(slotWriterNextTrack(int,int)) ); 0695 connect( m_writer, SIGNAL(buffer(int)), this, SIGNAL(bufferStatus(int)) ); 0696 connect( m_writer, SIGNAL(deviceBuffer(int)), this, SIGNAL(deviceBuffer(int)) ); 0697 connect( m_writer, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)), this, SIGNAL(writeSpeed(int,K3b::Device::SpeedMultiplicator)) ); 0698 connect( m_writer, SIGNAL(finished(bool)), this, SLOT(slotWriterFinished(bool)) ); 0699 // connect( m_writer, SIGNAL(newTask(QString)), this, SIGNAL(newTask(QString)) ); 0700 connect( m_writer, SIGNAL(newSubTask(QString)), this, SIGNAL(newSubTask(QString)) ); 0701 connect( m_writer, SIGNAL(debuggingOutput(QString,QString)), 0702 this, SIGNAL(debuggingOutput(QString,QString)) ); 0703 0704 return true; 0705 } 0706 0707 0708 bool K3b::MixedJob::writeInfFiles() 0709 { 0710 K3b::InfFileWriter infFileWriter; 0711 K3b::AudioTrack* track = m_doc->audioDoc()->firstTrack(); 0712 while( track ) { 0713 0714 infFileWriter.setTrack( track->toCdTrack() ); 0715 infFileWriter.setTrackNumber( track->trackNumber() ); 0716 if( !m_doc->onTheFly() ) 0717 infFileWriter.setBigEndian( false ); 0718 0719 if( !infFileWriter.save( m_tempData->infFileName(track) ) ) 0720 return false; 0721 0722 track = track->next(); 0723 } 0724 return true; 0725 } 0726 0727 0728 bool K3b::MixedJob::writeTocFile() 0729 { 0730 // FIXME: create the tocfile in the same directory like all the other files. 0731 0732 delete m_tocFile; 0733 m_tocFile = new QTemporaryFile( "XXXXXX.toc" ); 0734 m_tocFile->open(); 0735 0736 // write the toc-file 0737 QTextStream s( m_tocFile ); 0738 0739 K3b::TocFileWriter tocFileWriter; 0740 0741 // 0742 // TOC 0743 // 0744 tocFileWriter.setData( m_doc->toToc( m_usedDataMode == K3b::DataMode2 0745 ? K3b::Device::Track::XA_FORM1 0746 : K3b::Device::Track::MODE1, 0747 m_doc->onTheFly() 0748 ? m_isoImager->size() 0749 : m_doc->dataDoc()->length() ) ); 0750 0751 // 0752 // CD-Text 0753 // 0754 if( m_doc->audioDoc()->cdText() ) { 0755 K3b::Device::CdText text = m_doc->audioDoc()->cdTextData(); 0756 // if data in first track we need to add a dummy cdtext 0757 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 0758 text.insert( 0, K3b::Device::TrackCdText() ); 0759 0760 tocFileWriter.setCdText( text ); 0761 } 0762 0763 // 0764 // Session to write 0765 // 0766 tocFileWriter.setSession( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION && 0767 m_currentAction == WRITING_ISO_IMAGE ? 2 : 1 ); 0768 0769 // 0770 // image filenames 0771 // 0772 if( !m_doc->onTheFly() ) { 0773 QStringList files; 0774 K3b::AudioTrack* track = m_doc->audioDoc()->firstTrack(); 0775 while( track ) { 0776 files += m_tempData->bufferFileName( track ); 0777 track = track->next(); 0778 } 0779 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 0780 files.prepend( m_isoImageFilePath ); 0781 else 0782 files.append( m_isoImageFilePath ); 0783 0784 tocFileWriter.setFilenames( files ); 0785 } 0786 0787 bool success = tocFileWriter.save( s ); 0788 0789 m_tocFile->close(); 0790 0791 // backup for debugging 0792 // KIO::del("/tmp/trueg/tocfile_debug_backup.toc",0L)->exec(); 0793 // KIO::copyAs( m_tocFile->name(), "/tmp/trueg/tocfile_debug_backup.toc",0L )->exec(); 0794 0795 return success; 0796 } 0797 0798 0799 void K3b::MixedJob::addAudioTracks( K3b::CdrecordWriter* writer ) 0800 { 0801 writer->addArgument( "-useinfo" ); 0802 0803 // add raw cdtext data 0804 if( m_doc->audioDoc()->cdText() ) { 0805 writer->setRawCdText( m_doc->audioDoc()->cdTextData().rawPackData() ); 0806 } 0807 0808 writer->addArgument( "-audio" ); 0809 0810 // we always pad because although K3b makes sure all tracks' length are multiples of 2352 0811 // it seems that normalize sometimes corrupts these lengths 0812 // FIXME: see K3b::AudioJob for the whole less4secs and zeroPregap handling 0813 writer->addArgument( "-pad" ); 0814 0815 // Allow tracks shorter than 4 seconds 0816 writer->addArgument( "-shorttrack" ); 0817 0818 // add all the audio tracks 0819 K3b::AudioTrack* track = m_doc->audioDoc()->firstTrack(); 0820 while( track ) { 0821 if( m_doc->onTheFly() ) { 0822 // this is only supported by cdrecord versions >= 2.01a13 0823 writer->addArgument( QFile::encodeName( m_tempData->infFileName( track ) ) ); 0824 } 0825 else { 0826 writer->addArgument( QFile::encodeName( m_tempData->bufferFileName( track ) ) ); 0827 } 0828 track = track->next(); 0829 } 0830 } 0831 0832 void K3b::MixedJob::addDataTrack( K3b::CdrecordWriter* writer ) 0833 { 0834 // add data track 0835 if( m_usedDataMode == K3b::DataMode2 ) { 0836 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 0837 if( cdrecordBin && cdrecordBin->hasFeature( "xamix" ) ) 0838 writer->addArgument( "-xa" ); 0839 else 0840 writer->addArgument( "-xa1" ); 0841 } 0842 else 0843 writer->addArgument( "-data" ); 0844 0845 if( m_doc->onTheFly() ) 0846 writer->addArgument( QString("-tsize=%1s").arg(m_isoImager->size()) )->addArgument("-"); 0847 else 0848 writer->addArgument( m_isoImageFilePath ); 0849 } 0850 0851 0852 void K3b::MixedJob::slotWriterNextTrack( int t, int ) 0853 { 0854 K3b::AudioTrack* track = 0; 0855 0856 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) { 0857 if( t > 1 ) 0858 track = m_doc->audioDoc()->getTrack(t-1); 0859 } 0860 else if( m_doc->mixedType() == K3b::MixedDoc::DATA_LAST_TRACK ) { 0861 if( t < m_doc->audioDoc()->numOfTracks()+1 ) 0862 track = m_doc->audioDoc()->getTrack(t); 0863 } 0864 else if( m_currentAction == WRITING_AUDIO_IMAGE ) 0865 track = m_doc->audioDoc()->getTrack(t); 0866 else 0867 t = m_doc->numOfTracks(); 0868 0869 if( track ) 0870 emit newSubTask( i18n("Writing track %1 of %2%3" 0871 ,t 0872 ,m_doc->numOfTracks() 0873 , track->title().isEmpty() || track->artist().isEmpty() 0874 ? QString() 0875 : " (" + track->artist() + " - " + track->title() + ')' ) ); 0876 else 0877 emit newSubTask( i18n("Writing track %1 of %2 (%3)", 0878 t, 0879 m_doc->numOfTracks(), 0880 i18n("ISO 9660 data")) ); 0881 } 0882 0883 0884 void K3b::MixedJob::slotWriterJobPercent( int p ) 0885 { 0886 double totalTasks = d->copies; 0887 double tasksDone = d->copiesDone; 0888 if( m_doc->audioDoc()->normalize() ) { 0889 totalTasks+=1.0; 0890 tasksDone+=1.0; 0891 } 0892 if( !m_doc->onTheFly() ) { 0893 totalTasks+=1.0; 0894 } 0895 0896 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0897 if( m_currentAction == WRITING_AUDIO_IMAGE ) { 0898 // the audio imager has finished in all cases 0899 // the iso imager only if this is not the first copy 0900 if( d->copiesDone > 0 ) 0901 tasksDone += 1.0; 0902 else if( !m_doc->onTheFly() ) 0903 tasksDone += m_audioDocPartOfProcess; 0904 0905 p = (int)((double)p*m_audioDocPartOfProcess); 0906 } 0907 else { 0908 // all images have been created 0909 if( !m_doc->onTheFly() ) 0910 tasksDone += 1.0; 0911 0912 p = (int)(100.0*m_audioDocPartOfProcess + (double)p*(1.0-m_audioDocPartOfProcess)); 0913 } 0914 } 0915 else if( !m_doc->onTheFly() ) 0916 tasksDone += 1.0; 0917 0918 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 0919 } 0920 0921 0922 void K3b::MixedJob::slotAudioDecoderPercent( int p ) 0923 { 0924 // the only thing finished here might be the isoimager which is part of this task 0925 if( !m_doc->onTheFly() ) { 0926 double totalTasks = d->copies+1; 0927 if( m_doc->audioDoc()->normalize() ) 0928 totalTasks+=1.0; 0929 0930 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) 0931 p = (int)((double)p*m_audioDocPartOfProcess); 0932 else 0933 p = (int)(100.0*(1.0-m_audioDocPartOfProcess) + (double)p*m_audioDocPartOfProcess); 0934 0935 emit percent( (int)((double)p / totalTasks) ); 0936 } 0937 } 0938 0939 0940 void K3b::MixedJob::slotAudioDecoderSubPercent( int p ) 0941 { 0942 if( !m_doc->onTheFly() ) { 0943 emit subPercent( p ); 0944 } 0945 } 0946 0947 0948 void K3b::MixedJob::slotIsoImagerPercent( int p ) 0949 { 0950 if( !m_doc->onTheFly() ) { 0951 emit subPercent( p ); 0952 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0953 0954 double totalTasks = d->copies+1.0; 0955 double tasksDone = d->copiesDone; 0956 if( m_doc->audioDoc()->normalize() ) { 0957 totalTasks+=1.0; 0958 // the normalizer finished 0959 tasksDone+=1.0; 0960 } 0961 0962 // the writing of the audio part finished 0963 tasksDone += m_audioDocPartOfProcess; 0964 0965 // the audio decoder finished (which is part of this task in terms of progress) 0966 p = (int)(100.0*m_audioDocPartOfProcess + (double)p*(1.0-m_audioDocPartOfProcess)); 0967 0968 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 0969 } 0970 else { 0971 double totalTasks = d->copies+1.0; 0972 if( m_doc->audioDoc()->normalize() ) 0973 totalTasks+=1.0; 0974 0975 emit percent( (int)((double)(p*(1.0-m_audioDocPartOfProcess)) / totalTasks) ); 0976 } 0977 } 0978 } 0979 0980 0981 bool K3b::MixedJob::startWriting() 0982 { 0983 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 0984 if( m_currentAction == WRITING_ISO_IMAGE) { 0985 if( m_doc->dummy() ) 0986 emit newTask( i18n("Simulating second session") ); 0987 else if( d->copies > 1 ) 0988 emit newTask( i18n("Writing second session of copy %1", d->copiesDone+1) ); 0989 else 0990 emit newTask( i18n("Writing second session") ); 0991 } 0992 else { 0993 if( m_doc->dummy() ) 0994 emit newTask( i18n("Simulating first session") ); 0995 else if( d->copies > 1 ) 0996 emit newTask( i18n("Writing first session of copy %1", d->copiesDone+1) ); 0997 else 0998 emit newTask( i18n("Writing first session") ); 0999 } 1000 } 1001 else if( m_doc->dummy() ) 1002 emit newTask( i18n("Simulating") ); 1003 else 1004 emit newTask( i18n("Writing Copy %1", d->copiesDone+1) ); 1005 1006 1007 // if we append the second session the cd is already in the drive 1008 if( !(m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION 1009 && m_currentAction == WRITING_ISO_IMAGE) ) { 1010 1011 emit newSubTask( i18n("Waiting for media") ); 1012 if( waitForMedium( m_doc->burner() ) == Device::MEDIA_UNKNOWN ) { 1013 cancel(); 1014 return false; 1015 } 1016 1017 // just to be sure we did not get canceled during the async discWaiting 1018 if( m_canceled ) 1019 return false; 1020 1021 // check if the project will fit on the CD 1022 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 1023 // the media is in and has been checked so this should be fast (hopefully) 1024 K3b::Msf mediaSize = m_doc->burner()->diskInfo().capacity(); 1025 if( mediaSize < m_projectSize ) { 1026 if( k3bcore->globalSettings()->overburn() ) { 1027 emit infoMessage( i18n("Trying to write more than the official disk capacity"), K3b::Job::MessageWarning ); 1028 } 1029 else { 1030 emit infoMessage( i18n("Data does not fit on disk."), MessageError ); 1031 return false; 1032 } 1033 } 1034 } 1035 } 1036 1037 // in case we determined the max possible writing speed we have to reset the speed on the writer job 1038 // here since an inserted media is necessary 1039 // the Max speed job will compare the max speed value with the supported values of the writer 1040 if( d->maxSpeed ) 1041 m_writer->setBurnSpeed( d->maxSpeedJob->maxSpeed() ); 1042 1043 emit burning(true); 1044 m_writer->start(); 1045 1046 if( m_doc->onTheFly() ) { 1047 if ( m_currentAction == WRITING_AUDIO_IMAGE ) { 1048 // now the writer is running and we can get it's stdin 1049 // we only use this method when writing on-the-fly since 1050 // we cannot easily change the audioDecode fd while it's working 1051 // which we would need to do since we write into several 1052 // image files. 1053 m_audioImager->writeTo( m_writer->ioDevice() ); 1054 m_audioImager->start(); 1055 } 1056 else { 1057 m_isoImager->start(); 1058 d->pipe.readFrom( m_isoImager->ioDevice() ); 1059 d->pipe.writeTo( m_writer->ioDevice() ); 1060 d->pipe.open(); 1061 } 1062 } 1063 1064 return true; 1065 } 1066 1067 1068 void K3b::MixedJob::createIsoImage() 1069 { 1070 m_currentAction = CREATING_ISO_IMAGE; 1071 1072 // prepare iso image file 1073 m_isoImageFilePath = m_tempFilePrefix + "_datatrack.iso"; 1074 1075 if( !m_doc->onTheFly() ) 1076 emit newTask( i18n("Creating ISO image file") ); 1077 emit newSubTask( i18n("Creating ISO image in %1", m_isoImageFilePath) ); 1078 emit infoMessage( i18n("Creating ISO image in %1", m_isoImageFilePath), MessageInfo ); 1079 1080 d->dataImageFile.setName( m_isoImageFilePath ); 1081 if ( d->dataImageFile.open( QIODevice::WriteOnly ) ) { 1082 m_isoImager->start(); 1083 d->pipe.readFrom( m_isoImager->ioDevice() ); 1084 d->pipe.writeTo( &d->dataImageFile, true ); 1085 d->pipe.open( true ); 1086 } 1087 else { 1088 emit infoMessage( i18n("Could not open %1 for writing", m_isoImageFilePath ), MessageError ); 1089 cleanupAfterError(); 1090 jobFinished(false); 1091 } 1092 } 1093 1094 1095 void K3b::MixedJob::cleanupAfterError() 1096 { 1097 m_errorOccuredAndAlreadyReported = true; 1098 // m_audioImager->cancel(); 1099 m_isoImager->cancel(); 1100 if( m_writer && m_writer->active() ) 1101 m_writer->cancel(); 1102 1103 delete m_tocFile; 1104 m_tocFile = 0; 1105 1106 // remove the temp files 1107 removeBufferFiles(); 1108 1109 #ifdef __GNUC__ 1110 #warning FIXME: eject medium if necessary after cleanupAfterError 1111 #endif 1112 } 1113 1114 1115 void K3b::MixedJob::removeBufferFiles() 1116 { 1117 if ( !m_doc->onTheFly() ) { 1118 emit infoMessage( i18n("Removing buffer files."), MessageInfo ); 1119 } 1120 1121 if( QFile::exists( m_isoImageFilePath ) ) 1122 if( !QFile::remove( m_isoImageFilePath ) ) 1123 emit infoMessage( i18n("Could not delete file %1.",m_isoImageFilePath), MessageError ); 1124 1125 // removes buffer images and temp toc or inf files 1126 m_tempData->cleanup(); 1127 } 1128 1129 1130 void K3b::MixedJob::determineWritingMode() 1131 { 1132 // we don't need this when only creating image and it is possible 1133 // that the burn device is null 1134 if( m_doc->onlyCreateImages() ) 1135 return; 1136 1137 // at first we determine the data mode 1138 // -------------------------------------------------------------- 1139 if( m_doc->dataDoc()->dataMode() == K3b::DataModeAuto ) { 1140 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) 1141 m_usedDataMode = K3b::DataMode2; 1142 else 1143 m_usedDataMode = K3b::DataMode1; 1144 } 1145 else 1146 m_usedDataMode = m_doc->dataDoc()->dataMode(); 1147 1148 const K3b::ExternalBin* cdrecordBin = k3bcore->externalBinManager()->binObject("cdrecord"); 1149 // we try to use cdrecord if possible 1150 bool cdrecordOnTheFly = false; 1151 bool cdrecordCdText = false; 1152 bool cdrecordUsable = false; 1153 1154 if( cdrecordBin ) { 1155 cdrecordOnTheFly = cdrecordBin->hasFeature( "audio-stdin" ); 1156 cdrecordCdText = cdrecordBin->hasFeature( "cdtext" ); 1157 cdrecordUsable = 1158 !( !cdrecordOnTheFly && m_doc->onTheFly() ) && 1159 !( m_doc->audioDoc()->cdText() && !cdrecordCdText ); 1160 } 1161 1162 // Writing Application 1163 // -------------------------------------------------------------- 1164 // cdrecord seems to have problems writing xa 1 disks in dao mode? At least on my system! 1165 if( writingApp() == K3b::WritingAppAuto ) { 1166 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 1167 if( m_doc->writingMode() == K3b::WritingModeSao || 1168 ( m_doc->writingMode() == K3b::WritingModeAuto && !cdrecordUsable ) ) { 1169 m_usedAudioWritingApp = K3b::WritingAppCdrdao; 1170 m_usedDataWritingApp = K3b::WritingAppCdrdao; 1171 } 1172 else { 1173 m_usedAudioWritingApp = K3b::WritingAppCdrecord; 1174 m_usedDataWritingApp = K3b::WritingAppCdrecord; 1175 } 1176 } 1177 else { 1178 if( cdrecordUsable ) { 1179 m_usedAudioWritingApp = K3b::WritingAppCdrecord; 1180 m_usedDataWritingApp = K3b::WritingAppCdrecord; 1181 } 1182 else { 1183 m_usedAudioWritingApp = K3b::WritingAppCdrdao; 1184 m_usedDataWritingApp = K3b::WritingAppCdrdao; 1185 } 1186 } 1187 } 1188 else { 1189 m_usedAudioWritingApp = writingApp(); 1190 m_usedDataWritingApp = writingApp(); 1191 } 1192 1193 // TODO: use K3b::Exceptions::brokenDaoAudio 1194 1195 // Writing Mode (TAO/DAO/RAW) 1196 // -------------------------------------------------------------- 1197 if( m_doc->writingMode() == K3b::WritingModeAuto ) { 1198 1199 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 1200 if( m_usedDataWritingApp == K3b::WritingAppCdrecord ) 1201 m_usedDataWritingMode = K3b::WritingModeTao; 1202 else 1203 m_usedDataWritingMode = K3b::WritingModeSao; 1204 1205 // default to Session at once for the audio part 1206 m_usedAudioWritingMode = K3b::WritingModeSao; 1207 } 1208 else { 1209 m_usedDataWritingMode = K3b::WritingModeTao; 1210 m_usedAudioWritingMode = K3b::WritingModeTao; 1211 } 1212 } 1213 else { 1214 m_usedAudioWritingMode = m_doc->writingMode(); 1215 m_usedDataWritingMode = m_doc->writingMode(); 1216 } 1217 1218 1219 if( m_usedDataWritingApp == K3b::WritingAppCdrecord ) { 1220 if( !cdrecordOnTheFly && m_doc->onTheFly() ) { 1221 m_doc->setOnTheFly( false ); 1222 emit infoMessage( i18n("On-the-fly writing with cdrecord < 2.01a13 not supported."), MessageError ); 1223 } 1224 1225 if( m_doc->audioDoc()->cdText() ) { 1226 if( !cdrecordCdText ) { 1227 m_doc->audioDoc()->writeCdText( false ); 1228 if (cdrecordBin) { 1229 emit infoMessage( i18n("Cdrecord %1 does not support CD-Text writing.",cdrecordBin->version()), MessageError ); 1230 } else { 1231 emit infoMessage( i18n("Cdrecord could not be found on your system." ), MessageError ); 1232 } 1233 } 1234 else if( m_usedAudioWritingMode == K3b::WritingModeTao ) { 1235 emit infoMessage( i18n("It is not possible to write CD-Text in TAO mode. Try DAO or RAW."), MessageWarning ); 1236 } 1237 } 1238 } 1239 } 1240 1241 1242 void K3b::MixedJob::normalizeFiles() 1243 { 1244 if( !m_normalizeJob ) { 1245 m_normalizeJob = new K3b::AudioNormalizeJob( this, this ); 1246 1247 connect( m_normalizeJob, SIGNAL(infoMessage(QString,int)), 1248 this, SIGNAL(infoMessage(QString,int)) ); 1249 connect( m_normalizeJob, SIGNAL(percent(int)), this, SLOT(slotNormalizeProgress(int)) ); 1250 connect( m_normalizeJob, SIGNAL(subPercent(int)), this, SLOT(slotNormalizeSubProgress(int)) ); 1251 connect( m_normalizeJob, SIGNAL(finished(bool)), this, SLOT(slotNormalizeJobFinished(bool)) ); 1252 connect( m_normalizeJob, SIGNAL(newTask(QString)), this, SIGNAL(newSubTask(QString)) ); 1253 connect( m_normalizeJob, SIGNAL(debuggingOutput(QString,QString)), 1254 this, SIGNAL(debuggingOutput(QString,QString)) ); 1255 } 1256 1257 // add all the files 1258 QList<QString> files; 1259 K3b::AudioTrack* track = m_doc->audioDoc()->firstTrack(); 1260 while( track ) { 1261 files.append( m_tempData->bufferFileName(track) ); 1262 track = track->next(); 1263 } 1264 1265 m_normalizeJob->setFilesToNormalize( files ); 1266 1267 emit newTask( i18n("Normalizing volume levels") ); 1268 m_normalizeJob->start(); 1269 } 1270 1271 void K3b::MixedJob::slotNormalizeJobFinished( bool success ) 1272 { 1273 if( m_canceled || m_errorOccuredAndAlreadyReported ) 1274 return; 1275 1276 if( success ) { 1277 if( m_doc->mixedType() == K3b::MixedDoc::DATA_FIRST_TRACK ) 1278 m_currentAction = WRITING_ISO_IMAGE; 1279 else 1280 m_currentAction = WRITING_AUDIO_IMAGE; 1281 1282 if( !prepareWriter() || !startWriting() ) { 1283 cleanupAfterError(); 1284 jobFinished(false); 1285 } 1286 } 1287 else { 1288 cleanupAfterError(); 1289 jobFinished(false); 1290 } 1291 } 1292 1293 void K3b::MixedJob::slotNormalizeProgress( int p ) 1294 { 1295 double totalTasks = d->copies+2.0; 1296 double tasksDone = 0; 1297 1298 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) { 1299 // the audio imager finished (m_audioDocPartOfProcess*1 task) 1300 // plus the normalize progress 1301 tasksDone = m_audioDocPartOfProcess; 1302 } 1303 else { 1304 // the iso and audio imagers already finished (one task) 1305 // plus the normalize progress 1306 tasksDone = 1.0; 1307 } 1308 1309 emit percent( (int)((100.0*tasksDone + (double)p) / totalTasks) ); 1310 } 1311 1312 1313 void K3b::MixedJob::slotNormalizeSubProgress( int p ) 1314 { 1315 emit subPercent( p ); 1316 } 1317 1318 1319 void K3b::MixedJob::prepareProgressInformation() 1320 { 1321 // calculate percentage of audio and data 1322 // this is also used in on-the-fly mode 1323 double ds = (double)m_doc->dataDoc()->length().totalFrames(); 1324 double as = (double)m_doc->audioDoc()->length().totalFrames(); 1325 m_audioDocPartOfProcess = as/(ds+as); 1326 } 1327 1328 1329 QString K3b::MixedJob::jobDescription() const 1330 { 1331 if( m_doc->mixedType() == K3b::MixedDoc::DATA_SECOND_SESSION ) 1332 return i18n("Writing Enhanced Audio CD") 1333 + ( m_doc->audioDoc()->title().isEmpty() 1334 ? QString() 1335 : QString( " (%1)" ).arg(m_doc->audioDoc()->title()) ); 1336 else 1337 return i18n("Writing Mixed Mode CD") 1338 + ( m_doc->audioDoc()->title().isEmpty() 1339 ? QString() 1340 : QString( " (%1)" ).arg(m_doc->audioDoc()->title()) ); 1341 } 1342 1343 1344 QString K3b::MixedJob::jobDetails() const 1345 { 1346 return ( i18ncp("%2 is of form XX:YY:ZZ, no pluralization needed" 1347 ,"1 track (%2 minutes audio data, %3 ISO 9660 data)" 1348 ,"%1 tracks (%2 minutes audio data, %3 ISO 9660 data)" 1349 ,m_doc->numOfTracks() 1350 ,m_doc->audioDoc()->length().toString() 1351 ,KIO::convertSize(m_doc->dataDoc()->size())) 1352 + ( m_doc->copies() > 1 && !m_doc->dummy() 1353 ? i18np(" - %1 copy", " - %1 copies", m_doc->copies()) 1354 : QString() ) ); 1355 } 1356 1357 #include "moc_k3bmixedjob.cpp"