diff options
| author | Linus Nielsen Feltzing <linus@haxx.se> | 2002-07-26 14:32:24 +0000 |
|---|---|---|
| committer | Linus Nielsen Feltzing <linus@haxx.se> | 2002-07-26 14:32:24 +0000 |
| commit | 42faf56472cbd803d4746d0d0866871c101050df (patch) | |
| tree | 123c638283bd77f67dc375ead34de5c080b4b7e6 | |
| parent | d5d38f120b458182a5c9c0f0b799f8f949376e45 (diff) | |
| download | rockbox-42faf56472cbd803d4746d0d0866871c101050df.zip rockbox-42faf56472cbd803d4746d0d0866871c101050df.tar.gz rockbox-42faf56472cbd803d4746d0d0866871c101050df.tar.bz2 rockbox-42faf56472cbd803d4746d0d0866871c101050df.tar.xz | |
New and improved ID3 and track change handling
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1455 a1c6a512-1295-4272-9138-f99709370657
| -rw-r--r-- | apps/wps.c | 145 | ||||
| -rw-r--r-- | firmware/mpeg.c | 203 |
2 files changed, 232 insertions, 116 deletions
@@ -44,75 +44,88 @@ static void draw_screen(struct mp3entry* id3) { lcd_clear_display(); - switch ( global_settings.wps_display ) { - case PLAY_DISPLAY_TRACK_TITLE: - { - char ch = '/'; - char* end; - char* szTok; - char* szDelimit; - char* szPeriod; - char szArtist[26]; - char szBuff[257]; - szBuff[sizeof(szBuff)-1] = 0; - - strncpy(szBuff, id3->path, sizeof(szBuff)); - - szTok = strtok_r(szBuff, "/", &end); - szTok = strtok_r(NULL, "/", &end); - - // Assume path format of: Genre/Artist/Album/Mp3_file - strncpy(szArtist,szTok,sizeof(szArtist)); - szArtist[sizeof(szArtist)-1] = 0; - szDelimit = strrchr(id3->path, ch); - lcd_puts(0,0, szArtist?szArtist:"<nothing>"); - - // removes the .mp3 from the end of the display buffer - szPeriod = strrchr(szDelimit, '.'); - if (szPeriod != NULL) - *szPeriod = 0; - - lcd_puts_scroll(0,LINE_Y,(++szDelimit)); - break; - } - case PLAY_DISPLAY_FILENAME_SCROLL: - { - char ch = '/'; - char* szLast = strrchr(id3->path, ch); - - if (szLast) - lcd_puts_scroll(0,0, (++szLast)); - else - lcd_puts_scroll(0,0, id3->path); - break; - } - case PLAY_DISPLAY_DEFAULT: - { - int l = 0; + if(!id3) + { +#ifdef HAVE_LCD_CHARCELLS + lcd_puts(0, 0, "End of list"); + lcd_puts(0, 1, "<Press ON>"); +#else + lcd_puts(0, 2, "<End of song list>"); + lcd_puts(5, 4, "Press ON"); +#endif + } + else + { + switch ( global_settings.wps_display ) { + case PLAY_DISPLAY_TRACK_TITLE: + { + char ch = '/'; + char* end; + char* szTok; + char* szDelimit; + char* szPeriod; + char szArtist[26]; + char szBuff[257]; + szBuff[sizeof(szBuff)-1] = 0; + + strncpy(szBuff, id3->path, sizeof(szBuff)); + + szTok = strtok_r(szBuff, "/", &end); + szTok = strtok_r(NULL, "/", &end); + + // Assume path format of: Genre/Artist/Album/Mp3_file + strncpy(szArtist,szTok,sizeof(szArtist)); + szArtist[sizeof(szArtist)-1] = 0; + szDelimit = strrchr(id3->path, ch); + lcd_puts(0,0, szArtist?szArtist:"<nothing>"); + + // removes the .mp3 from the end of the display buffer + szPeriod = strrchr(szDelimit, '.'); + if (szPeriod != NULL) + *szPeriod = 0; + + lcd_puts_scroll(0,LINE_Y,(++szDelimit)); + break; + } + case PLAY_DISPLAY_FILENAME_SCROLL: + { + char ch = '/'; + char* szLast = strrchr(id3->path, ch); + + if (szLast) + lcd_puts_scroll(0,0, (++szLast)); + else + lcd_puts_scroll(0,0, id3->path); + break; + } + case PLAY_DISPLAY_DEFAULT: + { + int l = 0; #ifdef HAVE_LCD_BITMAP - char buffer[64]; + char buffer[64]; - lcd_puts_scroll(0, l++, id3->path); - lcd_puts(0, l++, id3->title?id3->title:""); - lcd_puts(0, l++, id3->album?id3->album:""); - lcd_puts(0, l++, id3->artist?id3->artist:""); + lcd_puts_scroll(0, l++, id3->path); + lcd_puts(0, l++, id3->title?id3->title:""); + lcd_puts(0, l++, id3->album?id3->album:""); + lcd_puts(0, l++, id3->artist?id3->artist:""); - if(id3->vbr) - snprintf(buffer, sizeof(buffer), "%d kbit (avg)", - id3->bitrate); - else - snprintf(buffer, sizeof(buffer), "%d kbit", id3->bitrate); + if(id3->vbr) + snprintf(buffer, sizeof(buffer), "%d kbit (avg)", + id3->bitrate); + else + snprintf(buffer, sizeof(buffer), "%d kbit", id3->bitrate); - lcd_puts(0, l++, buffer); + lcd_puts(0, l++, buffer); - snprintf(buffer,sizeof(buffer), "%d Hz", id3->frequency); - lcd_puts(0, l++, buffer); + snprintf(buffer,sizeof(buffer), "%d Hz", id3->frequency); + lcd_puts(0, l++, buffer); #else - lcd_puts(0, l++, id3->artist?id3->artist:"<no artist>"); - lcd_puts_scroll(0, l++, id3->title?id3->title:"<no title>"); + lcd_puts(0, l++, id3->artist?id3->artist:"<no artist>"); + lcd_puts_scroll(0, l++, id3->title?id3->title:"<no title>"); #endif - break; + break; + } } } status_draw(); @@ -128,6 +141,7 @@ int wps_show(void) bool dont_go_to_menu = false; lcd_clear_display(); + draw_screen(id3); while ( 1 ) { int i; @@ -135,11 +149,12 @@ int wps_show(void) if(mpeg_has_changed_track()) { - lcd_stop_scroll(); + lcd_stop_scroll(); + id3 = mpeg_current_track(); draw_screen(id3); } - if (playing) + if (playing && id3) { #ifdef HAVE_LCD_BITMAP snprintf(buffer,sizeof(buffer), "Time: %d:%02d / %d:%02d", @@ -154,13 +169,12 @@ int wps_show(void) // Display time with the filename scroll only because the screen has room. if (global_settings.wps_display == PLAY_DISPLAY_FILENAME_SCROLL) { - snprintf(buffer,sizeof(buffer), "Time: %d:%02d / %d:%02d", id3->elapsed / 60000, id3->elapsed % 60000 / 1000, id3->length / 60000, id3->length % 60000 / 1000 ); - + lcd_puts(0, 1, buffer); lcd_update(); } @@ -289,6 +303,7 @@ int wps_show(void) { lcd_stop_scroll(); main_menu(); + id3 = mpeg_current_track(); draw_screen(id3); /* Prevent any stray BUTTON_REL events from going back to the main menu until we get a new diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 00b2d66..359db61 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c @@ -23,6 +23,8 @@ #include "id3.h" #include "mpeg.h" #include "ata.h" +#include "malloc.h" +#include "string.h" #ifndef SIMULATOR #include "i2c.h" #include "mas.h" @@ -139,15 +141,93 @@ int mpeg_sound_default(int setting) } /* list of tracks in memory */ -#define MAX_ID3_TAGS 12 -static struct { +#define MAX_ID3_TAGS (1<<4) /* Must be power of 2 */ +#define MAX_ID3_TAGS_MASK (MAX_ID3_TAGS - 1) + +struct id3tag +{ struct mp3entry id3; int mempos; -} id3tags[MAX_ID3_TAGS]; +}; + +static struct id3tag *id3tags[MAX_ID3_TAGS]; + static unsigned int current_track_counter = 0; static unsigned int last_track_counter = 0; #ifndef SIMULATOR + +static int tag_read_idx = 0; +static int tag_write_idx = 0; + +static int num_tracks_in_memory(void) +{ + return (tag_write_idx - tag_read_idx) & MAX_ID3_TAGS_MASK; +} +#endif + +#ifndef SIMULATOR +static void debug_tags(void) +{ +#ifdef DEBUG + int i; + + for(i = 0;i < MAX_ID3_TAGS;i++) + { + DEBUGF("id3tags[%d]: %08x", i, id3tags[i]); + if(id3tags[i]) + DEBUGF(" - %s", id3tags[i]->id3.path); + DEBUGF("\n"); + } + DEBUGF("read: %d, write :%d\n", tag_read_idx, tag_write_idx); + DEBUGF("num_tracks_in_memory: %d\n", num_tracks_in_memory()); +#endif +} + +static bool append_tag(struct id3tag *tag) +{ + if(num_tracks_in_memory() < MAX_ID3_TAGS - 1) + { + id3tags[tag_write_idx] = tag; + tag_write_idx = (tag_write_idx+1) & MAX_ID3_TAGS_MASK; + debug_tags(); + return true; + } + else + { + DEBUGF("Tag memory is full\n"); + return false; + } +} + +static void remove_current_tag(void) +{ + int oldidx = tag_read_idx; + struct id3tag *tag = id3tags[tag_read_idx]; + + if(num_tracks_in_memory() > 0) + { + /* First move the index, so nobody tries to access the tag */ + tag_read_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; + + /* Now delete it */ + id3tags[oldidx] = NULL; + free(tag); + debug_tags(); + } +} + +static void remove_all_tags(void) +{ + int i; + + for(i = 0;i < MAX_ID3_TAGS;i++) + remove_current_tag(); + debug_tags(); +} +#endif + +#ifndef SIMULATOR static int last_tag = 0; static int last_dma_tick = 0; static int pause_tick = 0; @@ -380,7 +460,8 @@ static void dma_tick(void) if(!(SCR0 & 0x80)) start_dma(); } - id3tags[0].id3.elapsed += (current_tick - last_dma_tick) * 1000 / HZ; + id3tags[tag_read_idx]->id3.elapsed += + (current_tick - last_dma_tick) * 1000 / HZ; last_dma_tick = current_tick; } } @@ -412,7 +493,7 @@ void DEI3(void) { int unplayed_space_left; int space_until_end_of_buffer; - int track_offset = 0; + int track_offset = (tag_read_idx+1) & MAX_ID3_TAGS_MASK; if(playing) { @@ -421,12 +502,12 @@ void DEI3(void) mp3buf_read = 0; /* First, check if we are on a track boundary */ - if (last_tag > 1) + if (num_tracks_in_memory() > 0) { - if (mp3buf_read == id3tags[1].mempos) + if (mp3buf_read == id3tags[track_offset]->mempos) { queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); - track_offset = 1; + track_offset = (track_offset+1) & MAX_ID3_TAGS_MASK; } } @@ -449,15 +530,15 @@ void DEI3(void) space_until_end_of_buffer); /* several tracks loaded? */ - if ((last_tag - track_offset) > 1) + if (num_tracks_in_memory() > 1) { /* will we move across the track boundary? */ - if (( mp3buf_read < id3tags[1+track_offset].mempos ) && + if (( mp3buf_read < id3tags[track_offset]->mempos ) && ((mp3buf_read+last_dma_chunk_size) > - id3tags[1+track_offset].mempos )) + id3tags[track_offset]->mempos )) { /* Make sure that we end exactly on the boundary */ - last_dma_chunk_size = id3tags[1+track_offset].mempos + last_dma_chunk_size = id3tags[track_offset]->mempos - mp3buf_read; } } @@ -468,6 +549,7 @@ void DEI3(void) else { DEBUGF("No more MP3 data. Stopping.\n"); + queue_post(&mpeg_queue, MPEG_TRACK_CHANGE, 0); CHCR3 = 0; /* Stop DMA interrupt */ playing = false; } @@ -483,11 +565,34 @@ void IMIA1(void) TSR1 &= ~0x01; } +static void add_track_to_tag_list(char *filename) +{ + struct id3tag *t; + + /* grab id3 tag of new file and + remember where in memory it starts */ + t = malloc(sizeof(struct id3tag)); + if(t) + { + mp3info(&(t->id3), filename); + t->mempos = mp3buf_write; + t->id3.elapsed = 0; + if(!append_tag(t)) + { + free(t); + DEBUGF("Tag list is full\n"); + } + } + else + { + DEBUGF("No memory available for id3 tag"); + } +} + /* If next_track is true, opens the next track, if false, opens prev track */ static int new_file(bool next_track) { char *trackname; - int i; do { trackname = peek_next_track( next_track ? 1 : -1 ); @@ -500,18 +605,9 @@ static int new_file(bool next_track) if(mpeg_file < 0) { DEBUGF("Couldn't open file: %s\n",trackname); } - else { - /* grab id3 tag of new file and remember where - in memory it starts */ - if ( last_tag < MAX_ID3_TAGS ) { - mp3info(&(id3tags[last_tag].id3), trackname); - id3tags[last_tag].mempos = mp3buf_write; - last_tag++; - for(i = 0;i < last_tag;i++) - { - DEBUGF("nf: %d, %x\n", i, id3tags[i].mempos); - } - } + else + { + add_track_to_tag_list(trackname); } } while ( mpeg_file < 0 ); @@ -527,6 +623,7 @@ static void stop_playing(void) close(mpeg_file); mpeg_file = -1; stop_dma(); + remove_all_tags(); } static void mpeg_thread(void) @@ -537,7 +634,6 @@ static void mpeg_thread(void) int unplayed_space_left; int amount_to_read; int amount_to_swap; - int i; play_pending = false; playing = false; @@ -559,6 +655,7 @@ static void mpeg_thread(void) stop_dma(); reset_mp3_buffer(); + remove_all_tags(); if(mpeg_file >= 0) close(mpeg_file); @@ -569,13 +666,8 @@ static void mpeg_thread(void) if ( new_file(true) == -1 ) return; } - - /* grab id3 tag of new file and - remember where in memory it starts */ - mp3info(&(id3tags[0].id3), ev.data); - id3tags[0].mempos = mp3buf_write; - last_tag=1; - id3tags[0].id3.elapsed = 0; + + add_track_to_tag_list((char *)ev.data); /* Make it read more data */ filling = true; @@ -618,12 +710,13 @@ static void mpeg_thread(void) stop_dma(); reset_mp3_buffer(); + /* Open the next file */ if (mpeg_file >= 0) close(mpeg_file); last_tag=0; if (new_file(true) < 0) { - DEBUGF("Finished Playing!\n"); + DEBUGF("No more files to play\n"); filling = false; } else { /* Make it read more data */ @@ -651,7 +744,7 @@ static void mpeg_thread(void) close(mpeg_file); last_tag=0; if (new_file(false) < 0) { - DEBUGF("Finished Playing!\n"); + DEBUGF("No more files to play\n"); filling = false; } else { /* Make it read more data */ @@ -701,7 +794,11 @@ static void mpeg_thread(void) playing yet. If not, do it. */ if(play_pending) { - if((mp3buf_swapwrite - mp3buf_read) >= MPEG_LOW_WATER) + /* If the filling has stopped, and we still haven't reached + the watermark, the file must be smaller than the + watermark. We must still play it. */ + if(((mp3buf_swapwrite - mp3buf_read) >= MPEG_LOW_WATER) || + !filling) { DEBUGF("P\n"); play_pending = false; @@ -779,11 +876,8 @@ static void mpeg_thread(void) DEBUGF("W\n"); } - if(!play_pending) - { - /* Tell ourselves that we want more data */ - queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); - } + /* Tell ourselves that we want more data */ + queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); } else { @@ -802,7 +896,7 @@ static void mpeg_thread(void) if(new_file(1) < 0) { /* No more data to play */ - DEBUGF("Finished playing\n"); + DEBUGF("No more files to play\n"); filling = false; } else @@ -821,13 +915,7 @@ static void mpeg_thread(void) /* Reset the AVC */ mpeg_sound_set(SOUND_AVC, -1); #endif - /* shift array so index 0 is current track */ - for (i=0; i<last_tag-1; i++) - { - id3tags[i] = id3tags[i+1]; - DEBUGF("tc: %d, %x\n", i, id3tags[i].mempos); - } - last_tag--; + remove_current_tag(); current_track_counter++; break; @@ -890,9 +978,20 @@ static void setup_sci0(void) } #endif /* SIMULATOR */ +#ifdef SIMULATOR +static struct mp3entry taginfo; +#endif + struct mp3entry* mpeg_current_track(void) { - return &(id3tags[0].id3); +#ifdef SIMULATOR + return &taginfo; +#else + if(num_tracks_in_memory()) + return &(id3tags[tag_read_idx]->id3); + else + return NULL; +#endif } bool mpeg_has_changed_track(void) @@ -908,7 +1007,7 @@ bool mpeg_has_changed_track(void) void mpeg_play(char* trackname) { #ifdef SIMULATOR - mp3info(&(id3tags[0].id3), trackname); + mp3info(&taginfo, trackname); #else queue_post(&mpeg_queue, MPEG_PLAY, trackname); #endif @@ -1217,4 +1316,6 @@ void mpeg_init(int volume, int bass, int treble, int loudness, int bass_boost, i mpeg_sound_set(SOUND_AVC, avc); #endif #endif /* !SIMULATOR */ + + memset(id3tags, sizeof(id3tags), 0); } |