/* * * $Id: k3btocfilewriter.cpp 619556 2007-01-03 17:38:12Z trueg $ * Copyright (C) 2004 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 "k3btocfilewriter.h" #include #include #include #include #include #include #include K3bTocFileWriter::K3bTocFileWriter() : m_hideFirstTrack(false), m_sessionToWrite(1) { } bool K3bTocFileWriter::save( const TQString& filename ) { TQFile f( filename ); if( !f.open( IO_WriteOnly ) ) { kdDebug() << "(K3bCueFileWriter) could not open file " << f.name() << endl; return false; } TQTextStream s( &f ); return save( s ); } bool K3bTocFileWriter::save( TQTextStream& t ) { writeHeader(t); if( !m_cdText.isEmpty() ) writeGlobalCdText(t); // // see if we have multiple sessions // int sessions = 1; for( K3bDevice::Toc::iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { if( (*it).session() > 1 ) sessions = (*it).session(); } if( m_sessionToWrite > sessions ) m_sessionToWrite = 1; // // We can only hide the first track if both the first and the second track are // audio tracks. // We also can only hide the first track in the first session. // bool hideFirstTrack = m_hideFirstTrack; if( m_toc.count() < 2 || m_toc[0].type() != K3bDevice::Track::AUDIO || m_toc[1].type() != K3bDevice::Track::AUDIO || (sessions > 1 && m_sessionToWrite != 1 ) ) hideFirstTrack = false; // the dataStart will be the offset in case we do not write the first session K3b::Msf dataStart; unsigned int trackIndex = 0; if( hideFirstTrack ) { const K3bDevice::Track& hiddenTrack = m_toc[0]; const K3bDevice::Track& track = m_toc[1]; t << "// Track number 1 (hidden) and track number 2 (as track 1)" << endl; t << "TRACK AUDIO" << endl; if( track.copyPermitted() ) t << "COPY" << endl; else t << "NO COPY" << endl; if( track.preEmphasis() ) t << "PRE_EMPHASIS" << endl; else t << "NO PRE_EMPHASIS" << endl; if( !m_cdText.isEmpty() ) writeTrackCdText( m_cdText[0], t ); // the "hidden" file will be used as pregap for the "first" track t << "AUDIOFILE "; writeDataSource( 0, t ); if( readFromStdin() ) t << hiddenTrack.firstSector().toString(); else t << " 0"; t << " " << hiddenTrack.length().toString() << endl; t << "START" << endl; // use the whole hidden file as pregap // now comes the "real" first track t << "AUDIOFILE "; writeDataSource( 1, t ); if( readFromStdin() ) t << track.firstSector().toString() << " "; else t << "0 "; // no index 0 for the last track. Or should we allow this??? if( m_toc.count() == 2 ) t << track.length().toString(); else t << track.realAudioLength().toString(); t << endl << endl; trackIndex+=2; } else { // // Seek to the first track to write. // In case we hid the first track above it was the first track anyway. // while( m_toc[trackIndex].session() < m_sessionToWrite && m_toc[trackIndex].session() > 0 ) ++trackIndex; dataStart = m_toc[trackIndex].firstSector(); } kdDebug() << "(K3bTocFileWriter) using offset of: " << dataStart.toString() << endl; while( trackIndex < m_toc.count() ) { if( m_toc[trackIndex].session() == 0 || m_toc[trackIndex].session() == m_sessionToWrite ) writeTrack( trackIndex, dataStart, t ); trackIndex++; } return ( t.tqdevice()->status() == IO_Ok ); } void K3bTocFileWriter::writeHeader( TQTextStream& t ) { // little comment t << "// TOC-file to use with cdrdao created by K3b " << k3bcore->version() << ", " << TQDateTime::tqcurrentDateTime().toString() << endl << endl; t << "// " << m_toc.count() << " tracks" << endl; if( m_toc.back().session() > 0 ) { t << "// " << m_toc.back().session() << " sessions" << endl << "// this is session number " << m_sessionToWrite << endl; } t << endl; // check the cd type if( m_toc.contentType() == K3bDevice::AUDIO ) { t << "CD_DA"; } else { bool hasMode2Tracks = false; for( K3bDevice::Toc::iterator it = m_toc.begin(); it != m_toc.end(); ++it ) { const K3bDevice::Track& track = *it; if( track.type() == K3bDevice::Track::DATA && (track.mode() == K3bDevice::Track::MODE2 || track.mode() == K3bDevice::Track::XA_FORM1 || track.mode() == K3bDevice::Track::XA_FORM2 ) ) { hasMode2Tracks = true; break; } } if( hasMode2Tracks ) t << "CD_ROM_XA"; else t << "CD_ROM"; } t << endl << endl; } void K3bTocFileWriter::writeTrack( unsigned int index, const K3b::Msf& offset, TQTextStream& t ) { const K3bDevice::Track& track = m_toc[index]; t << "// Track number " << (index+1) << endl; if( track.type() == K3bDevice::Track::AUDIO ) { t << "TRACK AUDIO" << endl; if( track.copyPermitted() ) t << "COPY" << endl; else t << "NO COPY" << endl; if( track.preEmphasis() ) t << "PRE_EMPHASIS" << endl; else t << "NO PRE_EMPHASIS" << endl; if( !m_cdText.isEmpty() ) writeTrackCdText( m_cdText[index], t ); // // cdrdao sees the pregap as part of the current track and not as part of // the previous like it really is. // if( index == 0 ) { if( (track.firstSector()-offset) > 0 ) { // // the first track is the only track K3b does not generate null-pregap data for // since cdrecord does not allow this. So We just do it here the same way and tell // cdrdao to create the first pregap for us // t << "PREGAP " << (track.firstSector()-offset).toString() << endl; } } else { const K3bDevice::Track& lastTrack = m_toc[index-1]; // // the pregap data // if( lastTrack.index0() > 0 ) { t << "AUDIOFILE "; writeDataSource( index-1, t ); if( readFromStdin() ) t << (lastTrack.firstSector() + lastTrack.index0() - offset).toString(); else t << (lastTrack.index0() - offset).toString(); t << " " << (lastTrack.length() - lastTrack.index0()).toString() << endl << "START" << endl; } } // // The track data // t << "AUDIOFILE "; writeDataSource( index, t ); if( readFromStdin() ) t << (track.firstSector() - offset).toString() << " "; else t << "0 "; // no index 0 for the last track. Or should we allow this??? if( index == m_toc.count()-1 ) t << track.length().toString(); else t << track.realAudioLength().toString(); t << endl; } else { if( track.mode() == K3bDevice::Track::XA_FORM1 ) t << "TRACK MODE2_FORM1" << endl; else if( track.mode() == K3bDevice::Track::XA_FORM2 ) t << "TRACK MODE2_FORM2" << endl; else t << "TRACK MODE1" << endl; if( !m_cdText.isEmpty() && !m_toc.contentType() != K3bDevice::DATA ) { // // insert fake cdtext // cdrdao does not work without it and it seems not to do any harm. // t << "CD_TEXT {" << endl << " LANGUAGE 0 {" << endl << " TITLE " << "\"\"" << endl << " PERFORMER " << "\"\"" << endl << " ISRC " << "\"\"" << endl << " ARRANGER " << "\"\"" << endl << " SONGWRITER " << "\"\"" << endl << " COMPOSER " << "\"\"" << endl << " MESSAGE " << "\"\"" << endl << " }" << endl << "}" << endl; } if( readFromStdin() ) t << "DATAFILE \"-\" " << track.length().toString() << endl; else t << "DATAFILE \"" << m_filenames[index] << "\"" << endl; t << endl; } t << endl; } void K3bTocFileWriter::writeGlobalCdText( TQTextStream& t ) { t << "CD_TEXT {" << endl; t << " LANGUAGE_MAP { 0: EN }" << endl; t << " LANGUAGE 0 {" << endl; t << " TITLE " << "\"" << m_cdText.title() << "\"" << endl; t << " PERFORMER " << "\"" << m_cdText.performer() << "\"" << endl; t << " DISC_ID " << "\"" << m_cdText.discId() << "\"" << endl; t << " UPC_EAN " << "\"" << m_cdText.upcEan() << "\"" << endl; t << endl; t << " ARRANGER " << "\"" << m_cdText.arranger() << "\"" << endl; t << " SONGWRITER " << "\"" << m_cdText.songwriter() << "\"" << endl; t << " COMPOSER " << "\"" << m_cdText.composer() << "\"" << endl; t << " MESSAGE " << "\"" << m_cdText.message() << "\"" << endl; t << " }" << endl; t << "}" << endl; t << endl; } void K3bTocFileWriter::writeTrackCdText( const K3bDevice::TrackCdText& track, TQTextStream& t ) { t << "CD_TEXT {" << endl; t << " LANGUAGE 0 {" << endl; t << " TITLE " << "\"" << track.title() << "\"" << endl; t << " PERFORMER " << "\"" << track.performer() << "\"" << endl; t << " ISRC " << "\"" << track.isrc() << "\"" << endl; t << " ARRANGER " << "\"" << track.arranger() << "\"" << endl; t << " SONGWRITER " << "\"" << track.songwriter() << "\"" << endl; t << " COMPOSER " << "\"" << track.composer() << "\"" << endl; t << " MESSAGE " << "\"" << track.message() << "\"" << endl; t << " }" << endl; t << "}" << endl; } void K3bTocFileWriter::writeDataSource( unsigned int trackIndex, TQTextStream& t ) { if( readFromStdin() ) t << "\"-\" "; else t << "\"" << m_filenames[trackIndex] << "\" "; } bool K3bTocFileWriter::readFromStdin() const { return ( m_toc.count() > m_filenames.count() ); }