summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2020-06-28 00:02:20 -0400
committerWilliam Wilgus <me.theuser@yahoo.com>2020-07-14 03:57:56 +0000
commit45915101d5338963e6359258513215a723ba1fd2 (patch)
treed8c2bc95bee3a533efac1185b64e9a39c49f5a9e
parent9adfab9b2b7e054d48697e06d392fc499f215d70 (diff)
downloadrockbox-45915101d5338963e6359258513215a723ba1fd2.tar.gz
rockbox-45915101d5338963e6359258513215a723ba1fd2.zip
Pictureflow Bugfixes & Usability fixes
First I discovered a bug in the code to display the currently playing album from the WPS --on a NULL id3->albumartist field PF would crash now checks for a match in id3->albumartist and then id3->artist if neither exists then the search uses <untagged> ditto for album The album index feature (recently added) did not check for enough room in the buffer on restore --save and restore code cleaned up a bit moved all buffers to their own struct tracks with no title now show filename rather than <UNTAGGED> Reworked album search function album search was going quadriatic resulting in some outrageous index build times [40mins+ for 4000 albums] building now done in stages and duplicates removed at end *MUCH FASTER* Album art empty album art is no longer stored in the art cache PF will now allow you to cancel building album art without forcing a rebuild next run, it will continue searching for album art in the background album art is now updated in the background on each start as well tracklist now rolls over at the end artist_index is now discarded after album_index is created Cleaned up some of the myriad of global variables Added quit prompt for index building Added sanity checking for album_index loaded from disk Change-Id: I8494cb7abcb1ae8645c223fc3c11dc0ee749883a
-rw-r--r--apps/plugins/pictureflow/pictureflow.c1739
1 files changed, 1208 insertions, 531 deletions
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c
index 7d94eeb31f..91174604ea 100644
--- a/apps/plugins/pictureflow/pictureflow.c
+++ b/apps/plugins/pictureflow/pictureflow.c
@@ -236,7 +236,7 @@ typedef fb_data pix_t;
236 236
237#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200 237#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200
238#define CACHE_PREFIX PLUGIN_DEMOS_DATA_DIR "/pictureflow" 238#define CACHE_PREFIX PLUGIN_DEMOS_DATA_DIR "/pictureflow"
239#define ALBUM_INDEX CACHE_PREFIX "/PF_album_idx.tmp" 239#define ALBUM_INDEX CACHE_PREFIX "/pictureflow_album.idx"
240 240
241#define EV_EXIT 9999 241#define EV_EXIT 9999
242#define EV_WAKEUP 1337 242#define EV_WAKEUP 1337
@@ -250,16 +250,83 @@ typedef fb_data pix_t;
250#define CACHE_UPDATE 1 250#define CACHE_UPDATE 1
251 251
252/* Error return values */ 252/* Error return values */
253#define SUCCESS 0
253#define ERROR_NO_ALBUMS -1 254#define ERROR_NO_ALBUMS -1
254#define ERROR_BUFFER_FULL -2 255#define ERROR_BUFFER_FULL -2
255#define ERROR_NO_ARTISTS -3 256#define ERROR_NO_ARTISTS -3
257#define ERROR_USER_ABORT -4
256 258
257/* current version for cover cache */ 259/* current version for cover cache */
258#define CACHE_VERSION 3 260#define CACHE_VERSION 3
259#define CONFIG_VERSION 1 261#define CONFIG_VERSION 1
260#define CONFIG_FILE "pictureflow.cfg" 262#define CONFIG_FILE "pictureflow.cfg"
263#define INDEX_HDR "PFID"
261 264
262/** structs we use */ 265/** structs we use */
266struct pf_config_t
267{
268 /* config values */
269 int slide_spacing;
270 int center_margin;
271
272 int num_slides;
273 int zoom;
274
275 int auto_wps;
276 int last_album;
277
278 int backlight_mode;
279 int cache_version;
280
281 int show_album_name;
282 bool resize;
283 bool show_fps;
284};
285
286struct pf_index_t {
287 uint32_t header; /*INDEX_HDR*/
288 uint16_t artist_ct;
289 uint16_t album_ct;
290
291 char *artist_names;
292 struct artist_data *artist_index;
293 size_t artist_len;
294
295 unsigned int album_untagged_idx;
296 char *album_names;
297 struct album_data *album_index;
298 size_t album_len;
299 long album_untagged_seek;
300
301 void * buf;
302 size_t buf_sz;
303};
304
305struct pf_track_t {
306 int count;
307 int cur_idx;
308 int sel;
309 int sel_pulse;
310 int last_sel;
311 int list_start;
312 int list_visible;
313 int list_y;
314 int list_h;
315 size_t borrowed;
316 struct track_data *index;
317 char *names;
318};
319
320struct albumart_t {
321 struct bitmap input_bmp;
322 char pfraw_file[MAX_PATH];
323 char file[MAX_PATH];
324 int idx;
325 int slides;
326 int inspected;
327 void * buf;
328 size_t buf_sz;
329};
263 330
264struct slide_data { 331struct slide_data {
265 int slide_index; 332 int slide_index;
@@ -277,14 +344,15 @@ struct slide_cache {
277}; 344};
278 345
279struct album_data { 346struct album_data {
280 int name_idx; 347 int name_idx; /* offset to the album name */
281 int artist_idx; 348 int artist_idx; /* offset to the artist name */
282 long seek; 349 long artist_seek; /* artist taglist position */
350 long seek; /* album taglist position */
283}; 351};
284 352
285struct artist_data { 353struct artist_data {
286 int name_idx; 354 int name_idx; /* offset to the artist name */
287 long seek; 355 long seek; /* artist taglist position */
288}; 356};
289 357
290struct track_data { 358struct track_data {
@@ -309,6 +377,16 @@ struct load_slide_event_data {
309 int cache_index; 377 int cache_index;
310}; 378};
311 379
380struct pf_slide_cache
381{
382 struct slide_cache cache[SLIDE_CACHE_SIZE];
383 int free;
384 int used;
385 int left_idx;
386 int right_idx;
387 int center_idx;
388};
389
312enum pf_scroll_line_type { 390enum pf_scroll_line_type {
313 PF_SCROLL_TRACK = 0, 391 PF_SCROLL_TRACK = 0,
314 PF_SCROLL_ALBUM, 392 PF_SCROLL_ALBUM,
@@ -354,37 +432,27 @@ static char* show_album_name_conf[] =
354#define MAX_SPACING 40 432#define MAX_SPACING 40
355#define MAX_MARGIN 80 433#define MAX_MARGIN 80
356 434
357/* config values and their defaults */ 435static struct albumart_t aa_cache;
358static int slide_spacing = DISPLAY_WIDTH / 4; 436static struct pf_config_t pf_cfg;
359static int center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12;
360static int num_slides = 4;
361static int zoom = 100;
362static bool show_fps = false;
363static int auto_wps = 0;
364static int last_album = 0;
365static int backlight_mode = 0;
366static bool resize = true;
367static int cache_version = 0;
368static int show_album_name = (LCD_HEIGHT > 100)
369 ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM;
370 437
371static struct configdata config[] = 438static struct configdata config[] =
372{ 439{
373 { TYPE_INT, 0, MAX_SPACING, { .int_p = &slide_spacing }, "slide spacing", 440 { TYPE_INT, 0, MAX_SPACING, { .int_p = &pf_cfg.slide_spacing }, "slide spacing",
374 NULL }, 441 NULL },
375 { TYPE_INT, 0, MAX_MARGIN, { .int_p = &center_margin }, "center margin", 442 { TYPE_INT, 0, MAX_MARGIN, { .int_p = &pf_cfg.center_margin }, "center margin",
376 NULL }, 443 NULL },
377 { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &num_slides }, "slides count", 444 { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &pf_cfg.num_slides }, "slides count",
378 NULL }, 445 NULL },
379 { TYPE_INT, 0, 300, { .int_p = &zoom }, "zoom", NULL }, 446 { TYPE_INT, 0, 300, { .int_p = &pf_cfg.zoom }, "zoom", NULL },
380 { TYPE_BOOL, 0, 1, { .bool_p = &show_fps }, "show fps", NULL }, 447 { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.show_fps }, "show fps", NULL },
381 { TYPE_BOOL, 0, 1, { .bool_p = &resize }, "resize", NULL }, 448 { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.resize }, "resize", NULL },
382 { TYPE_INT, 0, 100, { .int_p = &cache_version }, "cache version", NULL }, 449 { TYPE_INT, 0, 100, { .int_p = &pf_cfg.cache_version }, "cache version", NULL },
383 { TYPE_ENUM, 0, 5, { .int_p = &show_album_name }, "show album name", 450 { TYPE_ENUM, 0, 5, { .int_p = &pf_cfg.show_album_name }, "show album name",
384 show_album_name_conf }, 451 show_album_name_conf },
385 { TYPE_INT, 0, 2, { .int_p = &auto_wps }, "auto wps", NULL }, 452 { TYPE_INT, 0, 2, { .int_p = &pf_cfg.auto_wps }, "auto wps", NULL },
386 { TYPE_INT, 0, 999999, { .int_p = &last_album }, "last album", NULL }, 453 { TYPE_INT, 0, 999999, { .int_p = &pf_cfg.last_album }, "last album", NULL },
387 { TYPE_INT, 0, 1, { .int_p = &backlight_mode }, "backlight", NULL } 454 { TYPE_INT, 0, 1, { .int_p = &pf_cfg.backlight_mode }, "backlight", NULL },
455 { TYPE_INT, 0, 999999, { .int_p = &aa_cache.idx }, "art cache pos", NULL },
388}; 456};
389 457
390#define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata)) 458#define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata))
@@ -406,12 +474,7 @@ static PFreal offsetX;
406static PFreal offsetY; 474static PFreal offsetY;
407static int number_of_slides; 475static int number_of_slides;
408 476
409static struct slide_cache cache[SLIDE_CACHE_SIZE]; 477static struct pf_slide_cache pf_sldcache;
410static int cache_free;
411static int cache_used = -1;
412static int cache_left_index = -1;
413static int cache_right_index = -1;
414static int cache_center_index = -1;
415 478
416/* use long for aligning */ 479/* use long for aligning */
417unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; 480unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)];
@@ -426,29 +489,12 @@ static struct tagcache_search tcs;
426 489
427static struct buflib_context buf_ctx; 490static struct buflib_context buf_ctx;
428 491
429static struct album_data *album; 492static struct pf_index_t pf_idx;
430static struct artist_data *artist;
431 493
432static char *album_names; 494static struct pf_track_t pf_tracks;
433static int album_count;
434 495
435static char *artist_names;
436static int artist_count;
437
438static struct track_data *tracks;
439static char *track_names;
440static size_t borrowed = 0;
441static int track_count;
442static int track_index;
443static int selected_track;
444static int selected_track_pulse;
445void reset_track_list(void); 496void reset_track_list(void);
446 497
447void * buf;
448size_t buf_size;
449void * uniqbuf;
450size_t uniqbuf_size;
451
452static bool thread_is_running; 498static bool thread_is_running;
453 499
454static int cover_animation_keyframe; 500static int cover_animation_keyframe;
@@ -456,14 +502,8 @@ static int extra_fade;
456 502
457static struct pf_scroll_line_info scroll_line_info; 503static struct pf_scroll_line_info scroll_line_info;
458static struct pf_scroll_line scroll_lines[PF_MAX_SCROLL_LINES]; 504static struct pf_scroll_line scroll_lines[PF_MAX_SCROLL_LINES];
459static int prev_albumtxt_index = -1;
460static int last_selected_track = -1;
461
462static int start_index_track_list = 0;
463static int track_list_visible_entries = 0;
464static int track_list_y;
465static int track_list_h;
466 505
506enum ePFS{ePFS_ARTIST = 0, ePFS_ALBUM};
467/* 507/*
468 Proposals for transitions: 508 Proposals for transitions:
469 509
@@ -494,6 +534,45 @@ static int pf_state;
494static bool free_slide_prio(int prio); 534static bool free_slide_prio(int prio);
495bool load_new_slide(void); 535bool load_new_slide(void);
496int load_surface(int); 536int load_surface(int);
537static void draw_progressbar(int step, int count, char *msg);
538static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size);
539static void free_all_slide_prio(int prio);
540
541static bool confirm_quit(void)
542{
543 const struct text_message prompt =
544 { (const char*[]) {"Quit?", "Progress will be lost"}, 2};
545 enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL);
546 while (rb->button_get(false) == BUTTON_NONE)
547 ;;
548
549 if(response == YESNO_NO)
550 return false;
551 else
552 return true;
553}
554
555static void config_save(int cache_version)
556{
557 pf_cfg.cache_version = cache_version;
558 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
559}
560
561static void config_set_defaults(struct pf_config_t *cfg)
562{
563 cfg->slide_spacing = DISPLAY_WIDTH / 4;
564 cfg->center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12;
565 cfg->num_slides = 4;
566 cfg->zoom = 100;
567 cfg->show_fps = false;
568 cfg->auto_wps = 0;
569 cfg->last_album = 0;
570 cfg->backlight_mode = 0;
571 cfg->resize = true;
572 cfg->cache_version = 0;
573 cfg->show_album_name = (LCD_HEIGHT > 100)
574 ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM;
575}
497 576
498static inline PFreal fmul(PFreal a, PFreal b) 577static inline PFreal fmul(PFreal a, PFreal b)
499{ 578{
@@ -849,135 +928,538 @@ static void init_reflect_table(void)
849 (5 * REFLECT_HEIGHT); 928 (5 * REFLECT_HEIGHT);
850} 929}
851 930
852/** 931static int compare_album_artists (const void *a_v, const void *b_v)
853 Create an index of all artists and albums from the database.
854 Also store the artists and album names so we can access them later.
855 */
856static int create_album_index(void)
857{ 932{
858 artist = ((struct artist_data *)(buf_size + (char *) buf)) - 1; 933 uint32_t a = ((struct album_data *)a_v)->artist_idx;
859 rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); 934 uint32_t b = ((struct album_data *)b_v)->artist_idx;
860 artist_count = 0; 935 return (int)(a - b);
861 rb->tagcache_search(&tcs, tag_albumartist); 936}
937
938static void write_album_index(int idx, int name_idx,
939 long album_seek, int artist_idx, long artist_seek)
940{
941 pf_idx.album_index[idx].name_idx = name_idx;
942 pf_idx.album_index[idx].seek = album_seek;
943 pf_idx.album_index[idx].artist_idx = artist_idx;
944 pf_idx.album_index[idx].artist_seek = artist_seek;
945}
946
947static inline void write_album_entry(struct tagcache_search *tcs,
948 int name_idx, unsigned int len)
949{
950 write_album_index(-pf_idx.album_ct, name_idx, tcs->result_seek, 0, -1);
951 pf_idx.album_len += len;
952 pf_idx.album_ct++;
953
954 if (pf_idx.album_untagged_seek == -1 && rb->strcmp(UNTAGGED, tcs->result) == 0)
955 {
956 pf_idx.album_untagged_idx = name_idx;
957 pf_idx.album_untagged_seek = tcs->result_seek;
958 }
959}
960
961static void write_artist_entry(struct tagcache_search *tcs,
962 int name_idx, unsigned int len)
963{
964 pf_idx.artist_index[-pf_idx.artist_ct].name_idx = name_idx;
965 pf_idx.artist_index[-pf_idx.artist_ct].seek = tcs->result_seek;
966 pf_idx.artist_len += len;
967 pf_idx.artist_ct++;
968}
969
970/* adds tagcache_search results into artist/album index */
971static int get_tcs_search_res(int type, struct tagcache_search *tcs,
972 void **buf, size_t *bufsz)
973{
974 int ret = SUCCESS;
862 unsigned int l, name_idx = 0; 975 unsigned int l, name_idx = 0;
863 artist_names = buf; 976 void (*writefn)(struct tagcache_search *, int, unsigned int);
864 while (rb->tagcache_get_next(&tcs)) 977 int data_size;
978 if (type == ePFS_ARTIST)
979 {
980 writefn = &write_artist_entry;
981 data_size = sizeof(struct artist_data);
982 }
983 else
984 {
985 writefn = &write_album_entry;
986 data_size = sizeof(struct album_data);
987 }
988
989 while (rb->tagcache_get_next(tcs))
865 { 990 {
866 buf_size -= sizeof(struct artist_data); 991 if (rb->button_get(false) > BUTTON_NONE)
867 l = tcs.result_len; 992 {
868 artist[-artist_count].name_idx = name_idx; 993 if (confirm_quit())
869 artist[-artist_count].seek = tcs.result_seek; 994 {
870 if ( l > buf_size ) 995 ret = ERROR_USER_ABORT;
996 break;
997 } else
998 rb->lcd_clear_display();
999 }
1000
1001 *bufsz -= data_size;
1002
1003 l = tcs->result_len;
1004
1005 if ( l > *bufsz )
1006 {
871 /* not enough memory */ 1007 /* not enough memory */
872 return ERROR_BUFFER_FULL; 1008 ret = ERROR_BUFFER_FULL;
873 rb->strcpy(buf, tcs.result); 1009 break;
874 buf_size -= l; 1010 }
875 buf = l + (char *)buf; 1011
1012 rb->strcpy(*buf, tcs->result);
1013
1014 *bufsz -= l;
1015 *buf = l + (char *)*buf;
1016
1017 writefn(tcs, name_idx, l);
1018
876 name_idx += l; 1019 name_idx += l;
877 artist_count++;
878 } 1020 }
1021 rb->tagcache_search_finish(tcs);
1022 return ret;
1023}
1024
1025/*adds <untagged> albums/artist to existing album index */
1026static int create_album_untagged(struct tagcache_search *tcs,
1027 void **buf, size_t *bufsz)
1028{
1029 int ret = SUCCESS;
1030 int album_count = pf_idx.album_ct; /* store existing count */
1031 int total_count = pf_idx.album_ct + pf_idx.artist_ct * 2;
1032 long seek;
1033 int last, final, retry;
1034 int i, j;
1035 draw_splashscreen(*buf, *bufsz);
1036 draw_progressbar(0, total_count, "Searching " UNTAGGED);
1037
1038 /* search tagcache for all <untagged> albums & save the albumartist seek pos */
1039 if (rb->tagcache_search(tcs, tag_albumartist))
1040 {
1041 rb->tagcache_search_add_filter(tcs, tag_album, pf_idx.album_untagged_seek);
1042
1043 while (rb->tagcache_get_next(tcs))
1044 {
1045 if (rb->button_get(false) > BUTTON_NONE) {
1046 if (confirm_quit())
1047 return ERROR_USER_ABORT;
1048 else
1049 {
1050 rb->lcd_clear_display();
1051 draw_progressbar(pf_idx.album_ct, total_count,
1052 "Searching " UNTAGGED);
1053 }
1054 }
1055
1056 if (tcs->result_seek ==
1057 pf_idx.album_index[-(pf_idx.album_ct - 1)].artist_seek)
1058 continue;
1059
1060 if (sizeof(struct album_data) > *bufsz)
1061 {
1062 /* not enough memory */
1063 ret = ERROR_BUFFER_FULL;
1064 break;
1065 }
1066
1067 *bufsz -= sizeof(struct album_data);
1068 write_album_index(-pf_idx.album_ct, pf_idx.album_untagged_idx,
1069 pf_idx.album_untagged_seek, -1, tcs->result_seek);
1070
1071 pf_idx.album_ct++;
1072 draw_progressbar(pf_idx.album_ct, total_count, NULL);
1073 }
1074 rb->tagcache_search_finish(tcs);
1075
1076 if (ret == SUCCESS) {
1077 draw_splashscreen(*buf, *bufsz);
1078 draw_progressbar(0, pf_idx.album_ct, "Finalizing " UNTAGGED);
1079
1080 last = 0;
1081 final = pf_idx.artist_ct;
1082 retry = 0;
1083
1084 /* map the artist_seek position to the artist name index */
1085 for (j = album_count; j < pf_idx.album_ct; j++)
1086 {
1087 if (rb->button_get(false) > BUTTON_NONE) {
1088 if (confirm_quit())
1089 return ERROR_USER_ABORT;
1090 else
1091 {
1092 rb->lcd_clear_display();
1093 draw_progressbar(j, pf_idx.album_ct, "Finalizing " UNTAGGED);
1094 }
1095 }
1096
1097 draw_progressbar(j, pf_idx.album_ct, NULL);
1098 seek = pf_idx.album_index[-j].artist_seek;
1099
1100 retry_artist_lookup:
1101 retry++;
1102 for (i = last; i < final; i++)
1103 {
1104 if (seek == pf_idx.artist_index[i].seek)
1105 {
1106 int idx = pf_idx.artist_index[i].name_idx;
1107 pf_idx.album_index[-j].artist_idx = idx;
1108 last = i; /* last match, start here next loop */
1109 final = pf_idx.artist_ct;
1110 retry = 0;
1111 break;
1112 }
1113 }
1114 if (retry > 0 && retry < 2)
1115 {
1116 /* no match start back at beginning */
1117 final = last;
1118 last = 0;
1119 goto retry_artist_lookup;
1120 }
1121 }
1122 }
1123 }
1124
1125 return ret;
1126}
1127
1128/* Create an index of all artists from the database */
1129static int build_artist_index(struct tagcache_search *tcs,
1130 void **buf, size_t *bufsz)
1131{
1132 int i, res = SUCCESS;
1133 struct artist_data* tmp_artist;
1134
1135 /* artist index starts at end of buf it will be rearranged when finalized */
1136 pf_idx.artist_index = ((struct artist_data *)(*bufsz + (char *) *buf)) - 1;
1137 pf_idx.artist_ct = 0;
1138 pf_idx.artist_len = 0;
1139 /* artist names starts at beginning of buf */
1140 pf_idx.artist_names = *buf;
1141
1142 rb->tagcache_search(tcs, tag_albumartist);
1143 res = get_tcs_search_res(ePFS_ARTIST, tcs, &(*buf), bufsz);
1144 rb->tagcache_search_finish(tcs);
1145 if (res < SUCCESS)
1146 return res;
1147
1148 ALIGN_BUFFER(*buf, *bufsz, 4);
1149
1150 /* finalize the artist index */
1151 tmp_artist = (struct artist_data*)*buf;
1152 for (i = pf_idx.artist_ct - 1; i >= 0; i--)
1153 tmp_artist[i] = pf_idx.artist_index[-i];
1154
1155 pf_idx.artist_index = tmp_artist;
1156 /* move buf ptr to end of artist_index */
1157 *buf = pf_idx.artist_index + pf_idx.artist_ct;
1158 ALIGN_BUFFER(*buf, *bufsz, 4);
1159
1160 if (res == SUCCESS)
1161 {
1162 if (pf_idx.artist_ct > 0)
1163 res = pf_idx.artist_ct;
1164 else
1165 res = ERROR_NO_ALBUMS;
1166 }
1167
1168 return res;
1169}
1170
1171
1172/**
1173 Create an index of all artists and albums from the database.
1174 Also store the artists and album names so we can access them later.
1175 */
1176static int create_album_index(void)
1177{
1178 void *buf = pf_idx.buf;
1179 size_t buf_size = pf_idx.buf_sz;
1180
1181 struct album_data* tmp_album;
1182
1183 int i, j, last, final, retry, res;
1184
1185 draw_splashscreen(buf, buf_size);
1186 ALIGN_BUFFER(buf, buf_size, 4);
1187
1188/* Artists */
1189 res = build_artist_index(&tcs, &buf, &buf_size);
1190 if (res < SUCCESS)
1191 return res;
1192
1193/* Albums */
1194 pf_idx.album_ct = 0;
1195 pf_idx.album_len =0;
1196 pf_idx.album_untagged_idx = 0;
1197 pf_idx.album_untagged_seek = -1;
1198
1199 /* album_index starts at end of buf it will be rearranged when finalized */
1200 pf_idx.album_index = ((struct album_data *)(buf_size + (char *)buf)) - 1;
1201 /* album_names starts at the beginning of buf */
1202 pf_idx.album_names = buf;
1203
1204 rb->tagcache_search(&tcs, tag_album);
1205 res = get_tcs_search_res(ePFS_ALBUM, &tcs, &buf, &buf_size);
879 rb->tagcache_search_finish(&tcs); 1206 rb->tagcache_search_finish(&tcs);
1207 if (res < SUCCESS)
1208 return res;
880 ALIGN_BUFFER(buf, buf_size, 4); 1209 ALIGN_BUFFER(buf, buf_size, 4);
881 int i; 1210
882 struct artist_data* tmp_artist = (struct artist_data*)buf; 1211 /* Build artist list for untagged albums */
883 for (i = artist_count - 1; i >= 0; i--) 1212 res = create_album_untagged(&tcs, &buf, &buf_size);
884 tmp_artist[i] = artist[-i]; 1213
885 artist = tmp_artist; 1214 if (res < SUCCESS)
886 buf = artist + artist_count; 1215 return res;
887 1216
888 long artist_seek = 0; 1217 ALIGN_BUFFER(buf, buf_size, 4);
889 int j = 0; 1218
890 album_count = 0; 1219 /* finalize the album index */
891 name_idx = 0; 1220 tmp_album = (struct album_data*)buf;
892 album = ((struct album_data *)(buf_size + (char *) buf)) - 1; 1221 for (i = pf_idx.album_ct - 1; i >= 0; i--)
893 album_names = buf; 1222 tmp_album[i] = pf_idx.album_index[-i];
894 for (j = 0; j < artist_count; j++){ 1223
895 artist_seek = artist[j].seek; 1224 pf_idx.album_index = tmp_album;
896 rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); 1225 /* move buf ptr to end of album_index */
897 rb->tagcache_search(&tcs, tag_album); 1226 buf = pf_idx.album_index + pf_idx.album_ct;
898 /* Prevent duplicate entries in the search list. */ 1227 ALIGN_BUFFER(buf, buf_size, 4);
899 rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, uniqbuf_size); 1228
900 rb->tagcache_search_add_filter(&tcs, tag_albumartist, artist_seek); 1229/* Assign indices */
901 while (rb->tagcache_get_next(&tcs)) 1230 draw_splashscreen(buf, buf_size);
1231 draw_progressbar(0, pf_idx.album_ct, "Assigning Albums");
1232 for (j = 0; j < pf_idx.album_ct; j++)
1233 {
1234 if (rb->button_get(false) > BUTTON_NONE)
1235 {
1236 if (confirm_quit())
1237 return ERROR_USER_ABORT;
1238 else
1239 {
1240 rb->lcd_clear_display();
1241 draw_progressbar(j, pf_idx.album_ct, "Assigning Albums");
1242 }
1243
1244 }
1245
1246 draw_progressbar(j, pf_idx.album_ct, NULL);
1247 if (pf_idx.album_index[j].artist_seek >= 0) { continue; }
1248
1249 rb->tagcache_search(&tcs, tag_albumartist);
1250 rb->tagcache_search_add_filter(&tcs, tag_album, pf_idx.album_index[j].seek);
1251
1252 last = 0;
1253 final = pf_idx.artist_ct;
1254 retry = 0;
1255 if (rb->tagcache_get_next(&tcs))
902 { 1256 {
903 buf_size -= sizeof(struct album_data);
904 l = tcs.result_len;
905 album[-album_count].name_idx = name_idx;
906 album[-album_count].seek = tcs.result_seek;
907 album[-album_count].artist_idx = j;
908 if ( l > buf_size )
909 /* not enough memory */
910 return ERROR_BUFFER_FULL;
911 1257
912 rb->strcpy(buf, tcs.result); 1258retry_artist_lookup:
913 buf_size -= l; 1259 retry++;
914 buf = l + (char *)buf; 1260 for (i = last; i < final; i++)
915 name_idx += l; 1261 {
916 album_count++; 1262 if (tcs.result_seek == pf_idx.artist_index[i].seek)
1263 {
1264 int idx = pf_idx.artist_index[i].name_idx;
1265 pf_idx.album_index[j].artist_idx = idx;
1266 pf_idx.album_index[j].artist_seek = tcs.result_seek;
1267 last = i; /* last match, start here next loop */
1268 final = pf_idx.artist_ct;
1269 retry = 0;
1270 break;
1271 }
1272 }
1273 if (retry > 0 && retry < 2)
1274 {
1275 /* no match start back at beginning */
1276 final = last;
1277 last = 0;
1278 goto retry_artist_lookup;
1279 }
917 } 1280 }
918 rb->tagcache_search_finish(&tcs); 1281 rb->tagcache_search_finish(&tcs);
919 } 1282 }
1283 /* sort list order to find duplicates */
1284 rb->qsort(pf_idx.album_index, pf_idx.album_ct,
1285 sizeof(struct album_data), compare_album_artists);
1286
1287 draw_splashscreen(buf, buf_size);
1288 draw_progressbar(0, pf_idx.album_ct, "Removing duplicates");
1289 /* mark duplicate albums for deletion */
1290 for (i = 0; i < pf_idx.album_ct - 1; i++) /* -1 don't check last entry */
1291 {
1292 int idxi = pf_idx.album_index[i].artist_idx;
1293 int seeki = pf_idx.album_index[i].seek;
1294
1295 draw_progressbar(i, pf_idx.album_ct, NULL);
1296 for (j = i + 1; j < pf_idx.album_ct; j++)
1297 {
1298 if (idxi > 0 &&
1299 idxi == pf_idx.album_index[j].artist_idx &&
1300 seeki == pf_idx.album_index[j].seek)
1301 {
1302 pf_idx.album_index[j].artist_idx = -1;
1303 }
1304 else
1305 {
1306 i = j - 1;
1307 break;
1308 }
1309 }
1310 }
1311
1312 /* now fix the album list order */
1313 rb->qsort(pf_idx.album_index, pf_idx.album_ct,
1314 sizeof(struct album_data), compare_album_artists);
1315
1316 /* remove any extra untagged albums
1317 * extra space is orphaned till restart */
1318 for (i = 0; i < pf_idx.album_ct; i++)
1319 {
1320 if (pf_idx.album_index[i].artist_idx > 0)
1321 {
1322 if (i > 0) { i--; }
1323 pf_idx.album_index += i;
1324 pf_idx.album_ct -= i;
1325 break;
1326 }
1327 }
1328
920 ALIGN_BUFFER(buf, buf_size, 4); 1329 ALIGN_BUFFER(buf, buf_size, 4);
921 struct album_data* tmp_album = (struct album_data*)buf; 1330 pf_idx.buf = buf;
922 for (i = album_count - 1; i >= 0; i--) 1331 pf_idx.buf_sz = buf_size;
923 tmp_album[i] = album[-i]; 1332 pf_idx.artist_index = 0;
924 album = tmp_album;
925 buf = album + album_count;
926 1333
927 return (album_count > 0) ? 0 : ERROR_NO_ALBUMS; 1334 return (pf_idx.album_ct > 0) ? 0 : ERROR_NO_ALBUMS;
928} 1335}
929 1336
930 1337/*Saves the album index into a binary file to be recovered the
931/*Saves the artists+albums index into a binary file to be recovered the
932 next time PictureFlow is launched*/ 1338 next time PictureFlow is launched*/
933 1339
934static int save_album_index(void){ 1340static int save_album_index(void){
935 int fd = rb->creat(ALBUM_INDEX,0666); 1341 int fd = rb->creat(ALBUM_INDEX,0666);
1342
1343 struct pf_index_t data;
1344 memcpy(&data, &pf_idx, sizeof(struct pf_index_t));
1345
936 if(fd >= 0) 1346 if(fd >= 0)
937 { 1347 {
938 int unsigned_size = sizeof(unsigned int); 1348 rb->memcpy(&data.header, INDEX_HDR, sizeof(pf_idx.header));
939 int int_size = sizeof(int); 1349
940 rb->write(fd, artist_names, ((char *)buf - (char *)artist_names)); 1350 rb->write(fd, &data, sizeof(struct pf_index_t));
941 unsigned int artist_pos = (char *)artist - (char *)artist_names; 1351
942 rb->write(fd, &artist_pos, unsigned_size); 1352 rb->write(fd, data.artist_names, data.artist_len);
943 unsigned int album_names_pos = (char *)album_names - (char *)artist_names; 1353 rb->write(fd, data.album_names, data.album_len);
944 rb->write(fd, &album_names_pos, unsigned_size); 1354
945 unsigned int album_pos = (char *)album - (char *)artist_names; 1355 rb->write(fd, data.album_index, data.album_ct * sizeof(struct album_data));
946 rb->write(fd, &album_pos, unsigned_size); 1356
947 rb->write(fd, &artist_count, int_size);
948 rb->write(fd, &album_count, int_size);
949 rb->close(fd); 1357 rb->close(fd);
950 return 0; 1358 return 0;
951 } 1359 }
952 return -1; 1360 return -1;
953} 1361}
954 1362
955/*Loads the artists+albums index information stored in the hard drive*/ 1363/* reads data from save file to buffer */
1364static inline int read2buf(int fildes, void *buf, size_t nbyte){
1365 int read;
1366 read = rb->read(fildes, buf, nbyte);
1367 if (read < (int)nbyte)
1368 return 0;
1369
1370 return read;
1371}
956 1372
1373/*Loads the album_index information stored in the hard drive*/
957static int load_album_index(void){ 1374static int load_album_index(void){
958 int fr = rb->open(ALBUM_INDEX, O_RDONLY); 1375
1376 int i, fr = rb->open(ALBUM_INDEX, O_RDONLY);
1377 struct pf_index_t data;
1378
1379 void *bufstart = pf_idx.buf;
1380 unsigned int bufstart_sz = pf_idx.buf_sz;
1381
1382 void* buf = pf_idx.buf;
1383 size_t buf_size = pf_idx.buf_sz;
1384
1385 unsigned int name_sz, album_idx_sz;
1386 int album_idx, artist_idx;
1387
959 if (fr >= 0){ 1388 if (fr >= 0){
960 int unsigned_size = sizeof(unsigned int); 1389 const unsigned long filesize = rb->filesize(fr);
961 int int_size = sizeof(int); 1390 if (filesize > sizeof(data))
962 unsigned long filesize = rb->filesize(fr); 1391 {
963 unsigned int pos = 0; 1392 if (rb->read(fr, &data, sizeof(data)) == sizeof(data) &&
964 unsigned int extra_data_size = (sizeof(unsigned int)*3) + (sizeof(int)*2); 1393 rb->memcmp(&(data.header), INDEX_HDR, sizeof(data.header)) == 0)
965 rb->read(fr,buf ,filesize-extra_data_size); 1394 {
966 artist_names = buf; 1395 name_sz = data.artist_len + data.album_len;
967 buf = (char *)buf + (filesize-extra_data_size); 1396 album_idx_sz = data.album_ct * sizeof(struct album_data);
968 buf_size = buf_size-(filesize-extra_data_size); 1397
969 rb->read(fr,&pos ,unsigned_size); 1398 if (name_sz + album_idx_sz > bufstart_sz)
970 artist = (void *)artist_names + pos; 1399 goto failure;
971 rb->read(fr,&pos ,unsigned_size); 1400
972 album_names = (void *)artist_names + pos; 1401 //rb->lseek(fr, sizeof(data) + 1, SEEK_SET);
973 rb->read(fr,&pos ,unsigned_size); 1402 /* artist names */
974 album = (void *)artist_names + pos; 1403 ALIGN_BUFFER(buf, buf_size, 4);
975 rb->read(fr,&artist_count ,int_size); 1404 if (read2buf(fr, buf, data.artist_len) == 0)
976 rb->read(fr,&album_count ,int_size); 1405 goto failure;
977 rb->close(fr); 1406
978 return 0; 1407 data.artist_names = buf;
1408 buf = (char *)buf + data.artist_len;
1409 buf_size -= data.artist_len;
1410
1411 /* album names */
1412 ALIGN_BUFFER(buf, buf_size, 4);
1413 if (read2buf(fr, buf, data.album_len) == 0)
1414 goto failure;
1415
1416 data.album_names = buf;
1417 buf = (char *)buf + data.album_len;
1418 buf_size -= data.album_len;
1419
1420 /* index of album names */
1421 ALIGN_BUFFER(buf, buf_size, 4);
1422 if (read2buf(fr, buf, album_idx_sz) == 0)
1423 goto failure;
1424
1425 data.album_index = buf;
1426 buf = (char *)buf + album_idx_sz;
1427 buf_size -= album_idx_sz;
1428
1429 rb->close(fr);
1430
1431 /* sanity check loaded data */
1432 for (i = 0; i < data.album_ct; i++)
1433 {
1434 album_idx = data.album_index[i].name_idx;
1435 artist_idx = data.album_index[i].artist_idx;
1436 if (album_idx >= (int) data.album_len ||
1437 artist_idx >= (int) data.artist_len)
1438 {
1439 goto failure;
1440 }
1441 }
1442
1443 memcpy(&pf_idx, &data, sizeof(struct pf_index_t));
1444 pf_idx.buf = buf;
1445 pf_idx.buf_sz = buf_size;
1446
1447 return 0;
1448 }
1449 }
979 } 1450 }
1451
1452failure:
1453 rb->splash(HZ/2, "Failed to load index");
1454 if (fr >= 0)
1455 rb->close(fr);
1456
1457 pf_idx.buf = bufstart;
1458 pf_idx.buf_sz = bufstart_sz;
1459 pf_idx.artist_ct = 0;
1460 pf_idx.album_ct = 0;
980 return -1; 1461 return -1;
1462
981} 1463}
982 1464
983/** 1465/**
@@ -985,7 +1467,18 @@ static int load_album_index(void){
985 */ 1467 */
986static char* get_album_name(const int slide_index) 1468static char* get_album_name(const int slide_index)
987{ 1469{
988 return album_names + album[slide_index].name_idx; 1470 char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx;
1471 return name;
1472}
1473
1474/**
1475 Return a pointer to the album name of the given slide_index
1476 */
1477static char* get_album_name_idx(const int slide_index, int *idx)
1478{
1479 *idx = pf_idx.album_index[slide_index].name_idx;
1480 char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx;
1481 return name;
989} 1482}
990 1483
991/** 1484/**
@@ -993,13 +1486,14 @@ static char* get_album_name(const int slide_index)
993 */ 1486 */
994static char* get_album_artist(const int slide_index) 1487static char* get_album_artist(const int slide_index)
995{ 1488{
996 if (slide_index < album_count && slide_index >= 0){ 1489 if (slide_index < pf_idx.album_ct && slide_index >= 0){
997 int artist_pos = album[slide_index].artist_idx; 1490 int idx = pf_idx.album_index[slide_index].artist_idx;
998 if (artist_pos < artist_count && artist_pos >= 0){ 1491 if (idx >= 0 && idx < (int) pf_idx.artist_len) {
999 return artist_names + artist[artist_pos].name_idx; 1492 char *name = pf_idx.artist_names + idx;
1493 return name;
1000 } 1494 }
1001 } 1495 }
1002 return NULL; 1496 return "?";
1003} 1497}
1004 1498
1005 1499
@@ -1009,34 +1503,54 @@ static char* get_album_artist(const int slide_index)
1009 */ 1503 */
1010static char* get_track_name(const int track_index) 1504static char* get_track_name(const int track_index)
1011{ 1505{
1012 if ( track_index < track_count ) 1506 if (track_index >= 0 && track_index < pf_tracks.count )
1013 return track_names + tracks[track_index].name_idx; 1507 return pf_tracks.names + pf_tracks.index[track_index].name_idx;
1014 return 0; 1508 return 0;
1015} 1509}
1016#if PF_PLAYBACK_CAPABLE 1510#if PF_PLAYBACK_CAPABLE
1017static char* get_track_filename(const int track_index) 1511static char* get_track_filename(const int track_index)
1018{ 1512{
1019 if ( track_index < track_count ) 1513 if ( track_index < pf_tracks.count )
1020 return track_names + tracks[track_index].filename_idx; 1514 return pf_tracks.names + pf_tracks.index[track_index].filename_idx;
1021 return 0; 1515 return 0;
1022} 1516}
1023#endif 1517#endif
1024 1518
1025static int get_wps_current_index(void) 1519static int get_wps_current_index(void)
1026{ 1520{
1521 char* current_artist = UNTAGGED;
1522 char* current_album = UNTAGGED;
1027 struct mp3entry *id3 = rb->audio_current_track(); 1523 struct mp3entry *id3 = rb->audio_current_track();
1028 1524
1029 if(id3 && id3->album) { 1525 if(id3)
1526 {
1527 /* we could be looking for the artist in either field */
1528 if(id3->albumartist)
1529 current_artist = id3->albumartist;
1530 else if(id3->artist)
1531 current_artist = id3->artist;
1532
1533 if (id3->album && rb->strlen(id3->album) > 0)
1534 current_album = id3->album;
1535
1536 //rb->splashf(1000, "%s, %s", current_album, current_artist);
1537
1030 int i; 1538 int i;
1031 for( i=0; i < album_count; i++ ) 1539 int album_idx, artist_idx;
1540
1541 for (i = 0; i < pf_idx.album_ct; i++ )
1032 { 1542 {
1033 if(!rb->strcmp(album_names + album[i].name_idx, id3->album) && 1543 album_idx = pf_idx.album_index[i].name_idx;
1034 !rb->strcmp(artist_names + artist[album[i].artist_idx].name_idx, 1544 artist_idx = pf_idx.album_index[i].artist_idx;
1035 id3->albumartist)) 1545
1546 if(!rb->strcmp(pf_idx.album_names + album_idx, current_album) &&
1547 !rb->strcmp(pf_idx.artist_names + artist_idx, current_artist))
1036 return i; 1548 return i;
1037 } 1549 }
1550
1038 } 1551 }
1039 return last_album; 1552 rb->splash(HZ/2, "Album Not Found!");
1553 return pf_cfg.last_album;
1040} 1554}
1041 1555
1042/** 1556/**
@@ -1054,50 +1568,81 @@ static int compare_tracks (const void *a_v, const void *b_v)
1054 */ 1568 */
1055static void create_track_index(const int slide_index) 1569static void create_track_index(const int slide_index)
1056{ 1570{
1057 if ( slide_index == track_index ) 1571 char temp[MAX_PATH + 1];
1572 if ( slide_index == pf_tracks.cur_idx )
1058 return; 1573 return;
1059 track_index = slide_index;
1060 1574
1061 if (!rb->tagcache_search(&tcs, tag_title)) 1575 if (!rb->tagcache_search(&tcs, tag_title))
1062 goto fail; 1576 goto fail;
1063 1577
1064 rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); 1578 rb->tagcache_search_add_filter(&tcs, tag_album,
1065 rb->tagcache_search_add_filter(&tcs, tag_albumartist, 1579 pf_idx.album_index[slide_index].seek);
1066 artist[album[slide_index].artist_idx].seek); 1580
1581 if (pf_idx.album_index[slide_index].artist_idx >= 0)
1582 {
1583 rb->tagcache_search_add_filter(&tcs, tag_albumartist,
1584 pf_idx.album_index[slide_index].artist_seek);
1585 }
1067 1586
1068 track_count=0;
1069 int string_index = 0, track_num; 1587 int string_index = 0, track_num;
1070 int disc_num; 1588 int disc_num;
1589
1590 char* result = NULL;
1071 size_t out = 0; 1591 size_t out = 0;
1072 track_names = rb->buflib_buffer_out(&buf_ctx, &out); 1592
1073 borrowed += out; 1593 pf_tracks.count = 0;
1074 int avail = borrowed; 1594 pf_tracks.names = rb->buflib_buffer_out(&buf_ctx, &out);
1075 tracks = (struct track_data*)(track_names + borrowed); 1595 pf_tracks.borrowed += out;
1596 int avail = pf_tracks.borrowed;
1597 pf_tracks.index = (struct track_data*)(pf_tracks.names + pf_tracks.borrowed);
1076 while (rb->tagcache_get_next(&tcs)) 1598 while (rb->tagcache_get_next(&tcs))
1077 { 1599 {
1600 result = NULL;
1601 if (rb->strcmp(UNTAGGED, tcs.result) == 0)
1602 {
1603 /* show filename instead of <untaggged> */
1604 if (!rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename,
1605 temp, sizeof(temp) - 1))
1606 {
1607 goto fail;
1608 }
1609 result = temp;
1610 }
1611
1078 int len = 0, fn_idx = 0; 1612 int len = 0, fn_idx = 0;
1079 1613
1080 avail -= sizeof(struct track_data); 1614 avail -= sizeof(struct track_data);
1081 track_num = rb->tagcache_get_numeric(&tcs, tag_tracknumber); 1615 track_num = rb->tagcache_get_numeric(&tcs, tag_tracknumber);
1082 disc_num = rb->tagcache_get_numeric(&tcs, tag_discnumber); 1616 disc_num = rb->tagcache_get_numeric(&tcs, tag_discnumber);
1083 1617
1618 if (result)
1619 {
1620 /* if filename remove the '/' */
1621 result = rb->strrchr(result, PATH_SEPCH);
1622 if (result)
1623 result++;
1624 }
1625
1626 if (!result)
1627 result = tcs.result;
1628
1084 if (disc_num < 0) 1629 if (disc_num < 0)
1085 disc_num = 0; 1630 disc_num = 0;
1086retry: 1631retry:
1087 if (track_num > 0) 1632 if (track_num > 0)
1088 { 1633 {
1089 if (disc_num) 1634 if (disc_num)
1090 fn_idx = 1 + rb->snprintf(track_names + string_index , avail, 1635 fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail,
1091 "%d.%02d: %s", disc_num, track_num, tcs.result); 1636 "%d.%02d: %s", disc_num, track_num, result);
1092 else 1637 else
1093 fn_idx = 1 + rb->snprintf(track_names + string_index , avail, 1638 fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail,
1094 "%d: %s", track_num, tcs.result); 1639 "%d: %s", track_num, result);
1095 } 1640 }
1096 else 1641 else
1097 { 1642 {
1098 track_num = 0; 1643 track_num = 0;
1099 fn_idx = 1 + rb->snprintf(track_names + string_index, avail, 1644 fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail,
1100 "%s", tcs.result); 1645 "%s", result);
1101 } 1646 }
1102 if (fn_idx <= 0) 1647 if (fn_idx <= 0)
1103 goto fail; 1648 goto fail;
@@ -1106,11 +1651,12 @@ retry:
1106 if (remain >= MAX_PATH) 1651 if (remain >= MAX_PATH)
1107 { /* retrieve filename for building the playlist */ 1652 { /* retrieve filename for building the playlist */
1108 rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, 1653 rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename,
1109 track_names + string_index + fn_idx, remain); 1654 pf_tracks.names + string_index + fn_idx, remain);
1110 len = fn_idx + rb->strlen(track_names + string_index + fn_idx) + 1; 1655
1656 len = fn_idx + rb->strlen(pf_tracks.names + string_index + fn_idx) + 1;
1111 /* make sure track name and file name are really split by a \0, else 1657 /* make sure track name and file name are really split by a \0, else
1112 * get_track_name might fail */ 1658 * get_track_name might fail */
1113 *(track_names + string_index + fn_idx -1) = '\0'; 1659 *(pf_tracks.names + string_index + fn_idx -1) = '\0';
1114 1660
1115 } 1661 }
1116 else /* request more buffer so that track and filename fit */ 1662 else /* request more buffer so that track and filename fit */
@@ -1127,38 +1673,43 @@ retry:
1127 out = 0; 1673 out = 0;
1128 rb->buflib_buffer_out(&buf_ctx, &out); 1674 rb->buflib_buffer_out(&buf_ctx, &out);
1129 avail += out; 1675 avail += out;
1130 borrowed += out; 1676 pf_tracks.borrowed += out;
1131 1677
1132 struct track_data *new_tracks = 1678 struct track_data *new_tracks;
1133 (struct track_data *)(out + (uintptr_t)tracks); 1679 new_tracks = (struct track_data *)(out + (uintptr_t)pf_tracks.index);
1134 1680
1135 unsigned int bytes = track_count * sizeof(struct track_data); 1681 unsigned int bytes = pf_tracks.count * sizeof(struct track_data);
1136 if (track_count) 1682 if (pf_tracks.count)
1137 rb->memmove(new_tracks, tracks, bytes); 1683 rb->memmove(new_tracks, pf_tracks.index, bytes);
1138 tracks = new_tracks; 1684 pf_tracks.index = new_tracks;
1139 } 1685 }
1140 goto retry; 1686 goto retry;
1141 } 1687 }
1142 1688
1143 avail -= len; 1689 avail -= len;
1144 tracks--; 1690 pf_tracks.index--;
1145 tracks->sort = (disc_num << 24) + (track_num << 14) + track_count; 1691 pf_tracks.index->sort = (disc_num << 24) + (track_num << 14);
1146 tracks->name_idx = string_index; 1692 pf_tracks.index->sort += pf_tracks.count;
1147 tracks->seek = tcs.result_seek; 1693 pf_tracks.index->name_idx = string_index;
1694 pf_tracks.index->seek = tcs.result_seek;
1148#if PF_PLAYBACK_CAPABLE 1695#if PF_PLAYBACK_CAPABLE
1149 tracks->filename_idx = fn_idx + string_index; 1696 pf_tracks.index->filename_idx = fn_idx + string_index;
1150#endif 1697#endif
1151 track_count++; 1698 pf_tracks.count++;
1152 string_index += len; 1699 string_index += len;
1153 } 1700 }
1154 1701
1155 rb->tagcache_search_finish(&tcs); 1702 rb->tagcache_search_finish(&tcs);
1156 1703
1157 /* now fix the track list order */ 1704 /* now fix the track list order */
1158 rb->qsort(tracks, track_count, sizeof(struct track_data), compare_tracks); 1705 rb->qsort(pf_tracks.index, pf_tracks.count,
1706 sizeof(struct track_data), compare_tracks);
1707
1708 pf_tracks.cur_idx = slide_index;
1159 return; 1709 return;
1160fail: 1710fail:
1161 track_count = 0; 1711 rb->tagcache_search_finish(&tcs);
1712 pf_tracks.count = 0;
1162 return; 1713 return;
1163} 1714}
1164 1715
@@ -1176,14 +1727,16 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf,
1176 rb->strlcpy( buf, EMPTY_SLIDE, buflen ); 1727 rb->strlcpy( buf, EMPTY_SLIDE, buflen );
1177 } 1728 }
1178 1729
1179 if (!rb->tagcache_search(&tcs, tag_filename)) 1730 if (tcs.valid || !rb->tagcache_search(&tcs, tag_filename))
1180 return false; 1731 return false;
1181 1732
1182 bool result; 1733 bool result;
1183 /* find the first track of the album */ 1734 /* find the first track of the album */
1184 rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); 1735 rb->tagcache_search_add_filter(&tcs, tag_album,
1736 pf_idx.album_index[slide_index].seek);
1737
1185 rb->tagcache_search_add_filter(&tcs, tag_albumartist, 1738 rb->tagcache_search_add_filter(&tcs, tag_albumartist,
1186 artist[album[slide_index].artist_idx].seek); 1739 pf_idx.album_index[slide_index].artist_seek);
1187 1740
1188 if ( rb->tagcache_get_next(&tcs) ) { 1741 if ( rb->tagcache_get_next(&tcs) ) {
1189 struct mp3entry id3; 1742 struct mp3entry id3;
@@ -1198,9 +1751,12 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf,
1198#endif 1751#endif
1199 { 1752 {
1200 fd = rb->open(tcs.result, O_RDONLY); 1753 fd = rb->open(tcs.result, O_RDONLY);
1201 rb->get_metadata(&id3, fd, tcs.result); 1754 if (fd) {
1202 rb->close(fd); 1755 rb->get_metadata(&id3, fd, tcs.result);
1756 rb->close(fd);
1757 }
1203 } 1758 }
1759
1204 if ( search_albumart_files(&id3, ":", buf, buflen) ) 1760 if ( search_albumart_files(&id3, ":", buf, buflen) )
1205 result = true; 1761 result = true;
1206 else 1762 else
@@ -1217,10 +1773,8 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf,
1217/** 1773/**
1218 Draw the PictureFlow logo 1774 Draw the PictureFlow logo
1219 */ 1775 */
1220static void draw_splashscreen(void) 1776static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size)
1221{ 1777{
1222 unsigned char * buf_tmp = buf;
1223 size_t buf_tmp_size = buf_size;
1224 struct screen* display = rb->screens[SCREEN_MAIN]; 1778 struct screen* display = rb->screens[SCREEN_MAIN];
1225#if FB_DATA_SZ > 1 1779#if FB_DATA_SZ > 1
1226 ALIGN_BUFFER(buf_tmp, buf_tmp_size, sizeof(fb_data)); 1780 ALIGN_BUFFER(buf_tmp, buf_tmp_size, sizeof(fb_data));
@@ -1264,27 +1818,28 @@ static void draw_splashscreen(void)
1264/** 1818/**
1265 Draw a simple progress bar 1819 Draw a simple progress bar
1266 */ 1820 */
1267static void draw_progressbar(int step) 1821static void draw_progressbar(int step, int count, char *msg)
1268{ 1822{
1269 int txt_w, txt_h; 1823 static int txt_w, txt_h;
1270 const int bar_height = 22; 1824 const int bar_height = 22;
1271 const int w = LCD_WIDTH - 20; 1825 const int w = LCD_WIDTH - 20;
1272 const int x = 10; 1826 const int x = 10;
1273 1827 static int y;
1828 if (msg != NULL)
1829 {
1274#if LCD_DEPTH > 1 1830#if LCD_DEPTH > 1
1275 rb->lcd_set_background(N_BRIGHT(0)); 1831 rb->lcd_set_background(N_BRIGHT(0));
1276 rb->lcd_set_foreground(N_BRIGHT(255)); 1832 rb->lcd_set_foreground(N_BRIGHT(255));
1277#else 1833#else
1278 rb->lcd_set_drawmode(PICTUREFLOW_DRMODE); 1834 rb->lcd_set_drawmode(PICTUREFLOW_DRMODE);
1279#endif 1835#endif
1280 rb->lcd_clear_display(); 1836 rb->lcd_getstringsize(msg, &txt_w, &txt_h);
1281 rb->lcd_getstringsize("Preparing album artwork", &txt_w, &txt_h);
1282
1283 int y = (LCD_HEIGHT - txt_h)/2;
1284 1837
1285 rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, "Preparing album artwork"); 1838 y = (LCD_HEIGHT - txt_h)/2;
1286 y += (txt_h + 5);
1287 1839
1840 rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, msg);
1841 y += (txt_h + 5);
1842 }
1288#if LCD_DEPTH > 1 1843#if LCD_DEPTH > 1
1289 rb->lcd_set_foreground(N_BRIGHT(100)); 1844 rb->lcd_set_foreground(N_BRIGHT(100));
1290#endif 1845#endif
@@ -1293,7 +1848,7 @@ static void draw_progressbar(int step)
1293 rb->lcd_set_foreground(N_PIX(165, 231, 82)); 1848 rb->lcd_set_foreground(N_PIX(165, 231, 82));
1294#endif 1849#endif
1295 1850
1296 rb->lcd_fillrect(x+1, y+1, step * w / album_count, bar_height-2); 1851 rb->lcd_fillrect(x+1, y+1, step * w / count, bar_height-2);
1297#if LCD_DEPTH > 1 1852#if LCD_DEPTH > 1
1298 rb->lcd_set_foreground(N_BRIGHT(255)); 1853 rb->lcd_set_foreground(N_BRIGHT(255));
1299#endif 1854#endif
@@ -1327,7 +1882,7 @@ static bool save_pfraw(char* filename, struct bitmap *bm)
1327 struct pfraw_header bmph; 1882 struct pfraw_header bmph;
1328 bmph.width = bm->width; 1883 bmph.width = bm->width;
1329 bmph.height = bm->height; 1884 bmph.height = bm->height;
1330 int fh = rb->creat( filename , 0666); 1885 int fh = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
1331 if( fh < 0 ) return false; 1886 if( fh < 0 ) return false;
1332 rb->write( fh, &bmph, sizeof( struct pfraw_header ) ); 1887 rb->write( fh, &bmph, sizeof( struct pfraw_header ) );
1333 pix_t *data = (pix_t*)( bm->data ); 1888 pix_t *data = (pix_t*)( bm->data );
@@ -1341,62 +1896,99 @@ static bool save_pfraw(char* filename, struct bitmap *bm)
1341 return true; 1896 return true;
1342} 1897}
1343 1898
1344/** 1899static bool incremental_albumart_cache(bool verbose)
1345 Precomupte the album art images and store them in CACHE_PREFIX.
1346 Use the "?" bitmap if image is not found.
1347 */
1348static bool create_albumart_cache(void)
1349{ 1900{
1350 int ret; 1901 if (!aa_cache.buf)
1902 goto aa_failure;
1351 1903
1352 int i, slides = 0; 1904 if (aa_cache.inspected >= pf_idx.album_ct)
1353 struct bitmap input_bmp; 1905 return false;
1354 1906
1355 char pfraw_file[MAX_PATH]; 1907 int idx, ret;
1356 char albumart_file[MAX_PATH]; 1908 unsigned int hash_artist, hash_album;
1357 unsigned int format = FORMAT_NATIVE; 1909 unsigned int format = FORMAT_NATIVE;
1358 bool update = (cache_version == CACHE_UPDATE); 1910
1359 if (resize) 1911 bool update = (pf_cfg.cache_version == CACHE_UPDATE);
1912
1913 if (pf_cfg.resize)
1360 format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT; 1914 format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT;
1361 for (i=0; i < album_count; i++) 1915
1362 { 1916 idx = aa_cache.idx;
1363 draw_progressbar(i); 1917 if (idx >= pf_idx.album_ct || idx < 0) { idx = 0; } /* Rollover */
1364 rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", 1918
1365 mfnv(get_album_name(i)),mfnv(get_album_artist(i))); 1919
1366 /* delete existing cache, so it's a true rebuild */ 1920 aa_cache.idx++;
1367 if(rb->file_exists(pfraw_file)) { 1921 aa_cache.inspected++;
1368 if(update) { 1922 if (aa_cache.idx >= pf_idx.album_ct) { aa_cache.idx = 0; } /* Rollover */
1369 slides++; 1923
1370 continue; 1924 if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file)))
1371 } 1925 goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP);
1372 rb->remove(pfraw_file); 1926
1373 } 1927 hash_artist = mfnv(get_album_artist(idx));
1374 if (!get_albumart_for_index_from_db(i, albumart_file, MAX_PATH)) 1928 hash_album = mfnv(get_album_name(idx));
1375 rb->strcpy(albumart_file, EMPTY_SLIDE_BMP); 1929
1376 1930 rb->snprintf(aa_cache.pfraw_file, sizeof(aa_cache.pfraw_file),
1377 input_bmp.data = buf; 1931 CACHE_PREFIX "/%x%x.pfraw", hash_album, hash_artist);
1378 input_bmp.width = DISPLAY_WIDTH; 1932
1379 input_bmp.height = DISPLAY_HEIGHT; 1933 if(rb->file_exists(aa_cache.pfraw_file)) {
1380 ret = read_image_file(albumart_file, &input_bmp, buf_size, 1934 if(update) {
1381 format, &format_transposed); 1935 aa_cache.slides++;
1382 if (ret <= 0) { 1936 goto aa_success;
1383 rb->splashf(HZ, "Album art is bad: %s", get_album_name(i));
1384 rb->strcpy(albumart_file, EMPTY_SLIDE_BMP);
1385 ret = read_image_file(albumart_file, &input_bmp, buf_size,
1386 format, &format_transposed);
1387 if(ret <= 0)
1388 continue;
1389 } 1937 }
1390 if (!save_pfraw(pfraw_file, &input_bmp)) 1938 }
1391 { 1939
1392 rb->splash(HZ, "Could not write bmp"); 1940 aa_cache.input_bmp.data = aa_cache.buf;
1393 continue; 1941 aa_cache.input_bmp.width = DISPLAY_WIDTH;
1942 aa_cache.input_bmp.height = DISPLAY_HEIGHT;
1943
1944 ret = read_image_file(aa_cache.file, &aa_cache.input_bmp,
1945 aa_cache.buf_sz, format, &format_transposed);
1946 if (ret <= 0) {
1947 if (verbose) {
1948 rb->splashf(HZ, "Album art is bad: %s", get_album_name(idx));
1394 } 1949 }
1395 slides++; 1950
1396 if ( rb->button_get(false) == PF_MENU ) return false; 1951 goto aa_failure;
1952 }
1953 rb->remove(aa_cache.pfraw_file);
1954
1955 if (!save_pfraw(aa_cache.pfraw_file, &aa_cache.input_bmp))
1956 {
1957 if (verbose) { rb->splash(HZ, "Could not write bmp"); }
1958 goto aa_failure;
1959 }
1960 aa_cache.slides++;
1961
1962aa_failure:
1963 if (verbose)
1964 return false;
1965
1966aa_success:
1967 if (aa_cache.inspected >= pf_idx.album_ct)
1968 free_all_slide_prio(0);
1969
1970 if(verbose)/* direct interaction with user */
1971 return true;
1972
1973 return false;
1974}
1975
1976/**
1977 Precomupte the album art images and store them in CACHE_PREFIX.
1978 Use the "?" bitmap if image is not found.
1979 */
1980static bool create_albumart_cache(void)
1981{
1982 draw_splashscreen(pf_idx.buf, pf_idx.buf_sz);
1983 draw_progressbar(0, pf_idx.album_ct, "Preparing artwork");
1984 for (int i=0; i < pf_idx.album_ct; i++)
1985 {
1986 incremental_albumart_cache(true);
1987 draw_progressbar(aa_cache.inspected, pf_idx.album_ct, NULL);
1988 if (rb->button_get(false) > BUTTON_NONE)
1989 return true;
1397 } 1990 }
1398 draw_progressbar(i); 1991 if ( aa_cache.slides == 0 ) {
1399 if ( slides == 0 ) {
1400 /* Warn the user that we couldn't find any albumart */ 1992 /* Warn the user that we couldn't find any albumart */
1401 rb->splash(2*HZ, ID2P(LANG_NO_ALBUMART_FOUND)); 1993 rb->splash(2*HZ, ID2P(LANG_NO_ALBUMART_FOUND));
1402 return false; 1994 return false;
@@ -1410,19 +2002,23 @@ static bool create_albumart_cache(void)
1410 */ 2002 */
1411static int create_empty_slide(bool force) 2003static int create_empty_slide(bool force)
1412{ 2004{
2005 const unsigned int format = FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT;
2006
2007 if (!aa_cache.buf)
2008 return false;
2009
1413 if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) { 2010 if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) {
1414 struct bitmap input_bmp; 2011 aa_cache.input_bmp.width = DISPLAY_WIDTH;
1415 input_bmp.width = DISPLAY_WIDTH; 2012 aa_cache.input_bmp.height = DISPLAY_HEIGHT;
1416 input_bmp.height = DISPLAY_HEIGHT;
1417#if LCD_DEPTH > 1 2013#if LCD_DEPTH > 1
1418 input_bmp.format = FORMAT_NATIVE; 2014 aa_cache.input_bmp.format = FORMAT_NATIVE;
1419#endif 2015#endif
1420 input_bmp.data = (char*)buf; 2016 aa_cache.input_bmp.data = (char*)aa_cache.buf;
1421 scaled_read_bmp_file(EMPTY_SLIDE_BMP, &input_bmp, 2017
1422 buf_size, 2018 scaled_read_bmp_file(EMPTY_SLIDE_BMP, &aa_cache.input_bmp,
1423 FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT, 2019 aa_cache.buf_sz, format, &format_transposed);
1424 &format_transposed); 2020
1425 if (!save_pfraw(EMPTY_SLIDE, &input_bmp)) 2021 if (!save_pfraw(EMPTY_SLIDE, &aa_cache.input_bmp))
1426 return false; 2022 return false;
1427 } 2023 }
1428 2024
@@ -1502,23 +2098,23 @@ static bool create_pf_thread(void)
1502 * the LRU cache of slides, and the list of free cache slots. 2098 * the LRU cache of slides, and the list of free cache slots.
1503 */ 2099 */
1504 2100
1505#define seek_right_while(start, cond) \ 2101#define _SEEK_RIGHT_WHILE(start, cond) \
1506({ \ 2102({ \
1507 int ind_, next_ = (start); \ 2103 int ind_, next_ = (start); \
1508 do { \ 2104 do { \
1509 ind_ = next_; \ 2105 ind_ = next_; \
1510 next_ = cache[ind_].next; \ 2106 next_ = pf_sldcache.cache[ind_].next; \
1511 } while (next_ != cache_used && (cond)); \ 2107 } while (next_ != pf_sldcache.used && (cond)); \
1512 ind_; \ 2108 ind_; \
1513}) 2109})
1514 2110
1515#define seek_left_while(start, cond) \ 2111#define _SEEK_LEFT_WHILE(start, cond) \
1516({ \ 2112({ \
1517 int ind_, next_ = (start); \ 2113 int ind_, next_ = (start); \
1518 do { \ 2114 do { \
1519 ind_ = next_; \ 2115 ind_ = next_; \
1520 next_ = cache[ind_].prev; \ 2116 next_ = pf_sldcache.cache[ind_].prev; \
1521 } while (ind_ != cache_used && (cond)); \ 2117 } while (ind_ != pf_sldcache.used && (cond)); \
1522 ind_; \ 2118 ind_; \
1523}) 2119})
1524 2120
@@ -1528,8 +2124,8 @@ static bool create_pf_thread(void)
1528*/ 2124*/
1529static inline int lla_pop_item (int *head, int i) 2125static inline int lla_pop_item (int *head, int i)
1530{ 2126{
1531 int prev = cache[i].prev; 2127 int prev = pf_sldcache.cache[i].prev;
1532 int next = cache[i].next; 2128 int next = pf_sldcache.cache[i].next;
1533 if (i == next) 2129 if (i == next)
1534 { 2130 {
1535 *head = -1; 2131 *head = -1;
@@ -1537,8 +2133,8 @@ static inline int lla_pop_item (int *head, int i)
1537 } 2133 }
1538 else if (i == *head) 2134 else if (i == *head)
1539 *head = next; 2135 *head = next;
1540 cache[next].prev = prev; 2136 pf_sldcache.cache[next].prev = prev;
1541 cache[prev].next = next; 2137 pf_sldcache.cache[prev].next = next;
1542 return next; 2138 return next;
1543} 2139}
1544 2140
@@ -1561,11 +2157,11 @@ static inline int lla_pop_head (int *head)
1561static inline void lla_insert (int i, int p) 2157static inline void lla_insert (int i, int p)
1562{ 2158{
1563 int next = p; 2159 int next = p;
1564 int prev = cache[next].prev; 2160 int prev = pf_sldcache.cache[next].prev;
1565 cache[next].prev = i; 2161 pf_sldcache.cache[next].prev = i;
1566 cache[prev].next = i; 2162 pf_sldcache.cache[prev].next = i;
1567 cache[i].next = next; 2163 pf_sldcache.cache[i].next = next;
1568 cache[i].prev = prev; 2164 pf_sldcache.cache[i].prev = prev;
1569} 2165}
1570 2166
1571 2167
@@ -1577,8 +2173,8 @@ static inline void lla_insert_tail (int *head, int i)
1577 if (*head == -1) 2173 if (*head == -1)
1578 { 2174 {
1579 *head = i; 2175 *head = i;
1580 cache[i].next = i; 2176 pf_sldcache.cache[i].next = i;
1581 cache[i].prev = i; 2177 pf_sldcache.cache[i].prev = i;
1582 } else 2178 } else
1583 lla_insert(i, *head); 2179 lla_insert(i, *head);
1584} 2180}
@@ -1588,7 +2184,7 @@ static inline void lla_insert_tail (int *head, int i)
1588*/ 2184*/
1589static inline void lla_insert_after(int i, int p) 2185static inline void lla_insert_after(int i, int p)
1590{ 2186{
1591 p = cache[p].next; 2187 p = pf_sldcache.cache[p].next;
1592 lla_insert(i, p); 2188 lla_insert(i, p);
1593} 2189}
1594 2190
@@ -1611,16 +2207,16 @@ static inline void lla_insert_before(int *head, int i, int p)
1611*/ 2207*/
1612static inline void free_slide(int i) 2208static inline void free_slide(int i)
1613{ 2209{
1614 if (cache[i].hid != empty_slide_hid) 2210 if (pf_sldcache.cache[i].hid != empty_slide_hid)
1615 rb->buflib_free(&buf_ctx, cache[i].hid); 2211 rb->buflib_free(&buf_ctx, pf_sldcache.cache[i].hid);
1616 cache[i].index = -1; 2212 pf_sldcache.cache[i].index = -1;
1617 lla_pop_item(&cache_used, i); 2213 lla_pop_item(&pf_sldcache.used, i);
1618 lla_insert_tail(&cache_free, i); 2214 lla_insert_tail(&pf_sldcache.free, i);
1619 if (cache_used == -1) 2215 if (pf_sldcache.used == -1)
1620 { 2216 {
1621 cache_right_index = -1; 2217 pf_sldcache.right_idx = -1;
1622 cache_left_index = -1; 2218 pf_sldcache.left_idx = -1;
1623 cache_center_index = -1; 2219 pf_sldcache.center_idx = -1;
1624 } 2220 }
1625} 2221}
1626 2222
@@ -1631,13 +2227,17 @@ static inline void free_slide(int i)
1631*/ 2227*/
1632static bool free_slide_prio(int prio) 2228static bool free_slide_prio(int prio)
1633{ 2229{
1634 if (cache_used == -1) 2230 if (pf_sldcache.used == -1)
1635 return false; 2231 return false;
1636 int i, l = cache_used, r = cache[cache_used].prev, prio_max; 2232
1637 int prio_l = cache[l].index < center_index ? 2233 int i, prio_max;
1638 center_index - cache[l].index : 0; 2234 int l = pf_sldcache.used;
1639 int prio_r = cache[r].index > center_index ? 2235 int r = pf_sldcache.cache[pf_sldcache.used].prev;
1640 cache[r].index - center_index : 0; 2236
2237 int prio_l = pf_sldcache.cache[l].index < center_index ?
2238 center_index - pf_sldcache.cache[l].index : 0;
2239 int prio_r = pf_sldcache.cache[r].index > center_index ?
2240 pf_sldcache.cache[r].index - center_index : 0;
1641 if (prio_l > prio_r) 2241 if (prio_l > prio_r)
1642 { 2242 {
1643 i = l; 2243 i = l;
@@ -1648,16 +2248,27 @@ static bool free_slide_prio(int prio)
1648 } 2248 }
1649 if (prio_max > prio) 2249 if (prio_max > prio)
1650 { 2250 {
1651 if (i == cache_left_index) 2251 if (i == pf_sldcache.left_idx)
1652 cache_left_index = cache[i].next; 2252 pf_sldcache.left_idx = pf_sldcache.cache[i].next;
1653 if (i == cache_right_index) 2253 if (i == pf_sldcache.right_idx)
1654 cache_right_index = cache[i].prev; 2254 pf_sldcache.right_idx = pf_sldcache.cache[i].prev;
1655 free_slide(i); 2255 free_slide(i);
1656 return true; 2256 return true;
1657 } else 2257 } else
1658 return false; 2258 return false;
1659} 2259}
1660 2260
2261
2262/**
2263 Free all slides ranked above the given priority.
2264*/
2265static void free_all_slide_prio(int prio)
2266{
2267 while (free_slide_prio(prio))
2268 ;;
2269}
2270
2271
1661/** 2272/**
1662 Read the pfraw image given as filename and return the hid of the buffer 2273 Read the pfraw image given as filename and return the hid of the buffer
1663 */ 2274 */
@@ -1666,7 +2277,7 @@ static int read_pfraw(char* filename, int prio)
1666 struct pfraw_header bmph; 2277 struct pfraw_header bmph;
1667 int fh = rb->open(filename, O_RDONLY); 2278 int fh = rb->open(filename, O_RDONLY);
1668 if( fh < 0 ) { 2279 if( fh < 0 ) {
1669 cache_version = CACHE_UPDATE; 2280 /* pf_cfg.cache_version = CACHE_UPDATE; -- don't invalidate on missing pfraw */
1670 return empty_slide_hid; 2281 return empty_slide_hid;
1671 } 2282 }
1672 else 2283 else
@@ -1711,19 +2322,20 @@ static inline bool load_and_prepare_surface(const int slide_index,
1711 const int prio) 2322 const int prio)
1712{ 2323{
1713 char pfraw_file[MAX_PATH]; 2324 char pfraw_file[MAX_PATH];
1714 2325 unsigned int hash_artist = mfnv(get_album_artist(slide_index));
2326 unsigned int hash_album = mfnv(get_album_name(slide_index));
1715 2327
1716 rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", 2328 rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw",
1717 mfnv(get_album_name(slide_index)),mfnv(get_album_artist(slide_index))); 2329 hash_album, hash_artist);
1718 2330
1719 int hid = read_pfraw(pfraw_file, prio); 2331 int hid = read_pfraw(pfraw_file, prio);
1720 if (!hid) 2332 if (!hid)
1721 return false; 2333 return false;
1722 2334
1723 cache[cache_index].hid = hid; 2335 pf_sldcache.cache[cache_index].hid = hid;
1724 2336
1725 if ( cache_index < SLIDE_CACHE_SIZE ) { 2337 if ( cache_index < SLIDE_CACHE_SIZE ) {
1726 cache[cache_index].index = slide_index; 2338 pf_sldcache.cache[cache_index].index = slide_index;
1727 } 2339 }
1728 2340
1729 return true; 2341 return true;
@@ -1737,107 +2349,121 @@ static inline bool load_and_prepare_surface(const int slide_index,
1737bool load_new_slide(void) 2349bool load_new_slide(void)
1738{ 2350{
1739 int i = -1; 2351 int i = -1;
1740 if (cache_center_index != -1) 2352
2353 if (pf_sldcache.center_idx != -1)
1741 { 2354 {
1742 int next, prev; 2355 int next, prev;
1743 if (cache[cache_center_index].index != center_index) 2356 if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index)
1744 { 2357 {
1745 if (cache[cache_center_index].index < center_index) 2358 if (pf_sldcache.cache[pf_sldcache.center_idx].index < center_index)
1746 { 2359 {
1747 cache_center_index = seek_right_while(cache_center_index, 2360 pf_sldcache.center_idx = _SEEK_RIGHT_WHILE(pf_sldcache.center_idx,
1748 cache[next_].index <= center_index); 2361 pf_sldcache.cache[next_].index <= center_index);
1749 prev = cache_center_index; 2362
1750 next = cache[cache_center_index].next; 2363 prev = pf_sldcache.center_idx;
2364 next = pf_sldcache.cache[pf_sldcache.center_idx].next;
1751 } 2365 }
1752 else 2366 else
1753 { 2367 {
1754 cache_center_index = seek_left_while(cache_center_index, 2368 pf_sldcache.center_idx = _SEEK_LEFT_WHILE(pf_sldcache.center_idx,
1755 cache[next_].index >= center_index); 2369 pf_sldcache.cache[next_].index >= center_index);
1756 next = cache_center_index; 2370
1757 prev = cache[cache_center_index].prev; 2371 next = pf_sldcache.center_idx;
2372 prev = pf_sldcache.cache[pf_sldcache.center_idx].prev;
1758 } 2373 }
1759 if (cache[cache_center_index].index != center_index) 2374 if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index)
1760 { 2375 {
1761 if (cache_free == -1) 2376 if (pf_sldcache.free == -1)
1762 free_slide_prio(0); 2377 free_slide_prio(0);
1763 i = lla_pop_head(&cache_free); 2378
2379 i = lla_pop_head(&pf_sldcache.free);
1764 if (!load_and_prepare_surface(center_index, i, 0)) 2380 if (!load_and_prepare_surface(center_index, i, 0))
1765 goto fail_and_refree; 2381 goto fail_and_refree;
1766 if (cache[next].index == -1) 2382
2383 if (pf_sldcache.cache[next].index == -1)
1767 { 2384 {
1768 if (cache[prev].index == -1) 2385 if (pf_sldcache.cache[prev].index == -1)
1769 goto insert_first_slide; 2386 goto insert_first_slide;
1770 else 2387 else
1771 next = cache[prev].next; 2388 next = pf_sldcache.cache[prev].next;
1772 } 2389 }
1773 lla_insert(i, next); 2390 lla_insert(i, next);
1774 if (cache[i].index < cache[cache_used].index) 2391 if (pf_sldcache.cache[i].index < pf_sldcache.cache[pf_sldcache.used].index)
1775 cache_used = i; 2392 pf_sldcache.used = i;
1776 cache_center_index = i; 2393
1777 cache_left_index = i; 2394 pf_sldcache.center_idx = i;
1778 cache_right_index = i; 2395 pf_sldcache.left_idx = i;
2396 pf_sldcache.right_idx = i;
1779 return true; 2397 return true;
1780 } 2398 }
1781 } 2399 }
1782 if (cache[cache_left_index].index > 2400 int left, center, right;
1783 cache[cache_center_index].index) 2401 left = pf_sldcache.cache[pf_sldcache.left_idx].index;
1784 cache_left_index = cache_center_index; 2402 center = pf_sldcache.cache[pf_sldcache.center_idx].index;
1785 if (cache[cache_right_index].index < 2403 right = pf_sldcache.cache[pf_sldcache.right_idx].index;
1786 cache[cache_center_index].index) 2404
1787 cache_right_index = cache_center_index; 2405 if (left > center)
1788 cache_left_index = seek_left_while(cache_left_index, 2406 pf_sldcache.left_idx = pf_sldcache.center_idx;
1789 cache[ind_].index - 1 == cache[next_].index); 2407 if (right < center)
1790 cache_right_index = seek_right_while(cache_right_index, 2408 pf_sldcache.right_idx = pf_sldcache.center_idx;
1791 cache[ind_].index - 1 == cache[next_].index); 2409
1792 int prio_l = cache[cache_center_index].index - 2410 pf_sldcache.left_idx = _SEEK_LEFT_WHILE(pf_sldcache.left_idx,
1793 cache[cache_left_index].index + 1; 2411 pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index);
1794 int prio_r = cache[cache_right_index].index - 2412
1795 cache[cache_center_index].index + 1; 2413 pf_sldcache.right_idx = _SEEK_RIGHT_WHILE(pf_sldcache.right_idx,
1796 if ((prio_l < prio_r || 2414 pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index);
1797 cache[cache_right_index].index >= number_of_slides) && 2415
1798 cache[cache_left_index].index > 0) 2416
2417 /* update indices */
2418 left = pf_sldcache.cache[pf_sldcache.left_idx].index;
2419 center = pf_sldcache.cache[pf_sldcache.center_idx].index;
2420 right = pf_sldcache.cache[pf_sldcache.right_idx].index;
2421
2422 int prio_l = center - left + 1;
2423 int prio_r = right - center + 1;
2424 if ((prio_l < prio_r || right >= number_of_slides) && left > 0)
1799 { 2425 {
1800 if (cache_free == -1 && !free_slide_prio(prio_l)) 2426 if (pf_sldcache.free == -1 && !free_slide_prio(prio_l))
1801 return false; 2427 return false;
1802 i = lla_pop_head(&cache_free); 2428
1803 if (load_and_prepare_surface(cache[cache_left_index].index 2429 i = lla_pop_head(&pf_sldcache.free);
1804 - 1, i, prio_l)) 2430 if (load_and_prepare_surface(left - 1, i, prio_l))
1805 { 2431 {
1806 lla_insert_before(&cache_used, i, cache_left_index); 2432 lla_insert_before(&pf_sldcache.used, i, pf_sldcache.left_idx);
1807 cache_left_index = i; 2433 pf_sldcache.left_idx = i;
1808 return true; 2434 return true;
1809 } 2435 }
1810 } else if(cache[cache_right_index].index < number_of_slides - 1) 2436 } else if(right < number_of_slides - 1)
1811 { 2437 {
1812 if (cache_free == -1 && !free_slide_prio(prio_r)) 2438 if (pf_sldcache.free == -1 && !free_slide_prio(prio_r))
1813 return false; 2439 return false;
1814 i = lla_pop_head(&cache_free); 2440
1815 if (load_and_prepare_surface(cache[cache_right_index].index 2441 i = lla_pop_head(&pf_sldcache.free);
1816 + 1, i, prio_r)) 2442 if (load_and_prepare_surface(right + 1, i, prio_r))
1817 { 2443 {
1818 lla_insert_after(i, cache_right_index); 2444 lla_insert_after(i, pf_sldcache.right_idx);
1819 cache_right_index = i; 2445 pf_sldcache.right_idx = i;
1820 return true; 2446 return true;
1821 } 2447 }
1822 } 2448 }
1823 } else { 2449 } else {
1824 i = lla_pop_head(&cache_free); 2450 i = lla_pop_head(&pf_sldcache.free);
1825 if (load_and_prepare_surface(center_index, i, 0)) 2451 if (load_and_prepare_surface(center_index, i, 0))
1826 { 2452 {
1827insert_first_slide: 2453insert_first_slide:
1828 cache[i].next = i; 2454 pf_sldcache.cache[i].next = i;
1829 cache[i].prev = i; 2455 pf_sldcache.cache[i].prev = i;
1830 cache_center_index = i; 2456 pf_sldcache.center_idx = i;
1831 cache_left_index = i; 2457 pf_sldcache.left_idx = i;
1832 cache_right_index = i; 2458 pf_sldcache.right_idx = i;
1833 cache_used = i; 2459 pf_sldcache.used = i;
1834 return true; 2460 return true;
1835 } 2461 }
1836 } 2462 }
1837fail_and_refree: 2463fail_and_refree:
1838 if (i != -1) 2464 if (i != -1)
1839 { 2465 {
1840 lla_insert_tail(&cache_free, i); 2466 lla_insert_tail(&pf_sldcache.free, i);
1841 } 2467 }
1842 return false; 2468 return false;
1843} 2469}
@@ -1869,13 +2495,13 @@ static inline struct dim *surface(const int slide_index)
1869 if (slide_index >= number_of_slides) 2495 if (slide_index >= number_of_slides)
1870 return 0; 2496 return 0;
1871 int i; 2497 int i;
1872 if ((i = cache_used ) != -1) 2498 if ((i = pf_sldcache.used ) != -1)
1873 { 2499 {
1874 do { 2500 do {
1875 if (cache[i].index == slide_index) 2501 if (pf_sldcache.cache[i].index == slide_index)
1876 return get_slide(cache[i].hid); 2502 return get_slide(pf_sldcache.cache[i].hid);
1877 i = cache[i].next; 2503 i = pf_sldcache.cache[i].next;
1878 } while (i != cache_used); 2504 } while (i != pf_sldcache.used);
1879 } 2505 }
1880 return get_slide(empty_slide_hid); 2506 return get_slide(empty_slide_hid);
1881} 2507}
@@ -1892,19 +2518,19 @@ static void reset_slides(void)
1892 center_slide.slide_index = center_index; 2518 center_slide.slide_index = center_index;
1893 2519
1894 int i; 2520 int i;
1895 for (i = 0; i < num_slides; i++) { 2521 for (i = 0; i < pf_cfg.num_slides; i++) {
1896 struct slide_data *si = &left_slides[i]; 2522 struct slide_data *si = &left_slides[i];
1897 si->angle = itilt; 2523 si->angle = itilt;
1898 si->cx = -(offsetX + slide_spacing * i * PFREAL_ONE); 2524 si->cx = -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE);
1899 si->cy = offsetY; 2525 si->cy = offsetY;
1900 si->slide_index = center_index - 1 - i; 2526 si->slide_index = center_index - 1 - i;
1901 si->distance = 0; 2527 si->distance = 0;
1902 } 2528 }
1903 2529
1904 for (i = 0; i < num_slides; i++) { 2530 for (i = 0; i < pf_cfg.num_slides; i++) {
1905 struct slide_data *si = &right_slides[i]; 2531 struct slide_data *si = &right_slides[i];
1906 si->angle = -itilt; 2532 si->angle = -itilt;
1907 si->cx = offsetX + slide_spacing * i * PFREAL_ONE; 2533 si->cx = offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE;
1908 si->cy = offsetY; 2534 si->cy = offsetY;
1909 si->slide_index = center_index + 1 + i; 2535 si->slide_index = center_index + 1 + i;
1910 si->distance = 0; 2536 si->distance = 0;
@@ -1928,14 +2554,14 @@ static void recalc_offsets(void)
1928{ 2554{
1929 PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF; 2555 PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF;
1930 PFreal zo; 2556 PFreal zo;
1931 PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + center_margin * 2557 PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF +
1932 PFREAL_ONE) * zoom / 100; 2558 pf_cfg.center_margin * PFREAL_ONE) * pf_cfg.zoom / 100;
1933 PFreal cosr, sinr; 2559 PFreal cosr, sinr;
1934 2560
1935 itilt = 70 * IANGLE_MAX / 360; /* approx. 70 degrees tilted */ 2561 itilt = 70 * IANGLE_MAX / 360; /* approx. 70 degrees tilted */
1936 cosr = fcos(-itilt); 2562 cosr = fcos(-itilt);
1937 sinr = fsin(-itilt); 2563 sinr = fsin(-itilt);
1938 zo = CAM_DIST_R * 100 / zoom - CAM_DIST_R + 2564 zo = CAM_DIST_R * 100 / pf_cfg.zoom - CAM_DIST_R +
1939 fmuln(MAXSLIDE_LEFT_R, sinr, PFREAL_SHIFT - 2, 0); 2565 fmuln(MAXSLIDE_LEFT_R, sinr, PFREAL_SHIFT - 2, 0);
1940 offsetX = xp - fmul(xs, cosr) + fmuln(xp, 2566 offsetX = xp - fmul(xs, cosr) + fmuln(xp,
1941 zo + fmuln(xs, sinr, PFREAL_SHIFT - 2, 0), PFREAL_SHIFT - 2, 0) 2567 zo + fmuln(xs, sinr, PFREAL_SHIFT - 2, 0), PFREAL_SHIFT - 2, 0)
@@ -2033,7 +2659,7 @@ static void render_slide(struct slide_data *slide, const int alpha)
2033 2659
2034 PFreal cosr = fcos(slide->angle); 2660 PFreal cosr = fcos(slide->angle);
2035 PFreal sinr = fsin(slide->angle); 2661 PFreal sinr = fsin(slide->angle);
2036 PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / zoom 2662 PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / pf_cfg.zoom
2037 - CAM_DIST_R - fmuln(MAXSLIDE_LEFT_R, fabs(sinr), PFREAL_SHIFT - 2, 0); 2663 - CAM_DIST_R - fmuln(MAXSLIDE_LEFT_R, fabs(sinr), PFREAL_SHIFT - 2, 0);
2038 PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni; 2664 PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni;
2039 PFreal xp = fdiv(CAM_DIST * (slide->cx + fmul(xs, cosr)), 2665 PFreal xp = fdiv(CAM_DIST * (slide->cx + fmul(xs, cosr)),
@@ -2132,7 +2758,7 @@ static void render_slide(struct slide_data *slide, const int alpha)
2132} 2758}
2133 2759
2134/** 2760/**
2135 Jump the the given slide_index 2761 Jump to the given slide_index
2136 */ 2762 */
2137static inline void set_current_slide(const int slide_index) 2763static inline void set_current_slide(const int slide_index)
2138{ 2764{
@@ -2202,8 +2828,8 @@ static void render_all_slides(void)
2202 /* TODO: Optimizes this by e.g. invalidating rects */ 2828 /* TODO: Optimizes this by e.g. invalidating rects */
2203 mylcd_clear_display(); 2829 mylcd_clear_display();
2204 2830
2205 int nleft = num_slides; 2831 int nleft = pf_cfg.num_slides;
2206 int nright = num_slides; 2832 int nright = pf_cfg.num_slides;
2207 2833
2208 int alpha; 2834 int alpha;
2209 int index; 2835 int index;
@@ -2242,7 +2868,7 @@ static void render_all_slides(void)
2242 } 2868 }
2243 } 2869 }
2244 alpha = 256; 2870 alpha = 256;
2245 if (step != 0 && num_slides <= 2) /* fading out center slide */ 2871 if (step != 0 && pf_cfg.num_slides <= 2) /* fading out center slide */
2246 alpha = (step > 0) ? 256 - fade / 2 : 128 + fade / 2; 2872 alpha = (step > 0) ? 256 - fade / 2 : 128 + fade / 2;
2247 render_slide(&center_slide, alpha); 2873 render_slide(&center_slide, alpha);
2248} 2874}
@@ -2291,9 +2917,9 @@ static void update_scroll_animation(void)
2291 rb->queue_post(&thread_q, EV_WAKEUP, 0); 2917 rb->queue_post(&thread_q, EV_WAKEUP, 0);
2292 slide_frame = index << 16; 2918 slide_frame = index << 16;
2293 center_slide.slide_index = center_index; 2919 center_slide.slide_index = center_index;
2294 for (i = 0; i < num_slides; i++) 2920 for (i = 0; i < pf_cfg.num_slides; i++)
2295 left_slides[i].slide_index = center_index - 1 - i; 2921 left_slides[i].slide_index = center_index - 1 - i;
2296 for (i = 0; i < num_slides; i++) 2922 for (i = 0; i < pf_cfg.num_slides; i++)
2297 right_slides[i].slide_index = center_index + 1 + i; 2923 right_slides[i].slide_index = center_index + 1 + i;
2298 } 2924 }
2299 2925
@@ -2310,21 +2936,21 @@ static void update_scroll_animation(void)
2310 return; 2936 return;
2311 } 2937 }
2312 2938
2313 for (i = 0; i < num_slides; i++) { 2939 for (i = 0; i < pf_cfg.num_slides; i++) {
2314 struct slide_data *si = &left_slides[i]; 2940 struct slide_data *si = &left_slides[i];
2315 si->angle = itilt; 2941 si->angle = itilt;
2316 si->cx = 2942 si->cx =
2317 -(offsetX + slide_spacing * i * PFREAL_ONE + step 2943 -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE + step
2318 * slide_spacing * ftick); 2944 * pf_cfg.slide_spacing * ftick);
2319 si->cy = offsetY; 2945 si->cy = offsetY;
2320 } 2946 }
2321 2947
2322 for (i = 0; i < num_slides; i++) { 2948 for (i = 0; i < pf_cfg.num_slides; i++) {
2323 struct slide_data *si = &right_slides[i]; 2949 struct slide_data *si = &right_slides[i];
2324 si->angle = -itilt; 2950 si->angle = -itilt;
2325 si->cx = 2951 si->cx =
2326 offsetX + slide_spacing * i * PFREAL_ONE - step 2952 offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE - step
2327 * slide_spacing * ftick; 2953 * pf_cfg.slide_spacing * ftick;
2328 si->cy = offsetY; 2954 si->cy = offsetY;
2329 } 2955 }
2330 2956
@@ -2409,13 +3035,13 @@ static int settings_menu(void)
2409 selection=rb->do_menu(&settings_menu,&selection, NULL, false); 3035 selection=rb->do_menu(&settings_menu,&selection, NULL, false);
2410 switch(selection) { 3036 switch(selection) {
2411 case 0: 3037 case 0:
2412 rb->set_bool(rb->str(LANG_DISPLAY_FPS), &show_fps); 3038 rb->set_bool(rb->str(LANG_DISPLAY_FPS), &pf_cfg.show_fps);
2413 reset_track_list(); 3039 reset_track_list();
2414 break; 3040 break;
2415 3041
2416 case 1: 3042 case 1:
2417 rb->set_int(rb->str(LANG_SPACING), "", 1, 3043 rb->set_int(rb->str(LANG_SPACING), "", 1,
2418 &slide_spacing, 3044 &pf_cfg.slide_spacing,
2419 NULL, 1, 0, 100, NULL ); 3045 NULL, 1, 0, 100, NULL );
2420 recalc_offsets(); 3046 recalc_offsets();
2421 reset_slides(); 3047 reset_slides();
@@ -2423,57 +3049,59 @@ static int settings_menu(void)
2423 3049
2424 case 2: 3050 case 2:
2425 rb->set_int(rb->str(LANG_CENTRE_MARGIN), "", 1, 3051 rb->set_int(rb->str(LANG_CENTRE_MARGIN), "", 1,
2426 &center_margin, 3052 &pf_cfg.center_margin,
2427 NULL, 1, 0, 80, NULL ); 3053 NULL, 1, 0, 80, NULL );
2428 recalc_offsets(); 3054 recalc_offsets();
2429 reset_slides(); 3055 reset_slides();
2430 break; 3056 break;
2431 3057
2432 case 3: 3058 case 3:
2433 rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, &num_slides, 3059 rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1,
2434 NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); 3060 &pf_cfg.num_slides, NULL, 1, 1, MAX_SLIDES_COUNT, NULL );
2435 recalc_offsets(); 3061 recalc_offsets();
2436 reset_slides(); 3062 reset_slides();
2437 break; 3063 break;
2438 3064
2439 case 4: 3065 case 4:
2440 rb->set_int(rb->str(LANG_ZOOM), "", 1, &zoom, 3066 rb->set_int(rb->str(LANG_ZOOM), "", 1, &pf_cfg.zoom,
2441 NULL, 1, 10, 300, NULL ); 3067 NULL, 1, 10, 300, NULL );
2442 recalc_offsets(); 3068 recalc_offsets();
2443 reset_slides(); 3069 reset_slides();
2444 break; 3070 break;
2445 case 5: 3071 case 5:
2446 rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), &show_album_name, 3072 rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE),
2447 INT, album_name_options, 5, NULL); 3073 &pf_cfg.show_album_name, INT, album_name_options, 5, NULL);
2448 reset_track_list(); 3074 reset_track_list();
2449 recalc_offsets(); 3075 recalc_offsets();
2450 reset_slides(); 3076 reset_slides();
2451 break; 3077 break;
2452 case 6: 3078 case 6:
2453 old_val = resize; 3079 old_val = pf_cfg.resize;
2454 rb->set_bool(rb->str(LANG_RESIZE_COVERS), &resize); 3080 rb->set_bool(rb->str(LANG_RESIZE_COVERS), &pf_cfg.resize);
2455 if (old_val == resize) /* changed? */ 3081 if (old_val == pf_cfg.resize) /* changed? */
2456 break; 3082 break;
2457 /* fallthrough if changed, since cache needs to be rebuilt */ 3083 /* fallthrough if changed, since cache needs to be rebuilt */
2458 case 7: 3084 case 7:
2459 cache_version = CACHE_REBUILD; 3085 pf_cfg.cache_version = CACHE_REBUILD;
2460 rb->remove(EMPTY_SLIDE); 3086 rb->remove(EMPTY_SLIDE);
2461 configfile_save(CONFIG_FILE, config, 3087 configfile_save(CONFIG_FILE, config,
2462 CONFIG_NUM_ITEMS, CONFIG_VERSION); 3088 CONFIG_NUM_ITEMS, CONFIG_VERSION);
2463 rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); 3089 rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART));
2464 break; 3090 break;
2465 case 8: 3091 case 8:
2466 cache_version = CACHE_UPDATE; 3092 pf_cfg.cache_version = CACHE_UPDATE;
2467 rb->remove(EMPTY_SLIDE); 3093 rb->remove(EMPTY_SLIDE);
2468 configfile_save(CONFIG_FILE, config, 3094 configfile_save(CONFIG_FILE, config,
2469 CONFIG_NUM_ITEMS, CONFIG_VERSION); 3095 CONFIG_NUM_ITEMS, CONFIG_VERSION);
2470 rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); 3096 rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART));
2471 break; 3097 break;
2472 case 9: 3098 case 9:
2473 rb->set_option(rb->str(LANG_WPS_INTEGRATION), &auto_wps, INT, wps_options, 3, NULL); 3099 rb->set_option(rb->str(LANG_WPS_INTEGRATION),
3100 &pf_cfg.auto_wps, INT, wps_options, 3, NULL);
2474 break; 3101 break;
2475 case 10: 3102 case 10:
2476 rb->set_option(rb->str(LANG_BACKLIGHT), &backlight_mode, INT, backlight_options, 2, NULL); 3103 rb->set_option(rb->str(LANG_BACKLIGHT),
3104 &pf_cfg.backlight_mode, INT, backlight_options, 2, NULL);
2477 break; 3105 break;
2478 3106
2479 case MENU_ATTACHED_USB: 3107 case MENU_ATTACHED_USB:
@@ -2596,8 +3224,8 @@ static inline void draw_gradient(int y, int h)
2596 int r, inc, c; 3224 int r, inc, c;
2597 inc = (100 << 8) / h; 3225 inc = (100 << 8) / h;
2598 c = 0; 3226 c = 0;
2599 selected_track_pulse = (selected_track_pulse+1) % 10; 3227 pf_tracks.sel_pulse = (pf_tracks.sel_pulse+1) % 10;
2600 int c2 = selected_track_pulse - 5; 3228 int c2 = pf_tracks.sel_pulse - 5;
2601 for (r=0; r<h; r++) { 3229 for (r=0; r<h; r++) {
2602#ifdef HAVE_LCD_COLOR 3230#ifdef HAVE_LCD_COLOR
2603 mylcd_set_foreground(G_PIX(c2+80-(c >> 9), c2+100-(c >> 9), 3231 mylcd_set_foreground(G_PIX(c2+80-(c >> 9), c2+100-(c >> 9),
@@ -2616,30 +3244,30 @@ static inline void draw_gradient(int y, int h)
2616 3244
2617static void track_list_yh(int char_height) 3245static void track_list_yh(int char_height)
2618{ 3246{
2619 switch (show_album_name) 3247 switch (pf_cfg.show_album_name)
2620 { 3248 {
2621 case ALBUM_NAME_HIDE: 3249 case ALBUM_NAME_HIDE:
2622 track_list_y = (show_fps ? char_height : 0); 3250 pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0);
2623 track_list_h = LCD_HEIGHT - track_list_y; 3251 pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y;
2624 break; 3252 break;
2625 case ALBUM_NAME_BOTTOM: 3253 case ALBUM_NAME_BOTTOM:
2626 track_list_y = (show_fps ? char_height : 0); 3254 pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0);
2627 track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); 3255 pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3);
2628 break; 3256 break;
2629 case ALBUM_AND_ARTIST_TOP: 3257 case ALBUM_AND_ARTIST_TOP:
2630 track_list_y = char_height * 3; 3258 pf_tracks.list_y = char_height * 3;
2631 track_list_h = LCD_HEIGHT - track_list_y - 3259 pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y -
2632 (show_fps ? char_height : 0); 3260 (pf_cfg.show_fps ? char_height : 0);
2633 break; 3261 break;
2634 case ALBUM_AND_ARTIST_BOTTOM: 3262 case ALBUM_AND_ARTIST_BOTTOM:
2635 track_list_y = (show_fps ? char_height : 0); 3263 pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0);
2636 track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); 3264 pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3);
2637 break; 3265 break;
2638 case ALBUM_NAME_TOP: 3266 case ALBUM_NAME_TOP:
2639 default: 3267 default:
2640 track_list_y = char_height * 3; 3268 pf_tracks.list_y = char_height * 3;
2641 track_list_h = LCD_HEIGHT - track_list_y - 3269 pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y -
2642 (show_fps ? char_height : 0); 3270 (pf_cfg.show_fps ? char_height : 0);
2643 break; 3271 break;
2644 } 3272 }
2645} 3273}
@@ -2652,18 +3280,20 @@ void reset_track_list(void)
2652 int char_height = rb->screens[SCREEN_MAIN]->getcharheight(); 3280 int char_height = rb->screens[SCREEN_MAIN]->getcharheight();
2653 int total_height; 3281 int total_height;
2654 track_list_yh(char_height); 3282 track_list_yh(char_height);
2655 track_list_visible_entries = fmin( track_list_h/char_height , track_count ); 3283 pf_tracks.list_visible =
2656 start_index_track_list = 0; 3284 fmin( pf_tracks.list_h/char_height , pf_tracks.count );
2657 selected_track = 0; 3285
2658 last_selected_track = -1; 3286 pf_tracks.list_start = 0;
3287 pf_tracks.sel = 0;
3288 pf_tracks.last_sel = -1;
2659 3289
2660 /* let the tracklist start more centered 3290 /* let the tracklist start more centered
2661 * if the screen isn't filled with tracks */ 3291 * if the screen isn't filled with tracks */
2662 total_height = track_count*char_height; 3292 total_height = pf_tracks.count*char_height;
2663 if (total_height < track_list_h) 3293 if (total_height < pf_tracks.list_h)
2664 { 3294 {
2665 track_list_y += (track_list_h - total_height) / 2; 3295 pf_tracks.list_y += (pf_tracks.list_h - total_height) / 2;
2666 track_list_h = total_height; 3296 pf_tracks.list_h = total_height;
2667 } 3297 }
2668} 3298}
2669 3299
@@ -2673,24 +3303,25 @@ void reset_track_list(void)
2673static void show_track_list(void) 3303static void show_track_list(void)
2674{ 3304{
2675 mylcd_clear_display(); 3305 mylcd_clear_display();
2676 if ( center_slide.slide_index != track_index ) { 3306 if ( center_slide.slide_index != pf_tracks.cur_idx ) {
2677 create_track_index(center_slide.slide_index); 3307 create_track_index(center_slide.slide_index);
2678 reset_track_list(); 3308 reset_track_list();
2679 } 3309 }
2680 int titletxt_w, titletxt_x, color, titletxt_h; 3310 int titletxt_w, titletxt_x, color, titletxt_h;
2681 titletxt_h = rb->screens[SCREEN_MAIN]->getcharheight(); 3311 titletxt_h = rb->screens[SCREEN_MAIN]->getcharheight();
2682 3312
2683 int titletxt_y = track_list_y; 3313 int titletxt_y = pf_tracks.list_y;
2684 int track_i; 3314 int track_i;
2685 track_i = start_index_track_list; 3315 int fade;
2686 for (;track_i < track_list_visible_entries+start_index_track_list; 3316
2687 track_i++) 3317 track_i = pf_tracks.list_start;
3318 for (; track_i < pf_tracks.list_visible + pf_tracks.list_start; track_i++)
2688 { 3319 {
2689 char *trackname = get_track_name(track_i); 3320 char *trackname = get_track_name(track_i);
2690 if ( track_i == selected_track ) { 3321 if ( track_i == pf_tracks.sel ) {
2691 if (selected_track != last_selected_track) { 3322 if (pf_tracks.sel != pf_tracks.last_sel) {
2692 set_scroll_line(trackname, PF_SCROLL_TRACK); 3323 set_scroll_line(trackname, PF_SCROLL_TRACK);
2693 last_selected_track = selected_track; 3324 pf_tracks.last_sel = pf_tracks.sel;
2694 } 3325 }
2695 draw_gradient(titletxt_y, titletxt_h); 3326 draw_gradient(titletxt_y, titletxt_h);
2696 titletxt_x = get_scroll_line_offset(PF_SCROLL_TRACK); 3327 titletxt_x = get_scroll_line_offset(PF_SCROLL_TRACK);
@@ -2699,7 +3330,8 @@ static void show_track_list(void)
2699 else { 3330 else {
2700 titletxt_w = mylcd_getstringsize(trackname, NULL, NULL); 3331 titletxt_w = mylcd_getstringsize(trackname, NULL, NULL);
2701 titletxt_x = (LCD_WIDTH-titletxt_w)/2; 3332 titletxt_x = (LCD_WIDTH-titletxt_w)/2;
2702 color = 250 - (abs(selected_track - track_i) * 200 / track_count); 3333 fade = (abs(pf_tracks.sel - track_i) * 200 / pf_tracks.count);
3334 color = 250 - fade;
2703 } 3335 }
2704 mylcd_set_foreground(G_BRIGHT(color)); 3336 mylcd_set_foreground(G_BRIGHT(color));
2705 mylcd_putsxy(titletxt_x,titletxt_y,trackname); 3337 mylcd_putsxy(titletxt_x,titletxt_y,trackname);
@@ -2709,18 +3341,26 @@ static void show_track_list(void)
2709 3341
2710static void select_next_track(void) 3342static void select_next_track(void)
2711{ 3343{
2712 if ( selected_track < track_count - 1 ) { 3344 if ( pf_tracks.sel < pf_tracks.count - 1 ) {
2713 selected_track++; 3345 pf_tracks.sel++;
2714 if (selected_track==(track_list_visible_entries+start_index_track_list)) 3346 if (pf_tracks.sel==(pf_tracks.list_visible+pf_tracks.list_start))
2715 start_index_track_list++; 3347 pf_tracks.list_start++;
3348 } else {
3349 /* Rollover */
3350 pf_tracks.sel = 0;
3351 pf_tracks.list_start = 0;
2716 } 3352 }
2717} 3353}
2718 3354
2719static void select_prev_track(void) 3355static void select_prev_track(void)
2720{ 3356{
2721 if (selected_track > 0 ) { 3357 if (pf_tracks.sel > 0 ) {
2722 if (selected_track==start_index_track_list) start_index_track_list--; 3358 if (pf_tracks.sel==pf_tracks.list_start) pf_tracks.list_start--;
2723 selected_track--; 3359 pf_tracks.sel--;
3360 } else {
3361 /* Rolllover */
3362 pf_tracks.sel = pf_tracks.count - 1;
3363 pf_tracks.list_start = pf_tracks.count - pf_tracks.list_visible;
2724 } 3364 }
2725} 3365}
2726 3366
@@ -2732,7 +3372,7 @@ static void start_playback(bool append)
2732{ 3372{
2733 static int old_playlist = -1, old_shuffle = 0; 3373 static int old_playlist = -1, old_shuffle = 0;
2734 int count = 0; 3374 int count = 0;
2735 int position = selected_track; 3375 int position = pf_tracks.sel;
2736 int shuffle = rb->global_settings->playlist_shuffle; 3376 int shuffle = rb->global_settings->playlist_shuffle;
2737 /* reuse existing playlist if possible 3377 /* reuse existing playlist if possible
2738 * regenerate if shuffle is on or changed, since playlist index and 3378 * regenerate if shuffle is on or changed, since playlist index and
@@ -2751,14 +3391,14 @@ static void start_playback(bool append)
2751 if (rb->playlist_insert_track(NULL, get_track_filename(count), 3391 if (rb->playlist_insert_track(NULL, get_track_filename(count),
2752 PLAYLIST_INSERT_LAST, false, true) < 0) 3392 PLAYLIST_INSERT_LAST, false, true) < 0)
2753 break; 3393 break;
2754 } while(++count < track_count); 3394 } while(++count < pf_tracks.count);
2755 rb->playlist_sync(NULL); 3395 rb->playlist_sync(NULL);
2756 } 3396 }
2757 else 3397 else
2758 return; 3398 return;
2759 3399
2760 if (rb->global_settings->playlist_shuffle) 3400 if (rb->global_settings->playlist_shuffle)
2761 position = rb->playlist_shuffle(*rb->current_tick, selected_track); 3401 position = rb->playlist_shuffle(*rb->current_tick, pf_tracks.sel);
2762play: 3402play:
2763 /* TODO: can we adjust selected_track if !play_selected ? 3403 /* TODO: can we adjust selected_track if !play_selected ?
2764 * if shuffle, we can't predict the playing track easily, and for either 3404 * if shuffle, we can't predict the playing track easily, and for either
@@ -2775,12 +3415,14 @@ play:
2775 */ 3415 */
2776static void draw_album_text(void) 3416static void draw_album_text(void)
2777{ 3417{
2778 if (show_album_name == ALBUM_NAME_HIDE) 3418 if (pf_cfg.show_album_name == ALBUM_NAME_HIDE)
2779 return; 3419 return;
2780 3420
3421 static int prev_albumtxt_index = -1;
2781 int albumtxt_index; 3422 int albumtxt_index;
2782 int char_height; 3423 int char_height;
2783 int albumtxt_x, albumtxt_y, artisttxt_x; 3424 int albumtxt_x, albumtxt_y, artisttxt_x;
3425 int album_idx = 0;
2784 3426
2785 char *albumtxt; 3427 char *albumtxt;
2786 char *artisttxt; 3428 char *artisttxt;
@@ -2802,7 +3444,7 @@ static void draw_album_text(void)
2802 albumtxt_index = center_index; 3444 albumtxt_index = center_index;
2803 c= 255; 3445 c= 255;
2804 } 3446 }
2805 albumtxt = get_album_name(albumtxt_index); 3447 albumtxt = get_album_name_idx(albumtxt_index, &album_idx);
2806 3448
2807 mylcd_set_foreground(G_BRIGHT(c)); 3449 mylcd_set_foreground(G_BRIGHT(c));
2808 if (albumtxt_index != prev_albumtxt_index) { 3450 if (albumtxt_index != prev_albumtxt_index) {
@@ -2811,15 +3453,13 @@ static void draw_album_text(void)
2811 } 3453 }
2812 3454
2813 char_height = rb->screens[SCREEN_MAIN]->getcharheight(); 3455 char_height = rb->screens[SCREEN_MAIN]->getcharheight();
2814 switch(show_album_name){ 3456 switch(pf_cfg.show_album_name){
2815 case ALBUM_AND_ARTIST_TOP: 3457 case ALBUM_AND_ARTIST_TOP:
2816 albumtxt_y = 0; 3458 albumtxt_y = 0;
2817 break; 3459 break;
2818 case ALBUM_NAME_BOTTOM: 3460 case ALBUM_NAME_BOTTOM:
2819 albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 10);
2820 break;
2821 case ALBUM_AND_ARTIST_BOTTOM: 3461 case ALBUM_AND_ARTIST_BOTTOM:
2822 albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 20); 3462 albumtxt_y = (LCD_HEIGHT - (char_height * 5 / 2));
2823 break; 3463 break;
2824 case ALBUM_NAME_TOP: 3464 case ALBUM_NAME_TOP:
2825 default: 3465 default:
@@ -2828,15 +3468,21 @@ static void draw_album_text(void)
2828 } 3468 }
2829 3469
2830 albumtxt_x = get_scroll_line_offset(PF_SCROLL_ALBUM); 3470 albumtxt_x = get_scroll_line_offset(PF_SCROLL_ALBUM);
2831 mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt);
2832 3471
2833 if ((show_album_name == ALBUM_AND_ARTIST_TOP) 3472
2834 || (show_album_name == ALBUM_AND_ARTIST_BOTTOM)){ 3473 if ((pf_cfg.show_album_name == ALBUM_AND_ARTIST_TOP)
3474 || (pf_cfg.show_album_name == ALBUM_AND_ARTIST_BOTTOM)){
3475
3476 if (album_idx != (int) pf_idx.album_untagged_idx)
3477 mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt);
2835 3478
2836 artisttxt = get_album_artist(albumtxt_index); 3479 artisttxt = get_album_artist(albumtxt_index);
2837 set_scroll_line(artisttxt, PF_SCROLL_ARTIST); 3480 set_scroll_line(artisttxt, PF_SCROLL_ARTIST);
2838 artisttxt_x = get_scroll_line_offset(PF_SCROLL_ARTIST); 3481 artisttxt_x = get_scroll_line_offset(PF_SCROLL_ARTIST);
2839 mylcd_putsxy(artisttxt_x, albumtxt_y+20, artisttxt); 3482 int y_offset = char_height + char_height/2;
3483 mylcd_putsxy(artisttxt_x, albumtxt_y + y_offset, artisttxt);
3484 } else {
3485 mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt);
2840 } 3486 }
2841} 3487}
2842 3488
@@ -2857,7 +3503,7 @@ static void error_wait(const char *message)
2857 */ 3503 */
2858static int pictureflow_main(void) 3504static int pictureflow_main(void)
2859{ 3505{
2860 int ret; 3506 int ret = SUCCESS;
2861 3507
2862 rb->lcd_setfont(FONT_UI); 3508 rb->lcd_setfont(FONT_UI);
2863 3509
@@ -2868,10 +3514,13 @@ static int pictureflow_main(void)
2868 } 3514 }
2869 } 3515 }
2870 3516
3517 rb->memset(&aa_cache, 0, sizeof(struct albumart_t));
3518 config_set_defaults(&pf_cfg);
3519
2871 configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); 3520 configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
2872 if(auto_wps == 0) 3521 if(pf_cfg.auto_wps == 0)
2873 draw_splashscreen(); 3522 draw_splashscreen(pf_idx.buf, pf_idx.buf_sz);
2874 if(backlight_mode == 0) { 3523 if(pf_cfg.backlight_mode == 0) {
2875 /* Turn off backlight timeout */ 3524 /* Turn off backlight timeout */
2876 backlight_ignore_timeout(); 3525 backlight_ignore_timeout();
2877 } 3526 }
@@ -2879,19 +3528,20 @@ static int pictureflow_main(void)
2879 init_scroll_lines(); 3528 init_scroll_lines();
2880 init_reflect_table(); 3529 init_reflect_table();
2881 3530
2882 ALIGN_BUFFER(buf, buf_size, 4); 3531 ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4);
2883 3532
2884 /*Scan will trigger when no file is found or the option was activated*/ 3533 /*Scan will trigger when no file is found or the option was activated*/
2885 if ((cache_version != CACHE_VERSION)||(load_album_index() < 0)){ 3534 if ((pf_cfg.cache_version != CACHE_VERSION)||(load_album_index() < 0)){
2886 rb->splash(HZ/2,"Creating album index, please wait"); 3535 rb->splash(HZ/2,"Creating index, please wait");
2887 ret = create_album_index(); 3536 ret = create_album_index();
3537
2888 if (ret == 0){ 3538 if (ret == 0){
2889 save_album_index(); 3539 pf_cfg.cache_version = CACHE_REBUILD;
3540 if (save_album_index() < 0) {
3541 rb->splash(HZ, "Could not write index");
3542 };
2890 } 3543 }
2891 } 3544 }
2892 else{
2893 ret = 0;
2894 }
2895 3545
2896 if (ret == ERROR_BUFFER_FULL) { 3546 if (ret == ERROR_BUFFER_FULL) {
2897 error_wait("Not enough memory for album names"); 3547 error_wait("Not enough memory for album names");
@@ -2899,30 +3549,47 @@ static int pictureflow_main(void)
2899 } else if (ret == ERROR_NO_ALBUMS) { 3549 } else if (ret == ERROR_NO_ALBUMS) {
2900 error_wait("No albums found. Please enable database"); 3550 error_wait("No albums found. Please enable database");
2901 return PLUGIN_ERROR; 3551 return PLUGIN_ERROR;
3552 } else if (ret == ERROR_USER_ABORT) {
3553 error_wait("User aborted.");
3554 return PLUGIN_ERROR;
2902 } 3555 }
2903 3556
2904 ALIGN_BUFFER(buf, buf_size, 4); 3557 ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4);
2905 number_of_slides = album_count; 3558 number_of_slides = pf_idx.album_ct;
2906 if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { 3559
2907 cache_version = CACHE_REBUILD; 3560 size_t aa_bufsz = ALIGN_DOWN(pf_idx.buf_sz / 4, 0x4);
2908 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); 3561
2909 error_wait("Could not create album art cache"); 3562 if (aa_bufsz < DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(pix_t))
3563 {
3564 error_wait("Not enough memory for album art cache");
2910 return PLUGIN_ERROR; 3565 return PLUGIN_ERROR;
2911 } 3566 }
2912 3567
2913 if (!create_empty_slide(cache_version != CACHE_VERSION)) { 3568 pf_idx.buf_sz -= aa_bufsz;
2914 cache_version = CACHE_REBUILD; 3569 ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4);
2915 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); 3570 aa_cache.buf = (char*) pf_idx.buf + aa_bufsz;
3571 aa_cache.buf_sz = aa_bufsz;
3572 ALIGN_BUFFER(aa_cache.buf, aa_cache.buf_sz, 4);
3573
3574 if (!create_empty_slide(pf_cfg.cache_version != CACHE_VERSION)) {
3575 config_save(CACHE_REBUILD);
2916 error_wait("Could not load the empty slide"); 3576 error_wait("Could not load the empty slide");
2917 return PLUGIN_ERROR; 3577 return PLUGIN_ERROR;
2918 } 3578 }
2919 if (cache_version != CACHE_VERSION) 3579
3580 if ((pf_cfg.cache_version != CACHE_VERSION) && !create_albumart_cache()) {
3581 config_save(CACHE_REBUILD);
3582 error_wait("Could not create album art cache");
3583 } else if(aa_cache.inspected < pf_idx.album_ct) {
3584 rb->splash(HZ * 2, "Updating album art cache in background");
3585 }
3586
3587 if (pf_cfg.cache_version != CACHE_VERSION)
2920 { 3588 {
2921 cache_version = CACHE_VERSION; 3589 config_save(CACHE_VERSION);
2922 configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION);
2923 } 3590 }
2924 3591
2925 rb->buflib_init(&buf_ctx, (void *)buf, buf_size); 3592 rb->buflib_init(&buf_ctx, (void *)pf_idx.buf, pf_idx.buf_sz);
2926 3593
2927 if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0))) 3594 if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0)))
2928 { 3595 {
@@ -2939,19 +3606,25 @@ static int pictureflow_main(void)
2939 3606
2940 /* initialize */ 3607 /* initialize */
2941 for (i = 0; i < SLIDE_CACHE_SIZE; i++) { 3608 for (i = 0; i < SLIDE_CACHE_SIZE; i++) {
2942 cache[i].hid = 0; 3609 pf_sldcache.cache[i].hid = 0;
2943 cache[i].index = 0; 3610 pf_sldcache.cache[i].index = 0;
2944 cache[i].next = i + 1; 3611 pf_sldcache.cache[i].next = i + 1;
2945 cache[i].prev = i - 1; 3612 pf_sldcache.cache[i].prev = i - 1;
2946 } 3613 }
2947 cache[0].prev = i - 1; 3614 pf_sldcache.cache[0].prev = i - 1;
2948 cache[i - 1].next = 0; 3615 pf_sldcache.cache[i - 1].next = 0;
2949 cache_free = 0; 3616
3617 pf_sldcache.free = 0;
3618 pf_sldcache.used = -1;
3619 pf_sldcache.left_idx = -1;
3620 pf_sldcache.right_idx = -1;
3621 pf_sldcache.center_idx = -1;
3622
2950 buffer = LCD_BUF; 3623 buffer = LCD_BUF;
2951 3624
2952 pf_state = pf_idle; 3625 pf_state = pf_idle;
2953 3626
2954 track_index = -1; 3627 pf_tracks.cur_idx = -1;
2955 extra_fade = 0; 3628 extra_fade = 0;
2956 slide_frame = 0; 3629 slide_frame = 0;
2957 step = 0; 3630 step = 0;
@@ -3009,6 +3682,7 @@ static int pictureflow_main(void)
3009 break; 3682 break;
3010 case pf_idle: 3683 case pf_idle:
3011 render_all_slides(); 3684 render_all_slides();
3685 incremental_albumart_cache(false);
3012 break; 3686 break;
3013 } 3687 }
3014 3688
@@ -3019,7 +3693,7 @@ static int pictureflow_main(void)
3019 frames = 0; 3693 frames = 0;
3020 } 3694 }
3021 /* Draw FPS */ 3695 /* Draw FPS */
3022 if (show_fps) 3696 if (pf_cfg.show_fps)
3023 { 3697 {
3024#ifdef USEGSLIB 3698#ifdef USEGSLIB
3025 mylcd_set_foreground(G_BRIGHT(255)); 3699 mylcd_set_foreground(G_BRIGHT(255));
@@ -3027,7 +3701,7 @@ static int pictureflow_main(void)
3027 mylcd_set_foreground(G_PIX(255,0,0)); 3701 mylcd_set_foreground(G_PIX(255,0,0));
3028#endif 3702#endif
3029 rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps); 3703 rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps);
3030 if (show_album_name == ALBUM_NAME_TOP) 3704 if (pf_cfg.show_album_name == ALBUM_NAME_TOP)
3031 fpstxt_y = LCD_HEIGHT - 3705 fpstxt_y = LCD_HEIGHT -
3032 rb->screens[SCREEN_MAIN]->getcharheight(); 3706 rb->screens[SCREEN_MAIN]->getcharheight();
3033 else 3707 else
@@ -3057,9 +3731,9 @@ static int pictureflow_main(void)
3057 case PF_BACK: 3731 case PF_BACK:
3058 if ( pf_state == pf_show_tracks ) 3732 if ( pf_state == pf_show_tracks )
3059 { 3733 {
3060 rb->buflib_buffer_in(&buf_ctx, borrowed); 3734 rb->buflib_buffer_in(&buf_ctx, pf_tracks.borrowed);
3061 borrowed = 0; 3735 pf_tracks.borrowed = 0;
3062 track_index = -1; 3736 pf_tracks.cur_idx = -1;
3063 pf_state = pf_cover_out; 3737 pf_state = pf_cover_out;
3064 } 3738 }
3065 if (pf_state == pf_idle || pf_state == pf_scrolling) 3739 if (pf_state == pf_idle || pf_state == pf_scrolling)
@@ -3096,7 +3770,7 @@ static int pictureflow_main(void)
3096 break; 3770 break;
3097#if PF_PLAYBACK_CAPABLE 3771#if PF_PLAYBACK_CAPABLE
3098 case PF_CONTEXT: 3772 case PF_CONTEXT:
3099 if ( auto_wps != 0 ) { 3773 if ( pf_cfg.auto_wps != 0 ) {
3100 if( pf_state == pf_idle ) { 3774 if( pf_state == pf_idle ) {
3101 create_track_index(center_slide.slide_index); 3775 create_track_index(center_slide.slide_index);
3102 reset_track_list(); 3776 reset_track_list();
@@ -3104,7 +3778,7 @@ static int pictureflow_main(void)
3104 rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); 3778 rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST));
3105 } 3779 }
3106 else if( pf_state == pf_show_tracks ) { 3780 else if( pf_state == pf_show_tracks ) {
3107 rb->playlist_insert_track(NULL, get_track_filename(selected_track), 3781 rb->playlist_insert_track(NULL, get_track_filename(pf_tracks.sel),
3108 PLAYLIST_INSERT_LAST, false, true); 3782 PLAYLIST_INSERT_LAST, false, true);
3109 rb->playlist_sync(NULL); 3783 rb->playlist_sync(NULL);
3110 rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); 3784 rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST));
@@ -3113,18 +3787,18 @@ static int pictureflow_main(void)
3113 break; 3787 break;
3114#endif 3788#endif
3115 case PF_TRACKLIST: 3789 case PF_TRACKLIST:
3116 if ( auto_wps == 1 && pf_state == pf_idle ) { 3790 if ( pf_cfg.auto_wps == 1 && pf_state == pf_idle ) {
3117 pf_state = pf_cover_in; 3791 pf_state = pf_cover_in;
3118 break; 3792 break;
3119 } 3793 }
3120 case PF_SELECT: 3794 case PF_SELECT:
3121 if ( pf_state == pf_idle ) { 3795 if ( pf_state == pf_idle ) {
3122#if PF_PLAYBACK_CAPABLE 3796#if PF_PLAYBACK_CAPABLE
3123 if(auto_wps == 1) { 3797 if(pf_cfg.auto_wps == 1) {
3124 create_track_index(center_slide.slide_index); 3798 create_track_index(center_slide.slide_index);
3125 reset_track_list(); 3799 reset_track_list();
3126 start_playback(false); 3800 start_playback(false);
3127 last_album = center_index; 3801 pf_cfg.last_album = center_index;
3128 return PLUGIN_GOTO_WPS; 3802 return PLUGIN_GOTO_WPS;
3129 } 3803 }
3130 else 3804 else
@@ -3134,8 +3808,8 @@ static int pictureflow_main(void)
3134 else if ( pf_state == pf_show_tracks ) { 3808 else if ( pf_state == pf_show_tracks ) {
3135#if PF_PLAYBACK_CAPABLE 3809#if PF_PLAYBACK_CAPABLE
3136 start_playback(false); 3810 start_playback(false);
3137 if(auto_wps != 0) { 3811 if(pf_cfg.auto_wps != 0) {
3138 last_album = center_index; 3812 pf_cfg.last_album = center_index;
3139 return PLUGIN_GOTO_WPS; 3813 return PLUGIN_GOTO_WPS;
3140 } 3814 }
3141#endif 3815#endif
@@ -3154,6 +3828,10 @@ enum plugin_status plugin_start(const void *parameter)
3154{ 3828{
3155 int ret; 3829 int ret;
3156 (void) parameter; 3830 (void) parameter;
3831
3832 void * buf;
3833 size_t buf_size;
3834
3157 atexit(cleanup); 3835 atexit(cleanup);
3158 3836
3159#ifdef HAVE_ADJUSTABLE_CPU_FREQ 3837#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -3171,11 +3849,6 @@ enum plugin_status plugin_start(const void *parameter)
3171 } 3849 }
3172#endif 3850#endif
3173#endif 3851#endif
3174 /* create unique entry buffer with 1/4 of the plugin buffer */
3175 uniqbuf = buf;
3176 uniqbuf_size = ALIGN_DOWN(buf_size / 4, 0x8);
3177 buf += uniqbuf_size;
3178 buf_size -= uniqbuf_size;
3179 3852
3180#ifdef USEGSLIB 3853#ifdef USEGSLIB
3181 long grey_buf_used; 3854 long grey_buf_used;
@@ -3190,6 +3863,10 @@ enum plugin_status plugin_start(const void *parameter)
3190 buf = (void*)(grey_buf_used + (char*)buf); 3863 buf = (void*)(grey_buf_used + (char*)buf);
3191#endif 3864#endif
3192 3865
3866 /* store buffer pointers and sizes */
3867 pf_idx.buf = buf;
3868 pf_idx.buf_sz = buf_size;
3869
3193 ret = pictureflow_main(); 3870 ret = pictureflow_main();
3194 if ( ret == PLUGIN_OK || ret == PLUGIN_GOTO_WPS) { 3871 if ( ret == PLUGIN_OK || ret == PLUGIN_GOTO_WPS) {
3195 if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, 3872 if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS,