diff --git a/apps/playlist.c b/apps/playlist.c index 0cb9d09f32..f3081397f6 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 312964fd8c..e0c0841207 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 f8b6870863..41d04c2819 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 0x10 0x24 0x11 0x25 +0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume> +0x16 0x2b <(int) Byte offset into resume file> @@ -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); + /* 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 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 - /* calculate the checksum, check it and the header */ - chksum = calculate_config_checksum(); - - 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]) - { - DEBUGF( "load_config_buffer: header & checksum test ok\n" ); - last_checksum = chksum; - return 0; /* header and checksum is valid */ + 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; } - - /* 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; + + 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 (rtc_config_block[0x24] != 0xFF) - memcpy(&global_settings.total_uptime, &rtc_config_block[0x24], 4); + 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); + + 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 ba2a109f1a..f3f6d84327 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -21,6 +21,7 @@ #define __SETTINGS_H__ #include +#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 0de99b0335..e66d0f389c 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 d2660513a5..5312885f19 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 240bc96f07..5b30d2ba0e 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 5c8ba2d1b8..620f629e6e 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 1a5bc7441e..d76614f540 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 a8442f2e85..13562190ce 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; - 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); + 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); + + } /* 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 48367317dc..69110b34ec 100644 --- a/firmware/mpeg.h +++ b/firmware/mpeg.h @@ -22,7 +22,7 @@ #include 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 22623dcb5e..1446b82a4d 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) +{ +}