1 // (c) 2005 Martin Ehmke <ehmke@gmx.de>
2 // License: GNU General Public License V2
4 #define DEBUG_PREFIX "CueFile"
9 #include "enginecontroller.h"
10 #include "metabundle.h"
16 #include <QStringList>
17 #include <QTextStream>
20 CueFile
*CueFile::instance()
22 static CueFile
*s_instance
= 0;
26 s_instance
= new CueFile(EngineController::instance()); // FIXME berkus: le grand borkage (if engine is changed, e.g.)?
34 debug() << "shmack! destructed";
39 + - set and continue in the same state
41 track - switch to new state
44 v PERFORMER TITLE FILE TRACK INDEX PREGAP
46 file x x file track x x
48 index x x file track + x
50 1. Ignore FILE completely.
51 2. INDEX 00 is gap abs position in cue formats we care about (use it to calc length of prev track and then drop on the floor).
52 3. Ignore subsequent INDEX entries (INDEX 02, INDEX 03 etc). - FIXME? this behavior is different from state chart above.
53 4. For a valid cuefile at least TRACK and INDEX are required.
57 TRACK_FOUND
, // track found, index not yet found
63 * @return true if the cuefile could be successfully loaded
65 bool CueFile::load(int mediaLength
)
70 if( QFile::exists( m_cueFileName
) )
72 QFile
file( m_cueFileName
);
74 QString defaultArtist
= QString();
75 QString defaultAlbum
= QString();
76 QString artist
= QString();
77 QString title
= QString();
80 bool index00Present
= false;
84 if( file
.open( QIODevice::ReadOnly
) )
86 QTextStream
stream( &file
);
89 while ( !stream
.atEnd() )
91 line
= stream
.readLine().simplified();
93 if( line
.startsWith( "title", Qt::CaseInsensitive
) )
95 title
= line
.mid( 6 ).remove( '"' );
100 debug() << "Album: " << defaultAlbum
;
103 debug() << "Title: " << title
;
106 else if( line
.startsWith( "performer", Qt::CaseInsensitive
))
108 artist
= line
.mid( 10 ).remove( '"' );
111 defaultArtist
= artist
;
113 debug() << "Album Artist: " << defaultArtist
;
116 debug() << "Artist: " << artist
;
119 else if( line
.startsWith( "track", Qt::CaseInsensitive
) )
121 if( mode
== TRACK_FOUND
)
123 // not valid, because we have to have an index for the previous track
125 debug() << "Mode is TRACK_FOUND, abort.";
128 if( mode
== INDEX_FOUND
)
131 artist
= defaultArtist
;
133 debug() << "Inserting item: " << title
<< " - " << artist
<< " on " << defaultAlbum
<< " (" << track
<< ")";
134 // add previous entry to map
135 insert( index
, CueFileItem( title
, artist
, defaultAlbum
, track
, index
) );
141 track
= line
.section (' ',1,1).toInt();
142 debug() << "Track: " << track
;
145 else if( line
.startsWith( "index", Qt::CaseInsensitive
) )
147 if( mode
== TRACK_FOUND
)
149 int indexNo
= line
.section(' ',1,1).toInt();
153 QString splitMe
= line
.section( ' ', -1, -1 );
154 QStringList time
= splitMe
.split( ":", QString::SkipEmptyParts
);
156 index
= time
[0].toLong()*60*1000 + time
[1].toLong()*1000 + time
[2].toLong()*1000/75; //75 frames per second
158 if( prevIndex
!= -1 && !index00Present
) // set the prev track's length if there is INDEX01 present, but no INDEX00
160 length
= index
- prevIndex
;
161 debug() << "Setting length of track " << (*this)[prevIndex
].getTitle() << " to " << length
<< " msecs.";
162 (*this)[prevIndex
].setLength(length
);
165 index00Present
= false;
170 else if( indexNo
== 0 ) // gap, use to calc prev track length
172 QString splitMe
= line
.section( ' ', -1, -1 );
173 QStringList time
= splitMe
.split( ":", QString::SkipEmptyParts
);
175 length
= time
[0].toLong()*60*1000 + time
[1].toLong()*1000 + time
[2].toLong()*1000/75; //75 frames per second
177 if( prevIndex
!= -1 )
179 length
-= prevIndex
; //this[prevIndex].getIndex();
180 debug() << "Setting length of track " << (*this)[prevIndex
].getTitle() << " to " << length
<< " msecs.";
181 (*this)[prevIndex
].setLength(length
);
182 index00Present
= true;
189 debug() << "Skipping unsupported INDEX " << indexNo
;
194 // not valid, because we don't have an associated track
196 debug() << "Mode is not TRACK_FOUND but encountered INDEX, abort.";
199 debug() << "index: " << index
;
204 artist
= defaultArtist
;
206 debug() << "Inserting item: " << title
<< " - " << artist
<< " on " << defaultAlbum
<< " (" << track
<< ")";
207 // add previous entry to map
208 insert( index
, CueFileItem( title
, artist
, defaultAlbum
, track
, index
) );
213 * Because there is no way to set the length for the last track in a normal way,
214 * we have to do some magic here. Having the total length of the media file given
215 * we can set the lenth for the last track after all the cue file was loaded into array.
218 (*this)[index
].setLength(mediaLength
*1000 - index
);
219 debug() << "Setting length of track " << (*this)[index
].getTitle() << " to " << mediaLength
*1000 - index
<< " msecs.";
228 void CueFile::engineTrackPositionChanged( long position
, bool userSeek
)
230 Q_UNUSED( position
); Q_UNUSED( userSeek
);
231 //TODO: port 2.0 reimplement this
233 if(userSeek || position > m_lastSeekPos)
235 CueFile::Iterator it = end();
236 while( it != begin() )
239 // debug() << "Checking " << position << " against pos " << it.key()/1000 << " title " << it.data().getTitle();
240 if(it.key()/1000 <= position)
242 MetaBundle bundle = EngineController::instance()->bundle(); // take current one and modify it
243 if(it.data().getTitle() != bundle.title()
244 || it.data().getArtist() != bundle.artist()
245 || it.data().getAlbum() != bundle.album()
246 || it.data().getTrackNumber() != bundle.track())
248 bundle.setTitle(it.data().getTitle());
249 bundle.setArtist(it.data().getArtist());
250 bundle.setAlbum(it.data().getAlbum());
251 bundle.setTrack(it.data().getTrackNumber());
252 emit metaData(bundle);
254 long length = it.data().getLength();
255 if ( length == -1 ) // need to calculate
258 long nextKey = it == end() ? bundle.length() * 1000 : it.key();
260 length = qMax( nextKey - it.key(), 0L );
262 emit newCuePoint( position, it.key() / 1000, ( it.key() + length ) / 1000 );
269 m_lastSeekPos = position;*/
273 #include "cuefile.moc"