The much-anticipated queue patch by Hardeep Sidhu. Queue a file by holding down PLAY on it while playing other music.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3040 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
0e342181c3
commit
c78e1b07fe
10 changed files with 492 additions and 129 deletions
|
@ -23,5 +23,6 @@
|
||||||
#define AVERAGE_FILENAME_LENGTH 40
|
#define AVERAGE_FILENAME_LENGTH 40
|
||||||
#define MAX_DIR_LEVELS 10
|
#define MAX_DIR_LEVELS 10
|
||||||
#define MAX_PLAYLIST_SIZE 10000
|
#define MAX_PLAYLIST_SIZE 10000
|
||||||
|
#define MAX_QUEUED_FILES 100
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1221,3 +1221,18 @@ id: LANG_BATTERY_CAPACITY
|
||||||
desc: in settings_menu
|
desc: in settings_menu
|
||||||
eng: "Battery Capacity"
|
eng: "Battery Capacity"
|
||||||
new:
|
new:
|
||||||
|
|
||||||
|
id: LANG_QUEUE_QUEUED
|
||||||
|
desc: queued track name %s
|
||||||
|
eng: "Queued: %s"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_QUEUE_TOTAL
|
||||||
|
desc: number of queued tracks %d
|
||||||
|
eng: "Total queued: %d"
|
||||||
|
new:
|
||||||
|
|
||||||
|
id: LANG_QUEUE_FULL
|
||||||
|
desc: queue buffer full
|
||||||
|
eng: "Queue buffer full"
|
||||||
|
new:
|
||||||
|
|
364
apps/playlist.c
364
apps/playlist.c
|
@ -21,7 +21,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "playlist.h"
|
#include "playlist.h"
|
||||||
#include <file.h>
|
#include "file.h"
|
||||||
#include "sprintf.h"
|
#include "sprintf.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "mpeg.h"
|
#include "mpeg.h"
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
static struct playlist_info playlist;
|
static struct playlist_info playlist;
|
||||||
|
|
||||||
|
#define QUEUE_FILE ROCKBOX_DIR "/.queue_file"
|
||||||
#define PLAYLIST_BUFFER_SIZE (AVERAGE_FILENAME_LENGTH*MAX_FILES_IN_DIR)
|
#define PLAYLIST_BUFFER_SIZE (AVERAGE_FILENAME_LENGTH*MAX_FILES_IN_DIR)
|
||||||
|
|
||||||
static unsigned char playlist_buffer[PLAYLIST_BUFFER_SIZE];
|
static unsigned char playlist_buffer[PLAYLIST_BUFFER_SIZE];
|
||||||
|
@ -46,6 +47,207 @@ static int playlist_end_pos = 0;
|
||||||
|
|
||||||
static char now_playing[MAX_PATH+1];
|
static char now_playing[MAX_PATH+1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* remove any files and indices associated with the playlist
|
||||||
|
*/
|
||||||
|
static void empty_playlist(bool queue_resume)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
playlist.filename[0] = '\0';
|
||||||
|
playlist.index = 0;
|
||||||
|
playlist.queue_index = 0;
|
||||||
|
playlist.last_queue_index = 0;
|
||||||
|
playlist.amount = 0;
|
||||||
|
playlist.num_queued = 0;
|
||||||
|
playlist.start_queue = 0;
|
||||||
|
|
||||||
|
if (!queue_resume)
|
||||||
|
{
|
||||||
|
/* start with fresh queue file when starting new playlist */
|
||||||
|
remove(QUEUE_FILE);
|
||||||
|
fd = creat(QUEUE_FILE, 0);
|
||||||
|
if (fd > 0)
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update queue list after resume */
|
||||||
|
static void add_indices_to_queuelist(int seek)
|
||||||
|
{
|
||||||
|
int nread;
|
||||||
|
int fd = -1;
|
||||||
|
int i = seek;
|
||||||
|
int count = 0;
|
||||||
|
bool store_index;
|
||||||
|
char buf[MAX_PATH];
|
||||||
|
|
||||||
|
unsigned char *p = buf;
|
||||||
|
|
||||||
|
fd = open(QUEUE_FILE, O_RDONLY);
|
||||||
|
if(fd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nread = lseek(fd, seek, SEEK_SET);
|
||||||
|
if (nread < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
store_index = true;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
nread = read(fd, buf, MAX_PATH);
|
||||||
|
if(nread <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
|
||||||
|
for(count=0; count < nread; count++,p++) {
|
||||||
|
if(*p == '\n')
|
||||||
|
store_index = true;
|
||||||
|
else if(store_index)
|
||||||
|
{
|
||||||
|
store_index = false;
|
||||||
|
|
||||||
|
playlist.queue_indices[playlist.last_queue_index] = i+count;
|
||||||
|
playlist.last_queue_index =
|
||||||
|
(playlist.last_queue_index + 1) % MAX_QUEUED_FILES;
|
||||||
|
playlist.num_queued++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_next_index(int steps, bool *queue)
|
||||||
|
{
|
||||||
|
int current_index = playlist.index;
|
||||||
|
int next_index = -1;
|
||||||
|
|
||||||
|
if (global_settings.repeat_mode == REPEAT_ONE)
|
||||||
|
steps = 0;
|
||||||
|
else if (steps >= 0)
|
||||||
|
steps -= playlist.start_queue;
|
||||||
|
|
||||||
|
if (steps >= 0 && playlist.num_queued > 0 &&
|
||||||
|
playlist.num_queued - steps > 0)
|
||||||
|
*queue = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*queue = false;
|
||||||
|
if (playlist.num_queued)
|
||||||
|
{
|
||||||
|
if (steps >= 0)
|
||||||
|
steps -= (playlist.num_queued - 1);
|
||||||
|
else if (!playlist.start_queue)
|
||||||
|
steps += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (global_settings.repeat_mode)
|
||||||
|
{
|
||||||
|
case REPEAT_OFF:
|
||||||
|
if (*queue)
|
||||||
|
next_index = (playlist.queue_index+steps) % MAX_QUEUED_FILES;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (current_index < playlist.first_index)
|
||||||
|
current_index += playlist.amount;
|
||||||
|
current_index -= playlist.first_index;
|
||||||
|
|
||||||
|
next_index = current_index+steps;
|
||||||
|
if ((next_index < 0) || (next_index >= playlist.amount))
|
||||||
|
next_index = -1;
|
||||||
|
else
|
||||||
|
next_index = (next_index+playlist.first_index) %
|
||||||
|
playlist.amount;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REPEAT_ONE:
|
||||||
|
if (*queue && !playlist.start_queue)
|
||||||
|
next_index = playlist.queue_index;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
next_index = current_index;
|
||||||
|
*queue = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REPEAT_ALL:
|
||||||
|
default:
|
||||||
|
if (*queue)
|
||||||
|
next_index = (playlist.queue_index+steps) % MAX_QUEUED_FILES;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
next_index = (current_index+steps) % playlist.amount;
|
||||||
|
while (next_index < 0)
|
||||||
|
next_index += playlist.amount;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int playlist_amount(void)
|
||||||
|
{
|
||||||
|
return playlist.amount + playlist.num_queued;
|
||||||
|
}
|
||||||
|
|
||||||
|
int playlist_first_index(void)
|
||||||
|
{
|
||||||
|
return playlist.first_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
int playlist_get_resume_info(int *resume_index, int *queue_resume,
|
||||||
|
int *queue_resume_index)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
*resume_index = playlist.index;
|
||||||
|
|
||||||
|
if (playlist.num_queued > 0)
|
||||||
|
{
|
||||||
|
if (global_settings.save_queue_resume)
|
||||||
|
{
|
||||||
|
*queue_resume_index =
|
||||||
|
playlist.queue_indices[playlist.queue_index];
|
||||||
|
if (playlist.start_queue)
|
||||||
|
*queue_resume = QUEUE_BEGIN_PLAYLIST;
|
||||||
|
else
|
||||||
|
*queue_resume = QUEUE_BEGIN_QUEUE;
|
||||||
|
}
|
||||||
|
else if (!playlist.start_queue)
|
||||||
|
{
|
||||||
|
*queue_resume = QUEUE_OFF;
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*queue_resume = QUEUE_OFF;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *playlist_name(char *buf, int buf_size)
|
||||||
|
{
|
||||||
|
char *sep;
|
||||||
|
|
||||||
|
snprintf(buf, buf_size, "%s", playlist.filename+playlist.dirlen);
|
||||||
|
|
||||||
|
if (0 == buf[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Remove extension */
|
||||||
|
sep = strrchr(buf, '.');
|
||||||
|
if (NULL != sep)
|
||||||
|
*sep = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void playlist_clear(void)
|
void playlist_clear(void)
|
||||||
{
|
{
|
||||||
playlist_end_pos = 0;
|
playlist_end_pos = 0;
|
||||||
|
@ -66,73 +268,81 @@ int playlist_add(char *filename)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_next_index(int steps)
|
/* Add track to queue file */
|
||||||
|
int queue_add(char *filename)
|
||||||
{
|
{
|
||||||
int current_index = playlist.index;
|
int fd, seek, result;
|
||||||
int next_index = -1;
|
int len = strlen(filename);
|
||||||
|
|
||||||
switch (global_settings.repeat_mode)
|
if(playlist.num_queued >= MAX_QUEUED_FILES)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
fd = open(QUEUE_FILE, O_WRONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
seek = lseek(fd, 0, SEEK_END);
|
||||||
|
if (seek < 0)
|
||||||
{
|
{
|
||||||
case REPEAT_OFF:
|
close(fd);
|
||||||
if (current_index < playlist.first_index)
|
return -1;
|
||||||
current_index += playlist.amount;
|
|
||||||
current_index -= playlist.first_index;
|
|
||||||
|
|
||||||
next_index = current_index+steps;
|
|
||||||
if ((next_index < 0) || (next_index >= playlist.amount))
|
|
||||||
next_index = -1;
|
|
||||||
else
|
|
||||||
next_index = (next_index+playlist.first_index)%playlist.amount;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REPEAT_ONE:
|
|
||||||
next_index = current_index;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REPEAT_ALL:
|
|
||||||
default:
|
|
||||||
next_index = (current_index+steps) % playlist.amount;
|
|
||||||
while (next_index < 0)
|
|
||||||
next_index += playlist.amount;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return next_index;
|
filename[len] = '\n';
|
||||||
}
|
result = write(fd, filename, len+1);
|
||||||
|
if (result < 0)
|
||||||
/* the mpeg thread might ask us */
|
|
||||||
int playlist_amount(void)
|
|
||||||
{
|
{
|
||||||
return playlist.amount;
|
close(fd);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
filename[len] = '\0';
|
||||||
|
|
||||||
int playlist_first_index(void)
|
close(fd);
|
||||||
{
|
|
||||||
return playlist.first_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *playlist_name(char *buf, int buf_size)
|
if (playlist.num_queued <= 0)
|
||||||
{
|
playlist.start_queue = 1;
|
||||||
char *sep;
|
|
||||||
|
|
||||||
snprintf(buf, buf_size, "%s", playlist.filename+playlist.dirlen);
|
playlist.queue_indices[playlist.last_queue_index] = seek;
|
||||||
|
playlist.last_queue_index =
|
||||||
|
(playlist.last_queue_index + 1) % MAX_QUEUED_FILES;
|
||||||
|
playlist.num_queued++;
|
||||||
|
|
||||||
if (0 == buf[0])
|
mpeg_flush_and_reload_tracks();
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Remove extension */
|
return playlist.num_queued;
|
||||||
sep = strrchr(buf, '.');
|
|
||||||
if (NULL != sep)
|
|
||||||
*sep = 0;
|
|
||||||
|
|
||||||
return buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int playlist_next(int steps)
|
int playlist_next(int steps)
|
||||||
{
|
{
|
||||||
playlist.index = get_next_index(steps);
|
bool queue;
|
||||||
|
int index = get_next_index(steps, &queue);
|
||||||
|
|
||||||
return playlist.index;
|
if (queue)
|
||||||
|
{
|
||||||
|
int queue_diff = index - playlist.queue_index;
|
||||||
|
if (queue_diff < 0)
|
||||||
|
queue_diff += MAX_QUEUED_FILES;
|
||||||
|
|
||||||
|
playlist.num_queued -= queue_diff;
|
||||||
|
playlist.queue_index = index;
|
||||||
|
playlist.start_queue = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
playlist.index = index;
|
||||||
|
if (playlist.num_queued > 0 && !playlist.start_queue)
|
||||||
|
{
|
||||||
|
if (steps >= 0)
|
||||||
|
{
|
||||||
|
playlist.queue_index = playlist.last_queue_index;
|
||||||
|
playlist.num_queued = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
playlist.start_queue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* playlist_peek(int steps)
|
char* playlist_peek(int steps)
|
||||||
|
@ -145,12 +355,29 @@ char* playlist_peek(int steps)
|
||||||
char dir_buf[MAX_PATH+1];
|
char dir_buf[MAX_PATH+1];
|
||||||
char *dir_end;
|
char *dir_end;
|
||||||
int index;
|
int index;
|
||||||
|
bool queue;
|
||||||
|
|
||||||
index = get_next_index(steps);
|
index = get_next_index(steps, &queue);
|
||||||
if (index >= 0)
|
if (index < 0)
|
||||||
seek = playlist.indices[index];
|
return NULL;
|
||||||
|
|
||||||
|
if (queue)
|
||||||
|
{
|
||||||
|
seek = playlist.queue_indices[index];
|
||||||
|
fd = open(QUEUE_FILE, O_RDONLY);
|
||||||
|
if(-1 != fd)
|
||||||
|
{
|
||||||
|
buf = dir_buf;
|
||||||
|
lseek(fd, seek, SEEK_SET);
|
||||||
|
max = read(fd, buf, MAX_PATH);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
seek = playlist.indices[index];
|
||||||
|
|
||||||
if(playlist.in_ram)
|
if(playlist.in_ram)
|
||||||
{
|
{
|
||||||
|
@ -170,6 +397,7 @@ char* playlist_peek(int steps)
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Zero-terminate the file name */
|
/* Zero-terminate the file name */
|
||||||
seek=0;
|
seek=0;
|
||||||
|
@ -260,11 +488,13 @@ int play_list(char *dir, /* "current directory" */
|
||||||
playlist AFTER the shuffle */
|
playlist AFTER the shuffle */
|
||||||
int start_offset, /* offset in the file */
|
int start_offset, /* offset in the file */
|
||||||
int random_seed, /* used for shuffling */
|
int random_seed, /* used for shuffling */
|
||||||
int first_index ) /* first index of playlist */
|
int first_index, /* first index of playlist */
|
||||||
|
int queue_resume, /* resume queue list? */
|
||||||
|
int queue_resume_index ) /* queue list seek pos */
|
||||||
{
|
{
|
||||||
char *sep="";
|
char *sep="";
|
||||||
int dirlen;
|
int dirlen;
|
||||||
empty_playlist();
|
empty_playlist(queue_resume);
|
||||||
|
|
||||||
playlist.index = start_index;
|
playlist.index = start_index;
|
||||||
playlist.first_index = first_index;
|
playlist.first_index = first_index;
|
||||||
|
@ -343,6 +573,18 @@ int play_list(char *dir, /* "current directory" */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* update the queue indices */
|
||||||
|
if (queue_resume)
|
||||||
|
{
|
||||||
|
add_indices_to_queuelist(queue_resume_index);
|
||||||
|
|
||||||
|
if (queue_resume == QUEUE_BEGIN_PLAYLIST)
|
||||||
|
{
|
||||||
|
playlist.start_queue = 1;
|
||||||
|
playlist.index++; /* so we begin at the correct track */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!playlist.in_ram) {
|
if(!playlist.in_ram) {
|
||||||
lcd_puts(0,0,str(LANG_PLAYLIST_PLAY));
|
lcd_puts(0,0,str(LANG_PLAYLIST_PLAY));
|
||||||
status_draw();
|
status_draw();
|
||||||
|
@ -354,16 +596,6 @@ int play_list(char *dir, /* "current directory" */
|
||||||
return playlist.index;
|
return playlist.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* remove any filename and indices associated with the playlist
|
|
||||||
*/
|
|
||||||
void empty_playlist(void)
|
|
||||||
{
|
|
||||||
playlist.filename[0] = '\0';
|
|
||||||
playlist.index = 0;
|
|
||||||
playlist.amount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* calculate track offsets within a playlist file
|
* calculate track offsets within a playlist file
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,6 +36,13 @@ struct playlist_info
|
||||||
int seed; /* random seed */
|
int seed; /* random seed */
|
||||||
int amount; /* number of tracks in the index */
|
int amount; /* number of tracks in the index */
|
||||||
bool in_ram; /* True if the playlist is RAM-based */
|
bool in_ram; /* True if the playlist is RAM-based */
|
||||||
|
|
||||||
|
/* Queue function */
|
||||||
|
int queue_indices[MAX_QUEUED_FILES]; /* array of queue indices */
|
||||||
|
int last_queue_index; /* index of last queued track */
|
||||||
|
int queue_index; /* index of current playing queued track */
|
||||||
|
int num_queued; /* number of songs queued */
|
||||||
|
int start_queue; /* the first song was queued */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct playlist_info playlist;
|
extern struct playlist_info playlist;
|
||||||
|
@ -43,18 +50,23 @@ extern bool playlist_shuffle;
|
||||||
|
|
||||||
int play_list(char *dir, char *file, int start_index,
|
int play_list(char *dir, char *file, int start_index,
|
||||||
bool shuffled_index, int start_offset,
|
bool shuffled_index, int start_offset,
|
||||||
int random_seed, int first_index);
|
int random_seed, int first_index, int queue_resume,
|
||||||
|
int queue_resume_index);
|
||||||
char* playlist_peek(int steps);
|
char* playlist_peek(int steps);
|
||||||
char* playlist_name(char *name, int name_size);
|
char* playlist_name(char *name, int name_size);
|
||||||
int playlist_next(int steps);
|
int playlist_next(int steps);
|
||||||
void randomise_playlist( unsigned int seed );
|
void randomise_playlist( unsigned int seed );
|
||||||
void sort_playlist(bool start_current);
|
void sort_playlist(bool start_current);
|
||||||
void empty_playlist(void);
|
|
||||||
void add_indices_to_playlist(void);
|
void add_indices_to_playlist(void);
|
||||||
void playlist_clear(void);
|
void playlist_clear(void);
|
||||||
int playlist_add(char *filename);
|
int playlist_add(char *filename);
|
||||||
|
int queue_add(char *filename);
|
||||||
int playlist_amount(void);
|
int playlist_amount(void);
|
||||||
int playlist_first_index(void);
|
int playlist_first_index(void);
|
||||||
|
int playlist_get_resume_info(int *resume_index, int *queue_resume,
|
||||||
|
int *queue_resume_index);
|
||||||
|
|
||||||
|
enum { QUEUE_OFF, QUEUE_BEGIN_QUEUE, QUEUE_BEGIN_PLAYLIST, NUM_QUEUE_MODES };
|
||||||
|
|
||||||
#endif /* __PLAYLIST_H__ */
|
#endif /* __PLAYLIST_H__ */
|
||||||
|
|
||||||
|
|
|
@ -92,14 +92,10 @@ offset abs
|
||||||
0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
|
0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
|
||||||
0x16 0x2a <(int) Byte offset into resume file>
|
0x16 0x2a <(int) Byte offset into resume file>
|
||||||
0x1a 0x2e <time until disk spindown>
|
0x1a 0x2e <time until disk spindown>
|
||||||
0x1b 0x2f <browse current, play selected>
|
0x1b 0x2f <browse current, play selected, queue_resume>
|
||||||
0x1c 0x30 <peak meter hold timeout (bit 0-4)>,
|
0x1c 0x30 <peak meter hold timeout (bit 0-4)>,
|
||||||
peak_meter_performance (bit 7)
|
peak_meter_performance (bit 7)
|
||||||
0x1d 0x31 <peak meter clip hold timeout (bit 0-4)
|
0x1d 0x31 <(int) queue resume index>
|
||||||
0x1e 0x32 <peak meter release step size,
|
|
||||||
peak_meter_dbfs (bit 7)
|
|
||||||
0x1f 0x33 <peak meter min either in -db or in percent>
|
|
||||||
0x20 0x34 <peak meter max either in -db or in percent>
|
|
||||||
0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
|
0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
|
||||||
mic gain (bit 4-7)>
|
mic gain (bit 4-7)>
|
||||||
0x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)>
|
0x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)>
|
||||||
|
@ -125,7 +121,10 @@ modified unless the header & checksum test fails.
|
||||||
|
|
||||||
|
|
||||||
Rest of config block, only saved to disk:
|
Rest of config block, only saved to disk:
|
||||||
|
0xB0 peak meter clip hold timeout (bit 0-4)
|
||||||
|
0xB1 peak meter release step size, peak_meter_dbfs (bit 7)
|
||||||
|
0xB2 peak meter min either in -db or in percent
|
||||||
|
0xB3 peak meter max either in -db or in percent
|
||||||
0xB4 battery capacity
|
0xB4 battery capacity
|
||||||
0xB5 scroll step in pixels
|
0xB5 scroll step in pixels
|
||||||
0xB6 scroll start and endpoint delay
|
0xB6 scroll start and endpoint delay
|
||||||
|
@ -330,15 +329,13 @@ int settings_save( void )
|
||||||
config_block[0x1a] = (unsigned char)global_settings.disk_spindown;
|
config_block[0x1a] = (unsigned char)global_settings.disk_spindown;
|
||||||
config_block[0x1b] = (unsigned char)
|
config_block[0x1b] = (unsigned char)
|
||||||
(((global_settings.browse_current & 1)) |
|
(((global_settings.browse_current & 1)) |
|
||||||
((global_settings.play_selected & 1) << 1));
|
((global_settings.play_selected & 1) << 1) |
|
||||||
|
((global_settings.queue_resume & 3) << 2));
|
||||||
|
|
||||||
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
|
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold;
|
||||||
config_block[0x1d] = (unsigned char)global_settings.peak_meter_clip_hold |
|
|
||||||
(global_settings.peak_meter_performance ? 0x80 : 0);
|
memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4);
|
||||||
config_block[0x1e] = global_settings.peak_meter_release |
|
|
||||||
(global_settings.peak_meter_dbfs ? 0x80 : 0);
|
|
||||||
config_block[0x1f] = (unsigned char)global_settings.peak_meter_min;
|
|
||||||
config_block[0x20] = (unsigned char)global_settings.peak_meter_max;
|
|
||||||
config_block[0x21] = (unsigned char)
|
config_block[0x21] = (unsigned char)
|
||||||
((global_settings.repeat_mode & 3) |
|
((global_settings.repeat_mode & 3) |
|
||||||
((global_settings.rec_channels & 1) << 2) |
|
((global_settings.rec_channels & 1) << 2) |
|
||||||
|
@ -369,6 +366,13 @@ int settings_save( void )
|
||||||
config_block[0x29]=(unsigned char)(global_settings.topruntime >> 8);
|
config_block[0x29]=(unsigned char)(global_settings.topruntime >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config_block[0xb0] = (unsigned char)global_settings.peak_meter_clip_hold |
|
||||||
|
(global_settings.peak_meter_performance ? 0x80 : 0);
|
||||||
|
config_block[0xb1] = global_settings.peak_meter_release |
|
||||||
|
(global_settings.peak_meter_dbfs ? 0x80 : 0);
|
||||||
|
config_block[0xb2] = (unsigned char)global_settings.peak_meter_min;
|
||||||
|
config_block[0xb3] = (unsigned char)global_settings.peak_meter_max;
|
||||||
|
|
||||||
config_block[0xb4]=(global_settings.battery_capacity - 1000) / 50;
|
config_block[0xb4]=(global_settings.battery_capacity - 1000) / 50;
|
||||||
config_block[0xb5]=(unsigned char)global_settings.scroll_step;
|
config_block[0xb5]=(unsigned char)global_settings.scroll_step;
|
||||||
config_block[0xb6]=(unsigned char)global_settings.scroll_delay;
|
config_block[0xb6]=(unsigned char)global_settings.scroll_delay;
|
||||||
|
@ -595,27 +599,15 @@ void settings_load(void)
|
||||||
if (config_block[0x1b] != 0xFF) {
|
if (config_block[0x1b] != 0xFF) {
|
||||||
global_settings.browse_current = (config_block[0x1b]) & 1;
|
global_settings.browse_current = (config_block[0x1b]) & 1;
|
||||||
global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
|
global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
|
||||||
|
global_settings.queue_resume = (config_block[0x1b] >> 2) & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_block[0x1c] != 0xFF)
|
if (config_block[0x1c] != 0xFF)
|
||||||
global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
|
global_settings.peak_meter_hold = (config_block[0x1c]) & 0x1f;
|
||||||
|
|
||||||
if (config_block[0x1d] != 0xFF) {
|
if (config_block[0x1d] != 0xFF)
|
||||||
global_settings.peak_meter_clip_hold = (config_block[0x1d]) & 0x1f;
|
memcpy(&global_settings.queue_resume_index, &config_block[0x1d],
|
||||||
global_settings.peak_meter_performance =
|
4);
|
||||||
(config_block[0x1d] & 0x80) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_block[0x1e] != 0xFF) {
|
|
||||||
global_settings.peak_meter_release = config_block[0x1e] & 0x7f;
|
|
||||||
global_settings.peak_meter_dbfs = (config_block[0x1e] & 0x80) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config_block[0x1f] != 0xFF)
|
|
||||||
global_settings.peak_meter_min = config_block[0x1f];
|
|
||||||
|
|
||||||
if (config_block[0x20] != 0xFF)
|
|
||||||
global_settings.peak_meter_max = config_block[0x20];
|
|
||||||
|
|
||||||
if (config_block[0x21] != 0xFF)
|
if (config_block[0x21] != 0xFF)
|
||||||
{
|
{
|
||||||
|
@ -652,6 +644,16 @@ void settings_load(void)
|
||||||
global_settings.topruntime =
|
global_settings.topruntime =
|
||||||
config_block[0x28] | (config_block[0x29] << 8);
|
config_block[0x28] | (config_block[0x29] << 8);
|
||||||
|
|
||||||
|
global_settings.peak_meter_clip_hold = (config_block[0xb0]) & 0x1f;
|
||||||
|
global_settings.peak_meter_performance =
|
||||||
|
(config_block[0xb0] & 0x80) != 0;
|
||||||
|
|
||||||
|
global_settings.peak_meter_release = config_block[0xb1] & 0x7f;
|
||||||
|
global_settings.peak_meter_dbfs = (config_block[0xb1] & 0x80) != 0;
|
||||||
|
|
||||||
|
global_settings.peak_meter_min = config_block[0xb2];
|
||||||
|
global_settings.peak_meter_max = config_block[0xb3];
|
||||||
|
|
||||||
global_settings.battery_capacity = config_block[0xb4]*50 + 1000;
|
global_settings.battery_capacity = config_block[0xb4]*50 + 1000;
|
||||||
|
|
||||||
if (config_block[0xb5] != 0xff)
|
if (config_block[0xb5] != 0xff)
|
||||||
|
@ -857,6 +859,9 @@ void settings_reset(void) {
|
||||||
global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
|
global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
|
||||||
global_settings.resume_index = -1;
|
global_settings.resume_index = -1;
|
||||||
global_settings.resume_offset = -1;
|
global_settings.resume_offset = -1;
|
||||||
|
global_settings.save_queue_resume = true;
|
||||||
|
global_settings.queue_resume = 0;
|
||||||
|
global_settings.queue_resume_index = -1;
|
||||||
global_settings.disk_spindown = 5;
|
global_settings.disk_spindown = 5;
|
||||||
global_settings.disk_poweroff = false;
|
global_settings.disk_poweroff = false;
|
||||||
global_settings.buffer_margin = 0;
|
global_settings.buffer_margin = 0;
|
||||||
|
|
|
@ -94,6 +94,13 @@ struct user_settings
|
||||||
int resume_offset; /* byte offset in mp3 file */
|
int resume_offset; /* byte offset in mp3 file */
|
||||||
int resume_seed; /* random seed for playlist shuffle */
|
int resume_seed; /* random seed for playlist shuffle */
|
||||||
int resume_first_index; /* first index of playlist */
|
int resume_first_index; /* first index of playlist */
|
||||||
|
|
||||||
|
bool save_queue_resume; /* save queued songs for resume */
|
||||||
|
int queue_resume; /* resume queue file?: 0 = no
|
||||||
|
1 = resume at queue index
|
||||||
|
2 = resume at playlist index */
|
||||||
|
int queue_resume_index; /* queue index (seek point in queue file) */
|
||||||
|
|
||||||
unsigned char resume_file[MAX_PATH+1]; /* playlist name (or dir) */
|
unsigned char resume_file[MAX_PATH+1]; /* playlist name (or dir) */
|
||||||
unsigned char font_file[MAX_FILENAME+1]; /* last font */
|
unsigned char font_file[MAX_FILENAME+1]; /* last font */
|
||||||
unsigned char wps_file[MAX_FILENAME+1]; /* last wps */
|
unsigned char wps_file[MAX_FILENAME+1]; /* last wps */
|
||||||
|
|
74
apps/tree.c
74
apps/tree.c
|
@ -452,6 +452,36 @@ static int showdir(char *path, int start)
|
||||||
return filesindir;
|
return filesindir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void show_queue_display(int queue_count, char *filename)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
lcd_double_height(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LCD_BITMAP
|
||||||
|
lcd_setmargins(0,0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lcd_clear_display();
|
||||||
|
if (queue_count > 0)
|
||||||
|
{
|
||||||
|
char s[32];
|
||||||
|
|
||||||
|
snprintf(s, sizeof(s), str(LANG_QUEUE_QUEUED), filename);
|
||||||
|
lcd_puts(0,0,s);
|
||||||
|
|
||||||
|
snprintf(s, sizeof(s), str(LANG_QUEUE_TOTAL), queue_count);
|
||||||
|
lcd_puts(0,1,s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lcd_puts(0,0,str(LANG_QUEUE_FULL));
|
||||||
|
}
|
||||||
|
lcd_update();
|
||||||
|
sleep(HZ);
|
||||||
|
lcd_clear_display();
|
||||||
|
}
|
||||||
|
|
||||||
bool ask_resume(void)
|
bool ask_resume(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LCD_CHARCELLS
|
#ifdef HAVE_LCD_CHARCELLS
|
||||||
|
@ -518,7 +548,9 @@ void start_resume(void)
|
||||||
true, /* the index is AFTER shuffle */
|
true, /* the index is AFTER shuffle */
|
||||||
global_settings.resume_offset,
|
global_settings.resume_offset,
|
||||||
global_settings.resume_seed,
|
global_settings.resume_seed,
|
||||||
global_settings.resume_first_index);
|
global_settings.resume_first_index,
|
||||||
|
global_settings.queue_resume,
|
||||||
|
global_settings.queue_resume_index);
|
||||||
*slash='/';
|
*slash='/';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -537,7 +569,9 @@ void start_resume(void)
|
||||||
true,
|
true,
|
||||||
global_settings.resume_offset,
|
global_settings.resume_offset,
|
||||||
global_settings.resume_seed,
|
global_settings.resume_seed,
|
||||||
global_settings.resume_first_index);
|
global_settings.resume_first_index,
|
||||||
|
global_settings.queue_resume,
|
||||||
|
global_settings.queue_resume_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -556,7 +590,9 @@ void start_resume(void)
|
||||||
true,
|
true,
|
||||||
global_settings.resume_offset,
|
global_settings.resume_offset,
|
||||||
global_settings.resume_seed,
|
global_settings.resume_seed,
|
||||||
global_settings.resume_first_index);
|
global_settings.resume_first_index,
|
||||||
|
global_settings.queue_resume,
|
||||||
|
global_settings.queue_resume_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
status_set_playmode(STATUS_PLAY);
|
status_set_playmode(STATUS_PLAY);
|
||||||
|
@ -774,10 +810,10 @@ bool dirbrowse(char *root)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case TREE_ENTER:
|
case TREE_ENTER | BUTTON_REL:
|
||||||
case TREE_ENTER | BUTTON_REPEAT:
|
case TREE_ENTER | BUTTON_REPEAT:
|
||||||
#ifdef HAVE_RECORDER_KEYPAD
|
#ifdef HAVE_RECORDER_KEYPAD
|
||||||
case BUTTON_PLAY:
|
case BUTTON_PLAY | BUTTON_REL:
|
||||||
case BUTTON_PLAY | BUTTON_REPEAT:
|
case BUTTON_PLAY | BUTTON_REPEAT:
|
||||||
#endif
|
#endif
|
||||||
if ( !numentries )
|
if ( !numentries )
|
||||||
|
@ -798,6 +834,7 @@ bool dirbrowse(char *root)
|
||||||
dircursor=0;
|
dircursor=0;
|
||||||
dirstart=0;
|
dirstart=0;
|
||||||
} else {
|
} else {
|
||||||
|
static int repeat_count = 0;
|
||||||
int seed = current_tick;
|
int seed = current_tick;
|
||||||
bool play = false;
|
bool play = false;
|
||||||
int start_index=0;
|
int start_index=0;
|
||||||
|
@ -810,23 +847,40 @@ bool dirbrowse(char *root)
|
||||||
MAX_PATH, "%s/%s",
|
MAX_PATH, "%s/%s",
|
||||||
currdir, file->name);
|
currdir, file->name);
|
||||||
play_list(currdir, file->name, 0, false, 0,
|
play_list(currdir, file->name, 0, false, 0,
|
||||||
seed, 0);
|
seed, 0, 0, -1);
|
||||||
start_index = 0;
|
start_index = 0;
|
||||||
play = true;
|
play = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TREE_ATTR_MPA:
|
case TREE_ATTR_MPA:
|
||||||
|
if (button & BUTTON_REPEAT &&
|
||||||
|
mpeg_status() & MPEG_STATUS_PLAY)
|
||||||
|
{
|
||||||
|
int queue_count = queue_add(buf);
|
||||||
|
show_queue_display(queue_count,
|
||||||
|
file->name);
|
||||||
|
|
||||||
|
while( !(button_get(true) & BUTTON_REL) ) ;
|
||||||
|
|
||||||
|
repeat_count = 0;
|
||||||
|
restore = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
repeat_count = 0;
|
||||||
if ( global_settings.resume )
|
if ( global_settings.resume )
|
||||||
strncpy(global_settings.resume_file,
|
strncpy(global_settings.resume_file,
|
||||||
currdir, MAX_PATH);
|
currdir, MAX_PATH);
|
||||||
start_index = build_playlist(dircursor+dirstart);
|
start_index =
|
||||||
|
build_playlist(dircursor+dirstart);
|
||||||
|
|
||||||
/* it is important that we get back the index in
|
/* it is important that we get back the index
|
||||||
the (shuffled) list and stor that */
|
in the (shuffled) list and store that */
|
||||||
start_index = play_list(currdir, NULL,
|
start_index = play_list(currdir, NULL,
|
||||||
start_index, false,
|
start_index, false,
|
||||||
0, seed, 0);
|
0, seed, 0, 0, -1);
|
||||||
play = true;
|
play = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* wps config file */
|
/* wps config file */
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "main_menu.h"
|
#include "main_menu.h"
|
||||||
#include "ata.h"
|
#include "ata.h"
|
||||||
#include "screens.h"
|
#include "screens.h"
|
||||||
|
#include "playlist.h"
|
||||||
#ifdef HAVE_LCD_BITMAP
|
#ifdef HAVE_LCD_BITMAP
|
||||||
#include "icons.h"
|
#include "icons.h"
|
||||||
#include "peakmeter.h"
|
#include "peakmeter.h"
|
||||||
|
@ -437,10 +438,15 @@ static bool update(void)
|
||||||
global_settings.resume_offset != id3->offset ) {
|
global_settings.resume_offset != id3->offset ) {
|
||||||
DEBUGF("R%X,%X (%X)\n", global_settings.resume_offset,
|
DEBUGF("R%X,%X (%X)\n", global_settings.resume_offset,
|
||||||
id3->offset,id3);
|
id3->offset,id3);
|
||||||
global_settings.resume_index = id3->index;
|
|
||||||
|
if (!playlist_get_resume_info(&global_settings.resume_index,
|
||||||
|
&global_settings.queue_resume,
|
||||||
|
&global_settings.queue_resume_index))
|
||||||
|
{
|
||||||
global_settings.resume_offset = id3->offset;
|
global_settings.resume_offset = id3->offset;
|
||||||
settings_save();
|
settings_save();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if ( !id3 && track_changed ) {
|
else if ( !id3 && track_changed ) {
|
||||||
global_settings.resume_index = -1;
|
global_settings.resume_index = -1;
|
||||||
global_settings.resume_offset = -1;
|
global_settings.resume_offset = -1;
|
||||||
|
|
|
@ -21,13 +21,18 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int x11_open(char *name, int opts);
|
int x11_open(char *name, int opts);
|
||||||
|
int x11_creat(char *name, int mode);
|
||||||
|
int x11_remove(char *name);
|
||||||
|
|
||||||
#define open(x,y) x11_open(x,y)
|
#define open(x,y) x11_open(x,y)
|
||||||
|
#define creat(x,y) x11_open(x,y)
|
||||||
|
#define remove(x) x11_remove(x)
|
||||||
|
|
||||||
#include "../../firmware/common/file.h"
|
#include "../../firmware/common/file.h"
|
||||||
|
|
||||||
extern int open(char* pathname, int flags);
|
extern int open(char* pathname, int flags);
|
||||||
extern int close(int fd);
|
extern int close(int fd);
|
||||||
extern int read(int fd, void* buf, int count);
|
extern int read(int fd, void* buf, int count);
|
||||||
|
extern int write(int fd, void* buf, int count);
|
||||||
extern int lseek(int fd, int offset, int whence);
|
extern int lseek(int fd, int offset, int whence);
|
||||||
extern int printf(const char *format, ...);
|
extern int printf(const char *format, ...);
|
||||||
|
|
|
@ -109,6 +109,32 @@ int x11_open(char *name, int opts)
|
||||||
return open(name, opts);
|
return open(name, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int x11_creat(char *name, int mode)
|
||||||
|
{
|
||||||
|
char buffer[256]; /* sufficiently big */
|
||||||
|
|
||||||
|
if(name[0] == '/') {
|
||||||
|
sprintf(buffer, "%s%s", SIMULATOR_ARCHOS_ROOT, name);
|
||||||
|
|
||||||
|
debugf("We open the real file '%s'\n", buffer);
|
||||||
|
return creat(buffer, mode);
|
||||||
|
}
|
||||||
|
return creat(name, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x11_remove(char *name)
|
||||||
|
{
|
||||||
|
char buffer[256]; /* sufficiently big */
|
||||||
|
|
||||||
|
if(name[0] == '/') {
|
||||||
|
sprintf(buffer, "%s%s", SIMULATOR_ARCHOS_ROOT, name);
|
||||||
|
|
||||||
|
debugf("We open the real file '%s'\n", buffer);
|
||||||
|
return remove(buffer);
|
||||||
|
}
|
||||||
|
return remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
void fat_size(unsigned int* size, unsigned int* free)
|
void fat_size(unsigned int* size, unsigned int* free)
|
||||||
{
|
{
|
||||||
struct statfs fs;
|
struct statfs fs;
|
||||||
|
|
Loading…
Reference in a new issue