summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-08-16 14:41:47 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-08-16 14:41:47 +0000
commit6224cdb16677cae7b65b0598eec3381a6fb6a4aa (patch)
tree9ad9b39557492606c853e7f14c359bca5e0a3b65
parent085e77467565aba251c31721e92bc7ebd7baa61f (diff)
downloadrockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.zip
rockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.tar.gz
rockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.tar.bz2
rockbox-6224cdb16677cae7b65b0598eec3381a6fb6a4aa.tar.xz
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
-rw-r--r--apps/playlist.c16
-rw-r--r--apps/playlist.h5
-rw-r--r--apps/settings.c247
-rw-r--r--apps/settings.h8
-rw-r--r--apps/settings_menu.c7
-rw-r--r--apps/tree.c129
-rw-r--r--apps/wps.c22
-rw-r--r--firmware/drivers/ata.c1
-rw-r--r--firmware/id3.h4
-rw-r--r--firmware/mpeg.c74
-rw-r--r--firmware/mpeg.h2
-rw-r--r--uisimulator/common/stubs.c4
12 files changed, 377 insertions, 142 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index 0cb9d09..f308139 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -66,7 +66,7 @@ int playlist_add(char *filename)
return 0;
}
-char* playlist_next(int steps)
+char* playlist_next(int steps, int* index)
{
int seek;
int max;
@@ -103,7 +103,9 @@ char* playlist_next(int steps)
else
return NULL;
}
-
+
+ if (index)
+ *index = playlist.index;
/* Zero-terminate the file name */
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="";
int dirlen;
@@ -211,7 +217,7 @@ void play_list(char *dir, char *file, int start_index)
status_draw();
lcd_update();
}
- randomise_playlist( current_tick );
+ randomise_playlist( random_seed );
}
if(!playlist.in_ram) {
@@ -220,7 +226,7 @@ void play_list(char *dir, char *file, int start_index)
lcd_update();
}
/* also make the first song get playing */
- mpeg_play(playlist_next(0));
+ mpeg_play(start_offset);
}
/*
diff --git a/apps/playlist.h b/apps/playlist.h
index 312964f..e0c0841 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -40,8 +40,9 @@ typedef struct
extern playlist_info_t playlist;
extern bool playlist_shuffle;
-void play_list(char *dir, char *file, int start_index);
-char* playlist_next(int steps);
+void play_list(char *dir, char *file, int start_index,
+ int start_offset, int random_seed );
+char* playlist_next(int steps, int* id);
void randomise_playlist( unsigned int seed );
void sort_playlist(void);
void empty_playlist(void);
diff --git a/apps/settings.c b/apps/settings.c
index f8b6870..41d04c2 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -37,10 +37,9 @@
struct user_settings global_settings;
-static unsigned short last_checksum = 0;
-
#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>
0x10 0x24 <playlist options 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>
@@ -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
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"
-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 char cksum[2];
cksum[0] = cksum[1] = 0;
- for (i=0; i < CONFIG_BLOCK_SIZE - 2; i+=2 ) {
- cksum[0] ^= rtc_config_block[i];
- cksum[1] ^= rtc_config_block[i+1];
+ for (i=0; i < RTC_BLOCK_SIZE - 2; i+=2 ) {
+ cksum[0] ^= buf[i];
+ cksum[1] ^= buf[i+1];
}
return (cksum[0] << 8) | cksum[1];
@@ -112,12 +119,12 @@ static void init_config_buffer( void )
DEBUGF( "init_config_buffer()\n" );
/* reset to 0xff - all unused */
- memset(rtc_config_block, 0xff, CONFIG_BLOCK_SIZE);
+ memset(config_block, 0xff, CONFIG_BLOCK_SIZE);
/* insert header */
- rtc_config_block[0] = 'R';
- rtc_config_block[1] = 'o';
- rtc_config_block[2] = 'c';
- rtc_config_block[3] = CONFIG_BLOCK_VERSION;
+ config_block[0] = 'R';
+ config_block[1] = 'o';
+ config_block[2] = 'c';
+ config_block[3] = CONFIG_BLOCK_VERSION;
}
/*
@@ -126,7 +133,6 @@ static void init_config_buffer( void )
static int save_config_buffer( void )
{
unsigned short chksum;
-
#ifdef HAVE_RTC
unsigned int i;
#endif
@@ -134,36 +140,29 @@ static int save_config_buffer( void )
DEBUGF( "save_config_buffer()\n" );
/* update the checksum in the end of the block before saving */
- chksum = calculate_config_checksum();
- rtc_config_block[ CONFIG_BLOCK_SIZE - 2 ] = chksum >> 8;
- rtc_config_block[ CONFIG_BLOCK_SIZE - 1 ] = chksum & 0xff;
-
- /* don't save if no changes were made */
- if ( chksum == last_checksum )
- return 0;
- last_checksum = chksum;
+ chksum = calculate_config_checksum(config_block);
+ config_block[ RTC_BLOCK_SIZE - 2 ] = chksum >> 8;
+ config_block[ RTC_BLOCK_SIZE - 1 ] = chksum & 0xff;
#ifdef HAVE_RTC
/* 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
supports that, but this will have to do for now 8-) */
- for (i=0; i < CONFIG_BLOCK_SIZE; i++ ) {
- int r = rtc_write(0x14+i, rtc_config_block[i]);
+ for (i=0; i < RTC_BLOCK_SIZE; i++ ) {
+ int r = rtc_write(0x14+i, config_block[i]);
if (r) {
DEBUGF( "save_config_buffer: rtc_write failed at addr 0x%02x: %d\n", 14+i, r );
return r;
}
}
-#else
+#endif
- if(battery_level_safe() && (fat_startsector()!=0))
- ata_delayed_write( 61, rtc_config_block);
+ if (fat_startsector() != 0)
+ ata_delayed_write( 61, config_block);
else
return -1;
-#endif
-
return 0;
}
@@ -173,40 +172,61 @@ static int save_config_buffer( void )
static int load_config_buffer( void )
{
unsigned short chksum;
+ bool correct = false;
#ifdef HAVE_RTC
unsigned int i;
+ unsigned char rtc_block[RTC_BLOCK_SIZE];
#endif
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
- /* FIXME: the same comment applies here as for rtc_write */
- for (i=0; i < CONFIG_BLOCK_SIZE; i++ )
- rtc_config_block[i] = rtc_read(0x14+i);
-#else
- ata_read_sectors( 61, 1, rtc_config_block);
-#endif
-
- /* calculate the checksum, check it and the header */
- chksum = calculate_config_checksum();
+ /* read rtc block */
+ for (i=0; i < RTC_BLOCK_SIZE; i++ )
+ rtc_block[i] = rtc_read(0x14+i);
+
+ chksum = calculate_config_checksum(rtc_block);
- if (rtc_config_block[0] == 'R' &&
- rtc_config_block[1] == 'o' &&
- 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])
+ /* 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])
{
- DEBUGF( "load_config_buffer: header & checksum test ok\n" );
- last_checksum = chksum;
- return 0; /* header and checksum is valid */
+ memcpy(config_block, rtc_block, RTC_BLOCK_SIZE);
+ correct = true;
}
+#endif
- /* if checksum is not valid, initialize the config buffer to all-unused */
- DEBUGF( "load_config_buffer: header & checksum test failed\n" );
- init_config_buffer();
- return 1;
+ if ( !correct ) {
+ /* if checksum is not valid, clear the config buffer */
+ DEBUGF( "load_config_buffer: header & checksum test failed\n" );
+ init_config_buffer();
+ return -1;
+ }
+
+ return 0;
}
/*
@@ -218,33 +238,47 @@ int settings_save( void )
/* update the config block buffer with current
settings and save the block in the RTC */
- rtc_config_block[0x4] = (unsigned char)global_settings.volume;
- rtc_config_block[0x5] = (unsigned char)global_settings.balance;
- rtc_config_block[0x6] = (unsigned char)global_settings.bass;
- rtc_config_block[0x7] = (unsigned char)global_settings.treble;
- rtc_config_block[0x8] = (unsigned char)global_settings.loudness;
- rtc_config_block[0x9] = (unsigned char)global_settings.bass_boost;
+ config_block[0x4] = (unsigned char)global_settings.volume;
+ config_block[0x5] = (unsigned char)global_settings.balance;
+ config_block[0x6] = (unsigned char)global_settings.bass;
+ config_block[0x7] = (unsigned char)global_settings.treble;
+ config_block[0x8] = (unsigned char)global_settings.loudness;
+ config_block[0x9] = (unsigned char)global_settings.bass_boost;
- rtc_config_block[0xa] = (unsigned char)global_settings.contrast;
- rtc_config_block[0xb] = (unsigned char)global_settings.backlight;
- rtc_config_block[0xc] = (unsigned char)global_settings.poweroff;
- rtc_config_block[0xd] = (unsigned char)global_settings.resume;
+ config_block[0xa] = (unsigned char)global_settings.contrast;
+ config_block[0xb] = (unsigned char)global_settings.backlight;
+ config_block[0xc] = (unsigned char)global_settings.poweroff;
+ 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.mp3filter & 1) << 1) |
((global_settings.sort_case & 1) << 2) |
((global_settings.discharge & 1) << 3) |
((global_settings.statusbar & 1) << 4));
- rtc_config_block[0xf] = (unsigned char)
+ config_block[0xf] = (unsigned char)
((global_settings.scroll_speed << 3) |
(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())
{
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
is invalid) and decode the settings which are set in the block */
if (!load_config_buffer()) {
- if (rtc_config_block[0x4] != 0xFF)
- global_settings.volume = rtc_config_block[0x4];
- if (rtc_config_block[0x5] != 0xFF)
- global_settings.balance = rtc_config_block[0x5];
- if (rtc_config_block[0x6] != 0xFF)
- global_settings.bass = rtc_config_block[0x6];
- if (rtc_config_block[0x7] != 0xFF)
- global_settings.treble = rtc_config_block[0x7];
- if (rtc_config_block[0x8] != 0xFF)
- global_settings.loudness = rtc_config_block[0x8];
- if (rtc_config_block[0x9] != 0xFF)
- global_settings.bass_boost = rtc_config_block[0x9];
+ if (config_block[0x4] != 0xFF)
+ global_settings.volume = config_block[0x4];
+ if (config_block[0x5] != 0xFF)
+ global_settings.balance = config_block[0x5];
+ if (config_block[0x6] != 0xFF)
+ global_settings.bass = config_block[0x6];
+ if (config_block[0x7] != 0xFF)
+ global_settings.treble = config_block[0x7];
+ if (config_block[0x8] != 0xFF)
+ global_settings.loudness = config_block[0x8];
+ if (config_block[0x9] != 0xFF)
+ global_settings.bass_boost = config_block[0x9];
- if (rtc_config_block[0xa] != 0xFF) {
- global_settings.contrast = rtc_config_block[0xa];
+ if (config_block[0xa] != 0xFF) {
+ global_settings.contrast = config_block[0xa];
if ( global_settings.contrast < MIN_CONTRAST_SETTING )
global_settings.contrast = DEFAULT_CONTRAST_SETTING;
}
- if (rtc_config_block[0xb] != 0xFF)
- global_settings.backlight = rtc_config_block[0xb];
- if (rtc_config_block[0xc] != 0xFF)
- global_settings.poweroff = rtc_config_block[0xc];
- if (rtc_config_block[0xd] != 0xFF)
- global_settings.resume = rtc_config_block[0xd];
- if (rtc_config_block[0xe] != 0xFF) {
- global_settings.playlist_shuffle = rtc_config_block[0xe] & 1;
- global_settings.mp3filter = (rtc_config_block[0xe] >> 1) & 1;
- global_settings.sort_case = (rtc_config_block[0xe] >> 2) & 1;
- global_settings.discharge = (rtc_config_block[0xe] >> 3) & 1;
- global_settings.statusbar = (rtc_config_block[0xe] >> 4) & 1;
+ if (config_block[0xb] != 0xFF)
+ global_settings.backlight = config_block[0xb];
+ if (config_block[0xc] != 0xFF)
+ global_settings.poweroff = config_block[0xc];
+ if (config_block[0xd] != 0xFF)
+ global_settings.resume = config_block[0xd];
+ if (config_block[0xe] != 0xFF) {
+ global_settings.playlist_shuffle = config_block[0xe] & 1;
+ global_settings.mp3filter = (config_block[0xe] >> 1) & 1;
+ global_settings.sort_case = (config_block[0xe] >> 2) & 1;
+ global_settings.discharge = (config_block[0xe] >> 3) & 1;
+ global_settings.statusbar = (config_block[0xe] >> 4) & 1;
}
- c = rtc_config_block[0xf] >> 3;
+ c = config_block[0xf] >> 3;
if (c != 31)
global_settings.scroll_speed = c;
- c = rtc_config_block[0xf] & 7;
+ c = config_block[0xf] & 7;
if (c != 7)
global_settings.wps_display = c;
- if (rtc_config_block[0x11] != 0xFF)
- global_settings.avc = rtc_config_block[0x11];
+ if (config_block[0x10] != 0xFF)
+ global_settings.ff_rewind = config_block[0x10];
+
+ if (config_block[0x11] != 0xFF)
+ 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);
- if (rtc_config_block[0x24] != 0xFF)
- memcpy(&global_settings.total_uptime, &rtc_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_scroll_speed(global_settings.scroll_speed);
@@ -345,6 +393,7 @@ void settings_reset(void) {
global_settings.loudness = mpeg_sound_default(SOUND_LOUDNESS);
global_settings.bass_boost = mpeg_sound_default(SOUND_SUPERBASS);
global_settings.avc = mpeg_sound_default(SOUND_AVC);
+ global_settings.resume = true;
global_settings.contrast = DEFAULT_CONTRAST_SETTING;
global_settings.poweroff = DEFAULT_POWEROFF_SETTING;
global_settings.backlight = DEFAULT_BACKLIGHT_SETTING;
@@ -358,6 +407,8 @@ void settings_reset(void) {
global_settings.total_uptime = 0;
global_settings.scroll_speed = 8;
global_settings.ff_rewind = DEFAULT_FF_REWIND_SETTING;
+ global_settings.resume_index = -1;
+ global_settings.resume_offset = -1;
}
diff --git a/apps/settings.h b/apps/settings.h
index ba2a109..f3f6d84 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -21,6 +21,7 @@
#define __SETTINGS_H__
#include <stdbool.h>
+#include "file.h"
/* data structures */
@@ -49,8 +50,11 @@ struct user_settings
/* resume settings */
- int resume; /* power-on song resume: 0=no. 1=yes song. 2=yes pl */
- int track_time; /* number of seconds into the track to resume */
+ bool resume; /* resume option on/off */
+ 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 */
diff --git a/apps/settings_menu.c b/apps/settings_menu.c
index 0de99b0..e66d0f3 100644
--- a/apps/settings_menu.c
+++ b/apps/settings_menu.c
@@ -57,6 +57,11 @@ static void sort_case(void)
set_bool( "[Sort case sensitive]", &global_settings.sort_case );
}
+static void resume(void)
+{
+ set_bool( "[Resume]", &global_settings.resume );
+}
+
static void backlight_timer(void)
{
char* names[] = { "off", "on ",
@@ -153,13 +158,13 @@ void settings_menu(void)
{ "Time/Date", timedate_set },
#endif
{ "FF/Rewind", ff_rewind },
+ { "Resume", resume },
};
bool old_shuffle = global_settings.playlist_shuffle;
m=menu_init( items, sizeof items / sizeof(struct menu_items) );
menu_run(m);
menu_exit(m);
- settings_save();
if (old_shuffle != global_settings.playlist_shuffle)
{
diff --git a/apps/tree.c b/apps/tree.c
index d266051..5312885 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -102,12 +102,14 @@ extern unsigned char bitmap_icons_6x8[LastIcon][6];
#define TREE_EXIT BUTTON_LEFT
#define TREE_ENTER BUTTON_RIGHT
#define TREE_MENU BUTTON_F1
+#define RELEASE_MASK (BUTTON_OFF)
#else
#define TREE_NEXT BUTTON_RIGHT
#define TREE_PREV BUTTON_LEFT
#define TREE_EXIT BUTTON_STOP
#define TREE_ENTER BUTTON_PLAY
#define TREE_MENU BUTTON_MENU
+#define RELEASE_MASK (BUTTON_STOP)
#endif /* HAVE_RECORDER_KEYPAD */
#define TREE_ATTR_M3U 0x80 /* unused by FAT attributes */
@@ -292,6 +294,98 @@ static int showdir(char *path, int start)
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)
{
int numentries=0;
@@ -317,6 +411,9 @@ bool dirbrowse(char *root)
tree_max_on_screen = TREE_MAX_ON_SCREEN;
#endif
+ start_resume();
+ button_set_release(RELEASE_MASK);
+
memcpy(currdir,root,sizeof(currdir));
numentries = showdir(root, start);
if (numentries == -1)
@@ -350,6 +447,7 @@ bool dirbrowse(char *root)
restore = true;
}
break;
+
#ifdef HAVE_RECORDER_KEYPAD
case BUTTON_OFF:
mpeg_stop();
@@ -357,7 +455,15 @@ bool dirbrowse(char *root)
status_draw();
restore = true;
break;
+
+ case BUTTON_OFF | BUTTON_REL:
+#else
+ case BUTTON_STOP | BUTTON_REL:
#endif
+ global_settings.resume_index = -1;
+ settings_save();
+ break;
+
case TREE_ENTER:
#ifdef HAVE_RECORDER_KEYPAD
@@ -383,16 +489,34 @@ bool dirbrowse(char *root)
dircursor=0;
start=0;
} else {
+ int seed = current_tick;
lcd_stop_scroll();
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,
- dircache[dircursor+start].name, 0);
+ dircache[dircursor+start].name,
+ 0, 0, seed );
}
else {
+ if ( global_settings.resume )
+ strncpy(global_settings.resume_file,
+ currdir, MAX_PATH);
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_draw();
lcd_stop_scroll();
@@ -405,6 +529,7 @@ bool dirbrowse(char *root)
dirlevel = 0;
dircursor = 0;
start = 0;
+ global_settings.resume_index = -1;
}
}
restore = true;
diff --git a/apps/wps.c b/apps/wps.c
index 240bc96..5b30d2b 100644
--- a/apps/wps.c
+++ b/apps/wps.c
@@ -34,6 +34,7 @@
#include "powermgmt.h"
#include "status.h"
#include "main_menu.h"
+#include "ata.h"
#ifdef HAVE_LCD_BITMAP
#include "icons.h"
#include "widgets.h"
@@ -462,6 +463,13 @@ int wps_show(void)
{
mpeg_pause();
status_set_playmode(STATUS_PAUSE);
+ if (global_settings.resume) {
+ status_draw();
+ settings_save();
+#ifndef HAVE_RTC
+ ata_flush();
+#endif
+ }
}
else
{
@@ -577,7 +585,6 @@ int wps_show(void)
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
@@ -589,7 +596,6 @@ int wps_show(void)
#endif
{
mpeg_prev();
- status_set_playmode(STATUS_PLAY);
}
}
#ifdef HAVE_PLAYER_KEYPAD
@@ -612,7 +618,6 @@ int wps_show(void)
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
@@ -624,7 +629,6 @@ int wps_show(void)
#endif
{
mpeg_next();
- status_set_playmode(STATUS_PLAY);
}
}
#ifdef HAVE_PLAYER_KEYPAD
@@ -862,6 +866,16 @@ int wps_show(void)
if (mpeg_is_playing() && id3)
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();
break;
}
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 5c8ba2d..620f629 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -304,6 +304,7 @@ extern void ata_delayed_write(unsigned long sector, void* buf)
extern void ata_flush(void)
{
if ( delayed_write ) {
+ DEBUGF("ata_flush()\n");
delayed_write = false;
ata_write_sectors(delayed_sector_num, 1, delayed_sector);
}
diff --git a/firmware/id3.h b/firmware/id3.h
index 1a5bc74..d76614f 100644
--- a/firmware/id3.h
+++ b/firmware/id3.h
@@ -47,6 +47,10 @@ struct mp3entry {
/* these following two fields are used for local buffering */
char id3v2buf[300];
char id3v1buf[3][32];
+
+ /* resume related */
+ int offset; /* bytes played */
+ int index; /* playlist index */
};
#define VBR_FRAMES_FLAG 0x01
diff --git a/firmware/mpeg.c b/firmware/mpeg.c
index a8442f2..1356219 100644
--- a/firmware/mpeg.c
+++ b/firmware/mpeg.c
@@ -52,7 +52,8 @@
#define MPEG_SWAP_DATA 101
#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[] =
{
@@ -243,6 +244,7 @@ static void remove_all_tags(void)
}
#endif
+static bool paused; /* playback is paused */
#ifdef SIMULATOR
static bool playing = false;
static bool play_pending = false;
@@ -502,7 +504,7 @@ static void stop_dma(void)
static void dma_tick(void)
{
- if(playing)
+ if(playing && !paused)
{
/* Start DMA if it is disabled and the DEMAND pin is high */
if(!dma_on && (PBDR & 0x4000))
@@ -594,6 +596,7 @@ void DEI3(void)
DTCR3 = last_dma_chunk_size & 0xffff;
SAR3 = (unsigned int)mp3buf + mp3buf_read;
+ id3tags[tag_read_idx]->id3.offset += last_dma_chunk_size;
}
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 */
static int new_file(int steps)
{
- char *trackname;
-
do {
- trackname = playlist_next( steps );
+ char *trackname;
+ int index;
+
+ trackname = playlist_next( steps, &index );
if ( !trackname )
return -1;
@@ -666,6 +670,8 @@ static int new_file(int steps)
lseek(mpeg_file,
id3tags[tag_read_idx]->id3.id3v2len & ~1,
SEEK_SET);
+ id3tags[tag_read_idx]->id3.index = index;
+ id3tags[tag_read_idx]->id3.offset = 0;
}
} while ( mpeg_file < 0 );
@@ -706,6 +712,7 @@ static void mpeg_thread(void)
int amount_to_read;
int amount_to_swap;
int t1, t2;
+ int start_offset;
play_pending = false;
playing = false;
@@ -720,7 +727,7 @@ static void mpeg_thread(void)
switch(ev.id)
{
case MPEG_PLAY:
- DEBUGF("MPEG_PLAY %s\n",ev.data);
+ DEBUGF("MPEG_PLAY\n");
/* Stop the current stream */
play_pending = false;
playing = false;
@@ -732,18 +739,21 @@ static void mpeg_thread(void)
if(mpeg_file >= 0)
close(mpeg_file);
- mpeg_file = open((char*)ev.data, O_RDONLY);
- while (mpeg_file < 0) {
- DEBUGF("Couldn't open file: %s\n",ev.data);
- if ( new_file(1) == -1 )
- return;
+ if ( new_file(0) == -1 )
+ return;
+
+ start_offset = (int)ev.data;
+ if (start_offset) {
+ lseek(mpeg_file, start_offset, SEEK_SET);
+ id3tags[tag_read_idx]->id3.offset = start_offset;
}
+ else {
+ /* skip past id3v2 tag (to an even byte) */
+ lseek(mpeg_file,
+ id3tags[tag_read_idx]->id3.id3v2len & ~1,
+ SEEK_SET);
- add_track_to_tag_list((char *)ev.data);
- /* 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 */
filling = true;
@@ -752,6 +762,7 @@ static void mpeg_thread(void)
/* Tell the file loading code that we want to start playing
as soon as we have some data */
play_pending = true;
+ paused = false;
current_track_counter++;
break;
@@ -764,6 +775,7 @@ static void mpeg_thread(void)
case MPEG_PAUSE:
DEBUGF("MPEG_PAUSE\n");
/* Stop the current stream */
+ paused = true;
playing = false;
pause_tick = current_tick;
stop_dma();
@@ -775,6 +787,7 @@ static void mpeg_thread(void)
playing = true;
last_dma_tick += current_tick - pause_tick;
pause_tick = 0;
+ paused = false;
start_dma();
break;
@@ -799,7 +812,8 @@ static void mpeg_thread(void)
play_pending = true;
} else {
playing = true;
- start_dma();
+ if (!paused)
+ start_dma();
}
track_change();
@@ -931,7 +945,8 @@ static void mpeg_thread(void)
playing = true;
last_dma_tick = current_tick;
init_dma();
- start_dma();
+ if (!paused)
+ start_dma();
}
else
{
@@ -1016,7 +1031,8 @@ static void mpeg_thread(void)
last_dma_tick = current_tick;
init_dma();
- start_dma();
+ if (!paused)
+ start_dma();
/* Tell ourselves that we need more data */
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
@@ -1188,7 +1204,7 @@ static void setup_sci0(void)
static struct mp3entry taginfo;
#endif
-struct mp3entry* mpeg_current_track(void)
+struct mp3entry* mpeg_current_track()
{
#ifdef SIMULATOR
return &taginfo;
@@ -1210,13 +1226,17 @@ bool mpeg_has_changed_track(void)
return false;
}
-void mpeg_play(char* trackname)
+void mpeg_play(int offset)
{
#ifdef SIMULATOR
- mp3info(&taginfo, trackname);
- playing = true;
+ char* trackname = playlist_next( 0, NULL );
+ if ( trackname ) {
+ mp3info(&taginfo, trackname);
+ playing = true;
+ }
+ (void)offset;
#else
- queue_post(&mpeg_queue, MPEG_PLAY, trackname);
+ queue_post(&mpeg_queue, MPEG_PLAY, (void*)offset);
#endif
}
@@ -1252,7 +1272,7 @@ void mpeg_next(void)
#ifndef SIMULATOR
queue_post(&mpeg_queue, MPEG_NEXT, NULL);
#else
- char* file = playlist_next(1);
+ char* file = playlist_next(1,NULL);
mp3info(&taginfo, file);
current_track_counter++;
playing = true;
@@ -1264,7 +1284,7 @@ void mpeg_prev(void)
#ifndef SIMULATOR
queue_post(&mpeg_queue, MPEG_PREV, NULL);
#else
- char* file = playlist_next(-1);
+ char* file = playlist_next(-1,NULL);
mp3info(&taginfo, file);
current_track_counter--;
playing = true;
@@ -1282,7 +1302,7 @@ void mpeg_ff_rewind(int change)
bool mpeg_is_playing(void)
{
- return playing || play_pending;
+ return (playing || play_pending) && (!paused) ;
}
#ifndef SIMULATOR
diff --git a/firmware/mpeg.h b/firmware/mpeg.h
index 4836731..69110b3 100644
--- a/firmware/mpeg.h
+++ b/firmware/mpeg.h
@@ -22,7 +22,7 @@
#include <stdbool.h>
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_pause(void);
void mpeg_resume(void);
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c
index 22623dc..1446b82 100644
--- a/uisimulator/common/stubs.c
+++ b/uisimulator/common/stubs.c
@@ -80,3 +80,7 @@ void ata_delayed_write(unsigned long sector, void* buf)
{
ata_write_sectors(sector,1,buf);
}
+
+void ata_flush(void)
+{
+}