summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Nielsen Feltzing <linus@haxx.se>2002-07-26 14:32:24 +0000
committerLinus Nielsen Feltzing <linus@haxx.se>2002-07-26 14:32:24 +0000
commit42faf56472cbd803d4746d0d0866871c101050df (patch)
tree123c638283bd77f67dc375ead34de5c080b4b7e6
parentd5d38f120b458182a5c9c0f0b799f8f949376e45 (diff)
downloadrockbox-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.c145
-rw-r--r--firmware/mpeg.c203
2 files changed, 232 insertions, 116 deletions
diff --git a/apps/wps.c b/apps/wps.c
index 9840b50..3462be9 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -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);
}