File indexing completed on 2024-04-28 04:50:20

0001 /*
0002     SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org>
0003     SPDX-FileCopyrightText: 2009-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 
0010 #include "k3baudioripjob.h"
0011 
0012 #include "k3bcdparanoialib.h"
0013 #include "k3bcore.h"
0014 #include "k3bdevice.h"
0015 #include "k3btoc.h"
0016 #include "k3btrack.h"
0017 
0018 #include <KCDDB/CDInfo>
0019 
0020 #include <KLocalizedString>
0021 
0022 
0023 namespace K3b {
0024 
0025 
0026 class AudioRipJob::Private
0027 {
0028 public:
0029     Private()
0030         : paranoiaRetries(5),
0031           neverSkip(false),
0032           paranoiaLib(0),
0033           device(0),
0034           useIndex0(false) {
0035     }
0036     int paranoiaMode;
0037     int paranoiaRetries;
0038     int neverSkip;
0039 
0040     CdparanoiaLib* paranoiaLib;
0041 
0042     Device::Toc toc;
0043     Device::Device* device;
0044 
0045     bool useIndex0;
0046 };
0047 
0048 
0049 namespace {
0050 
0051 class AudioCdReader : public QIODevice
0052 {
0053 public:
0054     AudioCdReader( int trackIndex, AudioRipJob::Private* priv, QObject* parent = 0 );
0055     bool open( OpenMode mode ) override;
0056     bool isSequential() const override;
0057     qint64 size() const override;
0058 
0059 protected:
0060     qint64 writeData( const char* data, qint64 len ) override;
0061     qint64 readData( char* data, qint64 maxlen ) override;
0062 
0063 private:
0064     int m_trackIndex;
0065     AudioRipJob::Private* d;
0066 };
0067 
0068 
0069 AudioCdReader::AudioCdReader( int trackIndex, AudioRipJob::Private* priv, QObject* parent )
0070     : QIODevice( parent ),
0071       m_trackIndex( trackIndex ),
0072       d( priv )
0073 {
0074 }
0075 
0076 
0077 bool AudioCdReader::open( OpenMode mode )
0078 {
0079     if( !mode.testFlag( QIODevice::WriteOnly ) ) {
0080 
0081         const Device::Track& tt = d->toc[m_trackIndex-1];
0082 
0083         long endSec = ( (d->useIndex0 && tt.index0() > 0)
0084                         ? tt.firstSector().lba() + tt.index0().lba() - 1
0085                         : tt.lastSector().lba() );
0086 
0087         if( d->paranoiaLib->initReading( tt.firstSector().lba(), endSec ) ) {
0088             return QIODevice::open( mode );
0089         }
0090         else {
0091             setErrorString( i18n("Error while initializing audio ripping.") );
0092             return false;
0093         }
0094     }
0095     else {
0096         return false;
0097     }
0098 }
0099 
0100 
0101 bool AudioCdReader::isSequential() const
0102 {
0103     return false;
0104 }
0105 
0106 
0107 qint64 AudioCdReader::size() const
0108 {
0109     return d->toc[m_trackIndex-1].length().audioBytes();
0110 }
0111 
0112 
0113 qint64 AudioCdReader::writeData( const char* /*data*/, qint64 /*len*/ )
0114 {
0115     return -1;
0116 }
0117 
0118 
0119 qint64 AudioCdReader::readData( char* data, qint64 /*maxlen*/ )
0120 {
0121     int status = 0;
0122     char* buf = d->paranoiaLib->read( &status );
0123     if( status == CdparanoiaLib::S_OK ) {
0124         if( buf == 0 ) {
0125             return -1;
0126         }
0127         else {
0128             ::memcpy( data, buf, CD_FRAMESIZE_RAW );
0129             return CD_FRAMESIZE_RAW;
0130         }
0131     }
0132     else {
0133         setErrorString( i18n("Unrecoverable error while ripping track %1.",m_trackIndex) );
0134         return -1;
0135     }
0136 }
0137 
0138 } // namespace
0139 
0140 
0141 AudioRipJob::AudioRipJob( JobHandler* hdl, QObject* parent )
0142     :  MassAudioEncodingJob( false, hdl, parent ),
0143        d( new Private )
0144 {
0145 }
0146 
0147 
0148 AudioRipJob::~AudioRipJob()
0149 {
0150     delete d->paranoiaLib;
0151 }
0152 
0153 
0154 void AudioRipJob::setParanoiaMode( int mode )
0155 {
0156     d->paranoiaMode = mode;
0157 }
0158 
0159 
0160 void AudioRipJob::setMaxRetries( int r )
0161 {
0162     d->paranoiaRetries = r;
0163 }
0164 
0165 
0166 void AudioRipJob::setNeverSkip( bool b )
0167 {
0168     d->neverSkip = b;
0169 }
0170 
0171 
0172 void AudioRipJob::setUseIndex0( bool b )
0173 {
0174     d->useIndex0 = b;
0175 }
0176 
0177 
0178 void AudioRipJob::setDevice( Device::Device* device )
0179 {
0180     d->device = device;
0181 }
0182 
0183 
0184 QString AudioRipJob::jobDescription() const
0185 {
0186     if( cddbEntry().get( KCDDB::Title ).toString().isEmpty() )
0187         return i18n( "Ripping Audio Tracks" );
0188     else
0189         return i18n( "Ripping Audio Tracks From '%1'",
0190                      cddbEntry().get( KCDDB::Title ).toString() );
0191 }
0192 
0193 
0194 QString AudioRipJob::jobSource() const
0195 {
0196     if( d->device )
0197         return d->device->vendor() + ' ' + d->device->description();
0198     else
0199         return QString();
0200 }
0201 
0202 
0203 void AudioRipJob::start()
0204 {
0205     k3bcore->blockDevice( d->device );
0206     MassAudioEncodingJob::start();
0207 }
0208 
0209 
0210 void AudioRipJob::jobFinished( bool success )
0211 {
0212     k3bcore->unblockDevice( d->device );
0213     MassAudioEncodingJob::jobFinished( success );
0214 }
0215 
0216 
0217 bool AudioRipJob::init()
0218 {
0219     emit newTask( i18n("Extracting Digital Audio")  );
0220 
0221     if( !d->paranoiaLib ) {
0222         d->paranoiaLib = CdparanoiaLib::create();
0223     }
0224 
0225     if( !d->paranoiaLib ) {
0226         emit infoMessage( i18n("Could not load libcdparanoia."), Job::MessageError );
0227         return false;
0228     }
0229 
0230     // try to open the device
0231     if( !d->device ) {
0232         return false;
0233     }
0234 
0235     d->device->block(true);
0236 
0237     emit infoMessage( i18n("Reading CD table of contents."), Job::MessageInfo );
0238     d->toc = d->device->readToc();
0239 
0240     if( !d->paranoiaLib->initParanoia( d->device, d->toc ) ) {
0241         emit infoMessage( i18n("Could not open device %1",d->device->blockDeviceName()),
0242                           Job::MessageError );
0243         d->device->block(false);
0244 
0245         return false;
0246     }
0247 
0248     d->paranoiaLib->setParanoiaMode( d->paranoiaMode );
0249     d->paranoiaLib->setNeverSkip( d->neverSkip );
0250     d->paranoiaLib->setMaxRetries( d->paranoiaRetries );
0251 
0252 
0253     if( d->useIndex0 ) {
0254         emit newSubTask( i18n("Searching index 0 for all tracks") );
0255         d->device->indexScan( d->toc );
0256     }
0257 
0258     emit infoMessage( i18n("Starting digital audio extraction (ripping)."), Job::MessageInfo );
0259     return true;
0260 }
0261 
0262 
0263 void AudioRipJob::cleanup()
0264 {
0265     d->paranoiaLib->close();
0266     d->device->block(false);
0267 }
0268 
0269 
0270 Msf AudioRipJob::trackLength( int trackIndex ) const
0271 {
0272     if( d->useIndex0 )
0273         return d->toc[trackIndex-1].realAudioLength();
0274     else
0275         return d->toc[trackIndex-1].length();
0276 }
0277 
0278 
0279 QIODevice* AudioRipJob::createReader( int trackIndex ) const
0280 {
0281     return new AudioCdReader( trackIndex, d.data() );
0282 }
0283 
0284 
0285 void AudioRipJob::trackStarted(int trackIndex)
0286 {
0287     if (!cddbEntry().track(trackIndex - 1).get(KCDDB::Artist).toString().isEmpty() &&
0288         !cddbEntry().track(trackIndex - 1).get(KCDDB::Title).toString().isEmpty()) {
0289         emit newSubTask(i18n("Ripping track %1 (%2 - %3)",
0290                         trackIndex,
0291                         cddbEntry().track(trackIndex - 1).get(KCDDB::Artist).toString(),
0292                         cddbEntry().track(trackIndex - 1).get(KCDDB::Title).toString().trimmed()));
0293     } else
0294         emit newSubTask(i18n("Ripping track %1", trackIndex));
0295 }
0296 
0297 
0298 void AudioRipJob::trackFinished( int trackIndex, const QString& filename )
0299 {
0300     emit infoMessage( i18n("Successfully ripped track %1 to %2.", trackIndex, filename), Job::MessageInfo );
0301 }
0302 
0303 
0304 } // namespace K3b
0305 
0306 #include "moc_k3baudioripjob.cpp"