Added fast forward and rewind (without sound). Patch by Hardeep Sidhu.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1741 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
b42ac1dc4d
commit
0570497e3a
8 changed files with 341 additions and 90 deletions
|
@ -357,6 +357,7 @@ void settings_reset(void) {
|
||||||
global_settings.discharge = 0;
|
global_settings.discharge = 0;
|
||||||
global_settings.total_uptime = 0;
|
global_settings.total_uptime = 0;
|
||||||
global_settings.scroll_speed = 8;
|
global_settings.scroll_speed = 8;
|
||||||
|
global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,9 @@ struct user_settings
|
||||||
|
|
||||||
/* geeky persistent statistics */
|
/* geeky persistent statistics */
|
||||||
unsigned int total_uptime; /* total uptime since rockbox was first booted */
|
unsigned int total_uptime; /* total uptime since rockbox was first booted */
|
||||||
|
|
||||||
|
/* FF/Rewind step size (in seconds) */
|
||||||
|
int ff_rewind;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
|
@ -112,5 +115,6 @@ extern struct user_settings global_settings;
|
||||||
#define DEFAULT_POWEROFF_SETTING 0
|
#define DEFAULT_POWEROFF_SETTING 0
|
||||||
#define DEFAULT_BACKLIGHT_SETTING 5
|
#define DEFAULT_BACKLIGHT_SETTING 5
|
||||||
#define DEFAULT_WPS_DISPLAY 0
|
#define DEFAULT_WPS_DISPLAY 0
|
||||||
|
#define DEFAULT_FF_REWIND_SETTING 2
|
||||||
|
|
||||||
#endif /* __SETTINGS_H__ */
|
#endif /* __SETTINGS_H__ */
|
||||||
|
|
|
@ -132,6 +132,12 @@ static void timedate_set(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void ff_rewind(void)
|
||||||
|
{
|
||||||
|
set_int("[FF/Rewind Step Size]", "s", &global_settings.ff_rewind,
|
||||||
|
NULL, 1, 1, 999 );
|
||||||
|
}
|
||||||
|
|
||||||
void settings_menu(void)
|
void settings_menu(void)
|
||||||
{
|
{
|
||||||
int m;
|
int m;
|
||||||
|
@ -152,6 +158,7 @@ void settings_menu(void)
|
||||||
#ifdef HAVE_RTC
|
#ifdef HAVE_RTC
|
||||||
{ "Time/Date", timedate_set },
|
{ "Time/Date", timedate_set },
|
||||||
#endif
|
#endif
|
||||||
|
{ "FF/Rewind", ff_rewind },
|
||||||
};
|
};
|
||||||
bool old_shuffle = global_settings.playlist_shuffle;
|
bool old_shuffle = global_settings.playlist_shuffle;
|
||||||
|
|
||||||
|
|
188
apps/wps.c
188
apps/wps.c
|
@ -54,12 +54,13 @@
|
||||||
#define PLAY_DISPLAY_TRACK_TITLE 2
|
#define PLAY_DISPLAY_TRACK_TITLE 2
|
||||||
|
|
||||||
#ifdef HAVE_RECORDER_KEYPAD
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
#define RELEASE_MASK (BUTTON_F1 | BUTTON_DOWN)
|
#define RELEASE_MASK (BUTTON_F1 | BUTTON_DOWN | BUTTON_LEFT | BUTTON_RIGHT)
|
||||||
#else
|
#else
|
||||||
#define RELEASE_MASK (BUTTON_MENU | BUTTON_STOP)
|
#define RELEASE_MASK (BUTTON_MENU | BUTTON_STOP | BUTTON_LEFT | BUTTON_RIGHT)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool keys_locked = false;
|
bool keys_locked = false;
|
||||||
|
static bool ff_rewind = false;
|
||||||
|
|
||||||
static void draw_screen(struct mp3entry* id3)
|
static void draw_screen(struct mp3entry* id3)
|
||||||
{
|
{
|
||||||
|
@ -291,6 +292,39 @@ int player_id3_show(void)
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void display_file_time(unsigned int elapsed, unsigned int length)
|
||||||
|
{
|
||||||
|
char buffer[32];
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_BITMAP
|
||||||
|
snprintf(buffer,sizeof(buffer),
|
||||||
|
"Time:%3d:%02d/%d:%02d",
|
||||||
|
elapsed / 60000,
|
||||||
|
elapsed % 60000 / 1000,
|
||||||
|
length / 60000,
|
||||||
|
length % 60000 / 1000 );
|
||||||
|
|
||||||
|
lcd_puts(0, 6, buffer);
|
||||||
|
slidebar(0, LCD_HEIGHT-6, LCD_WIDTH, 6, elapsed*100/length, Grow_Right);
|
||||||
|
lcd_update();
|
||||||
|
#else
|
||||||
|
/* Display time with the filename scroll only because
|
||||||
|
the screen has room. */
|
||||||
|
if ((global_settings.wps_display == PLAY_DISPLAY_FILENAME_SCROLL) ||
|
||||||
|
ff_rewind )
|
||||||
|
{
|
||||||
|
snprintf(buffer,sizeof(buffer), "%d:%02d/%d:%02d ",
|
||||||
|
elapsed / 60000,
|
||||||
|
elapsed % 60000 / 1000,
|
||||||
|
length / 60000,
|
||||||
|
length % 60000 / 1000 );
|
||||||
|
|
||||||
|
lcd_puts(0, 1, buffer);
|
||||||
|
lcd_update();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void display_keylock_text(bool locked)
|
void display_keylock_text(bool locked)
|
||||||
{
|
{
|
||||||
lcd_stop_scroll();
|
lcd_stop_scroll();
|
||||||
|
@ -354,7 +388,7 @@ int wps_show(void)
|
||||||
bool pending_keylock = true; /* Keylock will go ON next time */
|
bool pending_keylock = true; /* Keylock will go ON next time */
|
||||||
int old_release_mask;
|
int old_release_mask;
|
||||||
int button;
|
int button;
|
||||||
char buffer[32];
|
int ff_rewind_count = 0;
|
||||||
|
|
||||||
old_release_mask = button_set_release(RELEASE_MASK);
|
old_release_mask = button_set_release(RELEASE_MASK);
|
||||||
|
|
||||||
|
@ -461,26 +495,112 @@ int wps_show(void)
|
||||||
status_draw();
|
status_draw();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_LEFT:
|
case BUTTON_LEFT | BUTTON_REPEAT:
|
||||||
if (keys_locked)
|
if (!keys_locked)
|
||||||
{
|
{
|
||||||
display_keylock_text(keys_locked);
|
if (ff_rewind)
|
||||||
draw_screen(id3);
|
{
|
||||||
break;
|
ff_rewind_count -= global_settings.ff_rewind*1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( mpeg_is_playing() && id3 && id3->length )
|
||||||
|
{
|
||||||
|
mpeg_pause();
|
||||||
|
status_set_playmode(STATUS_FASTBACKWARD);
|
||||||
|
status_draw();
|
||||||
|
ff_rewind = true;
|
||||||
|
ff_rewind_count = -global_settings.ff_rewind*1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)(id3->elapsed + ff_rewind_count) < 0)
|
||||||
|
ff_rewind_count = -id3->elapsed;
|
||||||
|
|
||||||
|
display_file_time(id3->elapsed + ff_rewind_count,
|
||||||
|
id3->length);
|
||||||
}
|
}
|
||||||
mpeg_prev();
|
|
||||||
status_set_playmode(STATUS_PLAY);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BUTTON_RIGHT:
|
case BUTTON_RIGHT | BUTTON_REPEAT:
|
||||||
if (keys_locked)
|
if (!keys_locked)
|
||||||
{
|
{
|
||||||
display_keylock_text(keys_locked);
|
if (ff_rewind)
|
||||||
draw_screen(id3);
|
{
|
||||||
break;
|
ff_rewind_count += global_settings.ff_rewind*1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( mpeg_is_playing() && id3 && id3->length )
|
||||||
|
{
|
||||||
|
mpeg_pause();
|
||||||
|
status_set_playmode(STATUS_FASTFORWARD);
|
||||||
|
status_draw();
|
||||||
|
ff_rewind = true;
|
||||||
|
ff_rewind_count = global_settings.ff_rewind*1000;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((id3->elapsed + ff_rewind_count) > id3->length)
|
||||||
|
ff_rewind_count = id3->length - id3->elapsed;
|
||||||
|
|
||||||
|
display_file_time(id3->elapsed + ff_rewind_count,
|
||||||
|
id3->length);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_LEFT | BUTTON_REL:
|
||||||
|
if (ff_rewind)
|
||||||
|
{
|
||||||
|
/* rewind */
|
||||||
|
mpeg_ff_rewind(ff_rewind_count);
|
||||||
|
ff_rewind_count = 0;
|
||||||
|
ff_rewind = false;
|
||||||
|
status_set_playmode(STATUS_PLAY);
|
||||||
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
draw_screen(id3);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (keys_locked)
|
||||||
|
{
|
||||||
|
display_keylock_text(keys_locked);
|
||||||
|
draw_screen(id3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mpeg_prev();
|
||||||
|
status_set_playmode(STATUS_PLAY);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BUTTON_RIGHT | BUTTON_REL:
|
||||||
|
if (ff_rewind)
|
||||||
|
{
|
||||||
|
/* fast forward */
|
||||||
|
mpeg_ff_rewind(ff_rewind_count);
|
||||||
|
ff_rewind_count = 0;
|
||||||
|
ff_rewind = false;
|
||||||
|
status_set_playmode(STATUS_PLAY);
|
||||||
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
draw_screen(id3);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (keys_locked)
|
||||||
|
{
|
||||||
|
display_keylock_text(keys_locked);
|
||||||
|
draw_screen(id3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mpeg_next();
|
||||||
|
status_set_playmode(STATUS_PLAY);
|
||||||
}
|
}
|
||||||
mpeg_next();
|
|
||||||
status_set_playmode(STATUS_PLAY);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef HAVE_PLAYER_KEYPAD
|
#ifdef HAVE_PLAYER_KEYPAD
|
||||||
|
@ -683,39 +803,7 @@ int wps_show(void)
|
||||||
#endif
|
#endif
|
||||||
case BUTTON_NONE: /* Timeout */
|
case BUTTON_NONE: /* Timeout */
|
||||||
if (mpeg_is_playing() && id3)
|
if (mpeg_is_playing() && id3)
|
||||||
{
|
display_file_time(id3->elapsed, id3->length);
|
||||||
#ifdef HAVE_LCD_BITMAP
|
|
||||||
snprintf(buffer,sizeof(buffer),
|
|
||||||
"Time:%3d:%02d/%d:%02d",
|
|
||||||
id3->elapsed / 60000,
|
|
||||||
id3->elapsed % 60000 / 1000,
|
|
||||||
id3->length / 60000,
|
|
||||||
id3->length % 60000 / 1000 );
|
|
||||||
|
|
||||||
lcd_puts(0, 6, buffer);
|
|
||||||
|
|
||||||
slidebar(0, LCD_HEIGHT-6, LCD_WIDTH, 6,
|
|
||||||
id3->elapsed*100/id3->length,
|
|
||||||
Grow_Right);
|
|
||||||
|
|
||||||
lcd_update();
|
|
||||||
#else
|
|
||||||
/* 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), "%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();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
status_draw();
|
status_draw();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -383,7 +383,7 @@ static int getsonglength(int fd, struct mp3entry *entry)
|
||||||
unsigned int filetime = 0;
|
unsigned int filetime = 0;
|
||||||
unsigned long header=0;
|
unsigned long header=0;
|
||||||
unsigned char tmp;
|
unsigned char tmp;
|
||||||
unsigned char frame[64];
|
unsigned char frame[156];
|
||||||
unsigned char* xing;
|
unsigned char* xing;
|
||||||
|
|
||||||
int version;
|
int version;
|
||||||
|
@ -412,7 +412,7 @@ static int getsonglength(int fd, struct mp3entry *entry)
|
||||||
|
|
||||||
/* Loop trough file until we find a frame header */
|
/* Loop trough file until we find a frame header */
|
||||||
bytecount = 0;
|
bytecount = 0;
|
||||||
restart:
|
restart:
|
||||||
do {
|
do {
|
||||||
header <<= 8;
|
header <<= 8;
|
||||||
if(!read(fd, &tmp, 1))
|
if(!read(fd, &tmp, 1))
|
||||||
|
@ -441,29 +441,29 @@ static int getsonglength(int fd, struct mp3entry *entry)
|
||||||
#endif
|
#endif
|
||||||
/* MPEG Audio Version */
|
/* MPEG Audio Version */
|
||||||
switch((header & 0x180000) >> 19) {
|
switch((header & 0x180000) >> 19) {
|
||||||
case 2:
|
case 2:
|
||||||
version = 2;
|
version = 2;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
version = 1;
|
version = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Layer */
|
/* Layer */
|
||||||
switch((header & 0x060000) >> 17) {
|
switch((header & 0x060000) >> 17) {
|
||||||
case 1:
|
case 1:
|
||||||
layer = 3;
|
layer = 3;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
layer = 2;
|
layer = 2;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
layer = 1;
|
layer = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bitrate */
|
/* Bitrate */
|
||||||
|
@ -488,24 +488,27 @@ static int getsonglength(int fd, struct mp3entry *entry)
|
||||||
|
|
||||||
/* Calculate bytes per frame, calculation depends on layer */
|
/* Calculate bytes per frame, calculation depends on layer */
|
||||||
switch(layer) {
|
switch(layer) {
|
||||||
case 1:
|
case 1:
|
||||||
bpf = bitrate_table[version - 1][layer - 1][bitindex];
|
bpf = bitrate_table[version - 1][layer - 1][bitindex];
|
||||||
bpf *= 48000;
|
bpf *= 48000;
|
||||||
bpf /= freqtab[version-1][freqindex] << (version - 1);
|
bpf /= freqtab[version-1][freqindex] << (version - 1);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
bpf = bitrate_table[version - 1][layer - 1][bitindex];
|
bpf = bitrate_table[version - 1][layer - 1][bitindex];
|
||||||
bpf *= 144000;
|
bpf *= 144000;
|
||||||
bpf /= freqtab[version-1][freqindex] << (version - 1);
|
bpf /= freqtab[version-1][freqindex] << (version - 1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
bpf = 1;
|
bpf = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate time per frame */
|
/* Calculate time per frame */
|
||||||
tpf = bs[layer] / (freqtab[version-1][freqindex] << (version - 1));
|
tpf = bs[layer] / (freqtab[version-1][freqindex] << (version - 1));
|
||||||
|
|
||||||
|
entry->bpf = bpf;
|
||||||
|
entry->tpf = tpf;
|
||||||
|
|
||||||
/* OK, we have found a frame. Let's see if it has a Xing header */
|
/* OK, we have found a frame. Let's see if it has a Xing header */
|
||||||
if(read(fd, frame, sizeof frame) < 0)
|
if(read(fd, frame, sizeof frame) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -535,21 +538,26 @@ static int getsonglength(int fd, struct mp3entry *entry)
|
||||||
/* Yes, it is a VBR file */
|
/* Yes, it is a VBR file */
|
||||||
entry->vbr = true;
|
entry->vbr = true;
|
||||||
|
|
||||||
if (xing[7] & 0x01) /* Is the frame count there? */
|
if (entry->vbrflags & VBR_FRAMES_FLAG) /* Is the frame count there? */
|
||||||
{
|
{
|
||||||
int framecount = (xing[8] << 24) | (xing[9] << 16) |
|
int framecount = (xing[8] << 24) | (xing[9] << 16) |
|
||||||
(xing[10] << 8) | xing[11];
|
(xing[10] << 8) | xing[11];
|
||||||
|
|
||||||
filetime = framecount * tpf;
|
filetime = framecount * tpf;
|
||||||
}
|
}
|
||||||
if (xing[7] & 0x02) /* is byte count there? */
|
|
||||||
|
if (entry->vbrflags & VBR_BYTES_FLAG) /* is byte count there? */
|
||||||
{
|
{
|
||||||
int bytecount = (xing[12] << 24) | (xing[13] << 16) |
|
int bytecount = (xing[12] << 24) | (xing[13] << 16) |
|
||||||
(xing[14] << 8) | xing[15];
|
(xing[14] << 8) | xing[15];
|
||||||
|
|
||||||
bitrate = bytecount * 8 / filetime;
|
bitrate = bytecount * 8 / filetime;
|
||||||
}
|
}
|
||||||
/* We don't care about the TOC just yet. Maybe another time. */
|
|
||||||
|
if (entry->vbrflags & VBR_TOC_FLAG) /* is table-of-contents there? */
|
||||||
|
{
|
||||||
|
memcpy( entry->toc, xing+16, 100 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->bitrate = bitrate;
|
entry->bitrate = bitrate;
|
||||||
|
|
|
@ -29,7 +29,6 @@ struct mp3entry {
|
||||||
int tracknum;
|
int tracknum;
|
||||||
int version;
|
int version;
|
||||||
int layer;
|
int layer;
|
||||||
bool vbr;
|
|
||||||
unsigned int bitrate;
|
unsigned int bitrate;
|
||||||
unsigned int frequency;
|
unsigned int frequency;
|
||||||
unsigned int id3v2len;
|
unsigned int id3v2len;
|
||||||
|
@ -37,12 +36,23 @@ struct mp3entry {
|
||||||
unsigned int filesize; /* in bytes */
|
unsigned int filesize; /* in bytes */
|
||||||
unsigned int length; /* song length */
|
unsigned int length; /* song length */
|
||||||
unsigned int elapsed; /* ms played */
|
unsigned int elapsed; /* ms played */
|
||||||
|
long bpf; /* bytes per frame */
|
||||||
|
long tpf; /* time per frame */
|
||||||
|
|
||||||
|
/* Xing VBR fields */
|
||||||
|
bool vbr;
|
||||||
|
unsigned char vbrflags;
|
||||||
|
unsigned char toc[100];/* table of contents */
|
||||||
|
|
||||||
/* these following two fields are used for local buffering */
|
/* these following two fields are used for local buffering */
|
||||||
char id3v2buf[300];
|
char id3v2buf[300];
|
||||||
char id3v1buf[3][32];
|
char id3v1buf[3][32];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VBR_FRAMES_FLAG 0x01
|
||||||
|
#define VBR_BYTES_FLAG 0x02
|
||||||
|
#define VBR_TOC_FLAG 0x04
|
||||||
|
|
||||||
bool mp3info(struct mp3entry *entry, char *filename);
|
bool mp3info(struct mp3entry *entry, char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
132
firmware/mpeg.c
132
firmware/mpeg.c
|
@ -47,6 +47,7 @@
|
||||||
#define MPEG_RESUME 4
|
#define MPEG_RESUME 4
|
||||||
#define MPEG_NEXT 5
|
#define MPEG_NEXT 5
|
||||||
#define MPEG_PREV 6
|
#define MPEG_PREV 6
|
||||||
|
#define MPEG_FF_REWIND 7
|
||||||
#define MPEG_NEED_DATA 100
|
#define MPEG_NEED_DATA 100
|
||||||
#define MPEG_SWAP_DATA 101
|
#define MPEG_SWAP_DATA 101
|
||||||
#define MPEG_TRACK_CHANGE 102
|
#define MPEG_TRACK_CHANGE 102
|
||||||
|
@ -216,6 +217,22 @@ static void remove_current_tag(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void remove_all_non_current_tags(void)
|
||||||
|
{
|
||||||
|
int i = (tag_read_idx+1) & MAX_ID3_TAGS_MASK;
|
||||||
|
|
||||||
|
while (i != tag_write_idx)
|
||||||
|
{
|
||||||
|
id3tags[i]->used = false;
|
||||||
|
id3tags[i] = NULL;
|
||||||
|
|
||||||
|
i = (i+1) & MAX_ID3_TAGS_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag_write_idx = (tag_read_idx+1) & MAX_ID3_TAGS_MASK;
|
||||||
|
debug_tags();
|
||||||
|
}
|
||||||
|
|
||||||
static void remove_all_tags(void)
|
static void remove_all_tags(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -823,6 +840,112 @@ static void mpeg_thread(void)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MPEG_FF_REWIND: {
|
||||||
|
struct mp3entry *id3 = mpeg_current_track();
|
||||||
|
int newtime = id3->elapsed + (int)ev.data;
|
||||||
|
int curpos, newpos, diffpos;
|
||||||
|
DEBUGF("MPEG_FF_REWIND\n");
|
||||||
|
|
||||||
|
if (id3->vbr && (id3->vbrflags & VBR_TOC_FLAG))
|
||||||
|
{
|
||||||
|
/* Use the TOC to find the new position */
|
||||||
|
int percent = (newtime*100)/id3->length;
|
||||||
|
int curtoc, nexttoc, nextpos, remainder;
|
||||||
|
|
||||||
|
if (percent > 99)
|
||||||
|
percent = 99;
|
||||||
|
|
||||||
|
curtoc = id3->toc[percent];
|
||||||
|
|
||||||
|
if (percent < 99)
|
||||||
|
nexttoc = id3->toc[percent+1];
|
||||||
|
else
|
||||||
|
nexttoc = 256;
|
||||||
|
|
||||||
|
newpos = (curtoc*id3->filesize)/256;
|
||||||
|
|
||||||
|
/* Use the remainder to get a more accurate position */
|
||||||
|
nextpos = (nexttoc*id3->filesize)/256;
|
||||||
|
remainder = (newtime*10000)/id3->length - (percent*100);
|
||||||
|
newpos += ((nextpos-newpos)*remainder)/100;
|
||||||
|
}
|
||||||
|
else if (id3->bpf && id3->tpf)
|
||||||
|
newpos = (newtime*id3->bpf)/id3->tpf;
|
||||||
|
else
|
||||||
|
/* Not enough information to FF/Rewind */
|
||||||
|
break;
|
||||||
|
|
||||||
|
newpos = newpos & ~1;
|
||||||
|
curpos = lseek(mpeg_file, 0, SEEK_CUR);
|
||||||
|
|
||||||
|
if (num_tracks_in_memory() > 1)
|
||||||
|
{
|
||||||
|
/* We have started loading other tracks that need to be
|
||||||
|
accounted for */
|
||||||
|
int i = tag_read_idx;
|
||||||
|
int j = tag_write_idx - 1;
|
||||||
|
|
||||||
|
if (j < 0)
|
||||||
|
j = MAX_ID3_TAGS - 1;
|
||||||
|
|
||||||
|
while (i != j)
|
||||||
|
{
|
||||||
|
curpos += id3tags[i]->id3.filesize;
|
||||||
|
i = (i+1) & MAX_ID3_TAGS_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diffpos = curpos - newpos;
|
||||||
|
|
||||||
|
#warning "Borde inte mp3buflen vara mp3buf_write?"
|
||||||
|
if(diffpos >= 0 && diffpos < mp3buflen)
|
||||||
|
{
|
||||||
|
/* We are changing to a position that's already in
|
||||||
|
memory */
|
||||||
|
mp3buf_read = mp3buf_write - diffpos;
|
||||||
|
if (mp3buf_read < 0)
|
||||||
|
{
|
||||||
|
mp3buf_read += mp3buflen;
|
||||||
|
}
|
||||||
|
|
||||||
|
playing = true;
|
||||||
|
last_dma_tick = current_tick;
|
||||||
|
init_dma();
|
||||||
|
start_dma();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Move to the new position in the file and start
|
||||||
|
loading data */
|
||||||
|
reset_mp3_buffer();
|
||||||
|
|
||||||
|
if (num_tracks_in_memory() > 1)
|
||||||
|
{
|
||||||
|
/* We have to reload the current track */
|
||||||
|
close(mpeg_file);
|
||||||
|
remove_all_non_current_tags();
|
||||||
|
|
||||||
|
mpeg_file = open(id3->path, O_RDONLY);
|
||||||
|
if (mpeg_file < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(-1 == lseek(mpeg_file, newpos, SEEK_SET))
|
||||||
|
break;
|
||||||
|
|
||||||
|
filling = true;
|
||||||
|
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||||
|
|
||||||
|
/* Tell the file loading code that we want to start playing
|
||||||
|
as soon as we have some data */
|
||||||
|
play_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
id3->elapsed = newtime;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case MPEG_SWAP_DATA:
|
case MPEG_SWAP_DATA:
|
||||||
free_space_left = mp3buf_write - mp3buf_swapwrite;
|
free_space_left = mp3buf_write - mp3buf_swapwrite;
|
||||||
|
|
||||||
|
@ -1128,6 +1251,15 @@ void mpeg_prev(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mpeg_ff_rewind(int change)
|
||||||
|
{
|
||||||
|
#ifndef SIMULATOR
|
||||||
|
queue_post(&mpeg_queue, MPEG_FF_REWIND, (void *)change);
|
||||||
|
#else
|
||||||
|
(void)change;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool mpeg_is_playing(void)
|
bool mpeg_is_playing(void)
|
||||||
{
|
{
|
||||||
return playing || play_pending;
|
return playing || play_pending;
|
||||||
|
|
|
@ -28,6 +28,7 @@ void mpeg_pause(void);
|
||||||
void mpeg_resume(void);
|
void mpeg_resume(void);
|
||||||
void mpeg_next(void);
|
void mpeg_next(void);
|
||||||
void mpeg_prev(void);
|
void mpeg_prev(void);
|
||||||
|
void mpeg_ff_rewind(int change);
|
||||||
bool mpeg_is_playing(void);
|
bool mpeg_is_playing(void);
|
||||||
void mpeg_sound_set(int setting, int value);
|
void mpeg_sound_set(int setting, int value);
|
||||||
int mpeg_sound_min(int setting);
|
int mpeg_sound_min(int setting);
|
||||||
|
|
Loading…
Reference in a new issue