File indexing completed on 2024-05-12 04:50:59
0001 /* 0002 SPDX-FileCopyrightText: 2005-2008 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2010 Michal Malek <michalm@jabster.pl> 0004 SPDX-FileCopyrightText: 1998-2010 Sebastian Trueg <trueg@k3b.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "k3baudiocdtrackreader.h" 0010 #include "k3baudiocdtracksource.h" 0011 #include "k3baudiodoc.h" 0012 #include "k3baudiotrack.h" 0013 #include "k3bcdparanoialib.h" 0014 #include "k3bcore.h" 0015 #include "k3bdevice.h" 0016 #include "k3btoc.h" 0017 #include "k3bthreadwidget.h" 0018 #include "k3b_i18n.h" 0019 0020 #include <QDebug> 0021 0022 #ifdef Q_OS_WIN32 0023 #undef S_OK 0024 #endif 0025 0026 namespace K3b { 0027 0028 class AudioCdTrackReader::Private 0029 { 0030 public: 0031 Private( AudioCdTrackSource& s ) 0032 : 0033 source( s ), 0034 initialized( false ), 0035 cdParanoiaLib( 0 ) 0036 { 0037 } 0038 0039 AudioCdTrackSource& source; 0040 bool initialized; 0041 QScopedPointer<CdparanoiaLib> cdParanoiaLib; 0042 0043 bool initParanoia(); 0044 void closeParanoia(); 0045 }; 0046 0047 0048 bool AudioCdTrackReader::Private::initParanoia() 0049 { 0050 if( !initialized ) { 0051 if( !cdParanoiaLib ) 0052 cdParanoiaLib.reset( CdparanoiaLib::create() ); 0053 0054 if( cdParanoiaLib ) { 0055 Device::Device* device = source.searchForAudioCD(); 0056 0057 // ask here for the cd since searchForAudioCD() may also be called from outside 0058 if( !device ) { 0059 // could not find the CD, so ask for it 0060 QString s = i18n("Please insert Audio CD %1%2" 0061 ,QString::number(source.discId()), 0062 source.cdTitle().isEmpty() || source.cdArtist().isEmpty() 0063 ? QString() 0064 : " (" + source.cdArtist() + " - " + source.cdTitle() + ')'); 0065 0066 while( Device::Device* dev = ThreadWidget::selectDevice( source.track()->doc()->view(), s ) ) { 0067 if( dev->readToc().discId() == source.discId() ) { 0068 device = dev; 0069 break; 0070 } 0071 } 0072 } 0073 0074 // user canceled 0075 if( !device ) 0076 return false; 0077 0078 source.setDevice( device ); 0079 k3bcore->blockDevice( device ); 0080 0081 if( source.toc().isEmpty() ) 0082 source.setToc( device->readToc() ); 0083 0084 if( !cdParanoiaLib->initParanoia( device, source.toc() ) ) { 0085 k3bcore->unblockDevice( device ); 0086 return false; 0087 } 0088 0089 if( source.doc() ) { 0090 cdParanoiaLib->setParanoiaMode( source.doc()->audioRippingParanoiaMode() ); 0091 cdParanoiaLib->setNeverSkip( !source.doc()->audioRippingIgnoreReadErrors() ); 0092 cdParanoiaLib->setMaxRetries( source.doc()->audioRippingRetries() ); 0093 } 0094 0095 const int start = source.toc()[source.cdTrackNumber()-1].firstSector().lba(); 0096 cdParanoiaLib->initReading( start + source.startOffset().lba(), 0097 start + source.lastSector().lba() ); 0098 0099 // we only block during the initialization because we cannot determine the end of the reading process :( 0100 k3bcore->unblockDevice( device ); 0101 0102 initialized = true; 0103 qDebug() << "cdParanoia initialized"; 0104 } 0105 } 0106 0107 return initialized; 0108 } 0109 0110 0111 void AudioCdTrackReader::Private::closeParanoia() 0112 { 0113 if( cdParanoiaLib && initialized ) { 0114 cdParanoiaLib->close(); 0115 } 0116 initialized = false; 0117 } 0118 0119 0120 AudioCdTrackReader::AudioCdTrackReader( AudioCdTrackSource& source, QObject* parent ) 0121 : QIODevice( parent ), 0122 d( new Private( source ) ) 0123 { 0124 } 0125 0126 0127 AudioCdTrackReader::~AudioCdTrackReader() 0128 { 0129 close(); 0130 } 0131 0132 0133 bool AudioCdTrackReader::open( QIODevice::OpenMode mode ) 0134 { 0135 if( !mode.testFlag( QIODevice::WriteOnly ) && 0136 d->initParanoia() ) { 0137 return QIODevice::open( mode ); 0138 } 0139 else { 0140 return false; 0141 } 0142 } 0143 0144 0145 void AudioCdTrackReader::close() 0146 { 0147 d->closeParanoia(); 0148 QIODevice::close(); 0149 } 0150 0151 0152 qint64 AudioCdTrackReader::writeData( const char* /*data*/, qint64 /*len*/ ) 0153 { 0154 return -1; 0155 } 0156 0157 0158 qint64 AudioCdTrackReader::readData( char* data, qint64 /*maxlen*/ ) 0159 { 0160 if( d->cdParanoiaLib && d->initialized ) { 0161 int status = 0; 0162 char* buf = d->cdParanoiaLib->read( &status, 0, false /* big endian */ ); 0163 if( status == CdparanoiaLib::S_OK ) { 0164 if( buf == 0 ) { 0165 // done 0166 d->closeParanoia(); 0167 return -1; 0168 } 0169 else { 0170 ::memcpy( data, buf, CD_FRAMESIZE_RAW ); 0171 return CD_FRAMESIZE_RAW; 0172 } 0173 } 0174 else { 0175 return -1; 0176 } 0177 } 0178 return -1; 0179 } 0180 0181 0182 bool AudioCdTrackReader::isSequential() const 0183 { 0184 return false; 0185 } 0186 0187 0188 qint64 AudioCdTrackReader::size() const 0189 { 0190 return d->source.length().audioBytes(); 0191 } 0192 0193 0194 bool AudioCdTrackReader::seek( qint64 pos ) 0195 { 0196 if( d->cdParanoiaLib && d->initialized ) { 0197 Msf msfPos = Msf::fromAudioBytes( pos ); 0198 const int start = d->source.toc()[d->source.cdTrackNumber()-1].firstSector().lba(); 0199 d->cdParanoiaLib->initReading( start + d->source.startOffset().lba() + msfPos.lba(), 0200 start + d->source.lastSector().lba() ); 0201 return QIODevice::seek( pos ); 0202 } 0203 else { 0204 return false; 0205 } 0206 } 0207 0208 } // namespace K3b