1
0
Fork 0
forked from len0rd/rockbox

Added resume. Works in dirs and playlists, shuffled or not. Resumes mid-song, but press pause on players before you shutdown so they get a chance to store the position on disk. Recorders use RTC ram. Todo: Time display is wrong after mid-track resume and ffd/rew is not handled.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1787 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Björn Stenberg 2002-08-16 14:41:47 +00:00
parent 085e774675
commit 6224cdb166
12 changed files with 379 additions and 144 deletions

View file

@ -66,7 +66,7 @@ int playlist_add(char *filename)
return 0; return 0;
} }
char* playlist_next(int steps) char* playlist_next(int steps, int* index)
{ {
int seek; int seek;
int max; int max;
@ -103,7 +103,9 @@ char* playlist_next(int steps)
else else
return NULL; return NULL;
} }
if (index)
*index = playlist.index;
/* Zero-terminate the file name */ /* Zero-terminate the file name */
seek=0; seek=0;
@ -165,7 +167,11 @@ char* playlist_next(int steps)
} }
} }
void play_list(char *dir, char *file, int start_index) void play_list(char *dir,
char *file,
int start_index,
int start_offset,
int random_seed )
{ {
char *sep=""; char *sep="";
int dirlen; int dirlen;
@ -211,7 +217,7 @@ void play_list(char *dir, char *file, int start_index)
status_draw(); status_draw();
lcd_update(); lcd_update();
} }
randomise_playlist( current_tick ); randomise_playlist( random_seed );
} }
if(!playlist.in_ram) { if(!playlist.in_ram) {
@ -220,7 +226,7 @@ void play_list(char *dir, char *file, int start_index)
lcd_update(); lcd_update();
} }
/* also make the first song get playing */ /* also make the first song get playing */
mpeg_play(playlist_next(0)); mpeg_play(start_offset);
} }
/* /*

View file

@ -40,8 +40,9 @@ typedef struct
extern playlist_info_t playlist; extern playlist_info_t playlist;
extern bool playlist_shuffle; extern bool playlist_shuffle;
void play_list(char *dir, char *file, int start_index); void play_list(char *dir, char *file, int start_index,
char* playlist_next(int steps); int start_offset, int random_seed );
char* playlist_next(int steps, int* id);
void randomise_playlist( unsigned int seed ); void randomise_playlist( unsigned int seed );
void sort_playlist(void); void sort_playlist(void);
void empty_playlist(void); void empty_playlist(void);

View file

@ -37,10 +37,9 @@
struct user_settings global_settings; struct user_settings global_settings;
static unsigned short last_checksum = 0;
#define CONFIG_BLOCK_VERSION 1 #define CONFIG_BLOCK_VERSION 1
#define CONFIG_BLOCK_SIZE 44 #define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
/******************************************** /********************************************
@ -64,6 +63,8 @@ offset abs
0x0f 0x23 <scroll speed & WPS display byte> 0x0f 0x23 <scroll speed & WPS display byte>
0x10 0x24 <playlist options byte> 0x10 0x24 <playlist options byte>
0x11 0x25 <AVC byte> 0x11 0x25 <AVC byte>
0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
0x16 0x2b <(int) Byte offset into resume file>
<all unused space filled with 0xff> <all unused space filled with 0xff>
@ -81,24 +82,30 @@ location used, and reset the setting in question with a factory default if
needed. Memory locations not used by a given version should not be needed. Memory locations not used by a given version should not be
modified unless the header & checksum test fails. modified unless the header & checksum test fails.
Rest of config block, only saved to disk:
0xF8 (int) Playlist shuffle seed
0xFC (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
*************************************/ *************************************/
#include "rtc.h" #include "rtc.h"
static unsigned char rtc_config_block[CONFIG_BLOCK_SIZE]; static unsigned char config_block[CONFIG_BLOCK_SIZE];
/* /*
* Calculates the checksum for the config block and places it in the given 2-byte buffer * Calculates the checksum for the config block and returns it
*/ */
static unsigned short calculate_config_checksum(void) static unsigned short calculate_config_checksum(unsigned char* buf)
{ {
unsigned int i; unsigned int i;
unsigned char cksum[2]; unsigned char cksum[2];
cksum[0] = cksum[1] = 0; cksum[0] = cksum[1] = 0;
for (i=0; i < CONFIG_BLOCK_SIZE - 2; i+=2 ) { for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
cksum[0] ^= rtc_config_block[i]; cksum[0] ^= buf[i];
cksum[1] ^= rtc_config_block[i+1]; cksum[1] ^= buf[i+1];
} }
return (cksum[0] << 8) | cksum[1]; return (cksum[0] << 8) | cksum[1];
@ -112,12 +119,12 @@ static void init_config_buffer( void )
DEBUGF( "init_config_buffer()\n" ); DEBUGF( "init_config_buffer()\n" );
/* reset to 0xff - all unused */ /* reset to 0xff - all unused */
memset(rtc_config_block, 0xff, CONFIG_BLOCK_SIZE); memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
/* insert header */ /* insert header */
rtc_config_block[0] = 'R'; config_block[0] = 'R';
rtc_config_block[1] = 'o'; config_block[1] = 'o';
rtc_config_block[2] = 'c'; config_block[2] = 'c';
rtc_config_block[3] = CONFIG_BLOCK_VERSION; config_block[3] = CONFIG_BLOCK_VERSION;
} }
/* /*
@ -126,7 +133,6 @@ static void init_config_buffer( void )
static int save_config_buffer( void ) static int save_config_buffer( void )
{ {
unsigned short chksum; unsigned short chksum;
#ifdef HAVE_RTC #ifdef HAVE_RTC
unsigned int i; unsigned int i;
#endif #endif
@ -134,36 +140,29 @@ static int save_config_buffer( void )
DEBUGF( "save_config_buffer()\n" ); DEBUGF( "save_config_buffer()\n" );
/* update the checksum in the end of the block before saving */ /* update the checksum in the end of the block before saving */
chksum = calculate_config_checksum(); chksum = calculate_config_checksum(config_block);
rtc_config_block[ CONFIG_BLOCK_SIZE - 2 ] = chksum >> 8; config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
rtc_config_block[ CONFIG_BLOCK_SIZE - 1 ] = chksum & 0xff; config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
/* don't save if no changes were made */
if ( chksum == last_checksum )
return 0;
last_checksum = chksum;
#ifdef HAVE_RTC #ifdef HAVE_RTC
/* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so /* FIXME: okay, it _would_ be cleaner and faster to implement rtc_write so
that it would write a number of bytes at a time since the RTC chip that it would write a number of bytes at a time since the RTC chip
supports that, but this will have to do for now 8-) */ supports that, but this will have to do for now 8-) */
for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) { for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
int r = rtc_write(0x14+i, rtc_config_block[i]); int r = rtc_write(0x14+i, config_block[i]);
if (r) { if (r) {
DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r ); DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r );
return r; return r;
} }
} }
#else #endif
if(battery_level_safe() && (fat_startsector()!=0)) if (fat_startsector() != 0)
ata_delayed_write( 61, rtc_config_block); ata_delayed_write( 61, config_block);
else else
return -1; return -1;
#endif
return 0; return 0;
} }
@ -173,40 +172,61 @@ static int save_config_buffer( void )
static int load_config_buffer( void ) static int load_config_buffer( void )
{ {
unsigned short chksum; unsigned short chksum;
bool correct = false;
#ifdef HAVE_RTC #ifdef HAVE_RTC
unsigned int i; unsigned int i;
unsigned char rtc_block[RTC_BLOCK_SIZE];
#endif #endif
DEBUGF( "load_config_buffer()\n" ); DEBUGF( "load_config_buffer()\n" );
if (fat_startsector() != 0) {
ata_read_sectors( 61, 1, config_block);
/* calculate the checksum, check it and the header */
chksum = calculate_config_checksum(config_block);
if (config_block[0] == 'R' &&
config_block[1] == 'o' &&
config_block[2] == 'c' &&
config_block[3] == CONFIG_BLOCK_VERSION &&
(chksum >> 8) == config_block[RTC_BLOCK_SIZE - 2] &&
(chksum & 0xff) == config_block[RTC_BLOCK_SIZE - 1])
{
DEBUGF( "load_config_buffer: header & checksum test ok\n" );
correct = true;
}
}
#ifdef HAVE_RTC #ifdef HAVE_RTC
/* FIXME: the same comment applies here as for rtc_write */ /* read rtc block */
for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) for (i=0; i < RTC_BLOCK_SIZE; i++ )
rtc_config_block[i] = rtc_read(0x14+i); rtc_block[i] = rtc_read(0x14+i);
#else
ata_read_sectors( 61, 1, rtc_config_block); chksum = calculate_config_checksum(rtc_block);
/* if rtc block is ok, use that */
if (rtc_block[0] == 'R' &&
rtc_block[1] == 'o' &&
rtc_block[2] == 'c' &&
rtc_block[3] == CONFIG_BLOCK_VERSION &&
(chksum >> 8) == rtc_block[RTC_BLOCK_SIZE - 2] &&
(chksum & 0xff) == rtc_block[RTC_BLOCK_SIZE - 1])
{
memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
correct = true;
}
#endif #endif
/* calculate the checksum, check it and the header */ if ( !correct ) {
chksum = calculate_config_checksum(); /* if checksum is not valid, clear the config buffer */
DEBUGF( "load_config_buffer: header & checksum test failed\n" );
if (rtc_config_block[0] == 'R' && init_config_buffer();
rtc_config_block[1] == 'o' && return -1;
rtc_config_block[2] == 'c' &&
rtc_config_block[3] == CONFIG_BLOCK_VERSION &&
(chksum >> 8) == rtc_config_block[CONFIG_BLOCK_SIZE - 2] &&
(chksum & 0xff) == rtc_config_block[CONFIG_BLOCK_SIZE - 1])
{
DEBUGF( "load_config_buffer: header & checksum test ok\n" );
last_checksum = chksum;
return 0; /* header and checksum is valid */
} }
/* if checksum is not valid, initialize the config buffer to all-unused */ return 0;
DEBUGF( "load_config_buffer: header & checksum test failed\n" );
init_config_buffer();
return 1;
} }
/* /*
@ -218,33 +238,47 @@ int settings_save( void )
/* update the config block buffer with current /* update the config block buffer with current
settings and save the block in the RTC */ settings and save the block in the RTC */
rtc_config_block[0x4] = (unsigned char)global_settings.volume; config_block[0x4] = (unsigned char)global_settings.volume;
rtc_config_block[0x5] = (unsigned char)global_settings.balance; config_block[0x5] = (unsigned char)global_settings.balance;
rtc_config_block[0x6] = (unsigned char)global_settings.bass; config_block[0x6] = (unsigned char)global_settings.bass;
rtc_config_block[0x7] = (unsigned char)global_settings.treble; config_block[0x7] = (unsigned char)global_settings.treble;
rtc_config_block[0x8] = (unsigned char)global_settings.loudness; config_block[0x8] = (unsigned char)global_settings.loudness;
rtc_config_block[0x9] = (unsigned char)global_settings.bass_boost; config_block[0x9] = (unsigned char)global_settings.bass_boost;
rtc_config_block[0xa] = (unsigned char)global_settings.contrast; config_block[0xa] = (unsigned char)global_settings.contrast;
rtc_config_block[0xb] = (unsigned char)global_settings.backlight; config_block[0xb] = (unsigned char)global_settings.backlight;
rtc_config_block[0xc] = (unsigned char)global_settings.poweroff; config_block[0xc] = (unsigned char)global_settings.poweroff;
rtc_config_block[0xd] = (unsigned char)global_settings.resume; config_block[0xd] = (unsigned char)global_settings.resume;
rtc_config_block[0xe] = (unsigned char) config_block[0xe] = (unsigned char)
((global_settings.playlist_shuffle & 1) | ((global_settings.playlist_shuffle & 1) |
((global_settings.mp3filter & 1) << 1) | ((global_settings.mp3filter & 1) << 1) |
((global_settings.sort_case & 1) << 2) | ((global_settings.sort_case & 1) << 2) |
((global_settings.discharge & 1) << 3) | ((global_settings.discharge & 1) << 3) |
((global_settings.statusbar & 1) << 4)); ((global_settings.statusbar & 1) << 4));
rtc_config_block[0xf] = (unsigned char) config_block[0xf] = (unsigned char)
((global_settings.scroll_speed << 3) | ((global_settings.scroll_speed << 3) |
(global_settings.wps_display & 7)); (global_settings.wps_display & 7));
rtc_config_block[0x11] = (unsigned char)global_settings.avc; config_block[0x10] = (unsigned char)global_settings.ff_rewind;
config_block[0x11] = (unsigned char)global_settings.avc;
memcpy(&rtc_config_block[0x24], &global_settings.total_uptime, 4); memcpy(&config_block[0x12], &global_settings.resume_index, 4);
memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
memcpy(&config_block[0xF8], &global_settings.resume_seed, 4);
memcpy(&config_block[0x24], &global_settings.total_uptime, 4);
strncpy(&config_block[0xFC], global_settings.resume_file, MAX_PATH);
DEBUGF("+Resume file %s\n",global_settings.resume_file);
DEBUGF("+Resume index %X offset %X\n",
global_settings.resume_index,
global_settings.resume_offset);
DEBUGF("+Resume shuffle %s seed %X\n",
global_settings.playlist_shuffle?"on":"off",
global_settings.resume_seed);
if(save_config_buffer()) if(save_config_buffer())
{ {
lcd_clear_display(); lcd_clear_display();
@ -277,51 +311,65 @@ void settings_load(void)
/* load the buffer from the RTC (resets it to all-unused if the block /* load the buffer from the RTC (resets it to all-unused if the block
is invalid) and decode the settings which are set in the block */ is invalid) and decode the settings which are set in the block */
if (!load_config_buffer()) { if (!load_config_buffer()) {
if (rtc_config_block[0x4] != 0xFF) if (config_block[0x4] != 0xFF)
global_settings.volume = rtc_config_block[0x4]; global_settings.volume = config_block[0x4];
if (rtc_config_block[0x5] != 0xFF) if (config_block[0x5] != 0xFF)
global_settings.balance = rtc_config_block[0x5]; global_settings.balance = config_block[0x5];
if (rtc_config_block[0x6] != 0xFF) if (config_block[0x6] != 0xFF)
global_settings.bass = rtc_config_block[0x6]; global_settings.bass = config_block[0x6];
if (rtc_config_block[0x7] != 0xFF) if (config_block[0x7] != 0xFF)
global_settings.treble = rtc_config_block[0x7]; global_settings.treble = config_block[0x7];
if (rtc_config_block[0x8] != 0xFF) if (config_block[0x8] != 0xFF)
global_settings.loudness = rtc_config_block[0x8]; global_settings.loudness = config_block[0x8];
if (rtc_config_block[0x9] != 0xFF) if (config_block[0x9] != 0xFF)
global_settings.bass_boost = rtc_config_block[0x9]; global_settings.bass_boost = config_block[0x9];
if (rtc_config_block[0xa] != 0xFF) { if (config_block[0xa] != 0xFF) {
global_settings.contrast = rtc_config_block[0xa]; global_settings.contrast = config_block[0xa];
if ( global_settings.contrast < MIN_CONTRAST_SETTING ) if ( global_settings.contrast < MIN_CONTRAST_SETTING )
global_settings.contrast = DEFAULT_CONTRAST_SETTING; global_settings.contrast = DEFAULT_CONTRAST_SETTING;
} }
if (rtc_config_block[0xb] != 0xFF) if (config_block[0xb] != 0xFF)
global_settings.backlight = rtc_config_block[0xb]; global_settings.backlight = config_block[0xb];
if (rtc_config_block[0xc] != 0xFF) if (config_block[0xc] != 0xFF)
global_settings.poweroff = rtc_config_block[0xc]; global_settings.poweroff = config_block[0xc];
if (rtc_config_block[0xd] != 0xFF) if (config_block[0xd] != 0xFF)
global_settings.resume = rtc_config_block[0xd]; global_settings.resume = config_block[0xd];
if (rtc_config_block[0xe] != 0xFF) { if (config_block[0xe] != 0xFF) {
global_settings.playlist_shuffle = rtc_config_block[0xe] & 1; global_settings.playlist_shuffle = config_block[0xe] & 1;
global_settings.mp3filter = (rtc_config_block[0xe] >> 1) & 1; global_settings.mp3filter = (config_block[0xe] >> 1) & 1;
global_settings.sort_case = (rtc_config_block[0xe] >> 2) & 1; global_settings.sort_case = (config_block[0xe] >> 2) & 1;
global_settings.discharge = (rtc_config_block[0xe] >> 3) & 1; global_settings.discharge = (config_block[0xe] >> 3) & 1;
global_settings.statusbar = (rtc_config_block[0xe] >> 4) & 1; global_settings.statusbar = (config_block[0xe] >> 4) & 1;
} }
c = rtc_config_block[0xf] >> 3; c = config_block[0xf] >> 3;
if (c != 31) if (c != 31)
global_settings.scroll_speed = c; global_settings.scroll_speed = c;
c = rtc_config_block[0xf] & 7; c = config_block[0xf] & 7;
if (c != 7) if (c != 7)
global_settings.wps_display = c; global_settings.wps_display = c;
if (rtc_config_block[0x11] != 0xFF) if (config_block[0x10] != 0xFF)
global_settings.avc = rtc_config_block[0x11]; global_settings.ff_rewind = config_block[0x10];
if (rtc_config_block[0x24] != 0xFF) if (config_block[0x11] != 0xFF)
memcpy(&global_settings.total_uptime, &rtc_config_block[0x24], 4); global_settings.avc = config_block[0x11];
if (config_block[0x12] != 0xFF)
memcpy(&global_settings.resume_index, &config_block[0x12], 4);
if (config_block[0x16] != 0xFF)
memcpy(&global_settings.resume_offset, &config_block[0x16], 4);
memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
if (config_block[0x24] != 0xFF)
memcpy(&global_settings.total_uptime, &config_block[0x24], 4);
strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
global_settings.resume_file[MAX_PATH]=0;
} }
lcd_set_contrast(global_settings.contrast); lcd_set_contrast(global_settings.contrast);
lcd_scroll_speed(global_settings.scroll_speed); lcd_scroll_speed(global_settings.scroll_speed);
@ -345,6 +393,7 @@ void settings_reset(void) {
global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS); global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS); global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
global_settings.avc = mpeg_sound_default(SOUND_AVC); global_settings.avc = mpeg_sound_default(SOUND_AVC);
global_settings.resume = true;
global_settings.contrast = DEFAULT_CONTRAST_SETTING; global_settings.contrast = DEFAULT_CONTRAST_SETTING;
global_settings.poweroff = DEFAULT_POWEROFF_SETTING; global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
global_settings.backlight = DEFAULT_BACKLIGHT_SETTING; global_settings.backlight = DEFAULT_BACKLIGHT_SETTING;
@ -358,6 +407,8 @@ void settings_reset(void) {
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; global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING;
global_settings.resume_index = -1;
global_settings.resume_offset = -1;
} }

View file

@ -21,6 +21,7 @@
#define __SETTINGS_H__ #define __SETTINGS_H__
#include <stdbool.h> #include <stdbool.h>
#include "file.h"
/* data structures */ /* data structures */
@ -49,8 +50,11 @@ struct user_settings
/* resume settings */ /* resume settings */
int resume; /* power-on song resume: 0=no. 1=yes song. 2=yes pl */ bool resume; /* resume option on/off */
int track_time; /* number of seconds into the track to resume */ int resume_index; /* index in playlist (-1 for no active resume) */
int resume_offset; /* byte offset in mp3 file */
int resume_seed; /* random seed for playlist shuffle */
unsigned char resume_file[MAX_PATH+1]; /* playlist name (or dir) */
/* misc options */ /* misc options */

View file

@ -57,6 +57,11 @@ static void sort_case(void)
set_bool( "[Sort case sensitive]", &global_settings.sort_case ); set_bool( "[Sort case sensitive]", &global_settings.sort_case );
} }
static void resume(void)
{
set_bool( "[Resume]", &global_settings.resume );
}
static void backlight_timer(void) static void backlight_timer(void)
{ {
char* names[] = { "off", "on ", char* names[] = { "off", "on ",
@ -153,13 +158,13 @@ void settings_menu(void)
{ "Time/Date", timedate_set }, { "Time/Date", timedate_set },
#endif #endif
{ "FF/Rewind", ff_rewind }, { "FF/Rewind", ff_rewind },
{ "Resume", resume },
}; };
bool old_shuffle = global_settings.playlist_shuffle; bool old_shuffle = global_settings.playlist_shuffle;
m=menu_init( items, sizeof items / sizeof(struct menu_items) ); m=menu_init( items, sizeof items / sizeof(struct menu_items) );
menu_run(m); menu_run(m);
menu_exit(m); menu_exit(m);
settings_save();
if (old_shuffle != global_settings.playlist_shuffle) if (old_shuffle != global_settings.playlist_shuffle)
{ {

View file

@ -102,12 +102,14 @@ extern unsigned char bitmap_icons_6x8[LastIcon][6];
#define TREE_EXIT BUTTON_LEFT #define TREE_EXIT BUTTON_LEFT
#define TREE_ENTER BUTTON_RIGHT #define TREE_ENTER BUTTON_RIGHT
#define TREE_MENU BUTTON_F1 #define TREE_MENU BUTTON_F1
#define RELEASE_MASK (BUTTON_OFF)
#else #else
#define TREE_NEXT BUTTON_RIGHT #define TREE_NEXT BUTTON_RIGHT
#define TREE_PREV BUTTON_LEFT #define TREE_PREV BUTTON_LEFT
#define TREE_EXIT BUTTON_STOP #define TREE_EXIT BUTTON_STOP
#define TREE_ENTER BUTTON_PLAY #define TREE_ENTER BUTTON_PLAY
#define TREE_MENU BUTTON_MENU #define TREE_MENU BUTTON_MENU
#define RELEASE_MASK (BUTTON_STOP)
#endif /* HAVE_RECORDER_KEYPAD */ #endif /* HAVE_RECORDER_KEYPAD */
#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */ #define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */
@ -292,6 +294,98 @@ static int showdir(char *path, int start)
return filesindir; return filesindir;
} }
bool ask_resume(void)
{
lcd_clear_display();
lcd_puts(0,0,"Resume?");
#ifdef HAVE_LCD_CHARCELLS
lcd_puts(0,1,"(Play/Stop)");
#else
lcd_puts(0,1,"Play = Yes");
lcd_puts(0,2,"Any other = No");
#endif
lcd_update();
if (button_get(true) == BUTTON_PLAY)
return true;
return false;
}
void start_resume(void)
{
if ( global_settings.resume &&
global_settings.resume_index != -1 ) {
int len = strlen(global_settings.resume_file);
DEBUGF("Resume file %s\n",global_settings.resume_file);
DEBUGF("Resume index %X offset %X\n",
global_settings.resume_index,
global_settings.resume_offset);
DEBUGF("Resume shuffle %s seed %X\n",
global_settings.playlist_shuffle?"on":"off",
global_settings.resume_seed);
/* playlist? */
if (!strcasecmp(&global_settings.resume_file[len-4], ".m3u")) {
char* slash;
/* check that the file exists */
int fd = open(global_settings.resume_file, O_RDONLY);
if(fd<0)
return;
close(fd);
if (!ask_resume())
return;
slash = strrchr(global_settings.resume_file,'/');
if (slash) {
*slash=0;
play_list(global_settings.resume_file,
slash+1,
global_settings.resume_index,
global_settings.resume_offset,
global_settings.resume_seed );
*slash='/';
}
else {
/* check that the dir exists */
DIR* dir = opendir(global_settings.resume_file);
if(!dir)
return;
closedir(dir);
if (!ask_resume())
return;
play_list("/",
global_settings.resume_file,
global_settings.resume_index,
global_settings.resume_offset,
global_settings.resume_seed );
}
}
else {
int start_index;
if (!ask_resume())
return;
if (showdir(global_settings.resume_file, 0) < 0 )
return;
start_index = build_playlist(global_settings.resume_index);
play_list(global_settings.resume_file,
NULL,
start_index,
global_settings.resume_offset,
global_settings.resume_seed);
}
status_set_playmode(STATUS_PLAY);
status_draw();
wps_show();
}
}
bool dirbrowse(char *root) bool dirbrowse(char *root)
{ {
int numentries=0; int numentries=0;
@ -317,6 +411,9 @@ bool dirbrowse(char *root)
tree_max_on_screen = TREE_MAX_ON_SCREEN; tree_max_on_screen = TREE_MAX_ON_SCREEN;
#endif #endif
start_resume();
button_set_release(RELEASE_MASK);
memcpy(currdir,root,sizeof(currdir)); memcpy(currdir,root,sizeof(currdir));
numentries = showdir(root, start); numentries = showdir(root, start);
if (numentries == -1) if (numentries == -1)
@ -350,6 +447,7 @@ bool dirbrowse(char *root)
restore = true; restore = true;
} }
break; break;
#ifdef HAVE_RECORDER_KEYPAD #ifdef HAVE_RECORDER_KEYPAD
case BUTTON_OFF: case BUTTON_OFF:
mpeg_stop(); mpeg_stop();
@ -357,7 +455,15 @@ bool dirbrowse(char *root)
status_draw(); status_draw();
restore = true; restore = true;
break; break;
case BUTTON_OFF | BUTTON_REL:
#else
case BUTTON_STOP | BUTTON_REL:
#endif #endif
global_settings.resume_index = -1;
settings_save();
break;
case TREE_ENTER: case TREE_ENTER:
#ifdef HAVE_RECORDER_KEYPAD #ifdef HAVE_RECORDER_KEYPAD
@ -383,16 +489,34 @@ bool dirbrowse(char *root)
dircursor=0; dircursor=0;
start=0; start=0;
} else { } else {
int seed = current_tick;
lcd_stop_scroll(); lcd_stop_scroll();
if(dircache[dircursor+start].attr & TREE_ATTR_M3U ) if(dircache[dircursor+start].attr & TREE_ATTR_M3U )
{ {
if ( global_settings.resume )
snprintf(global_settings.resume_file,
MAX_PATH, "%s/%s",
currdir,
dircache[dircursor+start].name);
play_list(currdir, play_list(currdir,
dircache[dircursor+start].name, 0); dircache[dircursor+start].name,
0, 0, seed );
} }
else { else {
if ( global_settings.resume )
strncpy(global_settings.resume_file,
currdir, MAX_PATH);
start_index = build_playlist(dircursor+start); start_index = build_playlist(dircursor+start);
play_list(currdir, NULL, start_index); play_list(currdir, NULL, start_index, 0, seed);
} }
if ( global_settings.resume ) {
global_settings.resume_index = 0;
global_settings.resume_offset = 0;
global_settings.resume_seed = seed;
settings_save();
}
status_set_playmode(STATUS_PLAY); status_set_playmode(STATUS_PLAY);
status_draw(); status_draw();
lcd_stop_scroll(); lcd_stop_scroll();
@ -405,6 +529,7 @@ bool dirbrowse(char *root)
dirlevel = 0; dirlevel = 0;
dircursor = 0; dircursor = 0;
start = 0; start = 0;
global_settings.resume_index = -1;
} }
} }
restore = true; restore = true;

View file

@ -34,6 +34,7 @@
#include "powermgmt.h" #include "powermgmt.h"
#include "status.h" #include "status.h"
#include "main_menu.h" #include "main_menu.h"
#include "ata.h"
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
#include "icons.h" #include "icons.h"
#include "widgets.h" #include "widgets.h"
@ -462,6 +463,13 @@ int wps_show(void)
{ {
mpeg_pause(); mpeg_pause();
status_set_playmode(STATUS_PAUSE); status_set_playmode(STATUS_PAUSE);
if (global_settings.resume) {
status_draw();
settings_save();
#ifndef HAVE_RTC
ata_flush();
#endif
}
} }
else else
{ {
@ -577,7 +585,6 @@ int wps_show(void)
mpeg_ff_rewind(ff_rewind_count); mpeg_ff_rewind(ff_rewind_count);
ff_rewind_count = 0; ff_rewind_count = 0;
ff_rewind = false; ff_rewind = false;
status_set_playmode(STATUS_PLAY);
#ifdef HAVE_LCD_CHARCELLS #ifdef HAVE_LCD_CHARCELLS
draw_screen(id3); draw_screen(id3);
#endif #endif
@ -589,7 +596,6 @@ int wps_show(void)
#endif #endif
{ {
mpeg_prev(); mpeg_prev();
status_set_playmode(STATUS_PLAY);
} }
} }
#ifdef HAVE_PLAYER_KEYPAD #ifdef HAVE_PLAYER_KEYPAD
@ -612,7 +618,6 @@ int wps_show(void)
mpeg_ff_rewind(ff_rewind_count); mpeg_ff_rewind(ff_rewind_count);
ff_rewind_count = 0; ff_rewind_count = 0;
ff_rewind = false; ff_rewind = false;
status_set_playmode(STATUS_PLAY);
#ifdef HAVE_LCD_CHARCELLS #ifdef HAVE_LCD_CHARCELLS
draw_screen(id3); draw_screen(id3);
#endif #endif
@ -624,7 +629,6 @@ int wps_show(void)
#endif #endif
{ {
mpeg_next(); mpeg_next();
status_set_playmode(STATUS_PLAY);
} }
} }
#ifdef HAVE_PLAYER_KEYPAD #ifdef HAVE_PLAYER_KEYPAD
@ -862,6 +866,16 @@ int wps_show(void)
if (mpeg_is_playing() && id3) if (mpeg_is_playing() && id3)
display_file_time(id3->elapsed, id3->length); display_file_time(id3->elapsed, id3->length);
/* save resume data */
if ( id3 &&
global_settings.resume &&
global_settings.resume_offset != id3->offset ) {
DEBUGF("R%X,%X (%X)\n",global_settings.resume_offset,id3->offset,id3);
global_settings.resume_index = id3->index;
global_settings.resume_offset = id3->offset;
settings_save();
}
status_draw(); status_draw();
break; break;
} }

View file

@ -304,6 +304,7 @@ extern void ata_delayed_write(unsigned long sector, void* buf)
extern void ata_flush(void) extern void ata_flush(void)
{ {
if ( delayed_write ) { if ( delayed_write ) {
DEBUGF("ata_flush()\n");
delayed_write = false; delayed_write = false;
ata_write_sectors(delayed_sector_num, 1, delayed_sector); ata_write_sectors(delayed_sector_num, 1, delayed_sector);
} }

View file

@ -47,6 +47,10 @@ struct mp3entry {
/* 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];
/* resume related */
int offset; /* bytes played */
int index; /* playlist index */
}; };
#define VBR_FRAMES_FLAG 0x01 #define VBR_FRAMES_FLAG 0x01

View file

@ -52,7 +52,8 @@
#define MPEG_SWAP_DATA 101 #define MPEG_SWAP_DATA 101
#define MPEG_TRACK_CHANGE 102 #define MPEG_TRACK_CHANGE 102
extern char* playlist_next(int steps); extern char* playlist_next(int steps, int* id);
extern void update_file_pos( int id, int pos );
static char *units[] = static char *units[] =
{ {
@ -243,6 +244,7 @@ static void remove_all_tags(void)
} }
#endif #endif
static bool paused; /* playback is paused */
#ifdef SIMULATOR #ifdef SIMULATOR
static bool playing = false; static bool playing = false;
static bool play_pending = false; static bool play_pending = false;
@ -502,7 +504,7 @@ static void stop_dma(void)
static void dma_tick(void) static void dma_tick(void)
{ {
if(playing) if(playing && !paused)
{ {
/* Start DMA if it is disabled and the DEMAND pin is high */ /* Start DMA if it is disabled and the DEMAND pin is high */
if(!dma_on && (PBDR & 0x4000)) if(!dma_on && (PBDR & 0x4000))
@ -594,6 +596,7 @@ void DEI3(void)
DTCR3 = last_dma_chunk_size & 0xffff; DTCR3 = last_dma_chunk_size & 0xffff;
SAR3 = (unsigned int)mp3buf + mp3buf_read; SAR3 = (unsigned int)mp3buf + mp3buf_read;
id3tags[tag_read_idx]->id3.offset += last_dma_chunk_size;
} }
else else
{ {
@ -646,10 +649,11 @@ static void add_track_to_tag_list(char *filename)
/* If next_track is true, opens the next track, if false, opens prev track */ /* If next_track is true, opens the next track, if false, opens prev track */
static int new_file(int steps) static int new_file(int steps)
{ {
char *trackname;
do { do {
trackname = playlist_next( steps ); char *trackname;
int index;
trackname = playlist_next( steps, &index );
if ( !trackname ) if ( !trackname )
return -1; return -1;
@ -666,6 +670,8 @@ static int new_file(int steps)
lseek(mpeg_file, lseek(mpeg_file,
id3tags[tag_read_idx]->id3.id3v2len & ~1, id3tags[tag_read_idx]->id3.id3v2len & ~1,
SEEK_SET); SEEK_SET);
id3tags[tag_read_idx]->id3.index = index;
id3tags[tag_read_idx]->id3.offset = 0;
} }
} while ( mpeg_file < 0 ); } while ( mpeg_file < 0 );
@ -706,6 +712,7 @@ static void mpeg_thread(void)
int amount_to_read; int amount_to_read;
int amount_to_swap; int amount_to_swap;
int t1, t2; int t1, t2;
int start_offset;
play_pending = false; play_pending = false;
playing = false; playing = false;
@ -720,7 +727,7 @@ static void mpeg_thread(void)
switch(ev.id) switch(ev.id)
{ {
case MPEG_PLAY: case MPEG_PLAY:
DEBUGF("MPEG_PLAY %s\n",ev.data); DEBUGF("MPEG_PLAY\n");
/* Stop the current stream */ /* Stop the current stream */
play_pending = false; play_pending = false;
playing = false; playing = false;
@ -732,18 +739,21 @@ static void mpeg_thread(void)
if(mpeg_file >= 0) if(mpeg_file >= 0)
close(mpeg_file); close(mpeg_file);
mpeg_file = open((char*)ev.data, O_RDONLY); if ( new_file(0) == -1 )
while (mpeg_file < 0) { return;
DEBUGF("Couldn't open file: %s\n",ev.data);
if ( new_file(1) == -1 )
return;
}
add_track_to_tag_list((char *)ev.data); start_offset = (int)ev.data;
/* skip past id3v2 tag (to an even byte) */ if (start_offset) {
lseek(mpeg_file, lseek(mpeg_file, start_offset, SEEK_SET);
id3tags[tag_read_idx]->id3.id3v2len & ~1, id3tags[tag_read_idx]->id3.offset = start_offset;
SEEK_SET); }
else {
/* skip past id3v2 tag (to an even byte) */
lseek(mpeg_file,
id3tags[tag_read_idx]->id3.id3v2len & ~1,
SEEK_SET);
}
/* Make it read more data */ /* Make it read more data */
filling = true; filling = true;
@ -752,6 +762,7 @@ static void mpeg_thread(void)
/* Tell the file loading code that we want to start playing /* Tell the file loading code that we want to start playing
as soon as we have some data */ as soon as we have some data */
play_pending = true; play_pending = true;
paused = false;
current_track_counter++; current_track_counter++;
break; break;
@ -764,6 +775,7 @@ static void mpeg_thread(void)
case MPEG_PAUSE: case MPEG_PAUSE:
DEBUGF("MPEG_PAUSE\n"); DEBUGF("MPEG_PAUSE\n");
/* Stop the current stream */ /* Stop the current stream */
paused = true;
playing = false; playing = false;
pause_tick = current_tick; pause_tick = current_tick;
stop_dma(); stop_dma();
@ -775,6 +787,7 @@ static void mpeg_thread(void)
playing = true; playing = true;
last_dma_tick += current_tick - pause_tick; last_dma_tick += current_tick - pause_tick;
pause_tick = 0; pause_tick = 0;
paused = false;
start_dma(); start_dma();
break; break;
@ -799,7 +812,8 @@ static void mpeg_thread(void)
play_pending = true; play_pending = true;
} else { } else {
playing = true; playing = true;
start_dma(); if (!paused)
start_dma();
} }
track_change(); track_change();
@ -931,7 +945,8 @@ static void mpeg_thread(void)
playing = true; playing = true;
last_dma_tick = current_tick; last_dma_tick = current_tick;
init_dma(); init_dma();
start_dma(); if (!paused)
start_dma();
} }
else else
{ {
@ -1016,7 +1031,8 @@ static void mpeg_thread(void)
last_dma_tick = current_tick; last_dma_tick = current_tick;
init_dma(); init_dma();
start_dma(); if (!paused)
start_dma();
/* Tell ourselves that we need more data */ /* Tell ourselves that we need more data */
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
@ -1188,7 +1204,7 @@ static void setup_sci0(void)
static struct mp3entry taginfo; static struct mp3entry taginfo;
#endif #endif
struct mp3entry* mpeg_current_track(void) struct mp3entry* mpeg_current_track()
{ {
#ifdef SIMULATOR #ifdef SIMULATOR
return &taginfo; return &taginfo;
@ -1210,13 +1226,17 @@ bool mpeg_has_changed_track(void)
return false; return false;
} }
void mpeg_play(char* trackname) void mpeg_play(int offset)
{ {
#ifdef SIMULATOR #ifdef SIMULATOR
mp3info(&taginfo, trackname); char* trackname = playlist_next( 0, NULL );
playing = true; if ( trackname ) {
mp3info(&taginfo, trackname);
playing = true;
}
(void)offset;
#else #else
queue_post(&mpeg_queue, MPEG_PLAY, trackname); queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
#endif #endif
} }
@ -1252,7 +1272,7 @@ void mpeg_next(void)
#ifndef SIMULATOR #ifndef SIMULATOR
queue_post(&mpeg_queue, MPEG_NEXT, NULL); queue_post(&mpeg_queue, MPEG_NEXT, NULL);
#else #else
char* file = playlist_next(1); char* file = playlist_next(1,NULL);
mp3info(&taginfo, file); mp3info(&taginfo, file);
current_track_counter++; current_track_counter++;
playing = true; playing = true;
@ -1264,7 +1284,7 @@ void mpeg_prev(void)
#ifndef SIMULATOR #ifndef SIMULATOR
queue_post(&mpeg_queue, MPEG_PREV, NULL); queue_post(&mpeg_queue, MPEG_PREV, NULL);
#else #else
char* file = playlist_next(-1); char* file = playlist_next(-1,NULL);
mp3info(&taginfo, file); mp3info(&taginfo, file);
current_track_counter--; current_track_counter--;
playing = true; playing = true;
@ -1282,7 +1302,7 @@ void mpeg_ff_rewind(int change)
bool mpeg_is_playing(void) bool mpeg_is_playing(void)
{ {
return playing || play_pending; return (playing || play_pending) && (!paused) ;
} }
#ifndef SIMULATOR #ifndef SIMULATOR

View file

@ -22,7 +22,7 @@
#include <stdbool.h> #include <stdbool.h>
void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc); void mpeg_init(int volume, int bass, int treble, int balance, int loudness, int bass_boost, int avc);
void mpeg_play(char* trackname); void mpeg_play(int offset);
void mpeg_stop(void); void mpeg_stop(void);
void mpeg_pause(void); void mpeg_pause(void);
void mpeg_resume(void); void mpeg_resume(void);

View file

@ -80,3 +80,7 @@ void ata_delayed_write(unsigned long sector, void* buf)
{ {
ata_write_sectors(sector,1,buf); ata_write_sectors(sector,1,buf);
} }
void ata_flush(void)
{
}