/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * Copyright (C) 2002 by Dave Chapman * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ /* Cue file example 1 - From a CD ripped using Exact Audio Copy PERFORMER "Blur" TITLE "Parklife" FILE "D:\Range.wav" WAVE TRACK 01 AUDIO TITLE "Girls & Boys" PERFORMER "Blur" INDEX 00 00:00:00 INDEX 01 00:00:33 TRACK 02 AUDIO TITLE "Tracy Jacks" PERFORMER "Blur" INDEX 00 04:49:01 INDEX 01 04:51:23 Example 2 - from "xmcd2cue" documentation, a program to convert cddb entries to cue files. TITLE "Pulse CD2" PERFORMER "Pink Floyd" REM Total length: 01:11:47 REM ID: d510d10d FILE "d510d10d.mp3" MP3 TRACK 01 AUDIO TITLE "The Dark Side of the Moon: Speak To Me" PREGAP 00:02:00 INDEX 01 00:00:00 TRACK 02 AUDIO TITLE "Breathe" INDEX 01 02:27:64 TRACK 03 AUDIO TITLE "On the Run" INDEX 01 05:01:16 Strategy: 1) The cue file is completely read into memory (maximum size of buffer is defined as MAX_CUEFILE_SIZE in applimits.h) 2) The memory buffer is parsed to extract TITLE/PERFORMER for the entire file, and TITLE/PERFORMER/INDEX for each of the tracks. The TITLE/PERFORMER strings are stored as offsets into this buffer, and the closing " character is replaced with zero in the buffer (to create proper C strings). With a MAX_CUEFILE_SIZE of 8192 bytes, and a MAX_TRACKS_IN_CUEFILE of 99 (the limit for an audio CD), the cuefile structure takes 9386 bytes of RAM. */ #include #include #include #ifdef DEBUG_STANDALONE #include #else #include #endif #include "cuefile.h" /* Read a cue file from disk to memory and then parse it */ #ifdef DEBUG_STANDALONE int lines; #endif int read_cuefile(struct cuefile_t* cuefile, char* mp3filename) { int fd; int nread; int i; int m,s,f; memcpy(cuefile->filename,mp3filename,MAX_PATH); i=strlen(cuefile->filename); if (i > 4) { cuefile->filename[i-3]='c'; cuefile->filename[i-2]='u'; cuefile->filename[i-1]='e'; } else { return -1; } fd=open(cuefile->filename,O_RDONLY); if(fd < 0) { return -1; } else { nread=read(fd,cuefile->buf,8192); close(fd); /* Make sure the buffer ends with a zero - it makes parsing simpler */ if (nread==8192) { nread--; } cuefile->buf[nread]=0; cuefile->n=0; cuefile->tracks[0].title_ofs=0; cuefile->tracks[0].performer_ofs=0; cuefile->filesize=nread; #ifdef DEBUG_STANDALONE lines=1; #endif i=0; while(ibuffer in each iteration */ while (cuefile->buf[i]==' ') i++; if (strncasecmp(&cuefile->buf[i],"TRACK ",6)==0) { cuefile->n++; cuefile->tracks[cuefile->n].title_ofs=0; cuefile->tracks[cuefile->n].performer_ofs=0; cuefile->tracks[cuefile->n].track_index_ofs=0; cuefile->tracks[cuefile->n].track_index=-1; } else if (strncasecmp(&cuefile->buf[i],"TITLE \"",7)==0) { i+=7; cuefile->tracks[cuefile->n].title_ofs=i; while((cuefile->buf[i]!='"') && (cuefile->buf[i]>=' ')) i++; if (cuefile->buf[i]!='"') return -1; cuefile->buf[i++]=0; } else if(strncasecmp(&cuefile->buf[i],"PERFORMER \"",11)==0) { i+=11; cuefile->tracks[cuefile->n].performer_ofs=i; while((cuefile->buf[i]!='"') && (cuefile->buf[i]>=' ')) i++; if (cuefile->buf[i]!='"') return -1; cuefile->buf[i++]=0; } else if(strncasecmp(&cuefile->buf[i],"INDEX ",6)==0) { /* We only read the first INDEX for a track */ if (cuefile->tracks[cuefile->n].track_index_ofs==0) { i+=6; while (cuefile->buf[i]==' ') i++; while ((cuefile->buf[i] >= '0') && (cuefile->buf[i]<='9')) i++; while (cuefile->buf[i]==' ') i++; cuefile->tracks[cuefile->n].track_index_ofs=i; m=0; s=0; f=0; while ((cuefile->buf[i] >= '0') && (cuefile->buf[i]<='9')) { m=(m*10)+(cuefile->buf[i]-'0'); i++; } if (cuefile->buf[i]==':') { i++; } else { return -1; } while ((cuefile->buf[i] >= '0') && (cuefile->buf[i]<='9')) { s=(s*10)+(cuefile->buf[i]-'0'); i++; } if (cuefile->buf[i]==':') { i++; while ((cuefile->buf[i] >= '0') && (cuefile->buf[i]<='9')) { f=(f*10)+(cuefile->buf[i]-'0'); i++; } } /* m is minutes, s is seconds, and f is frame number (0-75) */ /* track_index is in milliseconds */ cuefile->tracks[cuefile->n].track_index= ((f*1000)/76)+(s*1000)+(m*60000); /* Sanity check - index n must be greater than index (n-1) */ if (cuefile->n > 1) { if (cuefile->tracks[cuefile->n].track_index <= cuefile->tracks[cuefile->n-1].track_index) { return -1; } } } } /* Skip to end of line */ while ((ibuf[i]!='\n') && (cuefile->buf[i]!='\r')) i++; if ((cuefile->buf[i]=='\n') && (cuefile->buf[i+1]=='\r')) i+=2; else i++; #ifdef DEBUG_STANDALONE lines++; #endif } cuefile->buf[0]=0; } return 0; } void get_next_cue(int elapsed,struct cuefile_t* cuefile, int* next_subtrack) { int i=1; while ((i<=cuefile->n) && (cuefile->tracks[i].track_index < elapsed)) i++; if (i > cuefile->n) { *next_subtrack=-1; } else { *next_subtrack=cuefile->tracks[i].track_index; } } void get_prev_cue(int elapsed,struct cuefile_t* cuefile, int* prev_subtrack) { int i=1; while ((i<=cuefile->n) && (cuefile->tracks[i].track_index < elapsed-3000)) i++; if (i > 1) { *prev_subtrack=cuefile->tracks[i-1].track_index; } else { *prev_subtrack=cuefile->tracks[1].track_index; if (elapsed < *prev_subtrack) *prev_subtrack=0; } } #ifdef DEBUG_STANDALONE int main(int argc, char** argv) { int i,j; struct cuefile_t cuefile; printf("RAM used by cuefile structure: %d\n",sizeof(struct cuefile_t)); printf("argc: %d\n",argc); for (i=1;i