Index: rockbox/apps/tree.c =================================================================== RCS file: /cvsroot/rockbox/apps/tree.c,v retrieving revision 1.155 diff -u -r1.155 tree.c --- rockbox/apps/tree.c 13 Jan 2003 12:54:59 -0000 1.155 +++ rockbox/apps/tree.c 14 Jan 2003 07:56:50 -0000 @@ -49,6 +49,7 @@ #include "viewer.h" #include "language.h" #include "screens.h" +#include "bookmark.h" #ifdef HAVE_LCD_BITMAP #include "widgets.h" @@ -143,6 +144,7 @@ #define TREE_ATTR_TXT 0x500 /* text file */ #define TREE_ATTR_FONT 0x800 /* font file */ #define TREE_ATTR_LNG 0x1000 /* binary lang file */ +#define TREE_ATTR_BMF 0x2000 /* book mark file */ #define TREE_ATTR_MASK 0xffd0 /* which bits tree.c uses (above + DIR) */ static int build_playlist(int start_index) @@ -260,6 +262,8 @@ 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], ".bmf")) + dptr->attr |= TREE_ATTR_BMF; else if (!strcasecmp(&entry->d_name[len-4], ".lng")) dptr->attr |= TREE_ATTR_LNG; #ifdef HAVE_RECORDER_KEYPAD @@ -283,6 +287,7 @@ /* filter out non-music files */ if ( global_settings.dirfilter == SHOW_MUSIC && (!(dptr->attr & + //(ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U|TREE_ATTR_BMF))) ) { (ATTR_DIRECTORY|TREE_ATTR_MPA|TREE_ATTR_M3U))) ) { i--; continue; @@ -800,7 +805,8 @@ #ifdef HAVE_RECORDER_KEYPAD case BUTTON_OFF: - mpeg_stop(); + bookmark_autocreate(); + mpeg_stop(); status_set_playmode(STATUS_STOP); status_draw(); restore = true; @@ -845,15 +851,24 @@ lcd_stop_scroll(); switch ( file->attr & TREE_ATTR_MASK ) { - case TREE_ATTR_M3U: - if ( global_settings.resume ) + case TREE_ATTR_M3U: + snprintf(buf, sizeof buf, "%s/%s", currdir, file->name); + if(bookmark_autoload(buf)) + { + restore = true; + break; + } + else + { + //if ( global_settings.resume ) snprintf(global_settings.resume_file, - MAX_PATH, "%s/%s", - currdir, file->name); - play_list(currdir, file->name, 0, false, 0, - seed, 0, 0, -1); - start_index = 0; - play = true; + MAX_PATH, "%s/%s", + currdir, file->name); + play_list(currdir, file->name, 0, false, 0, + seed, 0, 0, -1); + start_index = 0; + play = true; + } break; case TREE_ATTR_MPA: @@ -871,19 +886,28 @@ } else { - repeat_count = 0; - if ( global_settings.resume ) + snprintf(buf, sizeof buf, "%s/%s", currdir, file->name); + if(bookmark_autoload(buf)) + { + restore = true; + break; + } + else + { + repeat_count = 0; + //if ( global_settings.resume ) strncpy(global_settings.resume_file, - currdir, MAX_PATH); - start_index = - build_playlist(dircursor+dirstart); - - /* 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; + currdir, MAX_PATH); + start_index = + build_playlist(dircursor+dirstart); + + /* 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; + } } break; @@ -901,6 +925,13 @@ snprintf(buf, sizeof buf, "%s/%s", currdir, file->name); settings_load_config(buf); + restore = true; + break; + + case TREE_ATTR_BMF: + snprintf(buf, sizeof buf, "%s/%s", + currdir, file->name); + bookmark_load(buf, true); restore = true; break; Index: rockbox/apps/wps.c =================================================================== RCS file: /cvsroot/rockbox/apps/wps.c,v retrieving revision 1.171 diff -u -r1.171 wps.c --- rockbox/apps/wps.c 9 Jan 2003 00:54:59 -0000 1.171 +++ rockbox/apps/wps.c 14 Jan 2003 07:56:51 -0000 @@ -44,6 +44,7 @@ #include "peakmeter.h" #endif #include "lang.h" +#include "bookmark.h" #define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */ /* 3% of 30min file == 54s step size */ @@ -907,7 +908,8 @@ current_track_path[0] != '\0') set_current_file(current_track_path); - mpeg_stop(); + bookmark_autocreate(); + mpeg_stop(); status_set_playmode(STATUS_STOP); return 0; --- rockbox/apps/bookmark.c 2003-01-14 00:03:03.000000000 -0800 +++ rockbox/apps/bookmark.c 2003-01-13 13:40:00.000000000 -0800 @@ -0,0 +1,591 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2003 by rockbox@samuraipanda.com + * + * 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. + * + ****************************************************************************/ + + //-------------------------------------------------------------------------- + // TBD/Bugs + //-------------------------------------------------------------------------- + // 1. For some reason, bookmarks will occasionally fail to load. + // If this happens, then the rockbox will continually prompt + // to load the file, even if told not to. Turning the rockbox + // off can get out of this loop. + // FIX NOTE: The loop part appears to be fixed, but the load may still fail, though I + // think this is a bug lower in the stack. + // 2. Develop own play capability. Currently, bookmark_load() calls + // tree.c:play_resume() to handle the actuall playback + // 3. In order to load a bookmark, resume must be set to "ask" or "yes". This + // shouldn't be a requirement. This could be solved by fixing issue 2. + // FIX NOTE: This has been fixed by storing the current global_settings.resume value, + // overwriting the global value with ASK or YES, and then restoring it + // after play_resume is called. + // 4. Centralize where the bookmarks are created so that the user doesn't have + // to track down the bookmark files. Also, if the user is playing a playlist. + // the bookmark file will be created in the directory of the file currently playing + // FIX NOTE: This may not happen. The way the code is now designed, it will create + // the bookmark in the directory of the playlist or in the directory of the MP3. + // 5. Format the bookmark file better. The single line isn't the most readable. + // 6. Bookmark files are created, but they don't show up until the next time the + // directory is loaded. + // 7. Need to use the language files. + // 8. Redo the where bookmark_load reads the file. I should be able to consolodate + // this into a single function instead of a series of while loops. + // 9. Link function key 3 to bookmark_create(). + //10. Need to come up with an icon for .bmf files + //11. Need to create two separate bookmark creation paradigms. + // 1. auto-bookmarking: Store's the bookmark in directory of the MP3 or M3U and + // is over-written each time auto-create bookmark is called. + // 2. Manual bookmark creation. This may store in cental location (i.e. \bookmarks) and + // would never overwrite existing bookmarks. Instead it would increment with each new + // bookmark. Should also be able to specify if this is for the autobookmark or central + // location to avoid lots of bookmark files being created (see 13). + // FIX NOTES: The first has been done. It will automatically create a bookmark when OFF is pushed. + // and will prompt the user to autorun if the file exists. + //12. Need to create a global setting to determine if to prompt creation, don't + // create, or automatically create and the same for loading. Also + //13. To give the user the option to delete existing bookmarks and start from the beginning, otherwise + // there could be a lot of bookmarks scattered around over time. + //14. Need to create menus for auto-bookmark settings. + + +#include +#include +#include +#include + +/* +#include "applimits.h" +#include "file.h" +#include "font.h" +#include "backlight.h" +#include "kernel.h" +#include "tree.h" +#include "main_menu.h" +#include "sprintf.h" +#include "playlist.h" +#include "menu.h" +#include "wps-display.h" +#include "debug.h" +#include "ata.h" +#include "rolo.h" +#include "icons.h" +#include "lang.h" +#include "viewer.h" +#include "language.h" +#include "screens.h" +#include "bookmark.h" +*/ + +#include "lcd.h" +#include "button.h" +#include "usb.h" +#include "mpeg.h" +#include "wps.h" +#include "settings.h" +#include "bookmark.h" +#include "dir.h" +#include "status.h" + +#define SEPARATOR "*" //Must be one character +#define LANG_CREATE_BOOKMARK_QUERY "Bookmark?" +#define LANG_BOOKMARK_CONFIRM_RECORDER "PLAY = Yes" +#define LANG_BOOKMARK_CANCEL_RECORDER "Any Other = No" + +#define LANG_BOOKMARK_LOAD_QUERY_RECORDER "Load Bookmark?" + + +bool bookmark_query(void) +{ + bool done = false; + int key; + + // Prompting user to confirm bookmark creation + lcd_clear_display(); + lcd_puts(0,0, LANG_CREATE_BOOKMARK_QUERY); + lcd_puts(0,1, LANG_BOOKMARK_CONFIRM_RECORDER); + lcd_puts(0,2, LANG_BOOKMARK_CANCEL_RECORDER); + lcd_update(); + + while(!done) + { + /* Wait for a key to be pushed */ + key = button_get_w_tmo(HZ*5); + switch(key) { + case BUTTON_UP | BUTTON_REL: + case BUTTON_DOWN | BUTTON_REL: + case BUTTON_LEFT | BUTTON_REL: + case BUTTON_RIGHT | BUTTON_REL: + case BUTTON_ON | BUTTON_REL: + case BUTTON_OFF | BUTTON_REL: + done = true; + break; + + case BUTTON_PLAY: + bookmark_create(); + done = true; + break; + } + } + + return false; +} + +void bookmark_create(void) +// -------------------------------------------------------------------------- +// Writing a bookmark +// -------------------------------------------------------------------------- +// This bookmark capability takes the current resume information and +// writes it to a file whose name is based off of the currently playing file +// i.e. bookmarking /foo1/foo.mp3 creates the file /foo1/foo.bmf. +// This file contains the following line: +// resume_index*resume_offset*resume_seed*resume_first_index*queue_resume_index*resume_file* +{ + int file; + char new_file_name[MAX_PATH+5]; + char error_buf[MAX_PATH]; + struct mp3entry *id3 = NULL; + + + // First grab the currently playing file. + // If none are playing, exit. + id3 = mpeg_current_track(); + if(NULL == id3) + return; + + memset(new_file_name, 0, MAX_PATH); + memset(error_buf, 0, MAX_PATH); + + + //Creating the bookmark file name based on the MP3/M3U file name (i.e. foo.mp3 becomes foo.mp3.bmf) + //The bookmark file will exist in the same directory as the MP3 or M3U. + int len = strlen(global_settings.resume_file); + if(!strcasecmp(&global_settings.resume_file[len-4], ".m3u") || !strcasecmp(&global_settings.resume_file[len-4], ".mp3")) + snprintf(new_file_name, MAX_PATH+5, "%s.%s", global_settings.resume_file, "bmf"); + else + snprintf(new_file_name, MAX_PATH+5, "%s.%s", id3->path, "bmf"); // this handles the case when the resume file is a directory name. + + file = open (new_file_name, O_RDWR | O_CREAT | O_TRUNC); + + if(file >= 0) + { + /* Grab the resume data */ + if (id3) + { + + 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_first_index = playlist_first_index(); + global_settings.resume_seed = current_tick; + settings_save(); + } + else + { + bookmark_display_message("Unable retrieve bookmark information"); + close(file); + return; + } + } + else if (!id3) + { + bookmark_display_message("Unable to save data"); + close(file); + return; + } + + + //Writing the bookmark information to the file + char pTemp[12]; + + snprintf(pTemp, MAX_PATH, "%2d", global_settings.resume_index); + write (file, pTemp, strlen(pTemp)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + snprintf(pTemp, MAX_PATH, "%2d", global_settings.resume_offset); + write (file, pTemp, strlen(pTemp)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + snprintf(pTemp, MAX_PATH, "%2d", global_settings.resume_seed); + write (file, pTemp, strlen(pTemp)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + snprintf(pTemp, MAX_PATH, "%2d", global_settings.resume_first_index); + write (file, pTemp, strlen(pTemp)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + snprintf(pTemp, MAX_PATH, "%2d", global_settings.queue_resume_index); + write (file, pTemp, strlen(pTemp)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + write (file, global_settings.resume_file, strlen( global_settings.resume_file)); + + write (file, SEPARATOR, strlen(SEPARATOR)); //Printing Separator + + close (file); + + } + else + { + snprintf(error_buf, sizeof(error_buf), " Failed: %2d", file); + bookmark_display_message(error_buf); + } + +} + +bool bookmark_autocreate(void) +{ + // This is a place holder for when there is a global setting to auto create bookmarks. + // auto create bookmark options: 0=no, 1=ask, 2=yes + bookmark_create(); + return true; +} + + +bool bookmark_autoload(char* file) +{ + // This is a place holder for when there is a global setting to auto load bookmarks. + // The first thing that should happen is a query to a global setting about auto load. + // if yes or ask, then continue on, otherwise return FALSE. + // auto load bookmark options: 0=no, 1=ask, 2=yes + + char bookmark_file_name[MAX_PATH+5]; + bool done = false; + int key; + int fd; + + //Checking to see if a bookmark file exists. + snprintf(bookmark_file_name, MAX_PATH+5, "%s.%s", file, "bmf"); + fd = open(bookmark_file_name, O_RDONLY); + + if(fd<0) + return false; + + close(fd); + + // Prompting user to confirm bookmark creation + lcd_clear_display(); + lcd_puts(0,0, LANG_BOOKMARK_LOAD_QUERY_RECORDER); + lcd_puts(0,1, LANG_BOOKMARK_CONFIRM_RECORDER); + lcd_puts(0,2, LANG_BOOKMARK_CANCEL_RECORDER); + lcd_update(); + + while(!done) + { + /* Wait for a key to be pushed */ + key = button_get_w_tmo(HZ*5); + switch(key) + { + case BUTTON_UP | BUTTON_REL: + case BUTTON_DOWN | BUTTON_REL: + case BUTTON_LEFT | BUTTON_REL: + case BUTTON_RIGHT | BUTTON_REL: + case BUTTON_ON | BUTTON_REL: + case BUTTON_OFF | BUTTON_REL: + return false; + break; + case BUTTON_PLAY | BUTTON_REL: + bookmark_load(bookmark_file_name, false); + return true; + break; + } + } + return true; +} + +void bookmark_load(char* file, bool ask_resume_bookmark) +// -------------------------------------------------------------------------- +// Loading a bookmark +// -------------------------------------------------------------------------- +// When loaded, the bookmark_load function takes a bookmark file and reads the +// above line, one character at a time until it hits an astrick (*). Once it does, +// this signals that this is the end of a field. +// As each field is successfully loaded, it overwrites the existing resume information +// that is stored in memory. Once all fields have been successfully loaded, bookmark_load +// calls tree.c:start_resume(). +{ + + int fd; + int nread = 0; + char read_buf[MAX_PATH]; + char read_char[1]; + + char error_buf[MAX_PATH]; + bool success = true; + int read_count = 0; + + memset(read_buf, 0, MAX_PATH); + memset(error_buf, 0, MAX_PATH); + + fd = open(file, O_RDONLY); + + snprintf(error_buf, "%s: %2d", file, fd); // Not sure why, but this fixes bug #1, or at least band-aids it. + // This is probably because the kernal hasn't released the file fully + // after it is opened in bookmark_autoload(). + + if(fd >= 0) + { + //reading the global_settings.resume_index + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + nread = read(fd, read_char, 1); + if(nread <= 0) + { + + //snprintf(error_buf, MAX_PATH, "%2d:%2d:%s", fd, nread, read_char); + bookmark_display_message("global_settings.resume_index"); + success = false; + break; + } + if(strcmp(SEPARATOR, read_char)) + { + read_buf[read_count] = read_char[0]; + } + else + { + //bookmark_display_message(read_buf); + global_settings.resume_index = atoi(read_buf); + break; + } + read_count++; + } + + //reading the global_settings.resume_offset + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + nread = read(fd, read_char, 1); + if(nread <= 0) + { + bookmark_display_message("global_settings.resume_offset"); + success = false; + break; + } + if(strcmp(SEPARATOR, read_char)) + read_buf[read_count] = read_char[0]; + else + { + //bookmark_display_message(read_buf); + global_settings.resume_offset = atoi(read_buf); + break; + } + read_count++; + } + + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + //reading the global_settings.resume_seed + nread = read(fd, read_char, 1); + if(nread <= 0) + { + bookmark_display_message("global_settings.resume_seed"); + success = false; + break; + } + if(strcmp(SEPARATOR, read_char)) + read_buf[read_count] = read_char[0]; + else + { + //bookmark_display_message(read_buf); + global_settings.resume_seed = atoi(read_buf); + break; + } + read_count++; + } + + //reading the global_settings.resume_first_index + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + nread = read(fd, read_char, 1); + if(nread <= 0) + { + bookmark_display_message("global_settings.resume_first_index"); + success = false; + break; + } + + if(strcmp(SEPARATOR, read_char)) + read_buf[read_count] = read_char[0]; + else + { + //bookmark_display_message(read_buf); + global_settings.resume_first_index = atoi(read_buf); + break; + } + read_count++; + } + + //reading the global_settings.queue_resume_index + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + nread = read(fd, read_char, 1); + if(nread <= 0) + { + bookmark_display_message("global_settings.queue_resume_index"); + success = false; + break; + } + if(strcmp(SEPARATOR, read_char)) + read_buf[read_count] = read_char[0]; + else + { + //bookmark_display_message(read_buf); + global_settings.queue_resume_index = atoi(read_buf); + break; + } + read_count++; + } + + //reading the global_settings.resume_file + read_count = 0; + memset(read_buf, 0, MAX_PATH); + while(success) + { + nread = read(fd, read_char, 1); + if(nread <= 0) + { + bookmark_display_message("global_settings.resume_file"); + success = false; + break; + } + if(strcmp(SEPARATOR, read_char)) + read_buf[read_count] = read_char[0]; + else + { + //bookmark_display_message(read_buf); + strcpy(global_settings.resume_file, read_buf); + break; + } + read_count++; + } + + close (fd); + + + if(success) + { + + int temp_resume_setting = global_settings.resume; + if(ask_resume_bookmark) + global_settings.resume = RESUME_ASK; + else + global_settings.resume = RESUME_ON; + start_resume(); + global_settings.resume = temp_resume_setting; + + //bookmark_play(); //Not working yet!!! + } + else + bookmark_display_message("Unable to load bookmark"); + + } + else + bookmark_display_message("Unable to open bookmark"); + +} + + +void bookmark_display_message(char* message) +{ + bool done = false; + int key; + int y=0; + + lcd_clear_display(); + lcd_puts_scroll(0, y, message); + lcd_update(); + + while(!done) + { + // Wait for a key to be pushed + key = button_get_w_tmo(HZ*5); + switch(key) + { + case BUTTON_PLAY | BUTTON_REL: + done = true; + break; + } + } +} + + +void bookmark_play(void) +{ + int len = strlen(global_settings.resume_file); + 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); + + 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); + + 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(); + wps_show(); + +} + --- rockbox/apps/bookmark.h 2003-01-14 00:03:03.000000000 -0800 +++ rockbox/apps/bookmark.h 2003-01-13 13:13:00.000000000 -0800 @@ -0,0 +1,38 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: playlist.h,v 1.21 2002/10/17 09:34:48 adiamas Exp $ + * + * Copyright (C) 2002 by wavey@wavey.org + * + * 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 __BOOKMARK_H__ +#define __BOOKMARK_H__ + +#include +#include "file.h" +#include "applimits.h" + +bool bookmark_menu(void); +bool bookmark_query(void); +bool bookmark_autocreate(void); +bool auto_load_bookmark(void); +void bookmark_create(void); +void bookmark_load(char* file, bool ask_resume_bookmark); +void bookmark_display_message(char* message); +bool bookmark_autoload(char* file); +void bookmark_play(void); + +#endif /* __BOOKMARK_H__ */ +