/* * paranoia.cpp * * Copyright (C) 2002-2006 Christophe Thommeret * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "paranoia.h" #include "paranoia.moc" #define DEFAULT_DRIVE "/dev/cdrom" KiloConfig::KiloConfig( TQWidget *parent, TDEConfig *confile, const TQStringList &encoders ) : ParanoiaSettings( parent ) { int i; TDEIconLoader *icon = new TDEIconLoader(); okBtn->setGuiItem( KGuiItem(i18n("OK"), icon->loadIconSet("ok", TDEIcon::Small) ) ); cancelBtn->setGuiItem( KGuiItem(i18n("Cancel"), icon->loadIconSet("cancel", TDEIcon::Small) ) ); baseDirBtn->setIconSet( icon->loadIconSet("document-open", TDEIcon::Small) ); delete icon; connect( baseDirBtn, TQ_SIGNAL( clicked() ), this, TQ_SLOT( setBaseDir() ) ); Conf = confile; Conf->setGroup( "Paranoia" ); baseDirLineEdit->setText( Conf->readEntry( "Basedir", TQDir::homeDirPath() ) ); paranoiaGroup->setButton( Conf->readNumEntry( "Mode", 0 ) ); normCb->setChecked( Conf->readBoolEntry( "Normalize", false ) ); encoderComb->insertStringList( encoders ); TQString s = Conf->readEntry( "CurrentEncoder", "" ); if ( !s.isEmpty() ) { for ( i=0; i<(int)encoders.count(); i++ ) { if ( encoders[i]==s ) { encoderComb->setCurrentText( s ); } } } } void KiloConfig::setBaseDir() { Conf->setGroup( "Paranoia" ); TQString d = Conf->readEntry( "Basedir", TQDir::homeDirPath() ); TQString u = KFileDialog::getExistingDirectory( d ); if ( u!="" ) { baseDirLineEdit->setText( u ); Conf->writeEntry( "Basedir", u ); } } TQString KiloConfig::getEncoder() { return encoderComb->currentText(); } bool KiloConfig::getNormalize() { return normCb->isChecked(); } TQString KiloConfig::getBaseDir() { return baseDirLineEdit->text().stripWhiteSpace(); } int KiloConfig::getParanoiaMode() { return paranoiaGroup->selectedId(); } void KiloConfig::accept() { Conf->setGroup( "Paranoia" ); Conf->writeEntry( "Mode", paranoiaGroup->id( paranoiaGroup->selected() ) ); Conf->writeEntry( "CurrentEncoder", encoderComb->currentText() ); Conf->writeEntry( "Normalize", normCb->isChecked() ); done(Accepted); } KiloConfig::~KiloConfig() { } void paranoiaCallback( long int, paranoia_cb_mode_t ) { } Paranoia::Paranoia() { d = 0; p = 0; isRunning = false; } bool Paranoia::init( TQString dev ) { TQString s; TQFile f; if ( p!=0 ) paranoia_free( p ); if (d!=0 ) cdda_close( d ); nTracks = 0; dev = dev.stripWhiteSpace(); f.setName( dev ); if ( !f.exists() ) { /*if ( !findCdrom() ) { d = cdda_find_a_cdrom( CDDA_MESSAGE_PRINTIT, 0 ); if ( cdda_open( d )!=0 ) return false; }*/ return false; } else { d = cdda_identify( dev.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); if ( cdda_open( d )!=0 ) return false; } p = paranoia_init( d ); nTracks = cdda_tracks( d ); return true; } bool Paranoia::findCdrom() { TQFile *f; TQString c; TQString s=""; int pos, i; bool stop=false; char dev[4][4]={"","","",""}; f = new TQFile( "/proc/sys/dev/cdrom/info" ); if ( !f->open(IO_ReadOnly) ) return false; TQTextStream t( f ); while ( !t.eof() && !stop ) { s = t.readLine(); if ( s.contains("drive name:") ) stop = true; } if ( !stop ) return false; pos = s.find(":"); c = s.right( s.length()-pos-1 ); sscanf( c.latin1(), "%s %s %s %s", dev[0], dev[1], dev[2], dev[3] ); for ( i=0; i<4; i++ ) if ( procCdrom( dev[i] ) ) return true; f->close(); return false; } bool Paranoia::procCdrom( TQString name ) { int pos; if ( name.contains("sr") ) { pos = name.find("r"); name = name.right( name.length()-pos-1 ); name = "/dev/scd"+name; d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); if ( cdda_open( d )==0 ) return true; } else if ( name.contains("hd") ) { name = "/dev/"+name; d = cdda_identify( name.ascii(), CDDA_MESSAGE_PRINTIT, 0 ); if ( cdda_open( d )==0 ) return true; } return false; } void Paranoia::setMode( int mode ) { switch ( mode ) { case 0 : mode = PARANOIA_MODE_DISABLE; break; case 1 : mode = PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP; break; case 2 : mode = PARANOIA_MODE_FULL; } paranoia_modeset( p, mode ); } bool Paranoia::encode( const TQStringList &list, TQWidget *parent ) { TQStringList desktop; TQStringList encoderName; encodingList.clear(); encodingList = list; myParent = parent; // check for encoders TDETrader::OfferList offers = TDETrader::self()->query("KaffeineAudioEncoder"); TDETrader::OfferList::Iterator end(offers.end()); for(TDETrader::OfferList::Iterator it = offers.begin(); it != end; ++it) { KService::Ptr ptr = (*it); desktop.append( ptr->desktopEntryName() ); encoderName.append( ptr->name() ); } if ( !encoderName.count() ) { KMessageBox::error( myParent, i18n("No audio encoders could be found."), i18n("Warning") ); return false; } KiloConfig dlg( myParent, TDEGlobal::config(), encoderName ); int ret = dlg.exec(); if ( ret!=TQDialog::Accepted ) return false; normalize = dlg.getNormalize(); baseDir = dlg.getBaseDir(); paraMode = dlg.getParanoiaMode(); TQString s = dlg.getEncoder(); for ( ret=0; ret<(int)encoderName.count(); ++ret ) { if ( encoderName[ret]==s ) { encoderDesktop = desktop[ret]; break; } } if ( !loadEncoder( myParent ) ) return false; if ( !currentEncoder->options( myParent, TDEGlobal::config() ) ) { unloadEncoder(); return false; } if ( !setPath( baseDir, TQString(encodingList[0]).replace("/","_"), TQString(encodingList[1]).replace("/","_") ) ) { return false; } isRunning = true; start(); return true; } bool Paranoia::loadEncoder( TQWidget *parent ) { int error = 0; KService::Ptr service = KService::serviceByDesktopName( encoderDesktop ); if (!service) { KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) ); return false; } if ( service->serviceTypes().contains("KaffeineAudioEncoder") ) { currentEncoder = KParts::ComponentFactory::createPartInstanceFromService(service, 0, service->name().ascii(), 0, 0, 0, &error); if (error > 0) { KMessageBox::error( parent, i18n("Loading of encoder '%1' failed.").arg(encoderDesktop) ); return false; } else return true; } else return false; } void Paranoia::unloadEncoder() { //kdDebug()<<"Unload encoder ..."<unloadLibrary( service->library().ascii() ); //kdDebug()<<"... encoder unloaded."<> 8)); } void Paranoia::run() { signed short *buf; int i, n, len, retlen; long curpos, endpos; TQFile f, fn; float max; float factor; TQString s; char *encoded; int overallSectors=0; int sectorCount=0; progress = 0; sleep(2); // give some time for the player to be stopped setMode( paraMode ); for ( i=2; i<(int)encodingList.count(); ++i ) { n = encodingList[i].left(2).toInt(); overallSectors+= trackSectorSize( n ); } fn.setName( baseDir+".temp" ); for ( i=2; i<(int)encodingList.count(); ++i ) { n = encodingList[i].left(2).toInt(); s = TQString(encodingList[i]).replace("/","_")+currentEncoder->getExtension(); f.setName( baseDir+s ); initTrack( n ); max = 0; curpos = currentSector; endpos = endOfTrack; if ( normalize ) { len = CDIO_CD_FRAMESIZE_RAW; fn.open( IO_ReadWrite | IO_Truncate ); do { buf = paranoia_read_limited( p, paranoiaCallback, 3 ); if ( TQ_BYTE_ORDER == TQ_BIG_ENDIAN ) { for ( i=0; i0 ) { for ( n=0; nmax ) max = fabs(buf[n]); fn.writeBlock( (char*)buf, len ); ++sectorCount; progress = sectorCount*50/overallSectors; } if ( !isRunning ) len=0; } while ( curposstart( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) ); encoded = currentEncoder->getHeader( len ); if ( encoded ) f.writeBlock( encoded, len ); do { len = fn.readBlock( (char*)buf, CDIO_CD_FRAMESIZE_RAW ); if ( len>0 ) { if ( max<32760 ) for ( n=0; nencode( (char*)buf, len, retlen ); if ( encoded ) f.writeBlock( encoded, retlen ); ++sectorCount; progress = sectorCount*50/overallSectors; if ( !isRunning ) len=0; } } while ( len>0 ); encoded = currentEncoder->stop( len ); if ( encoded ) f.writeBlock( encoded, len ); delete [] buf; fn.remove(); } else { f.open( IO_ReadWrite | IO_Truncate ); currentEncoder->start( encodingList[i].remove(0,3), encodingList[0], encodingList[1], encodingList[i].left(2) ); encoded = currentEncoder->getHeader( len ); if ( encoded ) f.writeBlock( encoded, len ); len = CDIO_CD_FRAMESIZE_RAW; do { buf = paranoia_read_limited( p, paranoiaCallback, 3 ); if ( TQ_BYTE_ORDER == TQ_BIG_ENDIAN ) { for ( i=0; i0 ) { encoded = currentEncoder->encode( (char*)buf, len, retlen ); if ( encoded ) f.writeBlock( encoded, retlen ); ++sectorCount; progress = sectorCount*100/overallSectors; } if ( !isRunning ) len=0; } while ( curposstop( len ); if ( encoded ) f.writeBlock( encoded, len ); sleep(1); // cdparanoia seems to like that. } f.flush(); f.close(); } unloadEncoder(); isRunning = false; } int Paranoia::trackFirstSector( int t ) { return cdda_track_firstsector( d, t ); } int Paranoia::discFirstSector() { return cdda_disc_firstsector( d ); } int Paranoia::discLastSector() { return cdda_disc_lastsector( d ); } bool Paranoia::isAudio( int t ) { if ( cdda_track_audiop( d, t+1 ) ) return true; else return false; } TQString Paranoia::trackSize( int t ) { TQString s, c; long total; total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); if ( total>(1048576 ) ) s = c.setNum(total/1048576.0, 'f', 2)+" "+i18n("MB"); else if ( total>1024 ) s = c.setNum(total/1024.0, 'f', 2)+" "+i18n("KB"); else s = c.setNum(total*1.0, 'f', 2)+" "+i18n("Bytes"); return s; } long Paranoia::trackSectorSize( int t ) { return cdda_track_lastsector( d, t )-cdda_track_firstsector( d, t ); } TQString Paranoia::trackTime( int t ) { TQString c; long total, time; int m, s; if ( t<0 ) total = CDIO_CD_FRAMESIZE_RAW * (cdda_disc_lastsector( d )-cdda_disc_firstsector( d ) ); else total = CDIO_CD_FRAMESIZE_RAW * (cdda_track_lastsector( d, t+1 )-cdda_track_firstsector( d, t+1 ) ); time = (8 * total) / (44100 * 2 * 16); m = time/60; s = time%60; c.sprintf( "%.2i:%.2i", m, s ); return c; } Paranoia::~Paranoia() { if ( p!=0 ) paranoia_free( p ); if (d!=0 ) cdda_close( d ); } long Paranoia::getTracks() { return nTracks; }