/* * * $Id: k3baudiocdtracksource.cpp 676194 2007-06-16 08:59:19Z trueg $ * Copyright (C) 2005 Sebastian Trueg * * This file is part of the K3b project. * Copyright (C) 1998-2007 Sebastian Trueg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * See the file "COPYING" for the exact licensing terms. */ #include "k3baudiocdtracksource.h" #include "k3baudiotrack.h" #include "k3baudiodoc.h" #include #include #include #include #include #include #include #include #include K3bAudioCdTrackSource::K3bAudioCdTrackSource( const K3bDevice::Toc& toc, int cdTrackNumber, const K3bCddbResultEntry& cddb, K3bDevice::Device* dev ) : K3bAudioDataSource(), m_discId( toc.discId() ), m_length( toc[cdTrackNumber-1].length() ), m_toc( toc ), m_cdTrackNumber( cdTrackNumber ), m_cddbEntry( cddb ), m_lastUsedDevice( dev ), m_cdParanoiaLib( 0 ), m_initialized( false ) { } K3bAudioCdTrackSource::K3bAudioCdTrackSource( unsigned int discid, const K3b::Msf& length, int cdTrackNumber, const TQString& artist, const TQString& title, const TQString& cdArtist, const TQString& cdTitle ) : K3bAudioDataSource(), m_discId( discid ), m_length( length ), m_cdTrackNumber( cdTrackNumber ), m_lastUsedDevice( 0 ), m_cdParanoiaLib( 0 ), m_initialized( false ) { for( int i = 1; i < cdTrackNumber; ++i ) { m_cddbEntry.titles.append( TQString() ); m_cddbEntry.artists.append( TQString() ); } m_cddbEntry.titles.append( title ); m_cddbEntry.artists.append( artist ); m_cddbEntry.cdTitle = cdTitle; m_cddbEntry.cdArtist = cdArtist; } K3bAudioCdTrackSource::K3bAudioCdTrackSource( const K3bAudioCdTrackSource& source ) : K3bAudioDataSource( source ), m_discId( source.m_discId ), m_toc( source.m_toc ), m_cdTrackNumber( source.m_cdTrackNumber ), m_cddbEntry( source.m_cddbEntry ), m_lastUsedDevice( source.m_lastUsedDevice ), m_cdParanoiaLib( 0 ), m_initialized( false ) { } K3bAudioCdTrackSource::~K3bAudioCdTrackSource() { closeParanoia(); delete m_cdParanoiaLib; } bool K3bAudioCdTrackSource::initParanoia() { if( !m_initialized ) { if( !m_cdParanoiaLib ) m_cdParanoiaLib = K3bCdparanoiaLib::create(); if( m_cdParanoiaLib ) { m_lastUsedDevice = searchForAudioCD(); // ask here for the cd since searchForAudioCD() may also be called from outside if( !m_lastUsedDevice ) { // could not find the CD, so ask for it TQString s = i18n("Please insert Audio CD %1%2") .arg(m_discId, 0, 16) .arg(m_cddbEntry.cdTitle.isEmpty() || m_cddbEntry.cdArtist.isEmpty() ? TQString() : " (" + m_cddbEntry.cdArtist + " - " + m_cddbEntry.cdTitle + ")"); while( K3bDevice::Device* dev = K3bThreadWidget::selectDevice( track()->doc()->view(), s ) ) { if( searchForAudioCD( dev ) ) { m_lastUsedDevice = dev; break; } } } // user canceled if( !m_lastUsedDevice ) return false; k3bcore->blockDevice( m_lastUsedDevice ); if( m_toc.isEmpty() ) m_toc = m_lastUsedDevice->readToc(); if( !m_cdParanoiaLib->initParanoia( m_lastUsedDevice, m_toc ) ) { k3bcore->unblockDevice( m_lastUsedDevice ); return false; } if( doc() ) { m_cdParanoiaLib->setParanoiaMode( doc()->audioRippingParanoiaMode() ); m_cdParanoiaLib->setNeverSkip( !doc()->audioRippingIgnoreReadErrors() ); m_cdParanoiaLib->setMaxRetries( doc()->audioRippingRetries() ); } m_cdParanoiaLib->initReading( m_toc[m_cdTrackNumber-1].firstSector().lba() + startOffset().lba() + m_position.lba(), m_toc[m_cdTrackNumber-1].firstSector().lba() + lastSector().lba() ); // we only block during the initialization because we cannot determine the end of the reading process :( k3bcore->unblockDevice( m_lastUsedDevice ); m_initialized = true; kdDebug() << "(K3bAudioCdTrackSource) initialized." << endl; } } return m_initialized; } void K3bAudioCdTrackSource::closeParanoia() { if( m_cdParanoiaLib && m_initialized ) { m_cdParanoiaLib->close(); } m_initialized = false; } K3bDevice::Device* K3bAudioCdTrackSource::searchForAudioCD() const { kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD()" << endl; // first try the saved device if( m_lastUsedDevice && searchForAudioCD( m_lastUsedDevice ) ) return m_lastUsedDevice; const TQPtrList& devices = k3bcore->deviceManager()->readingDevices(); for( TQPtrListIterator it(devices); *it; ++it ) { if( searchForAudioCD( *it ) ) { return *it; } } kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD) failed." << endl; return 0; } bool K3bAudioCdTrackSource::searchForAudioCD( K3bDevice::Device* dev ) const { kdDebug() << "(K3bAudioCdTrackSource::searchForAudioCD(" << dev->description() << ")" << endl; K3bDevice::Toc toc = dev->readToc(); return ( toc.discId() == m_discId ); } void K3bAudioCdTrackSource::setDevice( K3bDevice::Device* dev ) { if( dev && dev != m_lastUsedDevice ) { m_lastUsedDevice = dev; if( m_initialized ) { } } } K3b::Msf K3bAudioCdTrackSource::originalLength() const { return m_length; } bool K3bAudioCdTrackSource::seek( const K3b::Msf& msf ) { // HACK: to reinitialize every time we restart the decoding if( msf == 0 && m_cdParanoiaLib ) closeParanoia(); m_position = msf; if( m_cdParanoiaLib ) m_cdParanoiaLib->initReading( m_toc[m_cdTrackNumber-1].firstSector().lba() + startOffset().lba() + m_position.lba(), m_toc[m_cdTrackNumber-1].firstSector().lba() + lastSector().lba() ); return true; } int K3bAudioCdTrackSource::read( char* data, unsigned int ) { if( initParanoia() ) { int status = 0; char* buf = m_cdParanoiaLib->read( &status, 0, false /* big endian */ ); if( status == K3bCdparanoiaLib::S_OK ) { if( buf == 0 ) { // done closeParanoia(); return 0; } else { ++m_position; ::memcpy( data, buf, CD_FRAMESIZE_RAW ); return CD_FRAMESIZE_RAW; } } else { // in case the reading fails we go back to "not initialized" closeParanoia(); return -1; } } else return -1; } TQString K3bAudioCdTrackSource::type() const { return i18n("CD Track"); } TQString K3bAudioCdTrackSource::sourceComment() const { return i18n("Track %1 from Audio CD %2").arg(m_cdTrackNumber).arg(m_discId,0,16); } K3bAudioDataSource* K3bAudioCdTrackSource::copy() const { return new K3bAudioCdTrackSource( *this ); }