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:
parent
085e774675
commit
6224cdb166
12 changed files with 379 additions and 144 deletions
|
@ -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;
|
||||
|
@ -104,6 +104,8 @@ char* playlist_next(int steps)
|
|||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
239
apps/settings.c
239
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" );
|
||||
|
||||
#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
|
||||
if (fat_startsector() != 0) {
|
||||
ata_read_sectors( 61, 1, config_block);
|
||||
|
||||
/* calculate the checksum, check it and the header */
|
||||
chksum = calculate_config_checksum();
|
||||
chksum = calculate_config_checksum(config_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 (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" );
|
||||
last_checksum = chksum;
|
||||
return 0; /* header and checksum is valid */
|
||||
correct = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* if checksum is not valid, initialize the config buffer to all-unused */
|
||||
#ifdef HAVE_RTC
|
||||
/* 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
|
||||
|
||||
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 -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -218,32 +238,46 @@ 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())
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
129
apps/tree.c
129
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;
|
||||
|
|
22
apps/wps.c
22
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,19 +739,22 @@ 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 )
|
||||
if ( new_file(0) == -1 )
|
||||
return;
|
||||
}
|
||||
|
||||
add_track_to_tag_list((char *)ev.data);
|
||||
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;
|
||||
queue_post(&mpeg_queue, MPEG_NEED_DATA, 0);
|
||||
|
@ -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,6 +812,7 @@ static void mpeg_thread(void)
|
|||
play_pending = true;
|
||||
} else {
|
||||
playing = true;
|
||||
if (!paused)
|
||||
start_dma();
|
||||
}
|
||||
|
||||
|
@ -931,6 +945,7 @@ static void mpeg_thread(void)
|
|||
playing = true;
|
||||
last_dma_tick = current_tick;
|
||||
init_dma();
|
||||
if (!paused)
|
||||
start_dma();
|
||||
}
|
||||
else
|
||||
|
@ -1016,6 +1031,7 @@ static void mpeg_thread(void)
|
|||
|
||||
last_dma_tick = current_tick;
|
||||
init_dma();
|
||||
if (!paused)
|
||||
start_dma();
|
||||
|
||||
/* Tell ourselves that we need more data */
|
||||
|
@ -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
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -80,3 +80,7 @@ void ata_delayed_write(unsigned long sector, void* buf)
|
|||
{
|
||||
ata_write_sectors(sector,1,buf);
|
||||
}
|
||||
|
||||
void ata_flush(void)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue