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:
parent
d5d38f120b
commit
42faf56472
2 changed files with 226 additions and 110 deletions
133
apps/wps.c
133
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;
|
||||
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
|
||||
|
|
203
firmware/mpeg.c
203
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,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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue