New and improved ID3 and track change handling

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1455 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Linus Nielsen Feltzing 2002-07-26 14:32:24 +00:00
parent d5d38f120b
commit 42faf56472
2 changed files with 226 additions and 110 deletions

View file

@ -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;
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));
strncpy(szBuff, id3->path, sizeof(szBuff));
szTok = strtok_r(szBuff, "/", &end);
szTok = strtok_r(NULL, "/", &end);
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>");
// 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;
// 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);
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 (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

View file

@ -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,14 +141,92 @@ 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;
@ -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);
}