#include "ata.h" #include //internal function to print integers on the LCD void lcd_int(DWRD d); // these have no tight latency requirements and can use the system exclusively void nextTrack() //goto next track { if(cur_mp3>=(mp3count-1)) return; clear(); find_next(); cur_mp3++; disp_file(); } void prevTrack() //goto previous track { if(cur_mp3==0) return; clear(); find_prev(); cur_mp3--; disp_file(); //debug code to print out the sector the track is located at // lcd_gotoxy(0,0); // lcd_int(play_sect); // lcd_putsf(" "); } // these routines below have tight latency requirements void requestNextSector1() //first part of the sector request { disp_file(); if(play_length>=track_length) nextTrack(); ATAPI_prep_sector1(); play_sect++; } BOOL requestNextSector2() //second part of the sector request { return ATAPI_prep_sector2(play_sect); } int fetchSomeData(char * dest) //read a portion of the sector data from the CDROM { //since we can't access external RAM we have to read into the xfer_buf... xfer_data(xfer_buf, DATA_BLOCK_SIZE>>1); //...then transfer to the real destination memcpy(dest, xfer_buf, DATA_BLOCK_SIZE); //debug statements to print out the first bits of the MP3 to check that the right //stuff has been read from the right place // lcd_clear(); // lcd_int(dest[0]); // lcd_putchar('-'); // lcd_int(dest[1]); // lcd_putchar('-'); // lcd_int(dest[2]); // lcd_putchar('-'); // lcd_int(dest[3]); // while(1); play_length += DATA_BLOCK_SIZE; return DATA_BLOCK_SIZE; } // returns # of bytes read BYTE isntmp3() { /* debug statements to print out info from the file table: lcd_clear(); lcd_putchar(sec_buf[cur_offs+sec_buf[cur_offs+32]+20]); lcd_putchar(sec_buf[cur_offs+sec_buf[cur_offs+32]+22]); lcd_putchar(sec_buf[cur_offs+sec_buf[cur_offs+32]+24]); lcd_putchar(sec_buf[cur_offs+sec_buf[cur_offs+32]+26]); lcd_putchar(sec_buf[cur_offs+34]); lcd_putchar(sec_buf[cur_offs+36]); lcd_putchar(sec_buf[cur_offs+38]); lcd_putchar(sec_buf[cur_offs+40]); lcd_putchar(sec_buf[cur_offs+42]); lcd_putchar(sec_buf[cur_offs+44]); lcd_putchar(sec_buf[cur_offs+46]); lcd_putchar(sec_buf[cur_offs+48]); delay_ms(1000); */ //check that this file entry is a file and has the .MP3 extension return ((sec_buf[cur_offs+25]&2) || (sec_buf[cur_offs+sec_buf[cur_offs+32]+28] != '3') || ((sec_buf[cur_offs+sec_buf[cur_offs+32]+26] != 'P') && (sec_buf[cur_offs+sec_buf[cur_offs+32]+26] != 'p')) || ((sec_buf[cur_offs+sec_buf[cur_offs+32]+24] != 'M') && (sec_buf[cur_offs+sec_buf[cur_offs+32]+24] != 'm')) || (sec_buf[cur_offs+sec_buf[cur_offs+32]+22] != '.')); } //print an integer to the LCD void lcd_int(DWRD d) { if(d>9) lcd_int(d/10); lcd_putchar((BYTE)((d%10) + '0')); } //print an integer to the serial port void sio_int(DWRD d) { if(d>9) sio_int(d/10); while(!(USR&32)); UDR = (BYTE)((d%10) + '0'); } //get a sector from the void get_sec(DWRD s) { //if we aren't in CD_REQUEST state, do the follow to get there switch(cd_state) { case CD_WAIT1: while(!requestNextSector2()); case CD_WAIT2: while(!ATAPI_sect_ready()); case CD_READ: while(cd_ctr < BUF_BLOCK_SIZE) cd_ctr += fetchSomeData(buf+producer+cd_ctr); default: } // do { // CDerror = FALSE; ATAPI_prep_sector(s); //prepare the sector ATAPI_wait_for_sect(); //wait for it to come back xfer_data(sec_buf, 1024); //transfer the data // } // while(CDerror); } BYTE find_next() //goto the next sector { DWRD old1; WORD old2; old1 = cur_sect; old2 = cur_offs; // get_sec(cur_sect); do { cur_offs += sec_buf[cur_offs]; //skip file info /* do we need a new sector? */ if((cur_offs >= 2048) || (sec_buf[cur_offs] == 0)) { cur_sect++; if(cur_sect > (root_dir+root_size-1)) { cur_sect = old1; cur_offs = old2; get_sec(cur_sect); return 0; } get_sec(cur_sect); cur_offs = 0; } } while(isntmp3()); sec = 0; play_sect = *(DWRD*)(sec_buf+cur_offs+2); //extract first sector of file play_length = 0; track_length = *(DWRD*)(sec_buf+cur_offs+10); //extract file length scroll = 0; scroll_dir = 0; if((sec_buf[cur_offs+32]-12)<=48) //is the name so long that we need to scroll? scroll_max = 0; else scroll_max = sec_buf[cur_offs+32]-12-48; return 1; } BYTE find_prev() { DWRD old1; WORD old2; WORD last_offs; WORD prev_offs; old1 = cur_sect; old2 = cur_offs; // get_sec(cur_sect); do { /* do we need a new sector? */ while(cur_offs == 0) { if(cur_sect == root_dir) { cur_sect = old1; cur_offs = old2; get_sec(cur_sect); return 0; } cur_sect--; cur_offs = 0; get_sec(cur_sect); last_offs = 0; //find last MP3 while((cur_offs < 2048) && sec_buf[cur_offs]) { if(!isntmp3()) last_offs = cur_offs; cur_offs += sec_buf[cur_offs]; } cur_offs = last_offs; } prev_offs = cur_offs; cur_offs = last_offs = 0; //search back to the MP3 that was just before the last one while(cur_offs != prev_offs) { if(!isntmp3()) last_offs = cur_offs; cur_offs += sec_buf[cur_offs]; } cur_offs = last_offs; } while(isntmp3()); sec = 0; play_sect = *(DWRD*)(sec_buf+cur_offs+2); //extract first sector of file play_length = 0; track_length = *(DWRD*)(sec_buf+cur_offs+10); //extract track length from file scroll = 0; scroll_dir = 0; if((sec_buf[cur_offs+32]-12)<=48) //do we need to scroll the track title? scroll_max = 0; else scroll_max = sec_buf[cur_offs+32]-12-48; return 1; } void disp_file() //display file track name and info { WORD i; lcd_clear(); for(i=0; (i<(sec_buf[cur_offs+32]-12)) && (i<48); i += 2) lcd_putchar(sec_buf[i+cur_offs+34+scroll]); lcd_gotoxy(0,1); lcd_putsf("Track "); lcd_int(cur_mp3+1); lcd_putchar('/'); lcd_int(mp3count); lcd_gotoxy(14,1); lcd_putsf("Time "); lcd_int(sec/2003); lcd_putchar(':'); lcd_putchar((BYTE)('0' + ((sec/334)%6))); lcd_putchar((BYTE)('0' + ((sec*10/334)%10))); } void process_root() { DWRD old1; WORD old2; old1 = cur_sect; old2 = cur_offs; get_sec(cur_sect); //go through finding all MP3 files while(find_next()) mp3count++; //start over cur_sect = old1; cur_offs = old2; get_sec(cur_sect); find_next(); //display MP3 files lcd_clear(); lcd_int(mp3count); lcd_putsf(" MP3 files found"); if(mp3count==0) { lcd_putsf("\nSorry, nothing to play"); while(1); } delay_ms(1000); disp_file(); /* debug routines to go through tracks by button presses while(1) { if((PINF.0==0) && (cur_mp3<(mp3count-1))) { //next track find_next(); cur_mp3++; disp_file(); delay_ms(100); while(PINF.0==0); delay_ms(100); } if((PINF.1==0) && cur_mp3) { //prev track find_prev(); cur_mp3--; disp_file(); delay_ms(100); while(PINF.1==0); delay_ms(100); } } */ } void initCD() { DWRD vol_desc=16; //clear it lcd_clear(); //write a constant string from flash lcd_putsf("MP3 CD SuperJukeBox V1.0"); lcd_putsf(" Reading CD-ROM.. "); ATA_init(); // 012345678901234567890123 do { get_sec(vol_desc); if((sec_buf[88] == 0x25) && (sec_buf[89] == 0x2F) && (sec_buf[40] == 0)) { //printf("JOLIET volume descriptor found at sector %ld\n",vol_desc); root_dir = *(DWRD*)(sec_buf+158); root_size = *(DWRD*)(sec_buf+166); root_size >>= 11; //printf("root dir at sector %ld is %ld sectors long\n", root_dir, root_size); cur_sect = root_dir; cur_offs = 0; //once we find the root, go there and process it process_root(); return; } vol_desc++; } while(sec_buf[0] != 0xFF); lcd_clear(); lcd_putsf("ERROR:\n"); lcd_putsf("JOLIET volume not found"); while(1); }