Added dynamic playlists. ON+PLAY->Playlist on a track, directory, or playlist from file browser to see available options.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3796 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Hardeep Sidhu 2003-07-01 21:05:43 +00:00
parent 928a09e3f4
commit 9e4262081b
24 changed files with 2310 additions and 1005 deletions

View file

@ -23,6 +23,5 @@
#define AVERAGE_FILENAME_LENGTH 40
#define MAX_DIR_LEVELS 10
#define MAX_PLAYLIST_SIZE 10000
#define MAX_QUEUED_FILES 100
#endif

View file

@ -1632,3 +1632,93 @@ id: LANG_STAR
desc: in the games menu
eng: "Star"
new:
id: LANG_QUEUE_LAST
desc: in onplay menu. queue a track/playlist at end of playlist.
eng: "Queue last"
new:
id: LANG_INSERT
desc: in onplay menu. insert a track/playlist into dynamic playlist.
eng: "Insert"
new:
id: LANG_INSERT_LAST
desc: in onplay menu. append a track/playlist into dynamic playlist.
eng: "Insert last"
new:
id: LANG_QUEUE_FIRST
desc: in onplay menu. queue a track/playlist into dynamic playlist.
eng: "Queue first"
new:
id: LANG_INSERT_FIRST
desc: in onplay menu. insert a track/playlist into dynamic playlist.
eng: "Insert first"
new:
id: LANG_SAVE_DYNAMIC_PLAYLIST
desc: in playlist menu.
eng: "Save Dynamic Playlist"
new:
id: LANG_PLAYLIST_MENU
desc: in main menu.
eng: "Playlist Options"
new:
id: LANG_PLAYLIST_INSERT_COUNT
desc: splash number of tracks inserted
eng: "Inserted %d tracks (%s)"
new:
id: LANG_PLAYLIST_QUEUE_COUNT
desc: splash number of tracks queued
eng: "Queued %d tracks (%s)"
new:
id: LANG_PLAYLIST_SAVE_COUNT
desc: splash number of tracks saved
eng: "Saved %d tracks (%s)"
new:
id: LANG_OFF_ABORT
desc: Used on recorder models
eng: "OFF to abort"
new:
id: LANG_STOP_ABORT
desc: Used on player models
eng: "STOP to abort"
new:
id: LANG_PLAYLIST_CONTROL_UPDATE_ERROR
desc: Playlist error
eng: "Error updating playlist control file"
new:
id: LANG_PLAYLIST_ACCESS_ERROR
desc: Playlist error
eng: "Error accessing playlist file"
new:
id: LANG_PLAYLIST_CONTROL_ACCESS_ERROR
desc: Playlist error
eng: "Error accessing playlist control file"
new:
id: LANG_PLAYLIST_DIRECTORY_ACCESS_ERROR
desc: Playlist error
eng: "Error accessing directory"
new:
id: LANG_PLAYLIST_CONTROL_INVALID
desc: Playlist resume error
eng: "Playlist control file is invalid"
new:
id: LANG_RECURSE_DIRECTORY
desc: In playlist menu
eng: "Recursively Insert Directories"
new:

View file

@ -43,6 +43,7 @@
#include "wps.h"
#include "buffer.h"
#include "screens.h"
#include "playlist_menu.h"
#ifdef HAVE_FMRADIO
#include "radio.h"
#endif
@ -266,7 +267,7 @@ bool main_menu(void)
{ str(LANG_RECORDING), recording_screen },
{ str(LANG_RECORDING_SETTINGS), recording_menu },
#endif
{ str(LANG_CREATE_PLAYLIST), create_playlist },
{ str(LANG_PLAYLIST_MENU), playlist_menu },
{ str(LANG_MENU_SHOW_ID3_INFO), browse_id3 },
{ str(LANG_SLEEP_TIMER), sleeptimer_screen },
#ifdef HAVE_ALARM_MOD

View file

@ -38,13 +38,103 @@
#include "screens.h"
#include "tree.h"
#include "buffer.h"
#include "settings.h"
#include "status.h"
#include "onplay.h"
static char* selected_file = NULL;
static bool reload_dir = false;
static int selected_file_attr = 0;
static int onplay_result = ONPLAY_OK;
static bool queue_file(void)
/* For playlist options */
struct playlist_args {
int position;
bool queue;
};
static bool add_to_playlist(int position, bool queue)
{
queue_add(selected_file);
bool new_playlist = !(mpeg_status() & MPEG_STATUS_PLAY);
if (new_playlist)
playlist_create(NULL, NULL);
if (selected_file_attr & TREE_ATTR_MPA)
playlist_insert_track(selected_file, position, queue);
else if (selected_file_attr & ATTR_DIRECTORY)
playlist_insert_directory(selected_file, position, queue);
else if (selected_file_attr & TREE_ATTR_M3U)
playlist_insert_playlist(selected_file, position, queue);
if (new_playlist && (playlist_amount() > 0))
{
/* nothing is currently playing so begin playing what we just
inserted */
if (global_settings.playlist_shuffle)
playlist_shuffle(current_tick, -1);
playlist_start(0,0);
status_set_playmode(STATUS_PLAY);
status_draw(false);
onplay_result = ONPLAY_START_PLAY;
}
return false;
}
/* Sub-menu for playlist options */
static bool playlist_options(void)
{
struct menu_items menu[6];
struct playlist_args args[6]; /* increase these 2 if you add entries! */
int m, i=0, result;
if (mpeg_status() & MPEG_STATUS_PLAY)
{
menu[i].desc = str(LANG_INSERT);
args[i].position = PLAYLIST_INSERT;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_INSERT_FIRST);
args[i].position = PLAYLIST_INSERT_FIRST;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_INSERT_LAST);
args[i].position = PLAYLIST_INSERT_LAST;
args[i].queue = false;
i++;
menu[i].desc = str(LANG_QUEUE);
args[i].position = PLAYLIST_INSERT;
args[i].queue = true;
i++;
menu[i].desc = str(LANG_QUEUE_FIRST);
args[i].position = PLAYLIST_INSERT_FIRST;
args[i].queue = true;
i++;
menu[i].desc = str(LANG_QUEUE_LAST);
args[i].position = PLAYLIST_INSERT_LAST;
args[i].queue = true;
i++;
}
else if ((selected_file_attr & TREE_ATTR_MPA) ||
(selected_file_attr & ATTR_DIRECTORY))
{
menu[i].desc = str(LANG_INSERT);
args[i].position = PLAYLIST_INSERT;
args[i].queue = false;
i++;
}
m = menu_init( menu, i );
result = menu_show(m);
if (result >= 0)
add_to_playlist(args[result].position, args[result].queue);
menu_exit(m);
return false;
}
@ -68,7 +158,7 @@ static bool delete_file(void)
switch (btn) {
case BUTTON_PLAY:
if (!remove(selected_file)) {
reload_dir = true;
onplay_result = ONPLAY_RELOAD_DIR;
lcd_clear_display();
lcd_puts(0,0,str(LANG_DELETED));
lcd_puts_scroll(0,1,selected_file);
@ -104,7 +194,7 @@ static bool rename_file(void)
sleep(HZ*2);
}
else
reload_dir = true;
onplay_result = ONPLAY_RELOAD_DIR;
}
return false;
@ -225,7 +315,7 @@ static bool vbr_fix(void)
if(mpeg_status()) {
splash(HZ*2, 0, true, str(LANG_VBRFIX_STOP_PLAY));
return reload_dir;
return onplay_result;
}
lcd_clear_display();
@ -356,12 +446,16 @@ int onplay(char* file, int attr)
struct menu_items menu[5]; /* increase this if you add entries! */
int m, i=0, result;
onplay_result = ONPLAY_OK;
selected_file = file;
if ((mpeg_status() & MPEG_STATUS_PLAY) && (attr & TREE_ATTR_MPA))
selected_file_attr = attr;
if ((attr & TREE_ATTR_MPA) || (attr & ATTR_DIRECTORY) ||
(attr & TREE_ATTR_M3U))
{
menu[i].desc = str(LANG_QUEUE);
menu[i].function = queue_file;
menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST);
menu[i].function = playlist_options;
i++;
}
@ -390,5 +484,5 @@ int onplay(char* file, int attr)
menu[result].function();
menu_exit(m);
return reload_dir;
return onplay_result;
}

View file

@ -21,4 +21,10 @@
int onplay(char* file, int attr);
enum {
ONPLAY_OK,
ONPLAY_RELOAD_DIR,
ONPLAY_START_PLAY
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -22,57 +22,56 @@
#include <stdbool.h>
#include "file.h"
#include "applimits.h"
#include "kernel.h"
/* playlist data */
struct playlist_info
{
char filename[MAX_PATH]; /* path name of m3u playlist on disk */
int fd; /* file descriptor of the open playlist */
int fd; /* descriptor of the open playlist file */
int control_fd; /* descriptor of the open control file */
int dirlen; /* Length of the path to the playlist file */
int *indices; /* array of indices */
int max_playlist_size; /* Max number of files in playlist. Mirror of
unsigned int *indices; /* array of indices */
int max_playlist_size; /* Max number of files in playlist. Mirror of
global_settings.max_files_in_playlist */
int buffer_size; /* Playlist buffer size */
bool in_ram; /* playlist stored in ram (dirplay) */
char *buffer; /* buffer for in-ram playlists */
int buffer_size; /* size of buffer */
int buffer_end_pos; /* last position where buffer was written */
int index; /* index of current playing track */
int first_index; /* index of first song in playlist */
int seed; /* random seed */
int amount; /* number of tracks in the index */
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 */
int last_insert_pos; /* last position we inserted a track */
struct mutex control_mutex; /* mutex for control file access */
};
extern struct playlist_info playlist;
extern bool playlist_shuffle;
void playlist_init(void);
int play_list(char *dir, char *file, int start_index,
bool shuffled_index, int start_offset,
int random_seed, int first_index, int queue_resume,
int queue_resume_index);
char* playlist_peek(int steps);
char* playlist_name(char *name, int name_size);
int playlist_next(int steps);
bool playlist_check(int steps);
void randomise_playlist( unsigned int seed );
void sort_playlist(bool start_current);
void add_indices_to_playlist(void);
void playlist_clear(void);
int playlist_create(char *dir, char *file);
int playlist_resume(void);
int playlist_add(char *filename);
int queue_add(char *filename);
int playlist_insert_track(char *filename, int position, bool queue);
int playlist_insert_directory(char *dirname, int position, bool queue);
int playlist_insert_playlist(char *filename, int position, bool queue);
int playlist_delete(int index);
int playlist_shuffle(int random_seed, int start_index);
int playlist_randomise(unsigned int seed, bool start_current);
int playlist_sort(bool start_current);
int playlist_start(int start_index, int offset);
bool playlist_check(int steps);
char *playlist_peek(int steps);
int playlist_next(int steps);
int playlist_get_resume_info(int *resume_index);
int playlist_get_display_index(void);
int playlist_amount(void);
int playlist_first_index(void);
int playlist_get_resume_info(int *resume_index, int *queue_resume,
int *queue_resume_index);
char *playlist_name(char *buf, int buf_size);
int playlist_save(char *filename);
enum { QUEUE_OFF, QUEUE_BEGIN_QUEUE, QUEUE_BEGIN_PLAYLIST, NUM_QUEUE_MODES };
enum {
PLAYLIST_PREPEND = -1,
PLAYLIST_INSERT = -2,
PLAYLIST_INSERT_LAST = -3,
PLAYLIST_INSERT_FIRST = -4
};
#endif /* __PLAYLIST_H__ */

71
apps/playlist_menu.c Normal file
View file

@ -0,0 +1,71 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Björn Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <string.h>
#include "menu.h"
#include "file.h"
#include "keyboard.h"
#include "playlist.h"
#include "tree.h"
#include "settings.h"
#include "lang.h"
#define DEFAULT_PLAYLIST_NAME "/dynamic.m3u"
static bool save_playlist(void)
{
char filename[MAX_PATH+1];
strncpy(filename, DEFAULT_PLAYLIST_NAME, sizeof(filename));
if (!kbd_input(filename, sizeof(filename)))
{
playlist_save(filename);
/* reload in case playlist was saved to cwd */
reload_directory();
}
return false;
}
static bool recurse_directory(void)
{
return (set_bool( str(LANG_RECURSE_DIRECTORY),
&global_settings.recursive_dir_insert));
}
bool playlist_menu(void)
{
int m;
bool result;
struct menu_items items[] = {
{ str(LANG_CREATE_PLAYLIST), create_playlist },
{ str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist },
{ str(LANG_RECURSE_DIRECTORY), recurse_directory },
};
m = menu_init( items, sizeof items / sizeof(struct menu_items) );
result = menu_run(m);
menu_exit(m);
return result;
}

24
apps/playlist_menu.h Normal file
View file

@ -0,0 +1,24 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 Björn Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _PLAYLIST_MENU_H
#define _PLAYLIST_MENU_H
bool playlist_menu(void);
#endif

View file

@ -341,9 +341,9 @@ bool f2_screen(void)
if(mpeg_status() & MPEG_STATUS_PLAY)
{
if (global_settings.playlist_shuffle)
randomise_playlist(current_tick);
playlist_randomise(current_tick, true);
else
sort_playlist(true);
playlist_sort(true);
}
used = true;
break;

View file

@ -62,7 +62,7 @@
struct user_settings global_settings;
char rockboxdir[] = ROCKBOX_DIR; /* config/font/data file directory */
#define CONFIG_BLOCK_VERSION 6
#define CONFIG_BLOCK_VERSION 7
#define CONFIG_BLOCK_SIZE 512
#define RTC_BLOCK_SIZE 44
@ -98,10 +98,10 @@ offset abs
0x12 0x26 <(int) Resume playlist index, or -1 if no playlist resume>
0x16 0x2a <(int) Byte offset into resume file>
0x1a 0x2e <time until disk spindown>
0x1b 0x2f <browse current, play selected, queue_resume>
0x1b 0x2f <browse current, play selected, recursive dir insert>
0x1c 0x30 <peak meter hold timeout (bit 0-4),
rec_editable (bit 7)>
0x1d 0x31 <(int) queue resume index>
0x1d 0x31 <unused>
0x21 0x35 <repeat mode (bit 0-1), rec. channels (bit 2),
mic gain (bit 4-7)>
0x22 0x36 <rec. quality (bit 0-2), source (bit 3-4), frequency (bit 5-7)>
@ -144,9 +144,9 @@ Rest of config block, only saved to disk:
0xB8 (char[20]) WPS file
0xCC (char[20]) Lang file
0xE0 (char[20]) Font file
0xF4 (int) Playlist first index
0xF8 (int) Playlist shuffle seed
0xFC-0x1FF (char[260]) Resume playlist (path/to/dir or path/to/playlist.m3u)
0xF4 <unused>
0xF8 <unused>
0xFC <unused>
*************************************/
@ -343,18 +343,19 @@ int settings_save( void )
memcpy(&config_block[0x12], &global_settings.resume_index, 4);
memcpy(&config_block[0x16], &global_settings.resume_offset, 4);
DEBUGF( "+Resume index %X offset %X\n",
global_settings.resume_index,
global_settings.resume_offset );
config_block[0x1a] = (unsigned char)global_settings.disk_spindown;
config_block[0x1b] = (unsigned char)
(((global_settings.browse_current & 1)) |
((global_settings.play_selected & 1) << 1) |
((global_settings.queue_resume & 3) << 2));
((global_settings.recursive_dir_insert & 1) << 2));
config_block[0x1c] = (unsigned char)global_settings.peak_meter_hold |
(global_settings.rec_editable?0x80:0);
memcpy(&config_block[0x1d], &global_settings.queue_resume_index, 4);
config_block[0x21] = (unsigned char)
((global_settings.repeat_mode & 3) |
((global_settings.rec_channels & 1) << 2) |
@ -415,17 +416,6 @@ int settings_save( void )
strncpy(&config_block[0xb8], global_settings.wps_file, MAX_FILENAME);
strncpy(&config_block[0xcc], global_settings.lang_file, MAX_FILENAME);
strncpy(&config_block[0xe0], global_settings.font_file, MAX_FILENAME);
memcpy(&config_block[0xF4], &global_settings.resume_first_index, 4);
memcpy(&config_block[0xF8], &global_settings.resume_seed, 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())
{
@ -655,7 +645,8 @@ void settings_load(void)
if (config_block[0x1b] != 0xFF) {
global_settings.browse_current = (config_block[0x1b]) & 1;
global_settings.play_selected = (config_block[0x1b] >> 1) & 1;
global_settings.queue_resume = (config_block[0x1b] >> 2) & 3;
global_settings.recursive_dir_insert =
(config_block[0x1b] >> 2) & 1;
}
if (config_block[0x1c] != 0xFF) {
@ -664,10 +655,6 @@ void settings_load(void)
(config_block[0x1c] & 0x80)?true:false;
}
if (config_block[0x1d] != 0xFF)
memcpy(&global_settings.queue_resume_index, &config_block[0x1d],
4);
if (config_block[0x21] != 0xFF)
{
global_settings.repeat_mode = config_block[0x21] & 3;
@ -745,14 +732,9 @@ void settings_load(void)
global_settings.max_files_in_playlist =
config_block[0xaa] | (config_block[0xab] << 8);
memcpy(&global_settings.resume_first_index, &config_block[0xF4], 4);
memcpy(&global_settings.resume_seed, &config_block[0xF8], 4);
strncpy(global_settings.wps_file, &config_block[0xb8], MAX_FILENAME);
strncpy(global_settings.lang_file, &config_block[0xcc], MAX_FILENAME);
strncpy(global_settings.font_file, &config_block[0xe0], MAX_FILENAME);
strncpy(global_settings.resume_file, &config_block[0xFC], MAX_PATH);
global_settings.resume_file[MAX_PATH]=0;
#ifdef HAVE_LCD_CHARCELLS
if (config_block[0xa8] != 0xff)
global_settings.jump_scroll = config_block[0xa8];
@ -1097,6 +1079,8 @@ bool settings_load_config(char* file)
else if (!strcasecmp(name, "max files in playlist"))
set_cfg_int(&global_settings.max_files_in_playlist, value,
1000, 20000);
else if (!strcasecmp(name, "recursive directory insert"))
set_cfg_bool(&global_settings.recursive_dir_insert, value);
}
close(fd);
@ -1385,6 +1369,9 @@ bool settings_save_config(void)
fprintf(fd, "max files in playlist: %d\r\n",
global_settings.max_files_in_playlist);
fprintf(fd, "recursive directory insert: %s\r\n",
boolopt[global_settings.recursive_dir_insert]);
close(fd);
lcd_clear_display();
@ -1450,9 +1437,6 @@ void settings_reset(void) {
global_settings.ff_rewind_accel = DEFAULT_FF_REWIND_ACCEL_SETTING;
global_settings.resume_index = -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_poweroff = false;
global_settings.buffer_margin = 0;
@ -1475,6 +1459,7 @@ void settings_reset(void) {
global_settings.max_files_in_dir = 400;
global_settings.max_files_in_playlist = 10000;
global_settings.show_icons = true;
global_settings.recursive_dir_insert = false;
}
bool set_bool(char* string, bool* variable )

View file

@ -103,16 +103,7 @@ struct user_settings
int resume; /* resume option: 0=off, 1=ask, 2=on */
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 */
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 font_file[MAX_FILENAME+1]; /* last font */
unsigned char wps_file[MAX_FILENAME+1]; /* last wps */
unsigned char lang_file[MAX_FILENAME+1]; /* last language */
@ -175,6 +166,7 @@ struct user_settings
int max_files_in_dir; /* Max entries in directory (file browser) */
int max_files_in_playlist; /* Max entries in playlist */
bool show_icons; /* 0=hide 1=show */
bool recursive_dir_insert;/* should directories be inserted recursively */
};
enum optiontype { INT, BOOL };

View file

@ -724,11 +724,11 @@ static bool playback_settings_menu(void)
{
if (global_settings.playlist_shuffle)
{
randomise_playlist(current_tick);
playlist_randomise(current_tick, true);
}
else
{
sort_playlist(true);
playlist_sort(true);
}
}
return result;

View file

@ -66,10 +66,6 @@ static int max_files_in_dir;
static char *name_buffer;
static int name_buffer_size; /* Size of allocated buffer */
static int name_buffer_length; /* Currently used amount */
struct entry {
short attr; /* FAT attributes + file type flags */
char *name;
};
static struct entry *dircache;
@ -87,6 +83,8 @@ static int boot_size = 0;
static int boot_cluster;
static bool boot_changed = false;
static bool dirbrowse(char *root);
void browse_root(void)
{
#ifndef SIMULATOR
@ -158,14 +156,13 @@ static int build_playlist(int start_index)
int i;
int start=start_index;
playlist_clear();
for(i = 0;i < filesindir;i++)
{
if(dircache[i].attr & TREE_ATTR_MPA)
{
DEBUGF("Adding %s\n", dircache[i].name);
playlist_add(dircache[i].name);
if (playlist_add(dircache[i].name) < 0)
break;
}
else
{
@ -237,6 +234,133 @@ static void showfileline(int line, int direntry, bool scroll)
}
}
/* load sorted directory into dircache. returns NULL on failure. */
struct entry* load_and_sort_directory(char *dirname, int dirfilter,
int *num_files, bool *buffer_full)
{
int i;
DIR *dir = opendir(dirname);
if(!dir)
return NULL; /* not a directory */
name_buffer_length = 0;
*buffer_full = false;
for ( i=0; i < max_files_in_dir; i++ ) {
int len;
struct dirent *entry = readdir(dir);
struct entry* dptr = &dircache[i];
if (!entry)
break;
len = strlen(entry->d_name);
/* skip directories . and .. */
if ((entry->attribute & ATTR_DIRECTORY) &&
(((len == 1) &&
(!strncmp(entry->d_name, ".", 1))) ||
((len == 2) &&
(!strncmp(entry->d_name, "..", 2))))) {
i--;
continue;
}
/* Skip FAT volume ID */
if (entry->attribute & ATTR_VOLUME_ID) {
i--;
continue;
}
/* filter out dotfiles and hidden files */
if (dirfilter != SHOW_ALL &&
((entry->d_name[0]=='.') ||
(entry->attribute & ATTR_HIDDEN))) {
i--;
continue;
}
dptr->attr = entry->attribute;
/* mark mp? and m3u files as such */
if ( !(dptr->attr & ATTR_DIRECTORY) && (len > 4) ) {
if (!strcasecmp(&entry->d_name[len-4], ".mp3") ||
(!strcasecmp(&entry->d_name[len-4], ".mp2")) ||
(!strcasecmp(&entry->d_name[len-4], ".mpa")))
dptr->attr |= TREE_ATTR_MPA;
else if (!strcasecmp(&entry->d_name[len-4], ".m3u"))
dptr->attr |= TREE_ATTR_M3U;
else if (!strcasecmp(&entry->d_name[len-4], ".cfg"))
dptr->attr |= TREE_ATTR_CFG;
else if (!strcasecmp(&entry->d_name[len-4], ".wps"))
dptr->attr |= TREE_ATTR_WPS;
else if (!strcasecmp(&entry->d_name[len-4], ".txt"))
dptr->attr |= TREE_ATTR_TXT;
else if (!strcasecmp(&entry->d_name[len-4], ".lng"))
dptr->attr |= TREE_ATTR_LNG;
#ifdef HAVE_RECORDER_KEYPAD
else if (!strcasecmp(&entry->d_name[len-4], ".fnt"))
dptr->attr |= TREE_ATTR_FONT;
else if (!strcasecmp(&entry->d_name[len-4], ".ajz"))
#else
else if (!strcasecmp(&entry->d_name[len-4], ".mod"))
#endif
dptr->attr |= TREE_ATTR_MOD;
else if (!strcasecmp(&entry->d_name[len-5], ".rock"))
dptr->attr |= TREE_ATTR_ROCK;
}
/* memorize/compare details about the boot file */
if ((currdir[1] == 0) && !strcmp(entry->d_name, BOOTFILE)) {
if (boot_size) {
if ((entry->size != boot_size) ||
(entry->startcluster != boot_cluster))
boot_changed = true;
}
boot_size = entry->size;
boot_cluster = entry->startcluster;
}
/* filter out all non-playlist files */
if ( dirfilter == SHOW_PLAYLIST &&
(!(dptr->attr &
(ATTR_DIRECTORY|TREE_ATTR_M3U))) ) {
i--;
continue;
}
/* filter out non-music files */
if ( dirfilter == SHOW_MUSIC &&
(!(dptr->attr &
(ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U))) ) {
i--;
continue;
}
/* filter out non-supported files */
if ( dirfilter == SHOW_SUPPORTED &&
(!(dptr->attr & TREE_ATTR_MASK)) ) {
i--;
continue;
}
if (len > name_buffer_size - name_buffer_length - 1) {
/* Tell the world that we ran out of buffer space */
*buffer_full = true;
break;
}
dptr->name = &name_buffer[name_buffer_length];
strcpy(dptr->name,entry->d_name);
name_buffer_length += len + 1;
}
*num_files = i;
closedir(dir);
strncpy(lastdir,dirname,sizeof(lastdir));
lastdir[sizeof(lastdir)-1] = 0;
qsort(dircache,i,sizeof(struct entry),compare);
return dircache;
}
static int showdir(char *path, int start)
{
@ -258,124 +382,9 @@ static int showdir(char *path, int start)
/* new dir? cache it */
if (strncmp(path,lastdir,sizeof(lastdir)) || reload_dir) {
DIR *dir = opendir(path);
if(!dir)
return -1; /* not a directory */
name_buffer_length = 0;
dir_buffer_full = false;
for ( i=0; i < max_files_in_dir; i++ ) {
int len;
struct dirent *entry = readdir(dir);
struct entry* dptr = &dircache[i];
if (!entry)
break;
len = strlen(entry->d_name);
/* skip directories . and .. */
if ((entry->attribute & ATTR_DIRECTORY) &&
(((len == 1) &&
(!strncmp(entry->d_name, ".", 1))) ||
((len == 2) &&
(!strncmp(entry->d_name, "..", 2))))) {
i--;
continue;
}
/* Skip FAT volume ID */
if (entry->attribute & ATTR_VOLUME_ID) {
i--;
continue;
}
/* filter out dotfiles and hidden files */
if (global_settings.dirfilter != SHOW_ALL &&
((entry->d_name[0]=='.') ||
(entry->attribute & ATTR_HIDDEN))) {
i--;
continue;
}
dptr->attr = entry->attribute;
/* mark mp? and m3u files as such */
if ( !(dptr->attr & ATTR_DIRECTORY) && (len > 4) ) {
if (!strcasecmp(&entry->d_name[len-4], ".mp3") ||
(!strcasecmp(&entry->d_name[len-4], ".mp2")) ||
(!strcasecmp(&entry->d_name[len-4], ".mpa")))
dptr->attr |= TREE_ATTR_MPA;
else if (!strcasecmp(&entry->d_name[len-4], ".m3u"))
dptr->attr |= TREE_ATTR_M3U;
else if (!strcasecmp(&entry->d_name[len-4], ".cfg"))
dptr->attr |= TREE_ATTR_CFG;
else if (!strcasecmp(&entry->d_name[len-4], ".wps"))
dptr->attr |= TREE_ATTR_WPS;
else if (!strcasecmp(&entry->d_name[len-4], ".txt"))
dptr->attr |= TREE_ATTR_TXT;
else if (!strcasecmp(&entry->d_name[len-4], ".lng"))
dptr->attr |= TREE_ATTR_LNG;
#ifdef HAVE_RECORDER_KEYPAD
else if (!strcasecmp(&entry->d_name[len-4], ".fnt"))
dptr->attr |= TREE_ATTR_FONT;
else if (!strcasecmp(&entry->d_name[len-4], ".ajz"))
#else
else if (!strcasecmp(&entry->d_name[len-4], ".mod"))
#endif
dptr->attr |= TREE_ATTR_MOD;
else if (!strcasecmp(&entry->d_name[len-5], ".rock"))
dptr->attr |= TREE_ATTR_ROCK;
}
/* memorize/compare details about the boot file */
if ((currdir[1] == 0) && !strcmp(entry->d_name, BOOTFILE)) {
if (boot_size) {
if ((entry->size != boot_size) ||
(entry->startcluster != boot_cluster))
boot_changed = true;
}
boot_size = entry->size;
boot_cluster = entry->startcluster;
}
/* filter out all non-playlist files */
if ( global_settings.dirfilter == SHOW_PLAYLIST &&
(!(dptr->attr &
(ATTR_DIRECTORY|TREE_ATTR_M3U))) ) {
i--;
continue;
}
/* filter out non-music files */
if ( global_settings.dirfilter == SHOW_MUSIC &&
(!(dptr->attr &
(ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U))) ) {
i--;
continue;
}
/* filter out non-supported files */
if ( global_settings.dirfilter == SHOW_SUPPORTED &&
(!(dptr->attr & TREE_ATTR_MASK)) ) {
i--;
continue;
}
if (len > name_buffer_size - name_buffer_length - 1) {
/* Tell the world that we ran out of buffer space */
dir_buffer_full = true;
break;
}
dptr->name = &name_buffer[name_buffer_length];
strcpy(dptr->name,entry->d_name);
name_buffer_length += len + 1;
}
filesindir = i;
closedir(dir);
strncpy(lastdir,path,sizeof(lastdir));
lastdir[sizeof(lastdir)-1] = 0;
qsort(dircache,filesindir,sizeof(struct entry),compare);
if (!load_and_sort_directory(path, global_settings.dirfilter,
&filesindir, &dir_buffer_full))
return -1;
if ( dir_buffer_full || filesindir == max_files_in_dir ) {
#ifdef HAVE_LCD_CHARCELLS
@ -531,7 +540,7 @@ static int showdir(char *path, int start)
return filesindir;
}
bool ask_resume(void)
static bool ask_resume(void)
{
#ifdef HAVE_LCD_CHARCELLS
lcd_double_height(false);
@ -570,92 +579,62 @@ bool ask_resume(void)
return false;
}
void start_resume(void)
/* load tracks from specified directory to resume play */
void resume_directory(char *dir)
{
bool buffer_full;
if (!load_and_sort_directory(dir, global_settings.dirfilter, &filesindir,
&buffer_full))
return;
lastdir[0] = 0;
build_playlist(0);
}
/* Returns the current working directory and also writes cwd to buf if
non-NULL. In case of error, returns NULL. */
char *getcwd(char *buf, int size)
{
if (!buf)
return currdir;
else if (size > 0)
{
strncpy(buf, currdir, size);
return buf;
}
else
return NULL;
}
/* Force a reload of the directory next time directory browser is called */
void reload_directory(void)
{
reload_dir = true;
}
static 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;
if (!ask_resume())
return;
if (playlist_resume() != -1)
{
playlist_start(global_settings.resume_index,
global_settings.resume_offset);
/* 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,
true, /* the index is AFTER shuffle */
global_settings.resume_offset,
global_settings.resume_seed,
global_settings.resume_first_index,
global_settings.queue_resume,
global_settings.queue_resume_index);
*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,
true,
global_settings.resume_offset,
global_settings.resume_seed,
global_settings.resume_first_index,
global_settings.queue_resume,
global_settings.queue_resume_index);
}
status_set_playmode(STATUS_PLAY);
status_draw(true);
wps_show();
}
else {
if (!ask_resume())
return;
if (showdir(global_settings.resume_file, 0) < 0 )
return;
lastdir[0] = '\0';
build_playlist(global_settings.resume_index);
play_list(global_settings.resume_file,
NULL,
global_settings.resume_index,
true,
global_settings.resume_offset,
global_settings.resume_seed,
global_settings.resume_first_index,
global_settings.queue_resume,
global_settings.queue_resume_index);
}
status_set_playmode(STATUS_PLAY);
status_draw(true);
wps_show();
else
return;
}
}
@ -751,19 +730,33 @@ static bool handle_on(int* ds, int* dc, int numentries, int tree_max_on_screen)
case BUTTON_PLAY:
case BUTTON_RC_PLAY:
case BUTTON_ON | BUTTON_PLAY:
case BUTTON_ON | BUTTON_PLAY: {
int onplay_result;
if (currdir[1])
snprintf(buf, sizeof buf, "%s/%s",
currdir, dircache[dircursor+dirstart].name);
else
snprintf(buf, sizeof buf, "/%s",
dircache[dircursor+dirstart].name);
if (onplay(buf, dircache[dircursor+dirstart].attr))
reload_dir = 1;
onplay_result = onplay(buf,
dircache[dircursor+dirstart].attr);
switch (onplay_result)
{
case ONPLAY_OK:
used = true;
break;
case ONPLAY_RELOAD_DIR:
reload_dir = 1;
used = true;
break;
case ONPLAY_START_PLAY:
used = false; /* this will enable the wps */
break;
}
exit = true;
used = true;
break;
}
case BUTTON_ON | BUTTON_REL:
case BUTTON_ON | TREE_PREV | BUTTON_REL:
case BUTTON_ON | TREE_NEXT | BUTTON_REL:
@ -793,7 +786,7 @@ static bool handle_on(int* ds, int* dc, int numentries, int tree_max_on_screen)
return used;
}
bool dirbrowse(char *root)
static bool dirbrowse(char *root)
{
int numentries=0;
char buf[MAX_PATH];
@ -934,41 +927,36 @@ bool dirbrowse(char *root)
lcd_stop_scroll();
switch ( file->attr & TREE_ATTR_MASK ) {
case TREE_ATTR_M3U:
if ( global_settings.resume ) {
if (currdir[1])
snprintf(global_settings.resume_file,
MAX_PATH, "%s/%s",
currdir, file->name);
else
snprintf(global_settings.resume_file,
MAX_PATH, "/%s", file->name);
}
play_list(currdir, file->name, 0, false, 0,
seed, 0, 0, -1);
start_index = 0;
play = true;
break;
case TREE_ATTR_MPA:
if ( global_settings.resume )
strncpy(global_settings.resume_file,
currdir, MAX_PATH);
start_index =
build_playlist(dircursor+dirstart);
/* when shuffling dir.: play all files even if the
file selected by user is not the first one */
if (global_settings.playlist_shuffle
&& !global_settings.play_selected)
if (playlist_create(currdir, file->name) != -1)
{
if (global_settings.playlist_shuffle)
playlist_shuffle(seed, -1);
start_index = 0;
/* it is important that we get back the index
in the (shuffled) list and store that */
start_index = play_list(currdir, NULL,
start_index, false,
0, seed, 0, 0, -1);
play = true;
playlist_start(start_index,0);
play = true;
}
break;
case TREE_ATTR_MPA:
if (playlist_create(currdir, NULL) != -1)
{
start_index =
build_playlist(dircursor+dirstart);
if (global_settings.playlist_shuffle)
{
start_index =
playlist_shuffle(seed,start_index);
/* when shuffling dir.: play all files
even if the file selected by user is
not the first one */
if (!global_settings.play_selected)
start_index = 0;
}
playlist_start(start_index, 0);
play = true;
}
break;
/* wps config file */
@ -1055,9 +1043,6 @@ bool dirbrowse(char *root)
shuffled list in case shuffle is enabled */
global_settings.resume_index = start_index;
global_settings.resume_offset = 0;
global_settings.resume_first_index =
playlist_first_index();
global_settings.resume_seed = seed;
settings_save();
}

View file

@ -21,6 +21,11 @@
#include <stdbool.h>
struct entry {
short attr; /* FAT attributes + file type flags */
char *name;
};
/* using attribute not used by FAT */
#define TREE_ATTR_MPA 0x40 /* mpeg audio file */
#define TREE_ATTR_M3U 0x80 /* playlist */
@ -36,7 +41,11 @@
void tree_init(void);
void browse_root(void);
void set_current_file(char *path);
bool dirbrowse(char *root);
bool create_playlist(void);
void resume_directory(char *dir);
char *getcwd(char *buf, int size);
void reload_directory(void);
struct entry* load_and_sort_directory(char *dirname, int dirfilter,
int *num_files, bool *buffer_full);
#endif

View file

@ -418,12 +418,7 @@ static char* get_tag(struct mp3entry* id3,
#endif
case 'p': /* Playlist Position */
*flags |= WPS_REFRESH_STATIC;
{
int index = id3->index - playlist_first_index();
if (index < 0)
index += playlist_amount();
snprintf(buf, buf_size, "%d", index + 1);
}
snprintf(buf, buf_size, "%d", playlist_get_display_index());
return buf;
case 'n': /* Playlist Name (without path) */

View file

@ -223,13 +223,8 @@ bool browse_id3(void)
case 7:
lcd_puts(0, 0, str(LANG_ID3_PLAYLIST));
{
int index = id3->index - playlist_first_index();
if (index < 0)
index += playlist_amount();
snprintf(scroll_text,sizeof(scroll_text), "%d/%d",
index + 1, playlist_amount());
}
snprintf(scroll_text,sizeof(scroll_text), "%d/%d",
playlist_get_display_index(), playlist_amount());
lcd_puts_scroll(0, 1, scroll_text);
break;
@ -455,9 +450,7 @@ static bool update(void)
DEBUGF("R%X,%X (%X)\n", global_settings.resume_offset,
id3->offset,id3);
if (!playlist_get_resume_info(&global_settings.resume_index,
&global_settings.queue_resume,
&global_settings.queue_resume_index))
if (!playlist_get_resume_info(&global_settings.resume_index))
{
global_settings.resume_offset = id3->offset;
settings_save();

View file

@ -33,7 +33,7 @@
The penalty is the RAM used for the cache and slightly more complex code.
*/
#define MAX_OPEN_FILES 4
#define MAX_OPEN_FILES 8
struct filedesc {
unsigned char cache[SECTOR_SIZE];

View file

@ -100,7 +100,7 @@ APPS = main.c tree.c menu.c credits.c main_menu.c icons.c language.c \
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
misc.c plugin.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c playlist_menu.c
ifeq ($(DISPLAY),-DHAVE_LCD_BITMAP)
APPS += bmp.c widgets.c
@ -160,6 +160,9 @@ $(OBJDIR)/demo_menu.o: $(APPDIR)/demo_menu.c
$(OBJDIR)/settings_menu.o: $(APPDIR)/settings_menu.c
$(CC) $(APPCFLAGS) -c $< -o $@
$(OBJDIR)/playlist_menu.o: $(APPDIR)/playlist_menu.c
$(CC) $(APPCFLAGS) -c $< -o $@
$(OBJDIR)/icons.o: $(MACHINEDIR)/icons.c
$(CC) $(APPCFLAGS) -c $< -o $@

View file

@ -29,7 +29,7 @@ int win32_filesize(int fd);
#define rename(x,y) win32_rename(x,y)
#define filesize(x) win32_filesize(x)
#define flush(x) _commit(x)
#define fsync(x) _commit(x)
#include "../../firmware/include/file.h"

View file

@ -103,3 +103,15 @@ int set_irq_level (int level)
static int _lv = 0;
return (_lv = level);
}
void mutex_init(struct mutex *m)
{
}
void mutex_lock(struct mutex *m)
{
}
void mutex_unlock(struct mutex *m)
{
}

View file

@ -43,7 +43,7 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../firmware/export" /I "../../firmware/drivers" /I "../../firmware/common" /I "../common" /I "../win32" /I "../../apps" /I "../../apps/recorder" /D "HAVE_LCD_BITMAP" /D "HAVE_RECORDER_KEYPAD" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GETTIMEOFDAY_TWO_ARGS" /D "SIMULATOR" /D APPSVERSION=\"WIN32SIM\" /FR /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../firmware/export" /I "../../firmware/drivers" /I "../../firmware/common" /I "../common" /I "../win32" /I "../../apps" /I "../../apps/recorder" /D "HAVE_LCD_BITMAP" /D "HAVE_RECORDER_KEYPAD" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GETTIMEOFDAY_TWO_ARGS" /D "SIMULATOR" /D APPSVERSION=\"WIN32SIM\" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x407 /d "_DEBUG"
@ -69,7 +69,7 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../firmware/export" /I "../../firmware/drivers" /I "../../firmware/common" /I "../common" /I "../win32" /I "../../apps" /I "../../apps/player" /D "HAVE_LCD_CHARCELLS" /D "HAVE_PLAYER_KEYPAD" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GETTIMEOFDAY_TWO_ARGS" /D "SIMULATOR" /D APPSVERSION=\"WIN32SIM\" /FR /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../../firmware/export" /I "../../firmware/drivers" /I "../../firmware/common" /I "../common" /I "../win32" /I "../../apps" /I "../../apps/player" /D "HAVE_LCD_CHARCELLS" /D "HAVE_PLAYER_KEYPAD" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "HAVE_CONFIG_H" /D "GETTIMEOFDAY_TWO_ARGS" /D "SIMULATOR" /D APPSVERSION=\"WIN32SIM\" /FR /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x407 /d "_DEBUG"
@ -369,6 +369,10 @@ SOURCE=..\..\apps\playlist.c
# End Source File
# Begin Source File
SOURCE=..\..\apps\playlist_menu.c
# End Source File
# Begin Source File
SOURCE=..\..\apps\plugin.c
# End Source File
# Begin Source File

View file

@ -95,7 +95,7 @@ APPS = main.c tree.c menu.c credits.c main_menu.c language.c\
screens.c peakmeter.c sleeptimer.c keyboard.c onplay.c\
misc.c plugin.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c
MENUS = games_menu.c demo_menu.c settings_menu.c sound_menu.c playlist_menu.c
ifeq ($(DISPLAY),-DHAVE_LCD_BITMAP)
APPS += bmp.c widgets.c
@ -156,6 +156,9 @@ $(OBJDIR)/demo_menu.o: $(APPDIR)/demo_menu.c
$(OBJDIR)/settings_menu.o: $(APPDIR)/settings_menu.c
$(CC) $(APPCFLAGS) -c $< -o $@
$(OBJDIR)/playlist_menu.o: $(APPDIR)/playlist_menu.c
$(CC) $(APPCFLAGS) -c $< -o $@
$(OBJDIR)/icons.o: $(MACHINEDIR)/icons.c
$(CC) $(APPCFLAGS) -c $< -o $@

View file

@ -22,6 +22,9 @@
#ifndef NO_REDEFINES_PLEASE
#define sleep(x) x11_sleep(x)
#define mutex_init(x) (void)x
#define mutex_lock(x) (void)x
#define mutex_unlock(x) (void)x
#endif