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"