diff options
-rw-r--r-- | apps/bookmark.c | 11 | ||||
-rw-r--r-- | apps/lang/english.lang | 35 | ||||
-rw-r--r-- | apps/menu.c | 2 | ||||
-rw-r--r-- | apps/onplay.c | 51 | ||||
-rw-r--r-- | apps/playlist.c | 1349 | ||||
-rw-r--r-- | apps/playlist.h | 48 | ||||
-rw-r--r-- | apps/playlist_menu.c | 2 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 400 | ||||
-rw-r--r-- | apps/playlist_viewer.h | 1 | ||||
-rw-r--r-- | apps/screens.c | 4 | ||||
-rw-r--r-- | apps/settings.c | 40 | ||||
-rw-r--r-- | apps/settings.h | 5 | ||||
-rw-r--r-- | apps/settings_menu.c | 4 | ||||
-rw-r--r-- | apps/wps-display.c | 2 |
14 files changed, 1308 insertions, 646 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c index 893c128a15..9e093c0d1f 100644 --- a/apps/bookmark.c +++ b/apps/bookmark.c | |||
@@ -140,7 +140,7 @@ static bool bookmark_load_menu(void) | |||
140 | return false; | 140 | return false; |
141 | else | 141 | else |
142 | { | 142 | { |
143 | char* name = playlist_get_name(global_temp_buffer, | 143 | char* name = playlist_get_name(NULL, global_temp_buffer, |
144 | sizeof(global_temp_buffer)); | 144 | sizeof(global_temp_buffer)); |
145 | if (generate_bookmark_file_name(name, | 145 | if (generate_bookmark_file_name(name, |
146 | global_bookmark_file_name, | 146 | global_bookmark_file_name, |
@@ -306,7 +306,7 @@ static bool write_bookmark(bool create_bookmark_file) | |||
306 | /* writing the bookmark */ | 306 | /* writing the bookmark */ |
307 | if (create_bookmark_file) | 307 | if (create_bookmark_file) |
308 | { | 308 | { |
309 | char* name = playlist_get_name(global_temp_buffer, | 309 | char* name = playlist_get_name(NULL, global_temp_buffer, |
310 | sizeof(global_temp_buffer)); | 310 | sizeof(global_temp_buffer)); |
311 | if (generate_bookmark_file_name(name, | 311 | if (generate_bookmark_file_name(name, |
312 | global_bookmark_file_name, | 312 | global_bookmark_file_name, |
@@ -428,12 +428,13 @@ static char* create_bookmark() | |||
428 | "%d;%d;%d;%d;%d;%d;%d;%s;%s", | 428 | "%d;%d;%d;%d;%d;%d;%d;%s;%s", |
429 | resume_index, | 429 | resume_index, |
430 | id3->offset, | 430 | id3->offset, |
431 | playlist_get_seed(), | 431 | playlist_get_seed(NULL), |
432 | 0, | 432 | 0, |
433 | id3->elapsed, | 433 | id3->elapsed, |
434 | global_settings.repeat_mode, | 434 | global_settings.repeat_mode, |
435 | global_settings.playlist_shuffle, | 435 | global_settings.playlist_shuffle, |
436 | playlist_get_name(global_temp_buffer,sizeof(global_temp_buffer)), | 436 | playlist_get_name(NULL, global_temp_buffer, |
437 | sizeof(global_temp_buffer)), | ||
437 | file+1); | 438 | file+1); |
438 | 439 | ||
439 | /* checking to see if the bookmark is valid */ | 440 | /* checking to see if the bookmark is valid */ |
@@ -1090,7 +1091,7 @@ static bool system_check(void) | |||
1090 | /* something bad happened while getting the queue information */ | 1091 | /* something bad happened while getting the queue information */ |
1091 | return false; | 1092 | return false; |
1092 | } | 1093 | } |
1093 | else if (playlist_modified()) | 1094 | else if (playlist_modified(NULL)) |
1094 | { | 1095 | { |
1095 | /* can't bookmark while in the queue */ | 1096 | /* can't bookmark while in the queue */ |
1096 | return false; | 1097 | return false; |
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 9995ac277b..f88e211192 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -1666,3 +1666,38 @@ id: LANG_CREATE_DIR | |||
1666 | desc: in main menu | 1666 | desc: in main menu |
1667 | eng: "Create directory" | 1667 | eng: "Create directory" |
1668 | new: | 1668 | new: |
1669 | |||
1670 | id: LANG_VIEW | ||
1671 | desc: in on+play menu | ||
1672 | eng: "View" | ||
1673 | new: | ||
1674 | |||
1675 | id: LANG_SHOW_INDICES | ||
1676 | desc: in playlist viewer menu | ||
1677 | eng: "Show Indices" | ||
1678 | new: | ||
1679 | |||
1680 | id: LANG_TRACK_DISPLAY | ||
1681 | desc: in playlist viewer on+play menu | ||
1682 | eng: "Track Display" | ||
1683 | new: | ||
1684 | |||
1685 | id: LANG_DISPLAY_TRACK_NAME_ONLY | ||
1686 | desc: track display options | ||
1687 | eng: "Track name only" | ||
1688 | new: | ||
1689 | |||
1690 | id: LANG_DISPLAY_FULL_PATH | ||
1691 | desc: track display options | ||
1692 | eng: "Full path" | ||
1693 | new: | ||
1694 | |||
1695 | id: LANG_REMOVE | ||
1696 | desc: in playlist viewer on+play menu | ||
1697 | eng: "Remove" | ||
1698 | new: | ||
1699 | |||
1700 | id: LANG_FILE_OPTIONS | ||
1701 | desc: in playlist viewer on+play menu | ||
1702 | eng: "File Options" | ||
1703 | new: | ||
diff --git a/apps/menu.c b/apps/menu.c index f317403f0d..0bd21b9108 100644 --- a/apps/menu.c +++ b/apps/menu.c | |||
@@ -44,7 +44,7 @@ struct menu { | |||
44 | int itemcount; | 44 | int itemcount; |
45 | }; | 45 | }; |
46 | 46 | ||
47 | #define MAX_MENUS 4 | 47 | #define MAX_MENUS 5 |
48 | 48 | ||
49 | #ifdef HAVE_LCD_BITMAP | 49 | #ifdef HAVE_LCD_BITMAP |
50 | 50 | ||
diff --git a/apps/onplay.c b/apps/onplay.c index 3e085cea59..2f0ee3b861 100644 --- a/apps/onplay.c +++ b/apps/onplay.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "buffer.h" | 40 | #include "buffer.h" |
41 | #include "settings.h" | 41 | #include "settings.h" |
42 | #include "status.h" | 42 | #include "status.h" |
43 | #include "playlist_viewer.h" | ||
43 | #include "onplay.h" | 44 | #include "onplay.h" |
44 | 45 | ||
45 | static char* selected_file = NULL; | 46 | static char* selected_file = NULL; |
@@ -60,7 +61,7 @@ static bool add_to_playlist(int position, bool queue) | |||
60 | playlist_create(NULL, NULL); | 61 | playlist_create(NULL, NULL); |
61 | 62 | ||
62 | if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) | 63 | if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) |
63 | playlist_insert_track(selected_file, position, queue); | 64 | playlist_insert_track(NULL, selected_file, position, queue); |
64 | else if (selected_file_attr & ATTR_DIRECTORY) | 65 | else if (selected_file_attr & ATTR_DIRECTORY) |
65 | { | 66 | { |
66 | bool recurse = false; | 67 | bool recurse = false; |
@@ -99,10 +100,11 @@ static bool add_to_playlist(int position, bool queue) | |||
99 | } | 100 | } |
100 | } | 101 | } |
101 | 102 | ||
102 | playlist_insert_directory(selected_file, position, queue, recurse); | 103 | playlist_insert_directory(NULL, selected_file, position, queue, |
104 | recurse); | ||
103 | } | 105 | } |
104 | else if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) | 106 | else if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) |
105 | playlist_insert_playlist(selected_file, position, queue); | 107 | playlist_insert_playlist(NULL, selected_file, position, queue); |
106 | 108 | ||
107 | if (new_playlist && (playlist_amount() > 0)) | 109 | if (new_playlist && (playlist_amount() > 0)) |
108 | { | 110 | { |
@@ -119,12 +121,36 @@ static bool add_to_playlist(int position, bool queue) | |||
119 | return false; | 121 | return false; |
120 | } | 122 | } |
121 | 123 | ||
124 | static bool view_playlist(void) | ||
125 | { | ||
126 | bool was_playing = mpeg_status() & MPEG_STATUS_PLAY; | ||
127 | bool result; | ||
128 | |||
129 | result = playlist_viewer_ex(selected_file); | ||
130 | |||
131 | if (!was_playing && (mpeg_status() & MPEG_STATUS_PLAY) && | ||
132 | onplay_result == ONPLAY_OK) | ||
133 | /* playlist was started from viewer */ | ||
134 | onplay_result = ONPLAY_START_PLAY; | ||
135 | |||
136 | return result; | ||
137 | } | ||
138 | |||
122 | /* Sub-menu for playlist options */ | 139 | /* Sub-menu for playlist options */ |
123 | static bool playlist_options(void) | 140 | static bool playlist_options(void) |
124 | { | 141 | { |
125 | struct menu_items menu[6]; | 142 | struct menu_items menu[7]; |
126 | struct playlist_args args[6]; /* increase these 2 if you add entries! */ | 143 | struct playlist_args args[7]; /* increase these 2 if you add entries! */ |
127 | int m, i=0, result; | 144 | int m, i=0, pstart=0, result; |
145 | bool ret = false; | ||
146 | |||
147 | if ((selected_file_attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) | ||
148 | { | ||
149 | menu[i].desc = str(LANG_VIEW); | ||
150 | menu[i].function = view_playlist; | ||
151 | i++; | ||
152 | pstart++; | ||
153 | } | ||
128 | 154 | ||
129 | if (mpeg_status() & MPEG_STATUS_PLAY) | 155 | if (mpeg_status() & MPEG_STATUS_PLAY) |
130 | { | 156 | { |
@@ -169,11 +195,13 @@ static bool playlist_options(void) | |||
169 | 195 | ||
170 | m = menu_init( menu, i ); | 196 | m = menu_init( menu, i ); |
171 | result = menu_show(m); | 197 | result = menu_show(m); |
172 | if (result >= 0) | 198 | if (result >= 0 && result < pstart) |
173 | add_to_playlist(args[result].position, args[result].queue); | 199 | ret = menu[result].function(); |
200 | else if (result >= pstart) | ||
201 | ret = add_to_playlist(args[result].position, args[result].queue); | ||
174 | menu_exit(m); | 202 | menu_exit(m); |
175 | 203 | ||
176 | return false; | 204 | return ret; |
177 | } | 205 | } |
178 | 206 | ||
179 | static bool delete_file(void) | 207 | static bool delete_file(void) |
@@ -489,8 +517,9 @@ int onplay(char* file, int attr) | |||
489 | selected_file = file; | 517 | selected_file = file; |
490 | selected_file_attr = attr; | 518 | selected_file_attr = attr; |
491 | 519 | ||
492 | if (((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) || (attr & ATTR_DIRECTORY) || | 520 | if (((attr & TREE_ATTR_MASK) == TREE_ATTR_MPA) || |
493 | (((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U) && (mpeg_status() & MPEG_STATUS_PLAY))) | 521 | (attr & ATTR_DIRECTORY) || |
522 | ((attr & TREE_ATTR_MASK) == TREE_ATTR_M3U)) | ||
494 | { | 523 | { |
495 | menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST); | 524 | menu[i].desc = str(LANG_PLAYINDICES_PLAYLIST); |
496 | menu[i].function = playlist_options; | 525 | menu[i].function = playlist_options; |
diff --git a/apps/playlist.c b/apps/playlist.c index 13919b2f02..8dede37d38 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -60,7 +60,9 @@ | |||
60 | The only resume info that needs to be saved is the current index in the | 60 | The only resume info that needs to be saved is the current index in the |
61 | playlist and the position in the track. When resuming, all the commands | 61 | playlist and the position in the track. When resuming, all the commands |
62 | in the control file will be reapplied so that the playlist indices are | 62 | in the control file will be reapplied so that the playlist indices are |
63 | exactly the same as before shutdown. | 63 | exactly the same as before shutdown. To avoid unnecessary disk |
64 | accesses, the shuffle mode settings are also saved in settings and only | ||
65 | flushed to disk when required. | ||
64 | */ | 66 | */ |
65 | 67 | ||
66 | #include <stdio.h> | 68 | #include <stdio.h> |
@@ -90,8 +92,6 @@ | |||
90 | 92 | ||
91 | #include "lang.h" | 93 | #include "lang.h" |
92 | 94 | ||
93 | static struct playlist_info playlist; | ||
94 | |||
95 | #define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control" | 95 | #define PLAYLIST_CONTROL_FILE ROCKBOX_DIR "/.playlist_control" |
96 | #define PLAYLIST_CONTROL_FILE_VERSION 2 | 96 | #define PLAYLIST_CONTROL_FILE_VERSION 2 |
97 | 97 | ||
@@ -123,70 +123,83 @@ static struct playlist_info playlist; | |||
123 | 123 | ||
124 | #define PLAYLIST_DISPLAY_COUNT 10 | 124 | #define PLAYLIST_DISPLAY_COUNT 10 |
125 | 125 | ||
126 | static struct playlist_info current_playlist; | ||
126 | static char now_playing[MAX_PATH+1]; | 127 | static char now_playing[MAX_PATH+1]; |
127 | 128 | ||
128 | static void empty_playlist(bool resume); | 129 | static void empty_playlist(struct playlist_info* playlist, bool resume); |
129 | static void update_playlist_filename(char *dir, char *file); | 130 | static void new_playlist(struct playlist_info* playlist, char *dir, |
130 | static int add_indices_to_playlist(void); | 131 | char *file); |
131 | static int add_track_to_playlist(char *filename, int position, bool queue, | 132 | static void create_control(struct playlist_info* playlist); |
133 | static int check_control(struct playlist_info* playlist); | ||
134 | static void update_playlist_filename(struct playlist_info* playlist, | ||
135 | char *dir, char *file); | ||
136 | static int add_indices_to_playlist(struct playlist_info* playlist, | ||
137 | char* buffer, int buflen); | ||
138 | static int add_track_to_playlist(struct playlist_info* playlist, | ||
139 | char *filename, int position, bool queue, | ||
132 | int seek_pos); | 140 | int seek_pos); |
133 | static int add_directory_to_playlist(char *dirname, int *position, bool queue, | 141 | static int add_directory_to_playlist(struct playlist_info* playlist, |
142 | char *dirname, int *position, bool queue, | ||
134 | int *count, bool recurse); | 143 | int *count, bool recurse); |
135 | static int remove_track_from_playlist(int position, bool write); | 144 | static int remove_track_from_playlist(struct playlist_info* playlist, |
136 | static int randomise_playlist(unsigned int seed, bool start_current, | 145 | int position, bool write); |
146 | static int randomise_playlist(struct playlist_info* playlist, | ||
147 | unsigned int seed, bool start_current, | ||
137 | bool write); | 148 | bool write); |
138 | static int sort_playlist(bool start_current, bool write); | 149 | static int sort_playlist(struct playlist_info* playlist, bool start_current, |
139 | static int get_next_index(int steps); | 150 | bool write); |
140 | static void find_and_set_playlist_index(unsigned int seek); | 151 | static int get_next_index(struct playlist_info* playlist, int steps); |
152 | static void find_and_set_playlist_index(struct playlist_info* playlist, | ||
153 | unsigned int seek); | ||
141 | static int compare(const void* p1, const void* p2); | 154 | static int compare(const void* p1, const void* p2); |
142 | static int get_filename(int seek, bool control_file, char *buf, | 155 | static int get_filename(struct playlist_info* playlist, int seek, |
143 | int buf_length); | 156 | bool control_file, char *buf, int buf_length); |
144 | static int format_track_path(char *dest, char *src, int buf_length, int max, | 157 | static int format_track_path(char *dest, char *src, int buf_length, int max, |
145 | char *dir); | 158 | char *dir); |
146 | static void display_playlist_count(int count, char *fmt); | 159 | static void display_playlist_count(int count, char *fmt); |
147 | static void display_buffer_full(void); | 160 | static void display_buffer_full(void); |
148 | static int flush_pending_control(void); | 161 | static int flush_pending_control(struct playlist_info* playlist); |
149 | static int rotate_index(int index); | 162 | static int rotate_index(struct playlist_info* playlist, int index); |
150 | 163 | ||
151 | /* | 164 | /* |
152 | * remove any files and indices associated with the playlist | 165 | * remove any files and indices associated with the playlist |
153 | */ | 166 | */ |
154 | static void empty_playlist(bool resume) | 167 | static void empty_playlist(struct playlist_info* playlist, bool resume) |
155 | { | 168 | { |
156 | playlist.filename[0] = '\0'; | 169 | playlist->filename[0] = '\0'; |
157 | 170 | ||
158 | if(playlist.fd >= 0) | 171 | if(playlist->fd >= 0) |
159 | /* If there is an already open playlist, close it. */ | 172 | /* If there is an already open playlist, close it. */ |
160 | close(playlist.fd); | 173 | close(playlist->fd); |
161 | playlist.fd = -1; | 174 | playlist->fd = -1; |
162 | 175 | ||
163 | if(playlist.control_fd >= 0) | 176 | if(playlist->control_fd >= 0) |
164 | close(playlist.control_fd); | 177 | close(playlist->control_fd); |
165 | playlist.control_fd = -1; | 178 | playlist->control_fd = -1; |
166 | 179 | playlist->control_created = false; | |
167 | playlist.in_ram = false; | 180 | |
168 | playlist.buffer[0] = 0; | 181 | playlist->in_ram = false; |
169 | playlist.buffer_end_pos = 0; | ||
170 | |||
171 | playlist.index = 0; | ||
172 | playlist.first_index = 0; | ||
173 | playlist.amount = 0; | ||
174 | playlist.last_insert_pos = -1; | ||
175 | playlist.seed = 0; | ||
176 | playlist.shuffle_modified = false; | ||
177 | playlist.deleted = false; | ||
178 | playlist.num_inserted_tracks = 0; | ||
179 | playlist.shuffle_flush = false; | ||
180 | |||
181 | if (!resume) | ||
182 | { | ||
183 | int fd; | ||
184 | 182 | ||
183 | if (playlist->buffer) | ||
184 | playlist->buffer[0] = 0; | ||
185 | |||
186 | playlist->buffer_end_pos = 0; | ||
187 | |||
188 | playlist->index = 0; | ||
189 | playlist->first_index = 0; | ||
190 | playlist->amount = 0; | ||
191 | playlist->last_insert_pos = -1; | ||
192 | playlist->seed = 0; | ||
193 | playlist->shuffle_modified = false; | ||
194 | playlist->deleted = false; | ||
195 | playlist->num_inserted_tracks = 0; | ||
196 | playlist->shuffle_flush = false; | ||
197 | |||
198 | if (!resume && playlist->current) | ||
199 | { | ||
185 | /* start with fresh playlist control file when starting new | 200 | /* start with fresh playlist control file when starting new |
186 | playlist */ | 201 | playlist */ |
187 | fd = creat(PLAYLIST_CONTROL_FILE, 0000200); | 202 | create_control(playlist); |
188 | if (fd >= 0) | ||
189 | close(fd); | ||
190 | 203 | ||
191 | /* Reset resume settings */ | 204 | /* Reset resume settings */ |
192 | global_settings.resume_first_index = 0; | 205 | global_settings.resume_first_index = 0; |
@@ -195,9 +208,86 @@ static void empty_playlist(bool resume) | |||
195 | } | 208 | } |
196 | 209 | ||
197 | /* | 210 | /* |
211 | * Initialize a new playlist for viewing/editing/playing. dir is the | ||
212 | * directory where the playlist is located and file is the filename. | ||
213 | */ | ||
214 | static void new_playlist(struct playlist_info* playlist, char *dir, | ||
215 | char *file) | ||
216 | { | ||
217 | empty_playlist(playlist, false); | ||
218 | |||
219 | if (!file) | ||
220 | { | ||
221 | file = ""; | ||
222 | |||
223 | if (dir && playlist->current) /* !current cannot be in_ram */ | ||
224 | playlist->in_ram = true; | ||
225 | else | ||
226 | dir = ""; /* empty playlist */ | ||
227 | } | ||
228 | |||
229 | update_playlist_filename(playlist, dir, file); | ||
230 | |||
231 | if (playlist->control_fd >= 0) | ||
232 | { | ||
233 | if (fprintf(playlist->control_fd, "P:%d:%s:%s\n", | ||
234 | PLAYLIST_CONTROL_FILE_VERSION, dir, file) > 0) | ||
235 | fsync(playlist->control_fd); | ||
236 | else | ||
237 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * create control file for playlist | ||
243 | */ | ||
244 | static void create_control(struct playlist_info* playlist) | ||
245 | { | ||
246 | playlist->control_fd = creat(playlist->control_filename, 0000200); | ||
247 | if (playlist->control_fd < 0) | ||
248 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | ||
249 | playlist->control_created = true; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * validate the control file. This may include creating/initializing it if | ||
254 | * necessary; | ||
255 | */ | ||
256 | static int check_control(struct playlist_info* playlist) | ||
257 | { | ||
258 | if (!playlist->control_created) | ||
259 | { | ||
260 | create_control(playlist); | ||
261 | |||
262 | if (playlist->control_fd >= 0) | ||
263 | { | ||
264 | char* dir = playlist->filename; | ||
265 | char* file = playlist->filename+playlist->dirlen; | ||
266 | char c = playlist->filename[playlist->dirlen-1]; | ||
267 | |||
268 | playlist->filename[playlist->dirlen-1] = '\0'; | ||
269 | |||
270 | if (fprintf(playlist->control_fd, "P:%d:%s:%s\n", | ||
271 | PLAYLIST_CONTROL_FILE_VERSION, dir, file) > 0) | ||
272 | fsync(playlist->control_fd); | ||
273 | else | ||
274 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
275 | |||
276 | playlist->filename[playlist->dirlen-1] = c; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | if (playlist->control_fd < 0) | ||
281 | return -1; | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
198 | * store directory and name of playlist file | 287 | * store directory and name of playlist file |
199 | */ | 288 | */ |
200 | static void update_playlist_filename(char *dir, char *file) | 289 | static void update_playlist_filename(struct playlist_info* playlist, |
290 | char *dir, char *file) | ||
201 | { | 291 | { |
202 | char *sep=""; | 292 | char *sep=""; |
203 | int dirlen = strlen(dir); | 293 | int dirlen = strlen(dir); |
@@ -210,9 +300,9 @@ static void update_playlist_filename(char *dir, char *file) | |||
210 | dirlen++; | 300 | dirlen++; |
211 | } | 301 | } |
212 | 302 | ||
213 | playlist.dirlen = dirlen; | 303 | playlist->dirlen = dirlen; |
214 | 304 | ||
215 | snprintf(playlist.filename, sizeof(playlist.filename), | 305 | snprintf(playlist->filename, sizeof(playlist->filename), |
216 | "%s%s%s", | 306 | "%s%s%s", |
217 | dir, sep, file); | 307 | dir, sep, file); |
218 | } | 308 | } |
@@ -220,19 +310,18 @@ static void update_playlist_filename(char *dir, char *file) | |||
220 | /* | 310 | /* |
221 | * calculate track offsets within a playlist file | 311 | * calculate track offsets within a playlist file |
222 | */ | 312 | */ |
223 | static int add_indices_to_playlist(void) | 313 | static int add_indices_to_playlist(struct playlist_info* playlist, |
314 | char* buffer, int buflen) | ||
224 | { | 315 | { |
225 | unsigned int nread; | 316 | unsigned int nread; |
226 | unsigned int i = 0; | 317 | unsigned int i = 0; |
227 | unsigned int count = 0; | 318 | unsigned int count = 0; |
228 | int buflen; | ||
229 | bool store_index; | 319 | bool store_index; |
230 | char *buffer; | ||
231 | unsigned char *p; | 320 | unsigned char *p; |
232 | 321 | ||
233 | if(-1 == playlist.fd) | 322 | if(-1 == playlist->fd) |
234 | playlist.fd = open(playlist.filename, O_RDONLY); | 323 | playlist->fd = open(playlist->filename, O_RDONLY); |
235 | if(playlist.fd < 0) | 324 | if(playlist->fd < 0) |
236 | return -1; /* failure */ | 325 | return -1; /* failure */ |
237 | 326 | ||
238 | #ifdef HAVE_LCD_BITMAP | 327 | #ifdef HAVE_LCD_BITMAP |
@@ -244,17 +333,20 @@ static int add_indices_to_playlist(void) | |||
244 | 333 | ||
245 | splash(0, true, str(LANG_PLAYLIST_LOAD)); | 334 | splash(0, true, str(LANG_PLAYLIST_LOAD)); |
246 | 335 | ||
247 | /* use mp3 buffer for maximum load speed */ | 336 | if (!buffer) |
248 | buflen = (mp3end - mp3buf); | 337 | { |
249 | buffer = mp3buf; | 338 | /* use mp3 buffer for maximum load speed */ |
339 | mpeg_stop(); | ||
250 | 340 | ||
341 | buffer = mp3buf; | ||
342 | buflen = (mp3end - mp3buf); | ||
343 | } | ||
344 | |||
251 | store_index = true; | 345 | store_index = true; |
252 | 346 | ||
253 | mpeg_stop(); | ||
254 | |||
255 | while(1) | 347 | while(1) |
256 | { | 348 | { |
257 | nread = read(playlist.fd, buffer, buflen); | 349 | nread = read(playlist->fd, buffer, buflen); |
258 | /* Terminate on EOF */ | 350 | /* Terminate on EOF */ |
259 | if(nread <= 0) | 351 | if(nread <= 0) |
260 | break; | 352 | break; |
@@ -275,9 +367,9 @@ static int add_indices_to_playlist(void) | |||
275 | if(*p != '#') | 367 | if(*p != '#') |
276 | { | 368 | { |
277 | /* Store a new entry */ | 369 | /* Store a new entry */ |
278 | playlist.indices[ playlist.amount ] = i+count; | 370 | playlist->indices[ playlist->amount ] = i+count; |
279 | playlist.amount++; | 371 | playlist->amount++; |
280 | if ( playlist.amount >= playlist.max_playlist_size ) { | 372 | if ( playlist->amount >= playlist->max_playlist_size ) { |
281 | display_buffer_full(); | 373 | display_buffer_full(); |
282 | return -1; | 374 | return -1; |
283 | } | 375 | } |
@@ -302,14 +394,15 @@ static int add_indices_to_playlist(void) | |||
302 | * matter what other tracks have been inserted. | 394 | * matter what other tracks have been inserted. |
303 | * PLAYLIST_INSERT_LAST - Add track to end of playlist | 395 | * PLAYLIST_INSERT_LAST - Add track to end of playlist |
304 | */ | 396 | */ |
305 | static int add_track_to_playlist(char *filename, int position, bool queue, | 397 | static int add_track_to_playlist(struct playlist_info* playlist, |
398 | char *filename, int position, bool queue, | ||
306 | int seek_pos) | 399 | int seek_pos) |
307 | { | 400 | { |
308 | int insert_position = position; | 401 | int insert_position = position; |
309 | unsigned int flags = PLAYLIST_INSERT_TYPE_INSERT; | 402 | unsigned int flags = PLAYLIST_INSERT_TYPE_INSERT; |
310 | int i; | 403 | int i; |
311 | 404 | ||
312 | if (playlist.amount >= playlist.max_playlist_size) | 405 | if (playlist->amount >= playlist->max_playlist_size) |
313 | { | 406 | { |
314 | display_buffer_full(); | 407 | display_buffer_full(); |
315 | return -1; | 408 | return -1; |
@@ -318,38 +411,38 @@ static int add_track_to_playlist(char *filename, int position, bool queue, | |||
318 | switch (position) | 411 | switch (position) |
319 | { | 412 | { |
320 | case PLAYLIST_PREPEND: | 413 | case PLAYLIST_PREPEND: |
321 | insert_position = playlist.first_index; | 414 | insert_position = playlist->first_index; |
322 | flags = PLAYLIST_INSERT_TYPE_PREPEND; | 415 | flags = PLAYLIST_INSERT_TYPE_PREPEND; |
323 | break; | 416 | break; |
324 | case PLAYLIST_INSERT: | 417 | case PLAYLIST_INSERT: |
325 | /* if there are already inserted tracks then add track to end of | 418 | /* if there are already inserted tracks then add track to end of |
326 | insertion list else add after current playing track */ | 419 | insertion list else add after current playing track */ |
327 | if (playlist.last_insert_pos >= 0 && | 420 | if (playlist->last_insert_pos >= 0 && |
328 | playlist.last_insert_pos < playlist.amount && | 421 | playlist->last_insert_pos < playlist->amount && |
329 | (playlist.indices[playlist.last_insert_pos]& | 422 | (playlist->indices[playlist->last_insert_pos]& |
330 | PLAYLIST_INSERT_TYPE_MASK) == PLAYLIST_INSERT_TYPE_INSERT) | 423 | PLAYLIST_INSERT_TYPE_MASK) == PLAYLIST_INSERT_TYPE_INSERT) |
331 | position = insert_position = playlist.last_insert_pos+1; | 424 | position = insert_position = playlist->last_insert_pos+1; |
332 | else if (playlist.amount > 0) | 425 | else if (playlist->amount > 0) |
333 | position = insert_position = playlist.index + 1; | 426 | position = insert_position = playlist->index + 1; |
334 | else | 427 | else |
335 | position = insert_position = 0; | 428 | position = insert_position = 0; |
336 | 429 | ||
337 | playlist.last_insert_pos = position; | 430 | playlist->last_insert_pos = position; |
338 | break; | 431 | break; |
339 | case PLAYLIST_INSERT_FIRST: | 432 | case PLAYLIST_INSERT_FIRST: |
340 | if (playlist.amount > 0) | 433 | if (playlist->amount > 0) |
341 | position = insert_position = playlist.index + 1; | 434 | position = insert_position = playlist->index + 1; |
342 | else | 435 | else |
343 | position = insert_position = 0; | 436 | position = insert_position = 0; |
344 | 437 | ||
345 | if (playlist.last_insert_pos < 0) | 438 | if (playlist->last_insert_pos < 0) |
346 | playlist.last_insert_pos = position; | 439 | playlist->last_insert_pos = position; |
347 | break; | 440 | break; |
348 | case PLAYLIST_INSERT_LAST: | 441 | case PLAYLIST_INSERT_LAST: |
349 | if (playlist.first_index > 0) | 442 | if (playlist->first_index > 0) |
350 | insert_position = playlist.first_index; | 443 | insert_position = playlist->first_index; |
351 | else | 444 | else |
352 | insert_position = playlist.amount; | 445 | insert_position = playlist->amount; |
353 | 446 | ||
354 | flags = PLAYLIST_INSERT_TYPE_APPEND; | 447 | flags = PLAYLIST_INSERT_TYPE_APPEND; |
355 | break; | 448 | break; |
@@ -359,52 +452,52 @@ static int add_track_to_playlist(char *filename, int position, bool queue, | |||
359 | flags |= PLAYLIST_QUEUED; | 452 | flags |= PLAYLIST_QUEUED; |
360 | 453 | ||
361 | /* shift indices so that track can be added */ | 454 | /* shift indices so that track can be added */ |
362 | for (i=playlist.amount; i>insert_position; i--) | 455 | for (i=playlist->amount; i>insert_position; i--) |
363 | playlist.indices[i] = playlist.indices[i-1]; | 456 | playlist->indices[i] = playlist->indices[i-1]; |
364 | 457 | ||
365 | /* update stored indices if needed */ | 458 | /* update stored indices if needed */ |
366 | if (playlist.amount > 0 && insert_position <= playlist.index) | 459 | if (playlist->amount > 0 && insert_position <= playlist->index) |
367 | playlist.index++; | 460 | playlist->index++; |
368 | 461 | ||
369 | if (playlist.amount > 0 && insert_position <= playlist.first_index && | 462 | if (playlist->amount > 0 && insert_position <= playlist->first_index && |
370 | position != PLAYLIST_PREPEND) | 463 | position != PLAYLIST_PREPEND) |
371 | { | 464 | { |
372 | playlist.first_index++; | 465 | playlist->first_index++; |
373 | 466 | ||
374 | if (seek_pos < 0) | 467 | if (seek_pos < 0 && playlist->current) |
375 | { | 468 | { |
376 | global_settings.resume_first_index = playlist.first_index; | 469 | global_settings.resume_first_index = playlist->first_index; |
377 | settings_save(); | 470 | settings_save(); |
378 | } | 471 | } |
379 | } | 472 | } |
380 | 473 | ||
381 | if (insert_position < playlist.last_insert_pos || | 474 | if (insert_position < playlist->last_insert_pos || |
382 | (insert_position == playlist.last_insert_pos && position < 0)) | 475 | (insert_position == playlist->last_insert_pos && position < 0)) |
383 | playlist.last_insert_pos++; | 476 | playlist->last_insert_pos++; |
384 | 477 | ||
385 | if (seek_pos < 0 && playlist.control_fd >= 0) | 478 | if (seek_pos < 0 && playlist->control_fd >= 0) |
386 | { | 479 | { |
387 | int result = -1; | 480 | int result = -1; |
388 | 481 | ||
389 | if (flush_pending_control() < 0) | 482 | if (flush_pending_control(playlist) < 0) |
390 | return -1; | 483 | return -1; |
391 | 484 | ||
392 | mutex_lock(&playlist.control_mutex); | 485 | mutex_lock(&playlist->control_mutex); |
393 | 486 | ||
394 | if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) | 487 | if (lseek(playlist->control_fd, 0, SEEK_END) >= 0) |
395 | { | 488 | { |
396 | if (fprintf(playlist.control_fd, "%c:%d:%d:", (queue?'Q':'A'), | 489 | if (fprintf(playlist->control_fd, "%c:%d:%d:", (queue?'Q':'A'), |
397 | position, playlist.last_insert_pos) > 0) | 490 | position, playlist->last_insert_pos) > 0) |
398 | { | 491 | { |
399 | /* save the position in file where track name is written */ | 492 | /* save the position in file where track name is written */ |
400 | seek_pos = lseek(playlist.control_fd, 0, SEEK_CUR); | 493 | seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR); |
401 | 494 | ||
402 | if (fprintf(playlist.control_fd, "%s\n", filename) > 0) | 495 | if (fprintf(playlist->control_fd, "%s\n", filename) > 0) |
403 | result = 0; | 496 | result = 0; |
404 | } | 497 | } |
405 | } | 498 | } |
406 | 499 | ||
407 | mutex_unlock(&playlist.control_mutex); | 500 | mutex_unlock(&playlist->control_mutex); |
408 | 501 | ||
409 | if (result < 0) | 502 | if (result < 0) |
410 | { | 503 | { |
@@ -413,10 +506,10 @@ static int add_track_to_playlist(char *filename, int position, bool queue, | |||
413 | } | 506 | } |
414 | } | 507 | } |
415 | 508 | ||
416 | playlist.indices[insert_position] = flags | seek_pos; | 509 | playlist->indices[insert_position] = flags | seek_pos; |
417 | 510 | ||
418 | playlist.amount++; | 511 | playlist->amount++; |
419 | playlist.num_inserted_tracks++; | 512 | playlist->num_inserted_tracks++; |
420 | 513 | ||
421 | return insert_position; | 514 | return insert_position; |
422 | } | 515 | } |
@@ -424,7 +517,8 @@ static int add_track_to_playlist(char *filename, int position, bool queue, | |||
424 | /* | 517 | /* |
425 | * Insert directory into playlist. May be called recursively. | 518 | * Insert directory into playlist. May be called recursively. |
426 | */ | 519 | */ |
427 | static int add_directory_to_playlist(char *dirname, int *position, bool queue, | 520 | static int add_directory_to_playlist(struct playlist_info* playlist, |
521 | char *dirname, int *position, bool queue, | ||
428 | int *count, bool recurse) | 522 | int *count, bool recurse) |
429 | { | 523 | { |
430 | char buf[MAX_PATH+1]; | 524 | char buf[MAX_PATH+1]; |
@@ -474,8 +568,8 @@ static int add_directory_to_playlist(char *dirname, int *position, bool queue, | |||
474 | { | 568 | { |
475 | /* recursively add directories */ | 569 | /* recursively add directories */ |
476 | snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name); | 570 | snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name); |
477 | result = add_directory_to_playlist(buf, position, queue, | 571 | result = add_directory_to_playlist(playlist, buf, position, |
478 | count, recurse); | 572 | queue, count, recurse); |
479 | if (result < 0) | 573 | if (result < 0) |
480 | break; | 574 | break; |
481 | 575 | ||
@@ -497,7 +591,8 @@ static int add_directory_to_playlist(char *dirname, int *position, bool queue, | |||
497 | 591 | ||
498 | snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name); | 592 | snprintf(buf, sizeof(buf), "%s/%s", dirname, files[i].name); |
499 | 593 | ||
500 | insert_pos = add_track_to_playlist(buf, *position, queue, -1); | 594 | insert_pos = add_track_to_playlist(playlist, buf, *position, |
595 | queue, -1); | ||
501 | if (insert_pos < 0) | 596 | if (insert_pos < 0) |
502 | { | 597 | { |
503 | result = -1; | 598 | result = -1; |
@@ -530,64 +625,65 @@ static int add_directory_to_playlist(char *dirname, int *position, bool queue, | |||
530 | /* | 625 | /* |
531 | * remove track at specified position | 626 | * remove track at specified position |
532 | */ | 627 | */ |
533 | static int remove_track_from_playlist(int position, bool write) | 628 | static int remove_track_from_playlist(struct playlist_info* playlist, |
629 | int position, bool write) | ||
534 | { | 630 | { |
535 | int i; | 631 | int i; |
536 | bool inserted; | 632 | bool inserted; |
537 | 633 | ||
538 | if (playlist.amount <= 0) | 634 | if (playlist->amount <= 0) |
539 | return -1; | 635 | return -1; |
540 | 636 | ||
541 | inserted = playlist.indices[position] & PLAYLIST_INSERT_TYPE_MASK; | 637 | inserted = playlist->indices[position] & PLAYLIST_INSERT_TYPE_MASK; |
542 | 638 | ||
543 | /* shift indices now that track has been removed */ | 639 | /* shift indices now that track has been removed */ |
544 | for (i=position; i<playlist.amount; i++) | 640 | for (i=position; i<playlist->amount; i++) |
545 | playlist.indices[i] = playlist.indices[i+1]; | 641 | playlist->indices[i] = playlist->indices[i+1]; |
546 | 642 | ||
547 | playlist.amount--; | 643 | playlist->amount--; |
548 | 644 | ||
549 | if (inserted) | 645 | if (inserted) |
550 | playlist.num_inserted_tracks--; | 646 | playlist->num_inserted_tracks--; |
551 | else | 647 | else |
552 | playlist.deleted = true; | 648 | playlist->deleted = true; |
553 | 649 | ||
554 | /* update stored indices if needed */ | 650 | /* update stored indices if needed */ |
555 | if (position < playlist.index) | 651 | if (position < playlist->index) |
556 | playlist.index--; | 652 | playlist->index--; |
557 | 653 | ||
558 | if (position < playlist.first_index) | 654 | if (position < playlist->first_index) |
559 | { | 655 | { |
560 | playlist.first_index--; | 656 | playlist->first_index--; |
561 | 657 | ||
562 | if (write) | 658 | if (write) |
563 | { | 659 | { |
564 | global_settings.resume_first_index = playlist.first_index; | 660 | global_settings.resume_first_index = playlist->first_index; |
565 | settings_save(); | 661 | settings_save(); |
566 | } | 662 | } |
567 | } | 663 | } |
568 | 664 | ||
569 | if (position <= playlist.last_insert_pos) | 665 | if (position <= playlist->last_insert_pos) |
570 | playlist.last_insert_pos--; | 666 | playlist->last_insert_pos--; |
571 | 667 | ||
572 | if (write && playlist.control_fd >= 0) | 668 | if (write && playlist->control_fd >= 0) |
573 | { | 669 | { |
574 | int result = -1; | 670 | int result = -1; |
575 | 671 | ||
576 | if (flush_pending_control() < 0) | 672 | if (flush_pending_control(playlist) < 0) |
577 | return -1; | 673 | return -1; |
578 | 674 | ||
579 | mutex_lock(&playlist.control_mutex); | 675 | mutex_lock(&playlist->control_mutex); |
580 | 676 | ||
581 | if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) | 677 | if (lseek(playlist->control_fd, 0, SEEK_END) >= 0) |
582 | { | 678 | { |
583 | if (fprintf(playlist.control_fd, "D:%d\n", position) > 0) | 679 | if (fprintf(playlist->control_fd, "D:%d\n", position) > 0) |
584 | { | 680 | { |
585 | fsync(playlist.control_fd); | 681 | fsync(playlist->control_fd); |
586 | result = 0; | 682 | result = 0; |
587 | } | 683 | } |
588 | } | 684 | } |
589 | 685 | ||
590 | mutex_unlock(&playlist.control_mutex); | 686 | mutex_unlock(&playlist->control_mutex); |
591 | 687 | ||
592 | if (result < 0) | 688 | if (result < 0) |
593 | { | 689 | { |
@@ -603,12 +699,14 @@ static int remove_track_from_playlist(int position, bool write) | |||
603 | * randomly rearrange the array of indices for the playlist. If start_current | 699 | * randomly rearrange the array of indices for the playlist. If start_current |
604 | * is true then update the index to the new index of the current playing track | 700 | * is true then update the index to the new index of the current playing track |
605 | */ | 701 | */ |
606 | static int randomise_playlist(unsigned int seed, bool start_current, bool write) | 702 | static int randomise_playlist(struct playlist_info* playlist, |
703 | unsigned int seed, bool start_current, | ||
704 | bool write) | ||
607 | { | 705 | { |
608 | int count; | 706 | int count; |
609 | int candidate; | 707 | int candidate; |
610 | int store; | 708 | int store; |
611 | unsigned int current = playlist.indices[playlist.index]; | 709 | unsigned int current = playlist->indices[playlist->index]; |
612 | 710 | ||
613 | /* seed 0 is used to identify sorted playlist for resume purposes */ | 711 | /* seed 0 is used to identify sorted playlist for resume purposes */ |
614 | if (seed == 0) | 712 | if (seed == 0) |
@@ -618,32 +716,32 @@ static int randomise_playlist(unsigned int seed, bool start_current, bool write) | |||
618 | srand(seed); | 716 | srand(seed); |
619 | 717 | ||
620 | /* randomise entire indices list */ | 718 | /* randomise entire indices list */ |
621 | for(count = playlist.amount - 1; count >= 0; count--) | 719 | for(count = playlist->amount - 1; count >= 0; count--) |
622 | { | 720 | { |
623 | /* the rand is from 0 to RAND_MAX, so adjust to our value range */ | 721 | /* the rand is from 0 to RAND_MAX, so adjust to our value range */ |
624 | candidate = rand() % (count + 1); | 722 | candidate = rand() % (count + 1); |
625 | 723 | ||
626 | /* now swap the values at the 'count' and 'candidate' positions */ | 724 | /* now swap the values at the 'count' and 'candidate' positions */ |
627 | store = playlist.indices[candidate]; | 725 | store = playlist->indices[candidate]; |
628 | playlist.indices[candidate] = playlist.indices[count]; | 726 | playlist->indices[candidate] = playlist->indices[count]; |
629 | playlist.indices[count] = store; | 727 | playlist->indices[count] = store; |
630 | } | 728 | } |
631 | 729 | ||
632 | if (start_current) | 730 | if (start_current) |
633 | find_and_set_playlist_index(current); | 731 | find_and_set_playlist_index(playlist, current); |
634 | 732 | ||
635 | /* indices have been moved so last insert position is no longer valid */ | 733 | /* indices have been moved so last insert position is no longer valid */ |
636 | playlist.last_insert_pos = -1; | 734 | playlist->last_insert_pos = -1; |
637 | 735 | ||
638 | playlist.seed = seed; | 736 | playlist->seed = seed; |
639 | if (playlist.num_inserted_tracks > 0 || playlist.deleted) | 737 | if (playlist->num_inserted_tracks > 0 || playlist->deleted) |
640 | playlist.shuffle_modified = true; | 738 | playlist->shuffle_modified = true; |
641 | 739 | ||
642 | if (write) | 740 | if (write) |
643 | { | 741 | { |
644 | /* Don't write to disk immediately. Instead, save in settings and | 742 | /* Don't write to disk immediately. Instead, save in settings and |
645 | only flush if playlist is modified (insertion/deletion) */ | 743 | only flush if playlist is modified (insertion/deletion) */ |
646 | playlist.shuffle_flush = true; | 744 | playlist->shuffle_flush = true; |
647 | global_settings.resume_seed = seed; | 745 | global_settings.resume_seed = seed; |
648 | settings_save(); | 746 | settings_save(); |
649 | } | 747 | } |
@@ -655,27 +753,28 @@ static int randomise_playlist(unsigned int seed, bool start_current, bool write) | |||
655 | * Sort the array of indices for the playlist. If start_current is true then | 753 | * Sort the array of indices for the playlist. If start_current is true then |
656 | * set the index to the new index of the current song. | 754 | * set the index to the new index of the current song. |
657 | */ | 755 | */ |
658 | static int sort_playlist(bool start_current, bool write) | 756 | static int sort_playlist(struct playlist_info* playlist, bool start_current, |
757 | bool write) | ||
659 | { | 758 | { |
660 | unsigned int current = playlist.indices[playlist.index]; | 759 | unsigned int current = playlist->indices[playlist->index]; |
661 | 760 | ||
662 | if (playlist.amount > 0) | 761 | if (playlist->amount > 0) |
663 | qsort(playlist.indices, playlist.amount, sizeof(playlist.indices[0]), | 762 | qsort(playlist->indices, playlist->amount, sizeof(playlist->indices[0]), |
664 | compare); | 763 | compare); |
665 | 764 | ||
666 | if (start_current) | 765 | if (start_current) |
667 | find_and_set_playlist_index(current); | 766 | find_and_set_playlist_index(playlist, current); |
668 | 767 | ||
669 | /* indices have been moved so last insert position is no longer valid */ | 768 | /* indices have been moved so last insert position is no longer valid */ |
670 | playlist.last_insert_pos = -1; | 769 | playlist->last_insert_pos = -1; |
671 | 770 | ||
672 | if (!playlist.num_inserted_tracks && !playlist.deleted) | 771 | if (!playlist->num_inserted_tracks && !playlist->deleted) |
673 | playlist.shuffle_modified = false; | 772 | playlist->shuffle_modified = false; |
674 | if (write && playlist.control_fd >= 0) | 773 | if (write && playlist->control_fd >= 0) |
675 | { | 774 | { |
676 | /* Don't write to disk immediately. Instead, save in settings and | 775 | /* Don't write to disk immediately. Instead, save in settings and |
677 | only flush if playlist is modified (insertion/deletion) */ | 776 | only flush if playlist is modified (insertion/deletion) */ |
678 | playlist.shuffle_flush = true; | 777 | playlist->shuffle_flush = true; |
679 | global_settings.resume_seed = 0; | 778 | global_settings.resume_seed = 0; |
680 | settings_save(); | 779 | settings_save(); |
681 | } | 780 | } |
@@ -687,26 +786,26 @@ static int sort_playlist(bool start_current, bool write) | |||
687 | * returns the index of the track that is "steps" away from current playing | 786 | * returns the index of the track that is "steps" away from current playing |
688 | * track. | 787 | * track. |
689 | */ | 788 | */ |
690 | static int get_next_index(int steps) | 789 | static int get_next_index(struct playlist_info* playlist, int steps) |
691 | { | 790 | { |
692 | int current_index = playlist.index; | 791 | int current_index = playlist->index; |
693 | int next_index = -1; | 792 | int next_index = -1; |
694 | 793 | ||
695 | if (playlist.amount <= 0) | 794 | if (playlist->amount <= 0) |
696 | return -1; | 795 | return -1; |
697 | 796 | ||
698 | switch (global_settings.repeat_mode) | 797 | switch (global_settings.repeat_mode) |
699 | { | 798 | { |
700 | case REPEAT_OFF: | 799 | case REPEAT_OFF: |
701 | { | 800 | { |
702 | current_index = rotate_index(current_index); | 801 | current_index = rotate_index(playlist, current_index); |
703 | 802 | ||
704 | next_index = current_index+steps; | 803 | next_index = current_index+steps; |
705 | if ((next_index < 0) || (next_index >= playlist.amount)) | 804 | if ((next_index < 0) || (next_index >= playlist->amount)) |
706 | next_index = -1; | 805 | next_index = -1; |
707 | else | 806 | else |
708 | next_index = (next_index+playlist.first_index) % | 807 | next_index = (next_index+playlist->first_index) % |
709 | playlist.amount; | 808 | playlist->amount; |
710 | 809 | ||
711 | break; | 810 | break; |
712 | } | 811 | } |
@@ -718,11 +817,11 @@ static int get_next_index(int steps) | |||
718 | case REPEAT_ALL: | 817 | case REPEAT_ALL: |
719 | default: | 818 | default: |
720 | { | 819 | { |
721 | next_index = (current_index+steps) % playlist.amount; | 820 | next_index = (current_index+steps) % playlist->amount; |
722 | while (next_index < 0) | 821 | while (next_index < 0) |
723 | next_index += playlist.amount; | 822 | next_index += playlist->amount; |
724 | 823 | ||
725 | if (steps >= playlist.amount) | 824 | if (steps >= playlist->amount) |
726 | { | 825 | { |
727 | int i, index; | 826 | int i, index; |
728 | 827 | ||
@@ -730,10 +829,10 @@ static int get_next_index(int steps) | |||
730 | next_index = -1; | 829 | next_index = -1; |
731 | 830 | ||
732 | /* second time around so skip the queued files */ | 831 | /* second time around so skip the queued files */ |
733 | for (i=0; i<playlist.amount; i++) | 832 | for (i=0; i<playlist->amount; i++) |
734 | { | 833 | { |
735 | if (playlist.indices[index] & PLAYLIST_QUEUE_MASK) | 834 | if (playlist->indices[index] & PLAYLIST_QUEUE_MASK) |
736 | index = (index+1) % playlist.amount; | 835 | index = (index+1) % playlist->amount; |
737 | else | 836 | else |
738 | { | 837 | { |
739 | next_index = index; | 838 | next_index = index; |
@@ -752,18 +851,24 @@ static int get_next_index(int steps) | |||
752 | * Search for the seek track and set appropriate indices. Used after shuffle | 851 | * Search for the seek track and set appropriate indices. Used after shuffle |
753 | * to make sure the current index is still pointing to correct track. | 852 | * to make sure the current index is still pointing to correct track. |
754 | */ | 853 | */ |
755 | static void find_and_set_playlist_index(unsigned int seek) | 854 | static void find_and_set_playlist_index(struct playlist_info* playlist, |
855 | unsigned int seek) | ||
756 | { | 856 | { |
757 | int i; | 857 | int i; |
758 | 858 | ||
759 | /* Set the index to the current song */ | 859 | /* Set the index to the current song */ |
760 | for (i=0; i<playlist.amount; i++) | 860 | for (i=0; i<playlist->amount; i++) |
761 | { | 861 | { |
762 | if (playlist.indices[i] == seek) | 862 | if (playlist->indices[i] == seek) |
763 | { | 863 | { |
764 | playlist.index = global_settings.resume_first_index = | 864 | playlist->index = playlist->first_index = i; |
765 | playlist.first_index = i; | 865 | |
766 | settings_save(); | 866 | if (playlist->current) |
867 | { | ||
868 | global_settings.resume_first_index = i; | ||
869 | settings_save(); | ||
870 | } | ||
871 | |||
767 | break; | 872 | break; |
768 | } | 873 | } |
769 | } | 874 | } |
@@ -799,8 +904,8 @@ static int compare(const void* p1, const void* p2) | |||
799 | /* | 904 | /* |
800 | * gets pathname for track at seek index | 905 | * gets pathname for track at seek index |
801 | */ | 906 | */ |
802 | static int get_filename(int seek, bool control_file, char *buf, | 907 | static int get_filename(struct playlist_info* playlist, int seek, |
803 | int buf_length) | 908 | bool control_file, char *buf, int buf_length) |
804 | { | 909 | { |
805 | int fd; | 910 | int fd; |
806 | int max = -1; | 911 | int max = -1; |
@@ -810,34 +915,34 @@ static int get_filename(int seek, bool control_file, char *buf, | |||
810 | if (buf_length > MAX_PATH+1) | 915 | if (buf_length > MAX_PATH+1) |
811 | buf_length = MAX_PATH+1; | 916 | buf_length = MAX_PATH+1; |
812 | 917 | ||
813 | if (playlist.in_ram && !control_file) | 918 | if (playlist->in_ram && !control_file) |
814 | { | 919 | { |
815 | strncpy(tmp_buf, &playlist.buffer[seek], sizeof(tmp_buf)); | 920 | strncpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf)); |
816 | tmp_buf[MAX_PATH] = '\0'; | 921 | tmp_buf[MAX_PATH] = '\0'; |
817 | max = strlen(tmp_buf) + 1; | 922 | max = strlen(tmp_buf) + 1; |
818 | } | 923 | } |
819 | else | 924 | else |
820 | { | 925 | { |
821 | if (control_file) | 926 | if (control_file) |
822 | fd = playlist.control_fd; | 927 | fd = playlist->control_fd; |
823 | else | 928 | else |
824 | { | 929 | { |
825 | if(-1 == playlist.fd) | 930 | if(-1 == playlist->fd) |
826 | playlist.fd = open(playlist.filename, O_RDONLY); | 931 | playlist->fd = open(playlist->filename, O_RDONLY); |
827 | 932 | ||
828 | fd = playlist.fd; | 933 | fd = playlist->fd; |
829 | } | 934 | } |
830 | 935 | ||
831 | if(-1 != fd) | 936 | if(-1 != fd) |
832 | { | 937 | { |
833 | if (control_file) | 938 | if (control_file) |
834 | mutex_lock(&playlist.control_mutex); | 939 | mutex_lock(&playlist->control_mutex); |
835 | 940 | ||
836 | lseek(fd, seek, SEEK_SET); | 941 | lseek(fd, seek, SEEK_SET); |
837 | max = read(fd, tmp_buf, buf_length); | 942 | max = read(fd, tmp_buf, buf_length); |
838 | 943 | ||
839 | if (control_file) | 944 | if (control_file) |
840 | mutex_unlock(&playlist.control_mutex); | 945 | mutex_unlock(&playlist->control_mutex); |
841 | } | 946 | } |
842 | 947 | ||
843 | if (max < 0) | 948 | if (max < 0) |
@@ -852,8 +957,8 @@ static int get_filename(int seek, bool control_file, char *buf, | |||
852 | } | 957 | } |
853 | } | 958 | } |
854 | 959 | ||
855 | strncpy(dir_buf, playlist.filename, playlist.dirlen-1); | 960 | strncpy(dir_buf, playlist->filename, playlist->dirlen-1); |
856 | dir_buf[playlist.dirlen-1] = 0; | 961 | dir_buf[playlist->dirlen-1] = 0; |
857 | 962 | ||
858 | return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf)); | 963 | return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf)); |
859 | } | 964 | } |
@@ -964,29 +1069,29 @@ static void display_buffer_full(void) | |||
964 | * Flush any pending control commands to disk. Called when playlist is being | 1069 | * Flush any pending control commands to disk. Called when playlist is being |
965 | * modified. Returns 0 on success and -1 on failure. | 1070 | * modified. Returns 0 on success and -1 on failure. |
966 | */ | 1071 | */ |
967 | static int flush_pending_control(void) | 1072 | static int flush_pending_control(struct playlist_info* playlist) |
968 | { | 1073 | { |
969 | int result = 0; | 1074 | int result = 0; |
970 | 1075 | ||
971 | if (playlist.shuffle_flush && global_settings.resume_seed >= 0) | 1076 | if (playlist->shuffle_flush && global_settings.resume_seed >= 0) |
972 | { | 1077 | { |
973 | /* pending shuffle */ | 1078 | /* pending shuffle */ |
974 | mutex_lock(&playlist.control_mutex); | 1079 | mutex_lock(&playlist->control_mutex); |
975 | 1080 | ||
976 | if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) | 1081 | if (lseek(playlist->control_fd, 0, SEEK_END) >= 0) |
977 | { | 1082 | { |
978 | if (global_settings.resume_seed == 0) | 1083 | if (global_settings.resume_seed == 0) |
979 | result = fprintf(playlist.control_fd, "U:%d\n", | 1084 | result = fprintf(playlist->control_fd, "U:%d\n", |
980 | playlist.first_index); | 1085 | playlist->first_index); |
981 | else | 1086 | else |
982 | result = fprintf(playlist.control_fd, "S:%d:%d\n", | 1087 | result = fprintf(playlist->control_fd, "S:%d:%d\n", |
983 | global_settings.resume_seed, playlist.first_index); | 1088 | global_settings.resume_seed, playlist->first_index); |
984 | 1089 | ||
985 | if (result > 0) | 1090 | if (result > 0) |
986 | { | 1091 | { |
987 | fsync(playlist.control_fd); | 1092 | fsync(playlist->control_fd); |
988 | 1093 | ||
989 | playlist.shuffle_flush = false; | 1094 | playlist->shuffle_flush = false; |
990 | global_settings.resume_seed = -1; | 1095 | global_settings.resume_seed = -1; |
991 | settings_save(); | 1096 | settings_save(); |
992 | 1097 | ||
@@ -998,7 +1103,7 @@ static int flush_pending_control(void) | |||
998 | else | 1103 | else |
999 | result = -1; | 1104 | result = -1; |
1000 | 1105 | ||
1001 | mutex_unlock(&playlist.control_mutex); | 1106 | mutex_unlock(&playlist->control_mutex); |
1002 | 1107 | ||
1003 | if (result < 0) | 1108 | if (result < 0) |
1004 | { | 1109 | { |
@@ -1013,11 +1118,11 @@ static int flush_pending_control(void) | |||
1013 | /* | 1118 | /* |
1014 | * Rotate indices such that first_index is index 0 | 1119 | * Rotate indices such that first_index is index 0 |
1015 | */ | 1120 | */ |
1016 | static int rotate_index(int index) | 1121 | static int rotate_index(struct playlist_info* playlist, int index) |
1017 | { | 1122 | { |
1018 | index -= playlist.first_index; | 1123 | index -= playlist->first_index; |
1019 | if (index < 0) | 1124 | if (index < 0) |
1020 | index += playlist.amount; | 1125 | index += playlist->amount; |
1021 | 1126 | ||
1022 | return index; | 1127 | return index; |
1023 | } | 1128 | } |
@@ -1027,15 +1132,20 @@ static int rotate_index(int index) | |||
1027 | */ | 1132 | */ |
1028 | void playlist_init(void) | 1133 | void playlist_init(void) |
1029 | { | 1134 | { |
1030 | playlist.fd = -1; | 1135 | struct playlist_info* playlist = ¤t_playlist; |
1031 | playlist.control_fd = -1; | 1136 | |
1032 | playlist.max_playlist_size = global_settings.max_files_in_playlist; | 1137 | playlist->current = true; |
1033 | playlist.indices = buffer_alloc(playlist.max_playlist_size * sizeof(int)); | 1138 | snprintf(playlist->control_filename, sizeof(playlist->control_filename), |
1034 | playlist.buffer_size = | 1139 | "%s", PLAYLIST_CONTROL_FILE); |
1140 | playlist->fd = -1; | ||
1141 | playlist->control_fd = -1; | ||
1142 | playlist->max_playlist_size = global_settings.max_files_in_playlist; | ||
1143 | playlist->indices = buffer_alloc(playlist->max_playlist_size * sizeof(int)); | ||
1144 | playlist->buffer_size = | ||
1035 | AVERAGE_FILENAME_LENGTH * global_settings.max_files_in_dir; | 1145 | AVERAGE_FILENAME_LENGTH * global_settings.max_files_in_dir; |
1036 | playlist.buffer = buffer_alloc(playlist.buffer_size); | 1146 | playlist->buffer = buffer_alloc(playlist->buffer_size); |
1037 | mutex_init(&playlist.control_mutex); | 1147 | mutex_init(&playlist->control_mutex); |
1038 | empty_playlist(true); | 1148 | empty_playlist(playlist, true); |
1039 | } | 1149 | } |
1040 | 1150 | ||
1041 | /* | 1151 | /* |
@@ -1043,36 +1153,13 @@ void playlist_init(void) | |||
1043 | */ | 1153 | */ |
1044 | int playlist_create(char *dir, char *file) | 1154 | int playlist_create(char *dir, char *file) |
1045 | { | 1155 | { |
1046 | empty_playlist(false); | 1156 | struct playlist_info* playlist = ¤t_playlist; |
1047 | |||
1048 | playlist.control_fd = open(PLAYLIST_CONTROL_FILE, O_RDWR); | ||
1049 | if (playlist.control_fd < 0) | ||
1050 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | ||
1051 | |||
1052 | if (!file) | ||
1053 | { | ||
1054 | file = ""; | ||
1055 | 1157 | ||
1056 | if (dir) | 1158 | new_playlist(playlist, dir, file); |
1057 | playlist.in_ram = true; | ||
1058 | else | ||
1059 | dir = ""; /* empty playlist */ | ||
1060 | } | ||
1061 | |||
1062 | update_playlist_filename(dir, file); | ||
1063 | 1159 | ||
1064 | if (playlist.control_fd >= 0) | 1160 | if (file) |
1065 | { | 1161 | /* load the playlist file */ |
1066 | if (fprintf(playlist.control_fd, "P:%d:%s:%s\n", | 1162 | add_indices_to_playlist(playlist, NULL, 0); |
1067 | PLAYLIST_CONTROL_FILE_VERSION, dir, file) > 0) | ||
1068 | fsync(playlist.control_fd); | ||
1069 | else | ||
1070 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
1071 | } | ||
1072 | |||
1073 | /* load the playlist file */ | ||
1074 | if (file[0] != '\0') | ||
1075 | add_indices_to_playlist(); | ||
1076 | 1163 | ||
1077 | return 0; | 1164 | return 0; |
1078 | } | 1165 | } |
@@ -1085,6 +1172,7 @@ int playlist_create(char *dir, char *file) | |||
1085 | */ | 1172 | */ |
1086 | int playlist_resume(void) | 1173 | int playlist_resume(void) |
1087 | { | 1174 | { |
1175 | struct playlist_info* playlist = ¤t_playlist; | ||
1088 | char *buffer; | 1176 | char *buffer; |
1089 | int buflen; | 1177 | int buflen; |
1090 | int nread; | 1178 | int nread; |
@@ -1107,17 +1195,18 @@ int playlist_resume(void) | |||
1107 | buflen = (mp3end - mp3buf); | 1195 | buflen = (mp3end - mp3buf); |
1108 | buffer = mp3buf; | 1196 | buffer = mp3buf; |
1109 | 1197 | ||
1110 | empty_playlist(true); | 1198 | empty_playlist(playlist, true); |
1111 | 1199 | ||
1112 | playlist.control_fd = open(PLAYLIST_CONTROL_FILE, O_RDWR); | 1200 | playlist->control_fd = open(playlist->control_filename, O_RDWR); |
1113 | if (playlist.control_fd < 0) | 1201 | if (playlist->control_fd < 0) |
1114 | { | 1202 | { |
1115 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 1203 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1116 | return -1; | 1204 | return -1; |
1117 | } | 1205 | } |
1206 | playlist->control_created = true; | ||
1118 | 1207 | ||
1119 | /* read a small amount first to get the header */ | 1208 | /* read a small amount first to get the header */ |
1120 | nread = read(playlist.control_fd, buffer, | 1209 | nread = read(playlist->control_fd, buffer, |
1121 | PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); | 1210 | PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); |
1122 | if(nread <= 0) | 1211 | if(nread <= 0) |
1123 | { | 1212 | { |
@@ -1174,18 +1263,18 @@ int playlist_resume(void) | |||
1174 | if (version != PLAYLIST_CONTROL_FILE_VERSION) | 1263 | if (version != PLAYLIST_CONTROL_FILE_VERSION) |
1175 | return -1; | 1264 | return -1; |
1176 | 1265 | ||
1177 | update_playlist_filename(str2, str3); | 1266 | update_playlist_filename(playlist, str2, str3); |
1178 | 1267 | ||
1179 | if (str3[0] != '\0') | 1268 | if (str3[0] != '\0') |
1180 | { | 1269 | { |
1181 | /* NOTE: add_indices_to_playlist() overwrites the | 1270 | /* NOTE: add_indices_to_playlist() overwrites the |
1182 | mp3buf so we need to reload control file | 1271 | mp3buf so we need to reload control file |
1183 | data */ | 1272 | data */ |
1184 | add_indices_to_playlist(); | 1273 | add_indices_to_playlist(playlist, NULL, 0); |
1185 | } | 1274 | } |
1186 | else if (str2[0] != '\0') | 1275 | else if (str2[0] != '\0') |
1187 | { | 1276 | { |
1188 | playlist.in_ram = true; | 1277 | playlist->in_ram = true; |
1189 | resume_directory(str2); | 1278 | resume_directory(str2); |
1190 | } | 1279 | } |
1191 | 1280 | ||
@@ -1216,11 +1305,11 @@ int playlist_resume(void) | |||
1216 | 1305 | ||
1217 | /* seek position is based on str3's position in | 1306 | /* seek position is based on str3's position in |
1218 | buffer */ | 1307 | buffer */ |
1219 | if (add_track_to_playlist(str3, position, queue, | 1308 | if (add_track_to_playlist(playlist, str3, position, |
1220 | total_read+(str3-buffer)) < 0) | 1309 | queue, total_read+(str3-buffer)) < 0) |
1221 | return -1; | 1310 | return -1; |
1222 | 1311 | ||
1223 | playlist.last_insert_pos = last_position; | 1312 | playlist->last_insert_pos = last_position; |
1224 | 1313 | ||
1225 | break; | 1314 | break; |
1226 | } | 1315 | } |
@@ -1238,8 +1327,8 @@ int playlist_resume(void) | |||
1238 | 1327 | ||
1239 | position = atoi(str1); | 1328 | position = atoi(str1); |
1240 | 1329 | ||
1241 | if (remove_track_from_playlist(position, | 1330 | if (remove_track_from_playlist(playlist, position, |
1242 | false) < 0) | 1331 | false) < 0) |
1243 | return -1; | 1332 | return -1; |
1244 | 1333 | ||
1245 | break; | 1334 | break; |
@@ -1259,13 +1348,14 @@ int playlist_resume(void) | |||
1259 | if (!sorted) | 1348 | if (!sorted) |
1260 | { | 1349 | { |
1261 | /* Always sort list before shuffling */ | 1350 | /* Always sort list before shuffling */ |
1262 | sort_playlist(false, false); | 1351 | sort_playlist(playlist, false, false); |
1263 | } | 1352 | } |
1264 | 1353 | ||
1265 | seed = atoi(str1); | 1354 | seed = atoi(str1); |
1266 | playlist.first_index = atoi(str2); | 1355 | playlist->first_index = atoi(str2); |
1267 | 1356 | ||
1268 | if (randomise_playlist(seed, false, false) < 0) | 1357 | if (randomise_playlist(playlist, seed, false, |
1358 | false) < 0) | ||
1269 | return -1; | 1359 | return -1; |
1270 | 1360 | ||
1271 | sorted = false; | 1361 | sorted = false; |
@@ -1281,9 +1371,9 @@ int playlist_resume(void) | |||
1281 | break; | 1371 | break; |
1282 | } | 1372 | } |
1283 | 1373 | ||
1284 | playlist.first_index = atoi(str1); | 1374 | playlist->first_index = atoi(str1); |
1285 | 1375 | ||
1286 | if (sort_playlist(false, false) < 0) | 1376 | if (sort_playlist(playlist, false, false) < 0) |
1287 | return -1; | 1377 | return -1; |
1288 | 1378 | ||
1289 | sorted = true; | 1379 | sorted = true; |
@@ -1291,7 +1381,7 @@ int playlist_resume(void) | |||
1291 | } | 1381 | } |
1292 | case resume_reset: | 1382 | case resume_reset: |
1293 | { | 1383 | { |
1294 | playlist.last_insert_pos = -1; | 1384 | playlist->last_insert_pos = -1; |
1295 | break; | 1385 | break; |
1296 | } | 1386 | } |
1297 | case resume_comment: | 1387 | case resume_comment: |
@@ -1407,17 +1497,17 @@ int playlist_resume(void) | |||
1407 | NOTE: because of this, control file must always end with a | 1497 | NOTE: because of this, control file must always end with a |
1408 | newline */ | 1498 | newline */ |
1409 | count = last_newline; | 1499 | count = last_newline; |
1410 | lseek(playlist.control_fd, total_read+count, SEEK_SET); | 1500 | lseek(playlist->control_fd, total_read+count, SEEK_SET); |
1411 | } | 1501 | } |
1412 | 1502 | ||
1413 | total_read += count; | 1503 | total_read += count; |
1414 | 1504 | ||
1415 | if (first) | 1505 | if (first) |
1416 | /* still looking for header */ | 1506 | /* still looking for header */ |
1417 | nread = read(playlist.control_fd, buffer, | 1507 | nread = read(playlist->control_fd, buffer, |
1418 | PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); | 1508 | PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); |
1419 | else | 1509 | else |
1420 | nread = read(playlist.control_fd, buffer, buflen); | 1510 | nread = read(playlist->control_fd, buffer, buflen); |
1421 | 1511 | ||
1422 | /* Terminate on EOF */ | 1512 | /* Terminate on EOF */ |
1423 | if(nread <= 0) | 1513 | if(nread <= 0) |
@@ -1426,17 +1516,17 @@ int playlist_resume(void) | |||
1426 | { | 1516 | { |
1427 | /* Apply shuffle command saved in settings */ | 1517 | /* Apply shuffle command saved in settings */ |
1428 | if (global_settings.resume_seed == 0) | 1518 | if (global_settings.resume_seed == 0) |
1429 | sort_playlist(false, true); | 1519 | sort_playlist(playlist, false, true); |
1430 | else | 1520 | else |
1431 | { | 1521 | { |
1432 | if (!sorted) | 1522 | if (!sorted) |
1433 | sort_playlist(false, false); | 1523 | sort_playlist(playlist, false, false); |
1434 | 1524 | ||
1435 | randomise_playlist(global_settings.resume_seed, false, | 1525 | randomise_playlist(playlist, global_settings.resume_seed, |
1436 | true); | 1526 | false, true); |
1437 | } | 1527 | } |
1438 | 1528 | ||
1439 | playlist.first_index = global_settings.resume_first_index; | 1529 | playlist->first_index = global_settings.resume_first_index; |
1440 | } | 1530 | } |
1441 | 1531 | ||
1442 | break; | 1532 | break; |
@@ -1451,43 +1541,364 @@ int playlist_resume(void) | |||
1451 | */ | 1541 | */ |
1452 | int playlist_add(char *filename) | 1542 | int playlist_add(char *filename) |
1453 | { | 1543 | { |
1544 | struct playlist_info* playlist = ¤t_playlist; | ||
1454 | int len = strlen(filename); | 1545 | int len = strlen(filename); |
1455 | 1546 | ||
1456 | if((len+1 > playlist.buffer_size - playlist.buffer_end_pos) || | 1547 | if((len+1 > playlist->buffer_size - playlist->buffer_end_pos) || |
1457 | (playlist.amount >= playlist.max_playlist_size)) | 1548 | (playlist->amount >= playlist->max_playlist_size)) |
1458 | { | 1549 | { |
1459 | display_buffer_full(); | 1550 | display_buffer_full(); |
1460 | return -1; | 1551 | return -1; |
1461 | } | 1552 | } |
1462 | 1553 | ||
1463 | playlist.indices[playlist.amount++] = playlist.buffer_end_pos; | 1554 | playlist->indices[playlist->amount++] = playlist->buffer_end_pos; |
1555 | |||
1556 | strcpy(&playlist->buffer[playlist->buffer_end_pos], filename); | ||
1557 | playlist->buffer_end_pos += len; | ||
1558 | playlist->buffer[playlist->buffer_end_pos++] = '\0'; | ||
1559 | |||
1560 | return 0; | ||
1561 | } | ||
1562 | |||
1563 | /* shuffle newly created playlist using random seed. */ | ||
1564 | int playlist_shuffle(int random_seed, int start_index) | ||
1565 | { | ||
1566 | struct playlist_info* playlist = ¤t_playlist; | ||
1567 | |||
1568 | unsigned int seek_pos = 0; | ||
1569 | bool start_current = false; | ||
1570 | |||
1571 | if (start_index >= 0 && global_settings.play_selected) | ||
1572 | { | ||
1573 | /* store the seek position before the shuffle */ | ||
1574 | seek_pos = playlist->indices[start_index]; | ||
1575 | playlist->index = global_settings.resume_first_index = | ||
1576 | playlist->first_index = start_index; | ||
1577 | start_current = true; | ||
1578 | } | ||
1579 | |||
1580 | splash(0, true, str(LANG_PLAYLIST_SHUFFLE)); | ||
1581 | |||
1582 | randomise_playlist(playlist, random_seed, start_current, true); | ||
1583 | |||
1584 | /* Flush shuffle command to disk */ | ||
1585 | flush_pending_control(playlist); | ||
1586 | |||
1587 | return playlist->index; | ||
1588 | } | ||
1589 | |||
1590 | /* start playing current playlist at specified index/offset */ | ||
1591 | int playlist_start(int start_index, int offset) | ||
1592 | { | ||
1593 | struct playlist_info* playlist = ¤t_playlist; | ||
1594 | |||
1595 | playlist->index = start_index; | ||
1596 | mpeg_play(offset); | ||
1597 | |||
1598 | return 0; | ||
1599 | } | ||
1600 | |||
1601 | /* Returns false if 'steps' is out of bounds, else true */ | ||
1602 | bool playlist_check(int steps) | ||
1603 | { | ||
1604 | struct playlist_info* playlist = ¤t_playlist; | ||
1605 | int index = get_next_index(playlist, steps); | ||
1606 | return (index >= 0); | ||
1607 | } | ||
1608 | |||
1609 | /* get trackname of track that is "steps" away from current playing track. | ||
1610 | NULL is used to identify end of playlist */ | ||
1611 | char* playlist_peek(int steps) | ||
1612 | { | ||
1613 | struct playlist_info* playlist = ¤t_playlist; | ||
1614 | int seek; | ||
1615 | int fd; | ||
1616 | char *temp_ptr; | ||
1617 | int index; | ||
1618 | bool control_file; | ||
1619 | |||
1620 | index = get_next_index(playlist, steps); | ||
1621 | if (index < 0) | ||
1622 | return NULL; | ||
1623 | |||
1624 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; | ||
1625 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; | ||
1626 | |||
1627 | if (get_filename(playlist, seek, control_file, now_playing, | ||
1628 | MAX_PATH+1) < 0) | ||
1629 | return NULL; | ||
1630 | |||
1631 | temp_ptr = now_playing; | ||
1632 | |||
1633 | if (!playlist->in_ram || control_file) | ||
1634 | { | ||
1635 | /* remove bogus dirs from beginning of path | ||
1636 | (workaround for buggy playlist creation tools) */ | ||
1637 | while (temp_ptr) | ||
1638 | { | ||
1639 | fd = open(temp_ptr, O_RDONLY); | ||
1640 | if (fd >= 0) | ||
1641 | { | ||
1642 | close(fd); | ||
1643 | break; | ||
1644 | } | ||
1645 | |||
1646 | temp_ptr = strchr(temp_ptr+1, '/'); | ||
1647 | } | ||
1648 | |||
1649 | if (!temp_ptr) | ||
1650 | { | ||
1651 | /* Even though this is an invalid file, we still need to pass a | ||
1652 | file name to the caller because NULL is used to indicate end | ||
1653 | of playlist */ | ||
1654 | return now_playing; | ||
1655 | } | ||
1656 | } | ||
1657 | |||
1658 | return temp_ptr; | ||
1659 | } | ||
1660 | |||
1661 | /* | ||
1662 | * Update indices as track has changed | ||
1663 | */ | ||
1664 | int playlist_next(int steps) | ||
1665 | { | ||
1666 | struct playlist_info* playlist = ¤t_playlist; | ||
1667 | int index; | ||
1668 | |||
1669 | if (steps > 0 && global_settings.repeat_mode != REPEAT_ONE) | ||
1670 | { | ||
1671 | int i, j; | ||
1672 | |||
1673 | /* We need to delete all the queued songs */ | ||
1674 | for (i=0, j=steps; i<j; i++) | ||
1675 | { | ||
1676 | index = get_next_index(playlist, i); | ||
1677 | |||
1678 | if (playlist->indices[index] & PLAYLIST_QUEUE_MASK) | ||
1679 | { | ||
1680 | remove_track_from_playlist(playlist, index, true); | ||
1681 | steps--; /* one less track */ | ||
1682 | } | ||
1683 | } | ||
1684 | } | ||
1685 | |||
1686 | index = get_next_index(playlist, steps); | ||
1687 | playlist->index = index; | ||
1688 | |||
1689 | if (playlist->last_insert_pos >= 0 && steps > 0) | ||
1690 | { | ||
1691 | /* check to see if we've gone beyond the last inserted track */ | ||
1692 | int cur = rotate_index(playlist, index); | ||
1693 | int last_pos = rotate_index(playlist, playlist->last_insert_pos); | ||
1694 | |||
1695 | if (cur > last_pos) | ||
1696 | { | ||
1697 | /* reset last inserted track */ | ||
1698 | playlist->last_insert_pos = -1; | ||
1699 | |||
1700 | if (playlist->control_fd >= 0) | ||
1701 | { | ||
1702 | int result = -1; | ||
1703 | |||
1704 | mutex_lock(&playlist->control_mutex); | ||
1705 | |||
1706 | if (lseek(playlist->control_fd, 0, SEEK_END) >= 0) | ||
1707 | { | ||
1708 | if (fprintf(playlist->control_fd, "R\n") > 0) | ||
1709 | { | ||
1710 | fsync(playlist->control_fd); | ||
1711 | result = 0; | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | mutex_unlock(&playlist->control_mutex); | ||
1716 | |||
1717 | if (result < 0) | ||
1718 | { | ||
1719 | splash(HZ*2, true, | ||
1720 | str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
1721 | return result; | ||
1722 | } | ||
1723 | } | ||
1724 | } | ||
1725 | } | ||
1726 | |||
1727 | return index; | ||
1728 | } | ||
1729 | |||
1730 | /* Get resume info for current playing song. If return value is -1 then | ||
1731 | settings shouldn't be saved. */ | ||
1732 | int playlist_get_resume_info(int *resume_index) | ||
1733 | { | ||
1734 | struct playlist_info* playlist = ¤t_playlist; | ||
1735 | |||
1736 | *resume_index = playlist->index; | ||
1737 | |||
1738 | return 0; | ||
1739 | } | ||
1740 | |||
1741 | /* Returns index of current playing track for display purposes. This value | ||
1742 | should not be used for resume purposes as it doesn't represent the actual | ||
1743 | index into the playlist */ | ||
1744 | int playlist_get_display_index(void) | ||
1745 | { | ||
1746 | struct playlist_info* playlist = ¤t_playlist; | ||
1747 | |||
1748 | /* first_index should always be index 0 for display purposes */ | ||
1749 | int index = rotate_index(playlist, playlist->index); | ||
1750 | |||
1751 | return (index+1); | ||
1752 | } | ||
1753 | |||
1754 | /* returns number of tracks in current playlist */ | ||
1755 | int playlist_amount(void) | ||
1756 | { | ||
1757 | return playlist_amount_ex(NULL); | ||
1758 | } | ||
1759 | |||
1760 | /* | ||
1761 | * Create a new playlist If playlist is not NULL then we're loading a | ||
1762 | * playlist off disk for viewing/editing. The index_buffer is used to store | ||
1763 | * playlist indices (required for and only used if !current playlist). The | ||
1764 | * temp_buffer (if not NULL) is used as a scratchpad when loading indices. | ||
1765 | */ | ||
1766 | int playlist_create_ex(struct playlist_info* playlist, char* dir, char* file, | ||
1767 | void* index_buffer, int index_buffer_size, | ||
1768 | void* temp_buffer, int temp_buffer_size) | ||
1769 | { | ||
1770 | if (!playlist) | ||
1771 | playlist = ¤t_playlist; | ||
1772 | else | ||
1773 | { | ||
1774 | /* Initialize playlist structure */ | ||
1775 | int r = rand() % 10; | ||
1776 | playlist->current = false; | ||
1777 | |||
1778 | /* Use random name for control file */ | ||
1779 | snprintf(playlist->control_filename, sizeof(playlist->control_filename), | ||
1780 | "%s.%d", PLAYLIST_CONTROL_FILE, r); | ||
1781 | playlist->fd = -1; | ||
1782 | playlist->control_fd = -1; | ||
1783 | |||
1784 | if (index_buffer) | ||
1785 | { | ||
1786 | int num_indices = index_buffer_size / sizeof(int); | ||
1787 | |||
1788 | if (num_indices > global_settings.max_files_in_playlist) | ||
1789 | num_indices = global_settings.max_files_in_playlist; | ||
1790 | |||
1791 | playlist->max_playlist_size = num_indices; | ||
1792 | playlist->indices = index_buffer; | ||
1793 | } | ||
1794 | else | ||
1795 | { | ||
1796 | playlist->max_playlist_size = current_playlist.max_playlist_size; | ||
1797 | playlist->indices = current_playlist.indices; | ||
1798 | } | ||
1799 | |||
1800 | playlist->buffer_size = 0; | ||
1801 | playlist->buffer = NULL; | ||
1802 | mutex_init(&playlist->control_mutex); | ||
1803 | } | ||
1804 | |||
1805 | new_playlist(playlist, dir, file); | ||
1464 | 1806 | ||
1465 | strcpy(&playlist.buffer[playlist.buffer_end_pos], filename); | 1807 | if (file) |
1466 | playlist.buffer_end_pos += len; | 1808 | /* load the playlist file */ |
1467 | playlist.buffer[playlist.buffer_end_pos++] = '\0'; | 1809 | add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size); |
1468 | 1810 | ||
1469 | return 0; | 1811 | return 0; |
1470 | } | 1812 | } |
1471 | 1813 | ||
1472 | /* | 1814 | /* |
1815 | * Set the specified playlist as the current. | ||
1816 | * NOTE: You will get undefined behaviour if something is already playing so | ||
1817 | * remember to stop before calling this. Also, this call will | ||
1818 | * effectively close your playlist, making it unusable. | ||
1819 | */ | ||
1820 | int playlist_set_current(struct playlist_info* playlist) | ||
1821 | { | ||
1822 | if (!playlist || (check_control(playlist) < 0)) | ||
1823 | return -1; | ||
1824 | |||
1825 | empty_playlist(¤t_playlist, false); | ||
1826 | |||
1827 | strncpy(current_playlist.filename, playlist->filename, | ||
1828 | sizeof(current_playlist.filename)); | ||
1829 | |||
1830 | current_playlist.fd = playlist->fd; | ||
1831 | |||
1832 | close(playlist->control_fd); | ||
1833 | remove(current_playlist.control_filename); | ||
1834 | if (rename(playlist->control_filename, | ||
1835 | current_playlist.control_filename) < 0) | ||
1836 | return -1; | ||
1837 | current_playlist.control_fd = open(current_playlist.control_filename, | ||
1838 | O_RDWR); | ||
1839 | if (current_playlist.control_fd < 0) | ||
1840 | return -1; | ||
1841 | current_playlist.control_created = true; | ||
1842 | |||
1843 | current_playlist.dirlen = playlist->dirlen; | ||
1844 | |||
1845 | if (playlist->indices && playlist->indices != current_playlist.indices) | ||
1846 | memcpy(current_playlist.indices, playlist->indices, | ||
1847 | playlist->max_playlist_size*sizeof(int)); | ||
1848 | |||
1849 | current_playlist.first_index = playlist->first_index; | ||
1850 | current_playlist.amount = playlist->amount; | ||
1851 | current_playlist.last_insert_pos = playlist->last_insert_pos; | ||
1852 | current_playlist.seed = playlist->seed; | ||
1853 | current_playlist.shuffle_modified = playlist->shuffle_modified; | ||
1854 | current_playlist.deleted = playlist->deleted; | ||
1855 | current_playlist.num_inserted_tracks = playlist->num_inserted_tracks; | ||
1856 | current_playlist.shuffle_flush = playlist->shuffle_flush; | ||
1857 | |||
1858 | return 0; | ||
1859 | } | ||
1860 | |||
1861 | /* | ||
1862 | * Close files and delete control file for non-current playlist. | ||
1863 | */ | ||
1864 | void playlist_close(struct playlist_info* playlist) | ||
1865 | { | ||
1866 | if (!playlist) | ||
1867 | return; | ||
1868 | |||
1869 | if (playlist->fd >= 0) | ||
1870 | close(playlist->fd); | ||
1871 | |||
1872 | if (playlist->control_fd >= 0) | ||
1873 | close(playlist->control_fd); | ||
1874 | |||
1875 | if (playlist->control_created) | ||
1876 | remove(playlist->control_filename); | ||
1877 | } | ||
1878 | |||
1879 | /* | ||
1473 | * Insert track into playlist at specified position (or one of the special | 1880 | * Insert track into playlist at specified position (or one of the special |
1474 | * positions). Returns position where track was inserted or -1 if error. | 1881 | * positions). Returns position where track was inserted or -1 if error. |
1475 | */ | 1882 | */ |
1476 | int playlist_insert_track(char *filename, int position, bool queue) | 1883 | int playlist_insert_track(struct playlist_info* playlist, char *filename, |
1884 | int position, bool queue) | ||
1477 | { | 1885 | { |
1478 | int result; | 1886 | int result; |
1479 | 1887 | ||
1480 | if (playlist.control_fd < 0) | 1888 | if (!playlist) |
1889 | playlist = ¤t_playlist; | ||
1890 | |||
1891 | if (check_control(playlist) < 0) | ||
1481 | { | 1892 | { |
1482 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 1893 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1483 | return -1; | 1894 | return -1; |
1484 | } | 1895 | } |
1485 | 1896 | ||
1486 | result = add_track_to_playlist(filename, position, queue, -1); | 1897 | result = add_track_to_playlist(playlist, filename, position, queue, -1); |
1487 | 1898 | ||
1488 | if (result != -1) | 1899 | if (result != -1) |
1489 | { | 1900 | { |
1490 | fsync(playlist.control_fd); | 1901 | fsync(playlist->control_fd); |
1491 | mpeg_flush_and_reload_tracks(); | 1902 | mpeg_flush_and_reload_tracks(); |
1492 | } | 1903 | } |
1493 | 1904 | ||
@@ -1497,14 +1908,17 @@ int playlist_insert_track(char *filename, int position, bool queue) | |||
1497 | /* | 1908 | /* |
1498 | * Insert all tracks from specified directory into playlist. | 1909 | * Insert all tracks from specified directory into playlist. |
1499 | */ | 1910 | */ |
1500 | int playlist_insert_directory(char *dirname, int position, bool queue, | 1911 | int playlist_insert_directory(struct playlist_info* playlist, char *dirname, |
1501 | bool recurse) | 1912 | int position, bool queue, bool recurse) |
1502 | { | 1913 | { |
1503 | int count = 0; | 1914 | int count = 0; |
1504 | int result; | 1915 | int result; |
1505 | char *count_str; | 1916 | char *count_str; |
1506 | 1917 | ||
1507 | if (playlist.control_fd < 0) | 1918 | if (!playlist) |
1919 | playlist = ¤t_playlist; | ||
1920 | |||
1921 | if (check_control(playlist) < 0) | ||
1508 | { | 1922 | { |
1509 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 1923 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1510 | return -1; | 1924 | return -1; |
@@ -1517,9 +1931,9 @@ int playlist_insert_directory(char *dirname, int position, bool queue, | |||
1517 | 1931 | ||
1518 | display_playlist_count(count, count_str); | 1932 | display_playlist_count(count, count_str); |
1519 | 1933 | ||
1520 | result = add_directory_to_playlist(dirname, &position, queue, &count, | 1934 | result = add_directory_to_playlist(playlist, dirname, &position, queue, |
1521 | recurse); | 1935 | &count, recurse); |
1522 | fsync(playlist.control_fd); | 1936 | fsync(playlist->control_fd); |
1523 | 1937 | ||
1524 | display_playlist_count(count, count_str); | 1938 | display_playlist_count(count, count_str); |
1525 | mpeg_flush_and_reload_tracks(); | 1939 | mpeg_flush_and_reload_tracks(); |
@@ -1528,9 +1942,10 @@ int playlist_insert_directory(char *dirname, int position, bool queue, | |||
1528 | } | 1942 | } |
1529 | 1943 | ||
1530 | /* | 1944 | /* |
1531 | * Insert all tracks from specified playlist into dynamic playlist | 1945 | * Insert all tracks from specified playlist into dynamic playlist. |
1532 | */ | 1946 | */ |
1533 | int playlist_insert_playlist(char *filename, int position, bool queue) | 1947 | int playlist_insert_playlist(struct playlist_info* playlist, char *filename, |
1948 | int position, bool queue) | ||
1534 | { | 1949 | { |
1535 | int fd; | 1950 | int fd; |
1536 | int max; | 1951 | int max; |
@@ -1542,7 +1957,10 @@ int playlist_insert_playlist(char *filename, int position, bool queue) | |||
1542 | int count = 0; | 1957 | int count = 0; |
1543 | int result = 0; | 1958 | int result = 0; |
1544 | 1959 | ||
1545 | if (playlist.control_fd < 0) | 1960 | if (!playlist) |
1961 | playlist = ¤t_playlist; | ||
1962 | |||
1963 | if (check_control(playlist) < 0) | ||
1546 | { | 1964 | { |
1547 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 1965 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1548 | return -1; | 1966 | return -1; |
@@ -1594,8 +2012,8 @@ int playlist_insert_playlist(char *filename, int position, bool queue) | |||
1594 | break; | 2012 | break; |
1595 | } | 2013 | } |
1596 | 2014 | ||
1597 | insert_pos = add_track_to_playlist(trackname, position, queue, | 2015 | insert_pos = add_track_to_playlist(playlist, trackname, position, |
1598 | -1); | 2016 | queue, -1); |
1599 | 2017 | ||
1600 | if (insert_pos < 0) | 2018 | if (insert_pos < 0) |
1601 | { | 2019 | { |
@@ -1624,9 +2042,10 @@ int playlist_insert_playlist(char *filename, int position, bool queue) | |||
1624 | } | 2042 | } |
1625 | 2043 | ||
1626 | close(fd); | 2044 | close(fd); |
1627 | fsync(playlist.control_fd); | 2045 | fsync(playlist->control_fd); |
1628 | 2046 | ||
1629 | *temp_ptr = '/'; | 2047 | if (temp_ptr) |
2048 | *temp_ptr = '/'; | ||
1630 | 2049 | ||
1631 | display_playlist_count(count, count_str); | 2050 | display_playlist_count(count, count_str); |
1632 | mpeg_flush_and_reload_tracks(); | 2051 | mpeg_flush_and_reload_tracks(); |
@@ -1638,20 +2057,23 @@ int playlist_insert_playlist(char *filename, int position, bool queue) | |||
1638 | * Delete track at specified index. If index is PLAYLIST_DELETE_CURRENT then | 2057 | * Delete track at specified index. If index is PLAYLIST_DELETE_CURRENT then |
1639 | * we want to delete the current playing track. | 2058 | * we want to delete the current playing track. |
1640 | */ | 2059 | */ |
1641 | int playlist_delete(int index) | 2060 | int playlist_delete(struct playlist_info* playlist, int index) |
1642 | { | 2061 | { |
1643 | int result = 0; | 2062 | int result = 0; |
1644 | 2063 | ||
1645 | if (playlist.control_fd < 0) | 2064 | if (!playlist) |
2065 | playlist = ¤t_playlist; | ||
2066 | |||
2067 | if (check_control(playlist) < 0) | ||
1646 | { | 2068 | { |
1647 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 2069 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1648 | return -1; | 2070 | return -1; |
1649 | } | 2071 | } |
1650 | 2072 | ||
1651 | if (index == PLAYLIST_DELETE_CURRENT) | 2073 | if (index == PLAYLIST_DELETE_CURRENT) |
1652 | index = playlist.index; | 2074 | index = playlist->index; |
1653 | 2075 | ||
1654 | result = remove_track_from_playlist(index, true); | 2076 | result = remove_track_from_playlist(playlist, index, true); |
1655 | 2077 | ||
1656 | if (result != -1) | 2078 | if (result != -1) |
1657 | mpeg_flush_and_reload_tracks(); | 2079 | mpeg_flush_and_reload_tracks(); |
@@ -1663,49 +2085,62 @@ int playlist_delete(int index) | |||
1663 | * Move track at index to new_index. Tracks between the two are shifted | 2085 | * Move track at index to new_index. Tracks between the two are shifted |
1664 | * appropriately. Returns 0 on success and -1 on failure. | 2086 | * appropriately. Returns 0 on success and -1 on failure. |
1665 | */ | 2087 | */ |
1666 | int playlist_move(int index, int new_index) | 2088 | int playlist_move(struct playlist_info* playlist, int index, int new_index) |
1667 | { | 2089 | { |
1668 | int result; | 2090 | int result; |
1669 | int seek; | 2091 | int seek; |
1670 | bool control_file; | 2092 | bool control_file; |
1671 | bool queue; | 2093 | bool queue; |
1672 | bool current = false; | 2094 | bool current = false; |
1673 | int r = rotate_index(new_index); | 2095 | int r; |
1674 | char filename[MAX_PATH]; | 2096 | char filename[MAX_PATH]; |
1675 | 2097 | ||
2098 | if (!playlist) | ||
2099 | playlist = ¤t_playlist; | ||
2100 | |||
2101 | if (check_control(playlist) < 0) | ||
2102 | { | ||
2103 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | ||
2104 | return -1; | ||
2105 | } | ||
2106 | |||
1676 | if (index == new_index) | 2107 | if (index == new_index) |
1677 | return -1; | 2108 | return -1; |
1678 | 2109 | ||
1679 | if (index == playlist.index) | 2110 | if (index == playlist->index) |
1680 | /* Moving the current track */ | 2111 | /* Moving the current track */ |
1681 | current = true; | 2112 | current = true; |
1682 | 2113 | ||
1683 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2114 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
1684 | queue = playlist.indices[index] & PLAYLIST_QUEUE_MASK; | 2115 | queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; |
1685 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | 2116 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
1686 | 2117 | ||
1687 | if (get_filename(seek, control_file, filename, sizeof(filename)) < 0) | 2118 | if (get_filename(playlist, seek, control_file, filename, |
2119 | sizeof(filename)) < 0) | ||
1688 | return -1; | 2120 | return -1; |
1689 | 2121 | ||
1690 | /* Delete track from original position */ | 2122 | /* Delete track from original position */ |
1691 | result = remove_track_from_playlist(index, true); | 2123 | result = remove_track_from_playlist(playlist, index, true); |
1692 | 2124 | ||
1693 | if (result != -1) | 2125 | if (result != -1) |
1694 | { | 2126 | { |
1695 | /* We want to insert the track at the position that was specified by | 2127 | /* We want to insert the track at the position that was specified by |
1696 | new_index. This may be different then new_index because of the | 2128 | new_index. This may be different then new_index because of the |
1697 | shifting that occurred after the delete */ | 2129 | shifting that occurred after the delete */ |
2130 | r = rotate_index(playlist, new_index); | ||
2131 | |||
1698 | if (r == 0) | 2132 | if (r == 0) |
1699 | /* First index */ | 2133 | /* First index */ |
1700 | new_index = PLAYLIST_PREPEND; | 2134 | new_index = PLAYLIST_PREPEND; |
1701 | else if (r == playlist.amount) | 2135 | else if (r == playlist->amount) |
1702 | /* Append */ | 2136 | /* Append */ |
1703 | new_index = PLAYLIST_INSERT_LAST; | 2137 | new_index = PLAYLIST_INSERT_LAST; |
1704 | else | 2138 | else |
1705 | /* Calculate index of desired position */ | 2139 | /* Calculate index of desired position */ |
1706 | new_index = (r+playlist.first_index)%playlist.amount; | 2140 | new_index = (r+playlist->first_index)%playlist->amount; |
1707 | 2141 | ||
1708 | result = add_track_to_playlist(filename, new_index, queue, -1); | 2142 | result = add_track_to_playlist(playlist, filename, new_index, queue, |
2143 | -1); | ||
1709 | 2144 | ||
1710 | if (result != -1) | 2145 | if (result != -1) |
1711 | { | 2146 | { |
@@ -1715,20 +2150,20 @@ int playlist_move(int index, int new_index) | |||
1715 | switch (new_index) | 2150 | switch (new_index) |
1716 | { | 2151 | { |
1717 | case PLAYLIST_PREPEND: | 2152 | case PLAYLIST_PREPEND: |
1718 | playlist.index = playlist.first_index; | 2153 | playlist->index = playlist->first_index; |
1719 | break; | 2154 | break; |
1720 | case PLAYLIST_INSERT_LAST: | 2155 | case PLAYLIST_INSERT_LAST: |
1721 | playlist.index = playlist.first_index - 1; | 2156 | playlist->index = playlist->first_index - 1; |
1722 | if (playlist.index < 0) | 2157 | if (playlist->index < 0) |
1723 | playlist.index += playlist.amount; | 2158 | playlist->index += playlist->amount; |
1724 | break; | 2159 | break; |
1725 | default: | 2160 | default: |
1726 | playlist.index = new_index; | 2161 | playlist->index = new_index; |
1727 | break; | 2162 | break; |
1728 | } | 2163 | } |
1729 | } | 2164 | } |
1730 | 2165 | ||
1731 | fsync(playlist.control_fd); | 2166 | fsync(playlist->control_fd); |
1732 | mpeg_flush_and_reload_tracks(); | 2167 | mpeg_flush_and_reload_tracks(); |
1733 | } | 2168 | } |
1734 | } | 2169 | } |
@@ -1736,46 +2171,18 @@ int playlist_move(int index, int new_index) | |||
1736 | return result; | 2171 | return result; |
1737 | } | 2172 | } |
1738 | 2173 | ||
1739 | /* shuffle newly created playlist using random seed. */ | ||
1740 | int playlist_shuffle(int random_seed, int start_index) | ||
1741 | { | ||
1742 | unsigned int seek_pos = 0; | ||
1743 | bool start_current = false; | ||
1744 | |||
1745 | if (start_index >= 0 && global_settings.play_selected) | ||
1746 | { | ||
1747 | /* store the seek position before the shuffle */ | ||
1748 | seek_pos = playlist.indices[start_index]; | ||
1749 | playlist.index = global_settings.resume_first_index = | ||
1750 | playlist.first_index = start_index; | ||
1751 | start_current = true; | ||
1752 | } | ||
1753 | |||
1754 | splash(0, true, str(LANG_PLAYLIST_SHUFFLE)); | ||
1755 | |||
1756 | randomise_playlist(random_seed, start_current, true); | ||
1757 | |||
1758 | /* Flush shuffle command to disk */ | ||
1759 | flush_pending_control(); | ||
1760 | |||
1761 | return playlist.index; | ||
1762 | } | ||
1763 | |||
1764 | /* shuffle currently playing playlist */ | 2174 | /* shuffle currently playing playlist */ |
1765 | int playlist_randomise(unsigned int seed, bool start_current) | 2175 | int playlist_randomise(struct playlist_info* playlist, unsigned int seed, |
2176 | bool start_current) | ||
1766 | { | 2177 | { |
1767 | int result = randomise_playlist(seed, start_current, true); | 2178 | int result; |
1768 | 2179 | ||
1769 | if (result != -1) | 2180 | if (!playlist) |
1770 | mpeg_flush_and_reload_tracks(); | 2181 | playlist = ¤t_playlist; |
1771 | 2182 | ||
1772 | return result; | 2183 | check_control(playlist); |
1773 | } | ||
1774 | 2184 | ||
1775 | /* sort currently playing playlist */ | 2185 | result = randomise_playlist(playlist, seed, start_current, true); |
1776 | int playlist_sort(bool start_current) | ||
1777 | { | ||
1778 | int result = sort_playlist(start_current, true); | ||
1779 | 2186 | ||
1780 | if (result != -1) | 2187 | if (result != -1) |
1781 | mpeg_flush_and_reload_tracks(); | 2188 | mpeg_flush_and_reload_tracks(); |
@@ -1783,231 +2190,119 @@ int playlist_sort(bool start_current) | |||
1783 | return result; | 2190 | return result; |
1784 | } | 2191 | } |
1785 | 2192 | ||
1786 | /* start playing current playlist at specified index/offset */ | 2193 | /* sort currently playing playlist */ |
1787 | int playlist_start(int start_index, int offset) | 2194 | int playlist_sort(struct playlist_info* playlist, bool start_current) |
1788 | { | ||
1789 | playlist.index = start_index; | ||
1790 | mpeg_play(offset); | ||
1791 | |||
1792 | return 0; | ||
1793 | } | ||
1794 | |||
1795 | /* Returns false if 'steps' is out of bounds, else true */ | ||
1796 | bool playlist_check(int steps) | ||
1797 | { | ||
1798 | int index = get_next_index(steps); | ||
1799 | return (index >= 0); | ||
1800 | } | ||
1801 | |||
1802 | /* get trackname of track that is "steps" away from current playing track. | ||
1803 | NULL is used to identify end of playlist */ | ||
1804 | char* playlist_peek(int steps) | ||
1805 | { | 2195 | { |
1806 | int seek; | 2196 | int result; |
1807 | int fd; | ||
1808 | char *temp_ptr; | ||
1809 | int index; | ||
1810 | bool control_file; | ||
1811 | 2197 | ||
1812 | index = get_next_index(steps); | 2198 | if (!playlist) |
1813 | if (index < 0) | 2199 | playlist = ¤t_playlist; |
1814 | return NULL; | ||
1815 | 2200 | ||
1816 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2201 | check_control(playlist); |
1817 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | ||
1818 | 2202 | ||
1819 | if (get_filename(seek, control_file, now_playing, MAX_PATH+1) < 0) | 2203 | result = sort_playlist(playlist, start_current, true); |
1820 | return NULL; | ||
1821 | 2204 | ||
1822 | temp_ptr = now_playing; | 2205 | if (result != -1) |
1823 | 2206 | mpeg_flush_and_reload_tracks(); | |
1824 | if (!playlist.in_ram || control_file) | ||
1825 | { | ||
1826 | /* remove bogus dirs from beginning of path | ||
1827 | (workaround for buggy playlist creation tools) */ | ||
1828 | while (temp_ptr) | ||
1829 | { | ||
1830 | fd = open(temp_ptr, O_RDONLY); | ||
1831 | if (fd >= 0) | ||
1832 | { | ||
1833 | close(fd); | ||
1834 | break; | ||
1835 | } | ||
1836 | |||
1837 | temp_ptr = strchr(temp_ptr+1, '/'); | ||
1838 | } | ||
1839 | |||
1840 | if (!temp_ptr) | ||
1841 | { | ||
1842 | /* Even though this is an invalid file, we still need to pass a | ||
1843 | file name to the caller because NULL is used to indicate end | ||
1844 | of playlist */ | ||
1845 | return now_playing; | ||
1846 | } | ||
1847 | } | ||
1848 | 2207 | ||
1849 | return temp_ptr; | 2208 | return result; |
1850 | } | 2209 | } |
1851 | 2210 | ||
1852 | /* | 2211 | /* returns true if playlist has been modified */ |
1853 | * Update indices as track has changed | 2212 | bool playlist_modified(struct playlist_info* playlist) |
1854 | */ | ||
1855 | int playlist_next(int steps) | ||
1856 | { | 2213 | { |
1857 | int index; | 2214 | if (!playlist) |
1858 | 2215 | playlist = ¤t_playlist; | |
1859 | if (steps > 0 && global_settings.repeat_mode != REPEAT_ONE) | ||
1860 | { | ||
1861 | int i, j; | ||
1862 | |||
1863 | /* We need to delete all the queued songs */ | ||
1864 | for (i=0, j=steps; i<j; i++) | ||
1865 | { | ||
1866 | index = get_next_index(i); | ||
1867 | |||
1868 | if (playlist.indices[index] & PLAYLIST_QUEUE_MASK) | ||
1869 | { | ||
1870 | remove_track_from_playlist(index, true); | ||
1871 | steps--; /* one less track */ | ||
1872 | } | ||
1873 | } | ||
1874 | } | ||
1875 | 2216 | ||
1876 | index = get_next_index(steps); | 2217 | if (playlist->shuffle_modified || |
1877 | playlist.index = index; | 2218 | playlist->deleted || |
2219 | playlist->num_inserted_tracks > 0) | ||
2220 | return true; | ||
1878 | 2221 | ||
1879 | if (playlist.last_insert_pos >= 0 && steps > 0) | ||
1880 | { | ||
1881 | /* check to see if we've gone beyond the last inserted track */ | ||
1882 | int cur = rotate_index(index); | ||
1883 | int last_pos = rotate_index(playlist.last_insert_pos); | ||
1884 | |||
1885 | if (cur > last_pos) | ||
1886 | { | ||
1887 | /* reset last inserted track */ | ||
1888 | playlist.last_insert_pos = -1; | ||
1889 | |||
1890 | if (playlist.control_fd >= 0) | ||
1891 | { | ||
1892 | int result = -1; | ||
1893 | |||
1894 | mutex_lock(&playlist.control_mutex); | ||
1895 | |||
1896 | if (lseek(playlist.control_fd, 0, SEEK_END) >= 0) | ||
1897 | { | ||
1898 | if (fprintf(playlist.control_fd, "R\n") > 0) | ||
1899 | { | ||
1900 | fsync(playlist.control_fd); | ||
1901 | result = 0; | ||
1902 | } | ||
1903 | } | ||
1904 | |||
1905 | mutex_unlock(&playlist.control_mutex); | ||
1906 | |||
1907 | if (result < 0) | ||
1908 | { | ||
1909 | splash(HZ*2, true, | ||
1910 | str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); | ||
1911 | return result; | ||
1912 | } | ||
1913 | } | ||
1914 | } | ||
1915 | } | ||
1916 | |||
1917 | return index; | ||
1918 | } | ||
1919 | |||
1920 | bool playlist_modified(void) | ||
1921 | { | ||
1922 | if ((mpeg_status() & MPEG_STATUS_PLAY)) | ||
1923 | { | ||
1924 | if (playlist.shuffle_modified || | ||
1925 | playlist.deleted || | ||
1926 | playlist.num_inserted_tracks > 0) | ||
1927 | return true; | ||
1928 | } | ||
1929 | return false; | 2222 | return false; |
1930 | } | 2223 | } |
1931 | 2224 | ||
1932 | int playlist_get_seed(void) | 2225 | /* returns index of first track in playlist */ |
2226 | int playlist_get_first_index(struct playlist_info* playlist) | ||
1933 | { | 2227 | { |
1934 | return playlist.seed; | 2228 | if (!playlist) |
2229 | playlist = ¤t_playlist; | ||
2230 | |||
2231 | return playlist->first_index; | ||
1935 | } | 2232 | } |
1936 | 2233 | ||
1937 | /* Get resume info for current playing song. If return value is -1 then | 2234 | /* returns shuffle seed of playlist */ |
1938 | settings shouldn't be saved. */ | 2235 | int playlist_get_seed(struct playlist_info* playlist) |
1939 | int playlist_get_resume_info(int *resume_index) | ||
1940 | { | 2236 | { |
1941 | *resume_index = playlist.index; | 2237 | if (!playlist) |
2238 | playlist = ¤t_playlist; | ||
1942 | 2239 | ||
1943 | return 0; | 2240 | return playlist->seed; |
1944 | } | 2241 | } |
1945 | 2242 | ||
1946 | /* Returns index of current playing track for display purposes. This value | 2243 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ |
1947 | should not be used for resume purposes as it doesn't represent the actual | 2244 | int playlist_amount_ex(struct playlist_info* playlist) |
1948 | index into the playlist */ | ||
1949 | int playlist_get_display_index(void) | ||
1950 | { | 2245 | { |
1951 | /* first_index should always be index 0 for display purposes */ | 2246 | if (!playlist) |
1952 | int index = rotate_index(playlist.index); | 2247 | playlist = ¤t_playlist; |
1953 | 2248 | ||
1954 | return (index+1); | 2249 | return playlist->amount; |
1955 | } | 2250 | } |
1956 | 2251 | ||
1957 | /* returns index of first track in playlist */ | 2252 | /* returns full path of playlist (minus extension) */ |
1958 | int playlist_get_first_index(void) | 2253 | char *playlist_name(struct playlist_info* playlist, char *buf, int buf_size) |
1959 | { | 2254 | { |
1960 | return playlist.first_index; | 2255 | char *sep; |
1961 | } | ||
1962 | 2256 | ||
1963 | char *playlist_get_name(char *buf, int buf_size) | 2257 | if (!playlist) |
1964 | { | 2258 | playlist = ¤t_playlist; |
1965 | snprintf(buf, buf_size, "%s", playlist.filename); | ||
1966 | 2259 | ||
2260 | snprintf(buf, buf_size, "%s", playlist->filename+playlist->dirlen); | ||
2261 | |||
1967 | if (!buf[0]) | 2262 | if (!buf[0]) |
1968 | return NULL; | 2263 | return NULL; |
1969 | 2264 | ||
1970 | return buf; | 2265 | /* Remove extension */ |
1971 | } | 2266 | sep = strrchr(buf, '.'); |
2267 | if (sep) | ||
2268 | *sep = 0; | ||
1972 | 2269 | ||
1973 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ | 2270 | return buf; |
1974 | int playlist_amount(void) | ||
1975 | { | ||
1976 | return playlist.amount; | ||
1977 | } | 2271 | } |
1978 | 2272 | ||
1979 | /* returns playlist name */ | 2273 | /* returns the playlist filename */ |
1980 | char *playlist_name(char *buf, int buf_size) | 2274 | char *playlist_get_name(struct playlist_info* playlist, char *buf, |
2275 | int buf_size) | ||
1981 | { | 2276 | { |
1982 | char *sep; | 2277 | if (!playlist) |
2278 | playlist = ¤t_playlist; | ||
1983 | 2279 | ||
1984 | snprintf(buf, buf_size, "%s", playlist.filename+playlist.dirlen); | 2280 | snprintf(buf, buf_size, "%s", playlist->filename); |
1985 | 2281 | ||
1986 | if (!buf[0]) | 2282 | if (!buf[0]) |
1987 | return NULL; | 2283 | return NULL; |
1988 | 2284 | ||
1989 | /* Remove extension */ | ||
1990 | sep = strrchr(buf, '.'); | ||
1991 | if (sep) | ||
1992 | *sep = 0; | ||
1993 | |||
1994 | return buf; | 2285 | return buf; |
1995 | } | 2286 | } |
1996 | 2287 | ||
1997 | /* Fills info structure with information about track at specified index. | 2288 | /* Fills info structure with information about track at specified index. |
1998 | Returns 0 on success and -1 on failure */ | 2289 | Returns 0 on success and -1 on failure */ |
1999 | int playlist_get_track_info(int index, struct playlist_track_info* info) | 2290 | int playlist_get_track_info(struct playlist_info* playlist, int index, |
2291 | struct playlist_track_info* info) | ||
2000 | { | 2292 | { |
2001 | int seek; | 2293 | int seek; |
2002 | bool control_file; | 2294 | bool control_file; |
2003 | 2295 | ||
2004 | if (index < 0 || index >= playlist.amount) | 2296 | if (!playlist) |
2297 | playlist = ¤t_playlist; | ||
2298 | |||
2299 | if (index < 0 || index >= playlist->amount) | ||
2005 | return -1; | 2300 | return -1; |
2006 | 2301 | ||
2007 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2302 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
2008 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | 2303 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
2009 | 2304 | ||
2010 | if (get_filename(seek, control_file, info->filename, | 2305 | if (get_filename(playlist, seek, control_file, info->filename, |
2011 | sizeof(info->filename)) < 0) | 2306 | sizeof(info->filename)) < 0) |
2012 | return -1; | 2307 | return -1; |
2013 | 2308 | ||
@@ -2015,20 +2310,20 @@ int playlist_get_track_info(int index, struct playlist_track_info* info) | |||
2015 | 2310 | ||
2016 | if (control_file) | 2311 | if (control_file) |
2017 | { | 2312 | { |
2018 | if (playlist.indices[index] & PLAYLIST_QUEUE_MASK) | 2313 | if (playlist->indices[index] & PLAYLIST_QUEUE_MASK) |
2019 | info->attr |= PLAYLIST_ATTR_QUEUED; | 2314 | info->attr |= PLAYLIST_ATTR_QUEUED; |
2020 | else | 2315 | else |
2021 | info->attr |= PLAYLIST_ATTR_INSERTED; | 2316 | info->attr |= PLAYLIST_ATTR_INSERTED; |
2022 | } | 2317 | } |
2023 | 2318 | ||
2024 | info->index = index; | 2319 | info->index = index; |
2025 | info->display_index = rotate_index(index) + 1; | 2320 | info->display_index = rotate_index(playlist, index) + 1; |
2026 | 2321 | ||
2027 | return 0; | 2322 | return 0; |
2028 | } | 2323 | } |
2029 | 2324 | ||
2030 | /* save the current dynamic playlist to specified file */ | 2325 | /* save the current dynamic playlist to specified file */ |
2031 | int playlist_save(char *filename) | 2326 | int playlist_save(struct playlist_info* playlist, char *filename) |
2032 | { | 2327 | { |
2033 | int fd; | 2328 | int fd; |
2034 | int i, index; | 2329 | int i, index; |
@@ -2036,13 +2331,10 @@ int playlist_save(char *filename) | |||
2036 | char tmp_buf[MAX_PATH+1]; | 2331 | char tmp_buf[MAX_PATH+1]; |
2037 | int result = 0; | 2332 | int result = 0; |
2038 | 2333 | ||
2039 | if (playlist.control_fd < 0) | 2334 | if (!playlist) |
2040 | { | 2335 | playlist = ¤t_playlist; |
2041 | splash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | ||
2042 | return -1; | ||
2043 | } | ||
2044 | 2336 | ||
2045 | if (playlist.amount <= 0) | 2337 | if (playlist->amount <= 0) |
2046 | return -1; | 2338 | return -1; |
2047 | 2339 | ||
2048 | /* use current working directory as base for pathname */ | 2340 | /* use current working directory as base for pathname */ |
@@ -2059,8 +2351,8 @@ int playlist_save(char *filename) | |||
2059 | 2351 | ||
2060 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); | 2352 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); |
2061 | 2353 | ||
2062 | index = playlist.first_index; | 2354 | index = playlist->first_index; |
2063 | for (i=0; i<playlist.amount; i++) | 2355 | for (i=0; i<playlist->amount; i++) |
2064 | { | 2356 | { |
2065 | bool control_file; | 2357 | bool control_file; |
2066 | bool queue; | 2358 | bool queue; |
@@ -2074,14 +2366,15 @@ int playlist_save(char *filename) | |||
2074 | #endif | 2366 | #endif |
2075 | break; | 2367 | break; |
2076 | 2368 | ||
2077 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2369 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
2078 | queue = playlist.indices[index] & PLAYLIST_QUEUE_MASK; | 2370 | queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; |
2079 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | 2371 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
2080 | 2372 | ||
2081 | /* Don't save queued files */ | 2373 | /* Don't save queued files */ |
2082 | if (!queue) | 2374 | if (!queue) |
2083 | { | 2375 | { |
2084 | if (get_filename(seek, control_file, tmp_buf, MAX_PATH+1) < 0) | 2376 | if (get_filename(playlist, seek, control_file, tmp_buf, |
2377 | MAX_PATH+1) < 0) | ||
2085 | { | 2378 | { |
2086 | result = -1; | 2379 | result = -1; |
2087 | break; | 2380 | break; |
@@ -2102,7 +2395,7 @@ int playlist_save(char *filename) | |||
2102 | yield(); | 2395 | yield(); |
2103 | } | 2396 | } |
2104 | 2397 | ||
2105 | index = (index+1)%playlist.amount; | 2398 | index = (index+1)%playlist->amount; |
2106 | } | 2399 | } |
2107 | 2400 | ||
2108 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); | 2401 | display_playlist_count(count, str(LANG_PLAYLIST_SAVE_COUNT)); |
diff --git a/apps/playlist.h b/apps/playlist.h index 020d3332cb..482cecd128 100644 --- a/apps/playlist.h +++ b/apps/playlist.h | |||
@@ -28,9 +28,12 @@ | |||
28 | 28 | ||
29 | struct playlist_info | 29 | struct playlist_info |
30 | { | 30 | { |
31 | bool current; /* current playing playlist */ | ||
31 | char filename[MAX_PATH]; /* path name of m3u playlist on disk */ | 32 | char filename[MAX_PATH]; /* path name of m3u playlist on disk */ |
33 | char control_filename[MAX_PATH]; /* full path of control file */ | ||
32 | int fd; /* descriptor of the open playlist file */ | 34 | int fd; /* descriptor of the open playlist file */ |
33 | int control_fd; /* descriptor of the open control file */ | 35 | int control_fd; /* descriptor of the open control file */ |
36 | bool control_created; /* has control file been created? */ | ||
34 | int dirlen; /* Length of the path to the playlist file */ | 37 | int dirlen; /* Length of the path to the playlist file */ |
35 | unsigned int *indices; /* array of indices */ | 38 | unsigned int *indices; /* array of indices */ |
36 | int max_playlist_size; /* Max number of files in playlist. Mirror of | 39 | int max_playlist_size; /* Max number of files in playlist. Mirror of |
@@ -63,33 +66,48 @@ struct playlist_track_info | |||
63 | int display_index; /* index of track for display */ | 66 | int display_index; /* index of track for display */ |
64 | }; | 67 | }; |
65 | 68 | ||
69 | /* Exported functions only for current playlist. */ | ||
66 | void playlist_init(void); | 70 | void playlist_init(void); |
67 | int playlist_create(char *dir, char *file); | 71 | int playlist_create(char *dir, char *file); |
68 | int playlist_resume(void); | 72 | int playlist_resume(void); |
69 | int playlist_add(char *filename); | 73 | int playlist_add(char *filename); |
70 | int playlist_insert_track(char *filename, int position, bool queue); | ||
71 | int playlist_insert_directory(char *dirname, int position, bool queue, | ||
72 | bool recurse); | ||
73 | int playlist_insert_playlist(char *filename, int position, bool queue); | ||
74 | int playlist_delete(int index); | ||
75 | int playlist_move(int index, int new_index); | ||
76 | int playlist_shuffle(int random_seed, int start_index); | 74 | int playlist_shuffle(int random_seed, int start_index); |
77 | int playlist_randomise(unsigned int seed, bool start_current); | ||
78 | int playlist_sort(bool start_current); | ||
79 | int playlist_start(int start_index, int offset); | 75 | int playlist_start(int start_index, int offset); |
80 | bool playlist_check(int steps); | 76 | bool playlist_check(int steps); |
81 | char *playlist_peek(int steps); | 77 | char *playlist_peek(int steps); |
82 | int playlist_next(int steps); | 78 | int playlist_next(int steps); |
83 | int playlist_get_resume_info(int *resume_index); | 79 | int playlist_get_resume_info(int *resume_index); |
84 | int playlist_get_display_index(void); | 80 | int playlist_get_display_index(void); |
85 | int playlist_get_first_index(void); | ||
86 | int playlist_amount(void); | 81 | int playlist_amount(void); |
87 | char *playlist_name(char *buf, int buf_size); | 82 | |
88 | int playlist_get_track_info(int index, struct playlist_track_info* info); | 83 | /* Exported functions for all playlists. Pass NULL for playlist_info |
89 | int playlist_save(char *filename); | 84 | structure to work with current playlist. */ |
90 | int playlist_get_seed(void); | 85 | int playlist_create_ex(struct playlist_info* playlist, char* dir, char* file, |
91 | char *playlist_get_name(char *buf, int buf_size); | 86 | void* index_buffer, int index_buffer_size, |
92 | bool playlist_modified(void); | 87 | void* temp_buffer, int temp_buffer_size); |
88 | int playlist_set_current(struct playlist_info* playlist); | ||
89 | void playlist_close(struct playlist_info* playlist); | ||
90 | int playlist_insert_track(struct playlist_info* playlist, char *filename, | ||
91 | int position, bool queue); | ||
92 | int playlist_insert_directory(struct playlist_info* playlist, char *dirname, | ||
93 | int position, bool queue, bool recurse); | ||
94 | int playlist_insert_playlist(struct playlist_info* playlist, char *filename, | ||
95 | int position, bool queue); | ||
96 | int playlist_delete(struct playlist_info* playlist, int index); | ||
97 | int playlist_move(struct playlist_info* playlist, int index, int new_index); | ||
98 | int playlist_randomise(struct playlist_info* playlist, unsigned int seed, | ||
99 | bool start_current); | ||
100 | int playlist_sort(struct playlist_info* playlist, bool start_current); | ||
101 | bool playlist_modified(struct playlist_info* playlist); | ||
102 | int playlist_get_first_index(struct playlist_info* playlist); | ||
103 | int playlist_get_seed(struct playlist_info* playlist); | ||
104 | int playlist_amount_ex(struct playlist_info* playlist); | ||
105 | char *playlist_name(struct playlist_info* playlist, char *buf, int buf_size); | ||
106 | char *playlist_get_name(struct playlist_info* playlist, char *buf, | ||
107 | int buf_size); | ||
108 | int playlist_get_track_info(struct playlist_info* playlist, int index, | ||
109 | struct playlist_track_info* info); | ||
110 | int playlist_save(struct playlist_info* playlist, char *filename); | ||
93 | 111 | ||
94 | enum { | 112 | enum { |
95 | PLAYLIST_PREPEND = -1, | 113 | PLAYLIST_PREPEND = -1, |
diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c index f4e4867a92..b2742781a1 100644 --- a/apps/playlist_menu.c +++ b/apps/playlist_menu.c | |||
@@ -39,7 +39,7 @@ static bool save_playlist(void) | |||
39 | 39 | ||
40 | if (!kbd_input(filename, sizeof(filename))) | 40 | if (!kbd_input(filename, sizeof(filename))) |
41 | { | 41 | { |
42 | playlist_save(filename); | 42 | playlist_save(NULL, filename); |
43 | 43 | ||
44 | /* reload in case playlist was saved to cwd */ | 44 | /* reload in case playlist was saved to cwd */ |
45 | reload_directory(); | 45 | reload_directory(); |
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 00da973732..20ac6c05a2 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include "icons.h" | 28 | #include "icons.h" |
29 | #include "menu.h" | 29 | #include "menu.h" |
30 | #include "plugin.h" | 30 | #include "plugin.h" |
31 | #include "keyboard.h" | ||
32 | #include "tree.h" | ||
33 | #include "onplay.h" | ||
31 | 34 | ||
32 | #ifdef HAVE_LCD_BITMAP | 35 | #ifdef HAVE_LCD_BITMAP |
33 | #include "widgets.h" | 36 | #include "widgets.h" |
@@ -35,6 +38,8 @@ | |||
35 | 38 | ||
36 | #include "lang.h" | 39 | #include "lang.h" |
37 | 40 | ||
41 | #include "playlist_viewer.h" | ||
42 | |||
38 | /* Defines for LCD display purposes. Taken from tree.c */ | 43 | /* Defines for LCD display purposes. Taken from tree.c */ |
39 | #ifdef HAVE_LCD_BITMAP | 44 | #ifdef HAVE_LCD_BITMAP |
40 | #define CURSOR_X (global_settings.scrollbar && \ | 45 | #define CURSOR_X (global_settings.scrollbar && \ |
@@ -46,7 +51,9 @@ | |||
46 | 51 | ||
47 | #define MARGIN_X ((global_settings.scrollbar && \ | 52 | #define MARGIN_X ((global_settings.scrollbar && \ |
48 | viewer.num_tracks > viewer.num_display_lines ? \ | 53 | viewer.num_tracks > viewer.num_display_lines ? \ |
49 | SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + ICON_WIDTH) | 54 | SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + \ |
55 | (global_settings.playlist_viewer_icons ? \ | ||
56 | ICON_WIDTH : 0)) | ||
50 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) | 57 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) |
51 | 58 | ||
52 | #define LINE_X 0 | 59 | #define LINE_X 0 |
@@ -67,11 +74,15 @@ | |||
67 | /* Maximum number of tracks we can have loaded at one time */ | 74 | /* Maximum number of tracks we can have loaded at one time */ |
68 | #define MAX_PLAYLIST_ENTRIES 200 | 75 | #define MAX_PLAYLIST_ENTRIES 200 |
69 | 76 | ||
77 | /* Default playlist name for saving */ | ||
78 | #define DEFAULT_PLAYLIST_NAME "/viewer.m3u" | ||
79 | |||
70 | /* Index of track on display line _pos */ | 80 | /* Index of track on display line _pos */ |
71 | #define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos)) | 81 | #define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos)) |
72 | 82 | ||
73 | /* Global playlist viewer settings */ | 83 | /* Global playlist viewer settings */ |
74 | struct playlist_viewer_info { | 84 | struct playlist_viewer_info { |
85 | struct playlist_info* playlist; /* playlist being viewed */ | ||
75 | char *name_buffer; /* Buffer used to store track names */ | 86 | char *name_buffer; /* Buffer used to store track names */ |
76 | int buffer_size; /* Size of name buffer */ | 87 | int buffer_size; /* Size of name buffer */ |
77 | 88 | ||
@@ -103,15 +114,19 @@ struct playlist_entry { | |||
103 | static struct playlist_viewer_info viewer; | 114 | static struct playlist_viewer_info viewer; |
104 | static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; | 115 | static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; |
105 | 116 | ||
117 | /* Used when viewing playlists on disk */ | ||
118 | static struct playlist_info temp_playlist; | ||
119 | |||
106 | #ifdef HAVE_LCD_BITMAP | 120 | #ifdef HAVE_LCD_BITMAP |
107 | extern unsigned char bitmap_icons_6x8[LastIcon][6]; | 121 | extern unsigned char bitmap_icons_6x8[LastIcon][6]; |
108 | #endif | 122 | #endif |
109 | 123 | ||
110 | static bool initialize(void); | 124 | static bool initialize(char* filename, bool reload); |
111 | static void load_playlist_entries(int start_index); | 125 | static void load_playlist_entries(int start_index); |
112 | static void load_playlist_entries_r(int end_index); | 126 | static void load_playlist_entries_r(int end_index); |
113 | static int load_entry(int index, int pos, char* p, int size); | 127 | static int load_entry(int index, int pos, char* p, int size); |
114 | static void format_name(char* dest, char* src); | 128 | static void format_name(char* dest, char* src); |
129 | static void format_line(struct playlist_entry* track, char* str, int len); | ||
115 | static void display_playlist(void); | 130 | static void display_playlist(void); |
116 | static void update_display_line(int line, bool scroll); | 131 | static void update_display_line(int line, bool scroll); |
117 | static void scroll_display(int lines); | 132 | static void scroll_display(int lines); |
@@ -120,18 +135,74 @@ static bool update_playlist(bool force); | |||
120 | #ifdef BUTTON_ON | 135 | #ifdef BUTTON_ON |
121 | static int onplay_menu(int index); | 136 | static int onplay_menu(int index); |
122 | #endif | 137 | #endif |
123 | 138 | static bool viewer_menu(void); | |
124 | /* Initialize the playlist viewer */ | 139 | static bool show_icons(void); |
125 | static bool initialize(void) | 140 | static bool show_indices(void); |
141 | static bool track_display(void); | ||
142 | static bool save_playlist(void); | ||
143 | |||
144 | /* Initialize the playlist viewer. */ | ||
145 | static bool initialize(char* filename, bool reload) | ||
126 | { | 146 | { |
127 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | 147 | char* buffer; |
148 | int buffer_size; | ||
149 | bool is_playing = mpeg_status() & MPEG_STATUS_PLAY; | ||
150 | |||
151 | if (!filename && !is_playing) | ||
128 | /* Nothing is playing, exit */ | 152 | /* Nothing is playing, exit */ |
129 | return false; | 153 | return false; |
130 | 154 | ||
131 | viewer.name_buffer = plugin_get_buffer(&viewer.buffer_size); | 155 | buffer = plugin_get_buffer(&buffer_size); |
132 | if (!viewer.name_buffer) | 156 | if (!buffer) |
133 | return false; | 157 | return false; |
134 | 158 | ||
159 | if (!filename) | ||
160 | viewer.playlist = NULL; | ||
161 | else | ||
162 | { | ||
163 | /* Viewing playlist on disk */ | ||
164 | char *dir, *file, *temp_ptr; | ||
165 | char *index_buffer = NULL; | ||
166 | int index_buffer_size = 0; | ||
167 | |||
168 | viewer.playlist = &temp_playlist; | ||
169 | |||
170 | /* Separate directory from filename */ | ||
171 | temp_ptr = strrchr(filename+1,'/'); | ||
172 | if (temp_ptr) | ||
173 | { | ||
174 | *temp_ptr = 0; | ||
175 | dir = filename; | ||
176 | file = temp_ptr + 1; | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | dir = "/"; | ||
181 | file = filename+1; | ||
182 | } | ||
183 | |||
184 | if (is_playing) | ||
185 | { | ||
186 | /* Something is playing, use half the plugin buffer for playlist | ||
187 | indices */ | ||
188 | index_buffer_size = buffer_size / 2; | ||
189 | index_buffer = buffer; | ||
190 | } | ||
191 | |||
192 | playlist_create_ex(viewer.playlist, dir, file, index_buffer, | ||
193 | index_buffer_size, buffer+index_buffer_size, | ||
194 | buffer_size-index_buffer_size); | ||
195 | |||
196 | if (temp_ptr) | ||
197 | *temp_ptr = '/'; | ||
198 | |||
199 | buffer += index_buffer_size; | ||
200 | buffer_size -= index_buffer_size; | ||
201 | } | ||
202 | |||
203 | viewer.name_buffer = buffer; | ||
204 | viewer.buffer_size = buffer_size; | ||
205 | |||
135 | #ifdef HAVE_LCD_BITMAP | 206 | #ifdef HAVE_LCD_BITMAP |
136 | { | 207 | { |
137 | char icon_chars[] = "MQ"; /* characters used as icons */ | 208 | char icon_chars[] = "MQ"; /* characters used as icons */ |
@@ -166,12 +237,20 @@ static bool initialize(void) | |||
166 | viewer.line_height = 1; | 237 | viewer.line_height = 1; |
167 | #endif | 238 | #endif |
168 | 239 | ||
169 | viewer.cursor_pos = 0; | ||
170 | viewer.move_track = -1; | 240 | viewer.move_track = -1; |
171 | 241 | ||
172 | /* Start displaying at current playing track */ | 242 | if (!reload) |
173 | viewer.first_display_index = playlist_get_display_index() - 1; | 243 | { |
174 | update_first_index(); | 244 | viewer.cursor_pos = 0; |
245 | |||
246 | if (!viewer.playlist) | ||
247 | /* Start displaying at current playing track */ | ||
248 | viewer.first_display_index = playlist_get_display_index() - 1; | ||
249 | else | ||
250 | viewer.first_display_index = 0; | ||
251 | |||
252 | update_first_index(); | ||
253 | } | ||
175 | 254 | ||
176 | if (!update_playlist(true)) | 255 | if (!update_playlist(true)) |
177 | return false; | 256 | return false; |
@@ -287,21 +366,19 @@ static int load_entry(int index, int pos, char* p, int size) | |||
287 | struct playlist_track_info info; | 366 | struct playlist_track_info info; |
288 | int len; | 367 | int len; |
289 | int result = 0; | 368 | int result = 0; |
290 | char name[MAX_PATH]; | ||
291 | 369 | ||
292 | /* Playlist viewer orders songs based on display index. We need to | 370 | /* Playlist viewer orders songs based on display index. We need to |
293 | convert to real playlist index to access track */ | 371 | convert to real playlist index to access track */ |
294 | index = (index + playlist_get_first_index()) % viewer.num_tracks; | 372 | index = (index + playlist_get_first_index(viewer.playlist)) % |
295 | if (playlist_get_track_info(index, &info) < 0) | 373 | viewer.num_tracks; |
374 | if (playlist_get_track_info(viewer.playlist, index, &info) < 0) | ||
296 | return -1; | 375 | return -1; |
297 | 376 | ||
298 | format_name(name, info.filename); | 377 | len = strlen(info.filename) + 1; |
299 | |||
300 | len = strlen(name) + 1; | ||
301 | 378 | ||
302 | if (len <= size) | 379 | if (len <= size) |
303 | { | 380 | { |
304 | strcpy(p, name); | 381 | strcpy(p, info.filename); |
305 | 382 | ||
306 | tracks[pos].name = p; | 383 | tracks[pos].name = p; |
307 | tracks[pos].index = info.index; | 384 | tracks[pos].index = info.index; |
@@ -319,18 +396,46 @@ static int load_entry(int index, int pos, char* p, int size) | |||
319 | /* Format trackname for display purposes */ | 396 | /* Format trackname for display purposes */ |
320 | static void format_name(char* dest, char* src) | 397 | static void format_name(char* dest, char* src) |
321 | { | 398 | { |
322 | char* p = strrchr(src, '/'); | 399 | switch (global_settings.playlist_viewer_track_display) |
323 | int len; | 400 | { |
401 | case 0: | ||
402 | default: | ||
403 | { | ||
404 | /* Only display the mp3 filename */ | ||
405 | char* p = strrchr(src, '/'); | ||
406 | int len; | ||
407 | |||
408 | strcpy(dest, p+1); | ||
409 | len = strlen(dest); | ||
410 | |||
411 | /* Remove the extension */ | ||
412 | if (!strcasecmp(&dest[len-4], ".mp3") || | ||
413 | !strcasecmp(&dest[len-4], ".mp2") || | ||
414 | !strcasecmp(&dest[len-4], ".mpa")) | ||
415 | dest[len-4] = '\0'; | ||
416 | |||
417 | break; | ||
418 | } | ||
419 | case 1: | ||
420 | /* Full path */ | ||
421 | strcpy(dest, src); | ||
422 | break; | ||
423 | } | ||
424 | } | ||
425 | |||
426 | /* Format display line */ | ||
427 | static void format_line(struct playlist_entry* track, char* str, int len) | ||
428 | { | ||
429 | char name[MAX_PATH]; | ||
324 | 430 | ||
325 | /* Only display the mp3 filename */ | 431 | format_name(name, track->name); |
326 | strcpy(dest, p+1); | 432 | |
327 | len = strlen(dest); | 433 | if (global_settings.playlist_viewer_indices) |
434 | /* Display playlist index */ | ||
435 | snprintf(str, len, "%d. %s", track->display_index, name); | ||
436 | else | ||
437 | snprintf(str, len, "%s", name); | ||
328 | 438 | ||
329 | /* Remove the extension */ | ||
330 | if (!strcasecmp(&dest[len-4], ".mp3") || | ||
331 | !strcasecmp(&dest[len-4], ".mp2") || | ||
332 | !strcasecmp(&dest[len-4], ".mpa")) | ||
333 | dest[len-4] = '\0'; | ||
334 | } | 439 | } |
335 | 440 | ||
336 | /* Display tracks on screen */ | 441 | /* Display tracks on screen */ |
@@ -349,41 +454,44 @@ static void display_playlist(void) | |||
349 | 454 | ||
350 | for (i=0; i<=num_display_tracks; i++) | 455 | for (i=0; i<=num_display_tracks; i++) |
351 | { | 456 | { |
352 | /* Icons */ | 457 | if (global_settings.playlist_viewer_icons) |
353 | if (tracks[INDEX(i)].index == viewer.current_playing_track) | ||
354 | { | 458 | { |
355 | /* Current playing track */ | 459 | /* Icons */ |
460 | if (tracks[INDEX(i)].index == viewer.current_playing_track) | ||
461 | { | ||
462 | /* Current playing track */ | ||
356 | #ifdef HAVE_LCD_BITMAP | 463 | #ifdef HAVE_LCD_BITMAP |
357 | int offset=0; | 464 | int offset=0; |
358 | if ( viewer.line_height > 8 ) | 465 | if ( viewer.line_height > 8 ) |
359 | offset = (viewer.line_height - 8) / 2; | 466 | offset = (viewer.line_height - 8) / 2; |
360 | lcd_bitmap(bitmap_icons_6x8[File], | 467 | lcd_bitmap(bitmap_icons_6x8[File], |
361 | CURSOR_X * 6 + CURSOR_WIDTH, | 468 | CURSOR_X * 6 + CURSOR_WIDTH, |
362 | MARGIN_Y+(i*viewer.line_height) + offset, | 469 | MARGIN_Y+(i*viewer.line_height) + offset, |
363 | 6, 8, true); | 470 | 6, 8, true); |
364 | #else | 471 | #else |
365 | lcd_putc(LINE_X-1, i, File); | 472 | lcd_putc(LINE_X-1, i, File); |
366 | #endif | 473 | #endif |
367 | } | 474 | } |
368 | else if (tracks[INDEX(i)].index == viewer.move_track) | 475 | else if (tracks[INDEX(i)].index == viewer.move_track) |
369 | { | 476 | { |
370 | /* Track we are moving */ | 477 | /* Track we are moving */ |
371 | #ifdef HAVE_LCD_BITMAP | 478 | #ifdef HAVE_LCD_BITMAP |
372 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | 479 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, |
373 | MARGIN_Y+(i*viewer.line_height), "M"); | 480 | MARGIN_Y+(i*viewer.line_height), "M"); |
374 | #else | 481 | #else |
375 | lcd_putc(LINE_X-1, i, 'M'); | 482 | lcd_putc(LINE_X-1, i, 'M'); |
376 | #endif | 483 | #endif |
377 | } | 484 | } |
378 | else if (tracks[INDEX(i)].queued) | 485 | else if (tracks[INDEX(i)].queued) |
379 | { | 486 | { |
380 | /* Queued track */ | 487 | /* Queued track */ |
381 | #ifdef HAVE_LCD_BITMAP | 488 | #ifdef HAVE_LCD_BITMAP |
382 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | 489 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, |
383 | MARGIN_Y+(i*viewer.line_height), "Q"); | 490 | MARGIN_Y+(i*viewer.line_height), "Q"); |
384 | #else | 491 | #else |
385 | lcd_putc(LINE_X-1, i, 'Q'); | 492 | lcd_putc(LINE_X-1, i, 'Q'); |
386 | #endif | 493 | #endif |
494 | } | ||
387 | } | 495 | } |
388 | 496 | ||
389 | update_display_line(i, false); | 497 | update_display_line(i, false); |
@@ -494,10 +602,8 @@ static void update_display_line(int line, bool scroll) | |||
494 | { | 602 | { |
495 | char str[MAX_PATH + 16]; | 603 | char str[MAX_PATH + 16]; |
496 | 604 | ||
497 | snprintf(str, sizeof(str), "%d. %s", | 605 | format_line(&tracks[INDEX(line)], str, sizeof(str)); |
498 | tracks[INDEX(line)].display_index, | 606 | |
499 | tracks[INDEX(line)].name); | ||
500 | |||
501 | if (scroll) | 607 | if (scroll) |
502 | { | 608 | { |
503 | #ifdef HAVE_LCD_BITMAP | 609 | #ifdef HAVE_LCD_BITMAP |
@@ -516,7 +622,7 @@ static void update_display_line(int line, bool scroll) | |||
516 | static void update_first_index(void) | 622 | static void update_first_index(void) |
517 | { | 623 | { |
518 | /* viewer.num_tracks may be invalid at this point */ | 624 | /* viewer.num_tracks may be invalid at this point */ |
519 | int num_tracks = playlist_amount(); | 625 | int num_tracks = playlist_amount_ex(viewer.playlist); |
520 | 626 | ||
521 | if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines) | 627 | if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines) |
522 | { | 628 | { |
@@ -535,14 +641,17 @@ static void update_first_index(void) | |||
535 | /* Update playlist in case something has changed or forced */ | 641 | /* Update playlist in case something has changed or forced */ |
536 | static bool update_playlist(bool force) | 642 | static bool update_playlist(bool force) |
537 | { | 643 | { |
538 | playlist_get_resume_info(&viewer.current_playing_track); | 644 | if (!viewer.playlist) |
645 | playlist_get_resume_info(&viewer.current_playing_track); | ||
646 | else | ||
647 | viewer.current_playing_track = -1; | ||
539 | 648 | ||
540 | if (force || playlist_amount() != viewer.num_tracks) | 649 | if (force || playlist_amount_ex(viewer.playlist) != viewer.num_tracks) |
541 | { | 650 | { |
542 | int index; | 651 | int index; |
543 | 652 | ||
544 | /* Reload tracks */ | 653 | /* Reload tracks */ |
545 | viewer.num_tracks = playlist_amount(); | 654 | viewer.num_tracks = playlist_amount_ex(viewer.playlist); |
546 | if (viewer.num_tracks < 0) | 655 | if (viewer.num_tracks < 0) |
547 | return false; | 656 | return false; |
548 | 657 | ||
@@ -571,16 +680,19 @@ static bool update_playlist(bool force) | |||
571 | changed. */ | 680 | changed. */ |
572 | static int onplay_menu(int index) | 681 | static int onplay_menu(int index) |
573 | { | 682 | { |
574 | struct menu_items menu[2]; /* increase this if you add entries! */ | 683 | struct menu_items menu[3]; /* increase this if you add entries! */ |
575 | int m, i=0, result, ret = 0; | 684 | int m, i=0, result, ret = 0; |
576 | bool current = (tracks[index].index == viewer.current_playing_track); | 685 | bool current = (tracks[index].index == viewer.current_playing_track); |
577 | 686 | ||
578 | menu[i].desc = str(LANG_DELETE); | 687 | menu[i].desc = str(LANG_REMOVE); |
579 | i++; | 688 | i++; |
580 | 689 | ||
581 | menu[i].desc = str(LANG_MOVE); | 690 | menu[i].desc = str(LANG_MOVE); |
582 | i++; | 691 | i++; |
583 | 692 | ||
693 | menu[i].desc = str(LANG_FILE_OPTIONS); | ||
694 | i++; | ||
695 | |||
584 | m = menu_init(menu, i); | 696 | m = menu_init(menu, i); |
585 | result = menu_show(m); | 697 | result = menu_show(m); |
586 | if (result == MENU_ATTACHED_USB) | 698 | if (result == MENU_ATTACHED_USB) |
@@ -597,7 +709,7 @@ static int onplay_menu(int index) | |||
597 | if (current) | 709 | if (current) |
598 | mpeg_stop(); | 710 | mpeg_stop(); |
599 | 711 | ||
600 | playlist_delete(tracks[index].index); | 712 | playlist_delete(viewer.playlist, tracks[index].index); |
601 | 713 | ||
602 | if (current) | 714 | if (current) |
603 | { | 715 | { |
@@ -618,6 +730,17 @@ static int onplay_menu(int index) | |||
618 | viewer.move_track = tracks[index].index; | 730 | viewer.move_track = tracks[index].index; |
619 | ret = 0; | 731 | ret = 0; |
620 | break; | 732 | break; |
733 | case 2: | ||
734 | { | ||
735 | onplay(tracks[index].name, TREE_ATTR_MPA); | ||
736 | |||
737 | if (!viewer.playlist) | ||
738 | ret = 1; | ||
739 | else | ||
740 | ret = 0; | ||
741 | |||
742 | break; | ||
743 | } | ||
621 | } | 744 | } |
622 | } | 745 | } |
623 | 746 | ||
@@ -627,17 +750,91 @@ static int onplay_menu(int index) | |||
627 | } | 750 | } |
628 | #endif | 751 | #endif |
629 | 752 | ||
630 | /* Main viewer function */ | 753 | /* Menu of viewer options. Invoked via F1(r) or Menu(p). */ |
754 | static bool viewer_menu(void) | ||
755 | { | ||
756 | int m; | ||
757 | bool result; | ||
758 | |||
759 | struct menu_items items[] = { | ||
760 | { str(LANG_SHOW_ICONS), show_icons }, | ||
761 | { str(LANG_SHOW_INDICES), show_indices }, | ||
762 | { str(LANG_TRACK_DISPLAY), track_display }, | ||
763 | { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, | ||
764 | }; | ||
765 | |||
766 | m=menu_init( items, sizeof(items) / sizeof(*items) ); | ||
767 | result = menu_run(m); | ||
768 | menu_exit(m); | ||
769 | |||
770 | settings_save(); | ||
771 | |||
772 | return result; | ||
773 | } | ||
774 | |||
775 | /* Show icons in viewer? */ | ||
776 | static bool show_icons(void) | ||
777 | { | ||
778 | return set_bool(str(LANG_SHOW_ICONS), | ||
779 | &global_settings.playlist_viewer_icons); | ||
780 | } | ||
781 | |||
782 | /* Show indices of tracks? */ | ||
783 | static bool show_indices(void) | ||
784 | { | ||
785 | return set_bool(str(LANG_SHOW_INDICES), | ||
786 | &global_settings.playlist_viewer_indices); | ||
787 | } | ||
788 | |||
789 | /* How to display a track */ | ||
790 | static bool track_display(void) | ||
791 | { | ||
792 | char* names[] = { | ||
793 | str(LANG_DISPLAY_TRACK_NAME_ONLY), | ||
794 | str(LANG_DISPLAY_FULL_PATH) | ||
795 | }; | ||
796 | |||
797 | return set_option(str(LANG_TRACK_DISPLAY), | ||
798 | &global_settings.playlist_viewer_track_display, INT, names, 2, NULL); | ||
799 | } | ||
800 | |||
801 | /* Save playlist to disk */ | ||
802 | static bool save_playlist(void) | ||
803 | { | ||
804 | char filename[MAX_PATH+1]; | ||
805 | |||
806 | strncpy(filename, DEFAULT_PLAYLIST_NAME, sizeof(filename)); | ||
807 | |||
808 | if (!kbd_input(filename, sizeof(filename))) | ||
809 | { | ||
810 | playlist_save(viewer.playlist, filename); | ||
811 | |||
812 | /* reload in case playlist was saved to cwd */ | ||
813 | reload_directory(); | ||
814 | } | ||
815 | |||
816 | return false; | ||
817 | } | ||
818 | |||
819 | /* View current playlist */ | ||
631 | bool playlist_viewer(void) | 820 | bool playlist_viewer(void) |
632 | { | 821 | { |
822 | return playlist_viewer_ex(NULL); | ||
823 | } | ||
824 | |||
825 | /* Main viewer function. Filename identifies playlist to be viewed. If NULL, | ||
826 | view current playlist. */ | ||
827 | bool playlist_viewer_ex(char* filename) | ||
828 | { | ||
829 | bool ret = false; /* return value */ | ||
633 | bool exit=false; /* exit viewer */ | 830 | bool exit=false; /* exit viewer */ |
634 | bool update=true; /* update display */ | 831 | bool update=true; /* update display */ |
635 | bool cursor_on=true; /* used for flashing cursor */ | 832 | bool cursor_on=true; /* used for flashing cursor */ |
636 | int old_cursor_pos; /* last cursor position */ | 833 | int old_cursor_pos; /* last cursor position */ |
637 | int button; | 834 | int button; |
638 | 835 | ||
639 | if (!initialize()) | 836 | if (!initialize(filename, false)) |
640 | return false; | 837 | goto exit; |
641 | 838 | ||
642 | old_cursor_pos = viewer.cursor_pos; | 839 | old_cursor_pos = viewer.cursor_pos; |
643 | 840 | ||
@@ -648,7 +845,7 @@ bool playlist_viewer(void) | |||
648 | /* Timeout so we can determine if play status has changed */ | 845 | /* Timeout so we can determine if play status has changed */ |
649 | button = button_get_w_tmo(HZ/2); | 846 | button = button_get_w_tmo(HZ/2); |
650 | 847 | ||
651 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | 848 | if (!viewer.playlist && !(mpeg_status() & MPEG_STATUS_PLAY)) |
652 | { | 849 | { |
653 | /* Play has stopped */ | 850 | /* Play has stopped */ |
654 | #ifdef HAVE_LCD_CHARCELLS | 851 | #ifdef HAVE_LCD_CHARCELLS |
@@ -657,7 +854,7 @@ bool playlist_viewer(void) | |||
657 | splash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); | 854 | splash(HZ, true, str(LANG_END_PLAYLIST_RECORDER)); |
658 | #endif | 855 | #endif |
659 | status_set_playmode(STATUS_STOP); | 856 | status_set_playmode(STATUS_STOP); |
660 | return false;; | 857 | goto exit; |
661 | } | 858 | } |
662 | 859 | ||
663 | if (viewer.move_track != -1 || !cursor_on) | 860 | if (viewer.move_track != -1 || !cursor_on) |
@@ -685,10 +882,13 @@ bool playlist_viewer(void) | |||
685 | #endif | 882 | #endif |
686 | } | 883 | } |
687 | 884 | ||
688 | playlist_get_resume_info(&track); | 885 | if (!viewer.playlist) |
886 | playlist_get_resume_info(&track); | ||
887 | else | ||
888 | track = -1; | ||
689 | 889 | ||
690 | if (track != viewer.current_playing_track || | 890 | if (track != viewer.current_playing_track || |
691 | playlist_amount() != viewer.num_tracks) | 891 | playlist_amount_ex(viewer.playlist) != viewer.num_tracks) |
692 | { | 892 | { |
693 | /* Playlist has changed (new track started?) */ | 893 | /* Playlist has changed (new track started?) */ |
694 | update_first_index(); | 894 | update_first_index(); |
@@ -769,7 +969,7 @@ bool playlist_viewer(void) | |||
769 | /* Move track */ | 969 | /* Move track */ |
770 | int ret; | 970 | int ret; |
771 | 971 | ||
772 | ret = playlist_move(viewer.move_track, | 972 | ret = playlist_move(viewer.playlist, viewer.move_track, |
773 | tracks[INDEX(viewer.cursor_pos)].index); | 973 | tracks[INDEX(viewer.cursor_pos)].index); |
774 | if (ret < 0) | 974 | if (ret < 0) |
775 | splash(HZ, true, str(LANG_MOVE_FAILED)); | 975 | splash(HZ, true, str(LANG_MOVE_FAILED)); |
@@ -777,7 +977,7 @@ bool playlist_viewer(void) | |||
777 | update_playlist(true); | 977 | update_playlist(true); |
778 | viewer.move_track = -1; | 978 | viewer.move_track = -1; |
779 | } | 979 | } |
780 | else | 980 | else if (!viewer.playlist) |
781 | { | 981 | { |
782 | /* Stop current track and play new track */ | 982 | /* Stop current track and play new track */ |
783 | mpeg_stop(); | 983 | mpeg_stop(); |
@@ -785,6 +985,22 @@ bool playlist_viewer(void) | |||
785 | status_set_playmode(STATUS_PLAY); | 985 | status_set_playmode(STATUS_PLAY); |
786 | update_playlist(false); | 986 | update_playlist(false); |
787 | } | 987 | } |
988 | else | ||
989 | { | ||
990 | /* Play track from playlist on disk */ | ||
991 | mpeg_stop(); | ||
992 | |||
993 | /* New playlist */ | ||
994 | if (playlist_set_current(viewer.playlist) < 0) | ||
995 | goto exit; | ||
996 | |||
997 | playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); | ||
998 | status_set_playmode(STATUS_PLAY); | ||
999 | |||
1000 | /* Our playlist is now the current list */ | ||
1001 | if (!initialize(NULL, true)) | ||
1002 | goto exit; | ||
1003 | } | ||
788 | 1004 | ||
789 | display_playlist(); | 1005 | display_playlist(); |
790 | update = true; | 1006 | update = true; |
@@ -799,13 +1015,15 @@ bool playlist_viewer(void) | |||
799 | ret = onplay_menu(INDEX(viewer.cursor_pos)); | 1015 | ret = onplay_menu(INDEX(viewer.cursor_pos)); |
800 | 1016 | ||
801 | if (ret < 0) | 1017 | if (ret < 0) |
802 | /* USB attached */ | 1018 | { |
803 | return true; | 1019 | ret = true; |
1020 | goto exit; | ||
1021 | } | ||
804 | else if (ret > 0) | 1022 | else if (ret > 0) |
805 | { | 1023 | { |
806 | /* Playlist changed */ | 1024 | /* Playlist changed */ |
807 | update_first_index(); | 1025 | update_first_index(); |
808 | update_playlist(true); | 1026 | update_playlist(false); |
809 | if (viewer.num_tracks <= 0) | 1027 | if (viewer.num_tracks <= 0) |
810 | exit = true; | 1028 | exit = true; |
811 | } | 1029 | } |
@@ -816,9 +1034,30 @@ bool playlist_viewer(void) | |||
816 | break; | 1034 | break; |
817 | } | 1035 | } |
818 | #endif /* BUTTON_ON */ | 1036 | #endif /* BUTTON_ON */ |
1037 | #ifdef HAVE_RECORDER_KEYPAD | ||
1038 | case BUTTON_F1: | ||
1039 | #else | ||
1040 | case BUTTON_MENU: | ||
1041 | #endif | ||
1042 | if (viewer_menu()) | ||
1043 | { | ||
1044 | ret = true; | ||
1045 | goto exit; | ||
1046 | } | ||
1047 | |||
1048 | display_playlist(); | ||
1049 | update = true; | ||
1050 | break; | ||
1051 | |||
819 | case SYS_USB_CONNECTED: | 1052 | case SYS_USB_CONNECTED: |
820 | usb_screen(); | 1053 | usb_screen(); |
821 | return true; | 1054 | ret = true; |
1055 | goto exit; | ||
1056 | break; | ||
1057 | |||
1058 | case BUTTON_NONE: | ||
1059 | status_draw(false); | ||
1060 | break; | ||
822 | } | 1061 | } |
823 | 1062 | ||
824 | if (update && !exit) | 1063 | if (update && !exit) |
@@ -852,5 +1091,8 @@ bool playlist_viewer(void) | |||
852 | } | 1091 | } |
853 | } | 1092 | } |
854 | 1093 | ||
855 | return false; | 1094 | exit: |
1095 | if (viewer.playlist) | ||
1096 | playlist_close(viewer.playlist); | ||
1097 | return ret; | ||
856 | } | 1098 | } |
diff --git a/apps/playlist_viewer.h b/apps/playlist_viewer.h index ecc5197566..69f9d03559 100644 --- a/apps/playlist_viewer.h +++ b/apps/playlist_viewer.h | |||
@@ -22,5 +22,6 @@ | |||
22 | #define _PLAYLIST_VIEWER_H_ | 22 | #define _PLAYLIST_VIEWER_H_ |
23 | 23 | ||
24 | bool playlist_viewer(void); | 24 | bool playlist_viewer(void); |
25 | bool playlist_viewer_ex(char* filename); | ||
25 | 26 | ||
26 | #endif | 27 | #endif |
diff --git a/apps/screens.c b/apps/screens.c index c2ffb44f3c..6987fc92e3 100644 --- a/apps/screens.c +++ b/apps/screens.c | |||
@@ -512,9 +512,9 @@ bool f2_screen(void) | |||
512 | if(mpeg_status() & MPEG_STATUS_PLAY) | 512 | if(mpeg_status() & MPEG_STATUS_PLAY) |
513 | { | 513 | { |
514 | if (global_settings.playlist_shuffle) | 514 | if (global_settings.playlist_shuffle) |
515 | playlist_randomise(current_tick, true); | 515 | playlist_randomise(NULL, current_tick, true); |
516 | else | 516 | else |
517 | playlist_sort(true); | 517 | playlist_sort(NULL, true); |
518 | } | 518 | } |
519 | used = true; | 519 | used = true; |
520 | break; | 520 | break; |
diff --git a/apps/settings.c b/apps/settings.c index bfc943bef0..7b9c1feb60 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -146,6 +146,9 @@ Rest of config block, only saved to disk: | |||
146 | caption backlight (bit 1) | 146 | caption backlight (bit 1) |
147 | car adapter mode (bit 2) | 147 | car adapter mode (bit 2) |
148 | line_in (Player only) (bit 3) | 148 | line_in (Player only) (bit 3) |
149 | playlist viewer icons (bit 4) | ||
150 | playlist viewer indices (bit 5) | ||
151 | playlist viewer track display (bit 6) | ||
149 | 0xAF <most-recent-bookmarks, auto-bookmark, autoload> | 152 | 0xAF <most-recent-bookmarks, auto-bookmark, autoload> |
150 | 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7) | 153 | 0xB0 peak meter clip hold timeout (bit 0-4), peak meter performance (bit 7) |
151 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) | 154 | 0xB1 peak meter release step size, peak_meter_dbfs (bit 7) |
@@ -421,7 +424,10 @@ int settings_save( void ) | |||
421 | ((global_settings.fade_on_stop & 1) | | 424 | ((global_settings.fade_on_stop & 1) | |
422 | ((global_settings.caption_backlight & 1) << 1) | | 425 | ((global_settings.caption_backlight & 1) << 1) | |
423 | ((global_settings.car_adapter_mode & 1) << 2) | | 426 | ((global_settings.car_adapter_mode & 1) << 2) | |
424 | ((global_settings.line_in & 1) << 3)); | 427 | ((global_settings.line_in & 1) << 3) | |
428 | ((global_settings.playlist_viewer_icons & 1) << 4) | | ||
429 | ((global_settings.playlist_viewer_indices & 1) << 5) | | ||
430 | ((global_settings.playlist_viewer_track_display & 1) << 6)); | ||
425 | config_block[0xaf] = ((global_settings.usemrb << 5) | | 431 | config_block[0xaf] = ((global_settings.usemrb << 5) | |
426 | (global_settings.autocreatebookmark << 2) | | 432 | (global_settings.autocreatebookmark << 2) | |
427 | (global_settings.autoloadbookmark)); | 433 | (global_settings.autoloadbookmark)); |
@@ -726,6 +732,12 @@ void settings_load(void) | |||
726 | global_settings.caption_backlight = (config_block[0xae] >> 1) & 1; | 732 | global_settings.caption_backlight = (config_block[0xae] >> 1) & 1; |
727 | global_settings.car_adapter_mode = (config_block[0xae] >> 2) & 1; | 733 | global_settings.car_adapter_mode = (config_block[0xae] >> 2) & 1; |
728 | global_settings.line_in = (config_block[0xae] >> 3) & 1; | 734 | global_settings.line_in = (config_block[0xae] >> 3) & 1; |
735 | global_settings.playlist_viewer_icons = | ||
736 | (config_block[0xae] >> 4) & 1; | ||
737 | global_settings.playlist_viewer_indices = | ||
738 | (config_block[0xae] >> 5) & 1; | ||
739 | global_settings.playlist_viewer_track_display = | ||
740 | (config_block[0xae] >> 6) & 1; | ||
729 | } | 741 | } |
730 | 742 | ||
731 | if(config_block[0xb0] != 0xff) { | 743 | if(config_block[0xb0] != 0xff) { |
@@ -1161,6 +1173,16 @@ bool settings_load_config(char* file) | |||
1161 | static char* options[] = {"off", "on", "unique only"}; | 1173 | static char* options[] = {"off", "on", "unique only"}; |
1162 | set_cfg_option(&global_settings.usemrb, value, options, 3); | 1174 | set_cfg_option(&global_settings.usemrb, value, options, 3); |
1163 | } | 1175 | } |
1176 | else if (!strcasecmp(name, "playlist viewer icons")) | ||
1177 | set_cfg_bool(&global_settings.playlist_viewer_icons, value); | ||
1178 | else if (!strcasecmp(name, "playlist viewer indices")) | ||
1179 | set_cfg_bool(&global_settings.playlist_viewer_indices, value); | ||
1180 | else if (!strcasecmp(name, "playlist viewer track display")) | ||
1181 | { | ||
1182 | static char* options[] = {"track name", "full path"}; | ||
1183 | set_cfg_option(&global_settings.playlist_viewer_track_display, | ||
1184 | value, options, 2); | ||
1185 | } | ||
1164 | } | 1186 | } |
1165 | 1187 | ||
1166 | close(fd); | 1188 | close(fd); |
@@ -1494,6 +1516,19 @@ bool settings_save_config(void) | |||
1494 | triopt[global_settings.recursive_dir_insert]); | 1516 | triopt[global_settings.recursive_dir_insert]); |
1495 | } | 1517 | } |
1496 | 1518 | ||
1519 | fprintf(fd, "#\r\n# Playlist viewer\r\n#\r\n"); | ||
1520 | { | ||
1521 | fprintf(fd, "playlist viewer icons: %s\r\n", | ||
1522 | boolopt[global_settings.playlist_viewer_icons]); | ||
1523 | fprintf(fd, "playlist viewer indices: %s\r\n", | ||
1524 | boolopt[global_settings.playlist_viewer_indices]); | ||
1525 | { | ||
1526 | static char* options[] = {"track name", "full path"}; | ||
1527 | fprintf(fd, "playlist viewer track display: %s\r\n", | ||
1528 | options[global_settings.playlist_viewer_track_display]); | ||
1529 | } | ||
1530 | } | ||
1531 | |||
1497 | close(fd); | 1532 | close(fd); |
1498 | 1533 | ||
1499 | lcd_clear_display(); | 1534 | lcd_clear_display(); |
@@ -1596,6 +1631,9 @@ void settings_reset(void) { | |||
1596 | global_settings.show_icons = true; | 1631 | global_settings.show_icons = true; |
1597 | global_settings.recursive_dir_insert = RECURSE_OFF; | 1632 | global_settings.recursive_dir_insert = RECURSE_OFF; |
1598 | global_settings.line_in = false; | 1633 | global_settings.line_in = false; |
1634 | global_settings.playlist_viewer_icons = true; | ||
1635 | global_settings.playlist_viewer_indices = true; | ||
1636 | global_settings.playlist_viewer_track_display = 0; | ||
1599 | } | 1637 | } |
1600 | 1638 | ||
1601 | bool set_bool(char* string, bool* variable ) | 1639 | bool set_bool(char* string, bool* variable ) |
diff --git a/apps/settings.h b/apps/settings.h index 436b5204d5..3634087cab 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -194,6 +194,11 @@ struct user_settings | |||
194 | int recursive_dir_insert; /* should directories be inserted recursively */ | 194 | int recursive_dir_insert; /* should directories be inserted recursively */ |
195 | 195 | ||
196 | bool line_in; /* false=off, true=active */ | 196 | bool line_in; /* false=off, true=active */ |
197 | |||
198 | /* playlist viewer settings */ | ||
199 | bool playlist_viewer_icons; /* display icons on viewer */ | ||
200 | bool playlist_viewer_indices; /* display playlist indices on viewer */ | ||
201 | int playlist_viewer_track_display; /* how to display tracks in viewer */ | ||
197 | }; | 202 | }; |
198 | 203 | ||
199 | enum optiontype { INT, BOOL }; | 204 | enum optiontype { INT, BOOL }; |
diff --git a/apps/settings_menu.c b/apps/settings_menu.c index cf7e55ae5b..24a67adc47 100644 --- a/apps/settings_menu.c +++ b/apps/settings_menu.c | |||
@@ -827,11 +827,11 @@ static bool playback_settings_menu(void) | |||
827 | { | 827 | { |
828 | if (global_settings.playlist_shuffle) | 828 | if (global_settings.playlist_shuffle) |
829 | { | 829 | { |
830 | playlist_randomise(current_tick, true); | 830 | playlist_randomise(NULL, current_tick, true); |
831 | } | 831 | } |
832 | else | 832 | else |
833 | { | 833 | { |
834 | playlist_sort(true); | 834 | playlist_sort(NULL, true); |
835 | } | 835 | } |
836 | } | 836 | } |
837 | return result; | 837 | return result; |
diff --git a/apps/wps-display.c b/apps/wps-display.c index 6553e9b542..a24cae9717 100644 --- a/apps/wps-display.c +++ b/apps/wps-display.c | |||
@@ -499,7 +499,7 @@ static char* get_tag(struct mp3entry* id3, | |||
499 | 499 | ||
500 | case 'n': /* Playlist Name (without path) */ | 500 | case 'n': /* Playlist Name (without path) */ |
501 | *flags |= WPS_REFRESH_STATIC; | 501 | *flags |= WPS_REFRESH_STATIC; |
502 | return playlist_name(buf, buf_size); | 502 | return playlist_name(NULL, buf, buf_size); |
503 | 503 | ||
504 | case 'e': /* Playlist Total Entries */ | 504 | case 'e': /* Playlist Total Entries */ |
505 | *flags |= WPS_REFRESH_STATIC; | 505 | *flags |= WPS_REFRESH_STATIC; |