From 45915101d5338963e6359258513215a723ba1fd2 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Sun, 28 Jun 2020 00:02:20 -0400 Subject: 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 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 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 --- apps/plugins/pictureflow/pictureflow.c | 1739 ++++++++++++++++++++++---------- 1 file 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; #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE + 0x200 #define CACHE_PREFIX PLUGIN_DEMOS_DATA_DIR "/pictureflow" -#define ALBUM_INDEX CACHE_PREFIX "/PF_album_idx.tmp" +#define ALBUM_INDEX CACHE_PREFIX "/pictureflow_album.idx" #define EV_EXIT 9999 #define EV_WAKEUP 1337 @@ -250,16 +250,83 @@ typedef fb_data pix_t; #define CACHE_UPDATE 1 /* Error return values */ +#define SUCCESS 0 #define ERROR_NO_ALBUMS -1 #define ERROR_BUFFER_FULL -2 #define ERROR_NO_ARTISTS -3 +#define ERROR_USER_ABORT -4 /* current version for cover cache */ #define CACHE_VERSION 3 #define CONFIG_VERSION 1 #define CONFIG_FILE "pictureflow.cfg" +#define INDEX_HDR "PFID" /** structs we use */ +struct pf_config_t +{ + /* config values */ + int slide_spacing; + int center_margin; + + int num_slides; + int zoom; + + int auto_wps; + int last_album; + + int backlight_mode; + int cache_version; + + int show_album_name; + bool resize; + bool show_fps; +}; + +struct pf_index_t { + uint32_t header; /*INDEX_HDR*/ + uint16_t artist_ct; + uint16_t album_ct; + + char *artist_names; + struct artist_data *artist_index; + size_t artist_len; + + unsigned int album_untagged_idx; + char *album_names; + struct album_data *album_index; + size_t album_len; + long album_untagged_seek; + + void * buf; + size_t buf_sz; +}; + +struct pf_track_t { + int count; + int cur_idx; + int sel; + int sel_pulse; + int last_sel; + int list_start; + int list_visible; + int list_y; + int list_h; + size_t borrowed; + struct track_data *index; + char *names; +}; + +struct albumart_t { + struct bitmap input_bmp; + char pfraw_file[MAX_PATH]; + char file[MAX_PATH]; + int idx; + int slides; + int inspected; + void * buf; + size_t buf_sz; +}; struct slide_data { int slide_index; @@ -277,14 +344,15 @@ struct slide_cache { }; struct album_data { - int name_idx; - int artist_idx; - long seek; + int name_idx; /* offset to the album name */ + int artist_idx; /* offset to the artist name */ + long artist_seek; /* artist taglist position */ + long seek; /* album taglist position */ }; struct artist_data { - int name_idx; - long seek; + int name_idx; /* offset to the artist name */ + long seek; /* artist taglist position */ }; struct track_data { @@ -309,6 +377,16 @@ struct load_slide_event_data { int cache_index; }; +struct pf_slide_cache +{ + struct slide_cache cache[SLIDE_CACHE_SIZE]; + int free; + int used; + int left_idx; + int right_idx; + int center_idx; +}; + enum pf_scroll_line_type { PF_SCROLL_TRACK = 0, PF_SCROLL_ALBUM, @@ -354,37 +432,27 @@ static char* show_album_name_conf[] = #define MAX_SPACING 40 #define MAX_MARGIN 80 -/* config values and their defaults */ -static int slide_spacing = DISPLAY_WIDTH / 4; -static int center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12; -static int num_slides = 4; -static int zoom = 100; -static bool show_fps = false; -static int auto_wps = 0; -static int last_album = 0; -static int backlight_mode = 0; -static bool resize = true; -static int cache_version = 0; -static int show_album_name = (LCD_HEIGHT > 100) - ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM; +static struct albumart_t aa_cache; +static struct pf_config_t pf_cfg; static struct configdata config[] = { - { TYPE_INT, 0, MAX_SPACING, { .int_p = &slide_spacing }, "slide spacing", + { TYPE_INT, 0, MAX_SPACING, { .int_p = &pf_cfg.slide_spacing }, "slide spacing", NULL }, - { TYPE_INT, 0, MAX_MARGIN, { .int_p = ¢er_margin }, "center margin", + { TYPE_INT, 0, MAX_MARGIN, { .int_p = &pf_cfg.center_margin }, "center margin", NULL }, - { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &num_slides }, "slides count", + { TYPE_INT, 0, MAX_SLIDES_COUNT, { .int_p = &pf_cfg.num_slides }, "slides count", NULL }, - { TYPE_INT, 0, 300, { .int_p = &zoom }, "zoom", NULL }, - { TYPE_BOOL, 0, 1, { .bool_p = &show_fps }, "show fps", NULL }, - { TYPE_BOOL, 0, 1, { .bool_p = &resize }, "resize", NULL }, - { TYPE_INT, 0, 100, { .int_p = &cache_version }, "cache version", NULL }, - { TYPE_ENUM, 0, 5, { .int_p = &show_album_name }, "show album name", + { TYPE_INT, 0, 300, { .int_p = &pf_cfg.zoom }, "zoom", NULL }, + { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.show_fps }, "show fps", NULL }, + { TYPE_BOOL, 0, 1, { .bool_p = &pf_cfg.resize }, "resize", NULL }, + { TYPE_INT, 0, 100, { .int_p = &pf_cfg.cache_version }, "cache version", NULL }, + { TYPE_ENUM, 0, 5, { .int_p = &pf_cfg.show_album_name }, "show album name", show_album_name_conf }, - { TYPE_INT, 0, 2, { .int_p = &auto_wps }, "auto wps", NULL }, - { TYPE_INT, 0, 999999, { .int_p = &last_album }, "last album", NULL }, - { TYPE_INT, 0, 1, { .int_p = &backlight_mode }, "backlight", NULL } + { TYPE_INT, 0, 2, { .int_p = &pf_cfg.auto_wps }, "auto wps", NULL }, + { TYPE_INT, 0, 999999, { .int_p = &pf_cfg.last_album }, "last album", NULL }, + { TYPE_INT, 0, 1, { .int_p = &pf_cfg.backlight_mode }, "backlight", NULL }, + { TYPE_INT, 0, 999999, { .int_p = &aa_cache.idx }, "art cache pos", NULL }, }; #define CONFIG_NUM_ITEMS (sizeof(config) / sizeof(struct configdata)) @@ -406,12 +474,7 @@ static PFreal offsetX; static PFreal offsetY; static int number_of_slides; -static struct slide_cache cache[SLIDE_CACHE_SIZE]; -static int cache_free; -static int cache_used = -1; -static int cache_left_index = -1; -static int cache_right_index = -1; -static int cache_center_index = -1; +static struct pf_slide_cache pf_sldcache; /* use long for aligning */ unsigned long thread_stack[THREAD_STACK_SIZE / sizeof(long)]; @@ -426,29 +489,12 @@ static struct tagcache_search tcs; static struct buflib_context buf_ctx; -static struct album_data *album; -static struct artist_data *artist; +static struct pf_index_t pf_idx; -static char *album_names; -static int album_count; +static struct pf_track_t pf_tracks; -static char *artist_names; -static int artist_count; - -static struct track_data *tracks; -static char *track_names; -static size_t borrowed = 0; -static int track_count; -static int track_index; -static int selected_track; -static int selected_track_pulse; void reset_track_list(void); -void * buf; -size_t buf_size; -void * uniqbuf; -size_t uniqbuf_size; - static bool thread_is_running; static int cover_animation_keyframe; @@ -456,14 +502,8 @@ static int extra_fade; static struct pf_scroll_line_info scroll_line_info; static struct pf_scroll_line scroll_lines[PF_MAX_SCROLL_LINES]; -static int prev_albumtxt_index = -1; -static int last_selected_track = -1; - -static int start_index_track_list = 0; -static int track_list_visible_entries = 0; -static int track_list_y; -static int track_list_h; +enum ePFS{ePFS_ARTIST = 0, ePFS_ALBUM}; /* Proposals for transitions: @@ -494,6 +534,45 @@ static int pf_state; static bool free_slide_prio(int prio); bool load_new_slide(void); int load_surface(int); +static void draw_progressbar(int step, int count, char *msg); +static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size); +static void free_all_slide_prio(int prio); + +static bool confirm_quit(void) +{ + const struct text_message prompt = + { (const char*[]) {"Quit?", "Progress will be lost"}, 2}; + enum yesno_res response = rb->gui_syncyesno_run(&prompt, NULL, NULL); + while (rb->button_get(false) == BUTTON_NONE) + ;; + + if(response == YESNO_NO) + return false; + else + return true; +} + +static void config_save(int cache_version) +{ + pf_cfg.cache_version = cache_version; + configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); +} + +static void config_set_defaults(struct pf_config_t *cfg) +{ + cfg->slide_spacing = DISPLAY_WIDTH / 4; + cfg->center_margin = (LCD_WIDTH - DISPLAY_WIDTH) / 12; + cfg->num_slides = 4; + cfg->zoom = 100; + cfg->show_fps = false; + cfg->auto_wps = 0; + cfg->last_album = 0; + cfg->backlight_mode = 0; + cfg->resize = true; + cfg->cache_version = 0; + cfg->show_album_name = (LCD_HEIGHT > 100) + ? ALBUM_NAME_TOP : ALBUM_NAME_BOTTOM; +} static inline PFreal fmul(PFreal a, PFreal b) { @@ -849,135 +928,538 @@ static void init_reflect_table(void) (5 * REFLECT_HEIGHT); } -/** - Create an index of all artists and albums from the database. - Also store the artists and album names so we can access them later. - */ -static int create_album_index(void) +static int compare_album_artists (const void *a_v, const void *b_v) { - artist = ((struct artist_data *)(buf_size + (char *) buf)) - 1; - rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); - artist_count = 0; - rb->tagcache_search(&tcs, tag_albumartist); + uint32_t a = ((struct album_data *)a_v)->artist_idx; + uint32_t b = ((struct album_data *)b_v)->artist_idx; + return (int)(a - b); +} + +static void write_album_index(int idx, int name_idx, + long album_seek, int artist_idx, long artist_seek) +{ + pf_idx.album_index[idx].name_idx = name_idx; + pf_idx.album_index[idx].seek = album_seek; + pf_idx.album_index[idx].artist_idx = artist_idx; + pf_idx.album_index[idx].artist_seek = artist_seek; +} + +static inline void write_album_entry(struct tagcache_search *tcs, + int name_idx, unsigned int len) +{ + write_album_index(-pf_idx.album_ct, name_idx, tcs->result_seek, 0, -1); + pf_idx.album_len += len; + pf_idx.album_ct++; + + if (pf_idx.album_untagged_seek == -1 && rb->strcmp(UNTAGGED, tcs->result) == 0) + { + pf_idx.album_untagged_idx = name_idx; + pf_idx.album_untagged_seek = tcs->result_seek; + } +} + +static void write_artist_entry(struct tagcache_search *tcs, + int name_idx, unsigned int len) +{ + pf_idx.artist_index[-pf_idx.artist_ct].name_idx = name_idx; + pf_idx.artist_index[-pf_idx.artist_ct].seek = tcs->result_seek; + pf_idx.artist_len += len; + pf_idx.artist_ct++; +} + +/* adds tagcache_search results into artist/album index */ +static int get_tcs_search_res(int type, struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int ret = SUCCESS; unsigned int l, name_idx = 0; - artist_names = buf; - while (rb->tagcache_get_next(&tcs)) + void (*writefn)(struct tagcache_search *, int, unsigned int); + int data_size; + if (type == ePFS_ARTIST) + { + writefn = &write_artist_entry; + data_size = sizeof(struct artist_data); + } + else + { + writefn = &write_album_entry; + data_size = sizeof(struct album_data); + } + + while (rb->tagcache_get_next(tcs)) { - buf_size -= sizeof(struct artist_data); - l = tcs.result_len; - artist[-artist_count].name_idx = name_idx; - artist[-artist_count].seek = tcs.result_seek; - if ( l > buf_size ) + if (rb->button_get(false) > BUTTON_NONE) + { + if (confirm_quit()) + { + ret = ERROR_USER_ABORT; + break; + } else + rb->lcd_clear_display(); + } + + *bufsz -= data_size; + + l = tcs->result_len; + + if ( l > *bufsz ) + { /* not enough memory */ - return ERROR_BUFFER_FULL; - rb->strcpy(buf, tcs.result); - buf_size -= l; - buf = l + (char *)buf; + ret = ERROR_BUFFER_FULL; + break; + } + + rb->strcpy(*buf, tcs->result); + + *bufsz -= l; + *buf = l + (char *)*buf; + + writefn(tcs, name_idx, l); + name_idx += l; - artist_count++; } + rb->tagcache_search_finish(tcs); + return ret; +} + +/*adds albums/artist to existing album index */ +static int create_album_untagged(struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int ret = SUCCESS; + int album_count = pf_idx.album_ct; /* store existing count */ + int total_count = pf_idx.album_ct + pf_idx.artist_ct * 2; + long seek; + int last, final, retry; + int i, j; + draw_splashscreen(*buf, *bufsz); + draw_progressbar(0, total_count, "Searching " UNTAGGED); + + /* search tagcache for all albums & save the albumartist seek pos */ + if (rb->tagcache_search(tcs, tag_albumartist)) + { + rb->tagcache_search_add_filter(tcs, tag_album, pf_idx.album_untagged_seek); + + while (rb->tagcache_get_next(tcs)) + { + if (rb->button_get(false) > BUTTON_NONE) { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(pf_idx.album_ct, total_count, + "Searching " UNTAGGED); + } + } + + if (tcs->result_seek == + pf_idx.album_index[-(pf_idx.album_ct - 1)].artist_seek) + continue; + + if (sizeof(struct album_data) > *bufsz) + { + /* not enough memory */ + ret = ERROR_BUFFER_FULL; + break; + } + + *bufsz -= sizeof(struct album_data); + write_album_index(-pf_idx.album_ct, pf_idx.album_untagged_idx, + pf_idx.album_untagged_seek, -1, tcs->result_seek); + + pf_idx.album_ct++; + draw_progressbar(pf_idx.album_ct, total_count, NULL); + } + rb->tagcache_search_finish(tcs); + + if (ret == SUCCESS) { + draw_splashscreen(*buf, *bufsz); + draw_progressbar(0, pf_idx.album_ct, "Finalizing " UNTAGGED); + + last = 0; + final = pf_idx.artist_ct; + retry = 0; + + /* map the artist_seek position to the artist name index */ + for (j = album_count; j < pf_idx.album_ct; j++) + { + if (rb->button_get(false) > BUTTON_NONE) { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(j, pf_idx.album_ct, "Finalizing " UNTAGGED); + } + } + + draw_progressbar(j, pf_idx.album_ct, NULL); + seek = pf_idx.album_index[-j].artist_seek; + + retry_artist_lookup: + retry++; + for (i = last; i < final; i++) + { + if (seek == pf_idx.artist_index[i].seek) + { + int idx = pf_idx.artist_index[i].name_idx; + pf_idx.album_index[-j].artist_idx = idx; + last = i; /* last match, start here next loop */ + final = pf_idx.artist_ct; + retry = 0; + break; + } + } + if (retry > 0 && retry < 2) + { + /* no match start back at beginning */ + final = last; + last = 0; + goto retry_artist_lookup; + } + } + } + } + + return ret; +} + +/* Create an index of all artists from the database */ +static int build_artist_index(struct tagcache_search *tcs, + void **buf, size_t *bufsz) +{ + int i, res = SUCCESS; + struct artist_data* tmp_artist; + + /* artist index starts at end of buf it will be rearranged when finalized */ + pf_idx.artist_index = ((struct artist_data *)(*bufsz + (char *) *buf)) - 1; + pf_idx.artist_ct = 0; + pf_idx.artist_len = 0; + /* artist names starts at beginning of buf */ + pf_idx.artist_names = *buf; + + rb->tagcache_search(tcs, tag_albumartist); + res = get_tcs_search_res(ePFS_ARTIST, tcs, &(*buf), bufsz); + rb->tagcache_search_finish(tcs); + if (res < SUCCESS) + return res; + + ALIGN_BUFFER(*buf, *bufsz, 4); + + /* finalize the artist index */ + tmp_artist = (struct artist_data*)*buf; + for (i = pf_idx.artist_ct - 1; i >= 0; i--) + tmp_artist[i] = pf_idx.artist_index[-i]; + + pf_idx.artist_index = tmp_artist; + /* move buf ptr to end of artist_index */ + *buf = pf_idx.artist_index + pf_idx.artist_ct; + ALIGN_BUFFER(*buf, *bufsz, 4); + + if (res == SUCCESS) + { + if (pf_idx.artist_ct > 0) + res = pf_idx.artist_ct; + else + res = ERROR_NO_ALBUMS; + } + + return res; +} + + +/** + Create an index of all artists and albums from the database. + Also store the artists and album names so we can access them later. + */ +static int create_album_index(void) +{ + void *buf = pf_idx.buf; + size_t buf_size = pf_idx.buf_sz; + + struct album_data* tmp_album; + + int i, j, last, final, retry, res; + + draw_splashscreen(buf, buf_size); + ALIGN_BUFFER(buf, buf_size, 4); + +/* Artists */ + res = build_artist_index(&tcs, &buf, &buf_size); + if (res < SUCCESS) + return res; + +/* Albums */ + pf_idx.album_ct = 0; + pf_idx.album_len =0; + pf_idx.album_untagged_idx = 0; + pf_idx.album_untagged_seek = -1; + + /* album_index starts at end of buf it will be rearranged when finalized */ + pf_idx.album_index = ((struct album_data *)(buf_size + (char *)buf)) - 1; + /* album_names starts at the beginning of buf */ + pf_idx.album_names = buf; + + rb->tagcache_search(&tcs, tag_album); + res = get_tcs_search_res(ePFS_ALBUM, &tcs, &buf, &buf_size); rb->tagcache_search_finish(&tcs); + if (res < SUCCESS) + return res; ALIGN_BUFFER(buf, buf_size, 4); - int i; - struct artist_data* tmp_artist = (struct artist_data*)buf; - for (i = artist_count - 1; i >= 0; i--) - tmp_artist[i] = artist[-i]; - artist = tmp_artist; - buf = artist + artist_count; - - long artist_seek = 0; - int j = 0; - album_count = 0; - name_idx = 0; - album = ((struct album_data *)(buf_size + (char *) buf)) - 1; - album_names = buf; - for (j = 0; j < artist_count; j++){ - artist_seek = artist[j].seek; - rb->memset(&tcs, 0, sizeof(struct tagcache_search) ); - rb->tagcache_search(&tcs, tag_album); - /* Prevent duplicate entries in the search list. */ - rb->tagcache_search_set_uniqbuf(&tcs, uniqbuf, uniqbuf_size); - rb->tagcache_search_add_filter(&tcs, tag_albumartist, artist_seek); - while (rb->tagcache_get_next(&tcs)) + + /* Build artist list for untagged albums */ + res = create_album_untagged(&tcs, &buf, &buf_size); + + if (res < SUCCESS) + return res; + + ALIGN_BUFFER(buf, buf_size, 4); + + /* finalize the album index */ + tmp_album = (struct album_data*)buf; + for (i = pf_idx.album_ct - 1; i >= 0; i--) + tmp_album[i] = pf_idx.album_index[-i]; + + pf_idx.album_index = tmp_album; + /* move buf ptr to end of album_index */ + buf = pf_idx.album_index + pf_idx.album_ct; + ALIGN_BUFFER(buf, buf_size, 4); + +/* Assign indices */ + draw_splashscreen(buf, buf_size); + draw_progressbar(0, pf_idx.album_ct, "Assigning Albums"); + for (j = 0; j < pf_idx.album_ct; j++) + { + if (rb->button_get(false) > BUTTON_NONE) + { + if (confirm_quit()) + return ERROR_USER_ABORT; + else + { + rb->lcd_clear_display(); + draw_progressbar(j, pf_idx.album_ct, "Assigning Albums"); + } + + } + + draw_progressbar(j, pf_idx.album_ct, NULL); + if (pf_idx.album_index[j].artist_seek >= 0) { continue; } + + rb->tagcache_search(&tcs, tag_albumartist); + rb->tagcache_search_add_filter(&tcs, tag_album, pf_idx.album_index[j].seek); + + last = 0; + final = pf_idx.artist_ct; + retry = 0; + if (rb->tagcache_get_next(&tcs)) { - buf_size -= sizeof(struct album_data); - l = tcs.result_len; - album[-album_count].name_idx = name_idx; - album[-album_count].seek = tcs.result_seek; - album[-album_count].artist_idx = j; - if ( l > buf_size ) - /* not enough memory */ - return ERROR_BUFFER_FULL; - rb->strcpy(buf, tcs.result); - buf_size -= l; - buf = l + (char *)buf; - name_idx += l; - album_count++; +retry_artist_lookup: + retry++; + for (i = last; i < final; i++) + { + if (tcs.result_seek == pf_idx.artist_index[i].seek) + { + int idx = pf_idx.artist_index[i].name_idx; + pf_idx.album_index[j].artist_idx = idx; + pf_idx.album_index[j].artist_seek = tcs.result_seek; + last = i; /* last match, start here next loop */ + final = pf_idx.artist_ct; + retry = 0; + break; + } + } + if (retry > 0 && retry < 2) + { + /* no match start back at beginning */ + final = last; + last = 0; + goto retry_artist_lookup; + } } rb->tagcache_search_finish(&tcs); } + /* sort list order to find duplicates */ + rb->qsort(pf_idx.album_index, pf_idx.album_ct, + sizeof(struct album_data), compare_album_artists); + + draw_splashscreen(buf, buf_size); + draw_progressbar(0, pf_idx.album_ct, "Removing duplicates"); + /* mark duplicate albums for deletion */ + for (i = 0; i < pf_idx.album_ct - 1; i++) /* -1 don't check last entry */ + { + int idxi = pf_idx.album_index[i].artist_idx; + int seeki = pf_idx.album_index[i].seek; + + draw_progressbar(i, pf_idx.album_ct, NULL); + for (j = i + 1; j < pf_idx.album_ct; j++) + { + if (idxi > 0 && + idxi == pf_idx.album_index[j].artist_idx && + seeki == pf_idx.album_index[j].seek) + { + pf_idx.album_index[j].artist_idx = -1; + } + else + { + i = j - 1; + break; + } + } + } + + /* now fix the album list order */ + rb->qsort(pf_idx.album_index, pf_idx.album_ct, + sizeof(struct album_data), compare_album_artists); + + /* remove any extra untagged albums + * extra space is orphaned till restart */ + for (i = 0; i < pf_idx.album_ct; i++) + { + if (pf_idx.album_index[i].artist_idx > 0) + { + if (i > 0) { i--; } + pf_idx.album_index += i; + pf_idx.album_ct -= i; + break; + } + } + ALIGN_BUFFER(buf, buf_size, 4); - struct album_data* tmp_album = (struct album_data*)buf; - for (i = album_count - 1; i >= 0; i--) - tmp_album[i] = album[-i]; - album = tmp_album; - buf = album + album_count; + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + pf_idx.artist_index = 0; - return (album_count > 0) ? 0 : ERROR_NO_ALBUMS; + return (pf_idx.album_ct > 0) ? 0 : ERROR_NO_ALBUMS; } - -/*Saves the artists+albums index into a binary file to be recovered the +/*Saves the album index into a binary file to be recovered the next time PictureFlow is launched*/ static int save_album_index(void){ int fd = rb->creat(ALBUM_INDEX,0666); + + struct pf_index_t data; + memcpy(&data, &pf_idx, sizeof(struct pf_index_t)); + if(fd >= 0) { - int unsigned_size = sizeof(unsigned int); - int int_size = sizeof(int); - rb->write(fd, artist_names, ((char *)buf - (char *)artist_names)); - unsigned int artist_pos = (char *)artist - (char *)artist_names; - rb->write(fd, &artist_pos, unsigned_size); - unsigned int album_names_pos = (char *)album_names - (char *)artist_names; - rb->write(fd, &album_names_pos, unsigned_size); - unsigned int album_pos = (char *)album - (char *)artist_names; - rb->write(fd, &album_pos, unsigned_size); - rb->write(fd, &artist_count, int_size); - rb->write(fd, &album_count, int_size); + rb->memcpy(&data.header, INDEX_HDR, sizeof(pf_idx.header)); + + rb->write(fd, &data, sizeof(struct pf_index_t)); + + rb->write(fd, data.artist_names, data.artist_len); + rb->write(fd, data.album_names, data.album_len); + + rb->write(fd, data.album_index, data.album_ct * sizeof(struct album_data)); + rb->close(fd); return 0; } return -1; } -/*Loads the artists+albums index information stored in the hard drive*/ +/* reads data from save file to buffer */ +static inline int read2buf(int fildes, void *buf, size_t nbyte){ + int read; + read = rb->read(fildes, buf, nbyte); + if (read < (int)nbyte) + return 0; + + return read; +} +/*Loads the album_index information stored in the hard drive*/ static int load_album_index(void){ - int fr = rb->open(ALBUM_INDEX, O_RDONLY); + + int i, fr = rb->open(ALBUM_INDEX, O_RDONLY); + struct pf_index_t data; + + void *bufstart = pf_idx.buf; + unsigned int bufstart_sz = pf_idx.buf_sz; + + void* buf = pf_idx.buf; + size_t buf_size = pf_idx.buf_sz; + + unsigned int name_sz, album_idx_sz; + int album_idx, artist_idx; + if (fr >= 0){ - int unsigned_size = sizeof(unsigned int); - int int_size = sizeof(int); - unsigned long filesize = rb->filesize(fr); - unsigned int pos = 0; - unsigned int extra_data_size = (sizeof(unsigned int)*3) + (sizeof(int)*2); - rb->read(fr,buf ,filesize-extra_data_size); - artist_names = buf; - buf = (char *)buf + (filesize-extra_data_size); - buf_size = buf_size-(filesize-extra_data_size); - rb->read(fr,&pos ,unsigned_size); - artist = (void *)artist_names + pos; - rb->read(fr,&pos ,unsigned_size); - album_names = (void *)artist_names + pos; - rb->read(fr,&pos ,unsigned_size); - album = (void *)artist_names + pos; - rb->read(fr,&artist_count ,int_size); - rb->read(fr,&album_count ,int_size); - rb->close(fr); - return 0; + const unsigned long filesize = rb->filesize(fr); + if (filesize > sizeof(data)) + { + if (rb->read(fr, &data, sizeof(data)) == sizeof(data) && + rb->memcmp(&(data.header), INDEX_HDR, sizeof(data.header)) == 0) + { + name_sz = data.artist_len + data.album_len; + album_idx_sz = data.album_ct * sizeof(struct album_data); + + if (name_sz + album_idx_sz > bufstart_sz) + goto failure; + + //rb->lseek(fr, sizeof(data) + 1, SEEK_SET); + /* artist names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, data.artist_len) == 0) + goto failure; + + data.artist_names = buf; + buf = (char *)buf + data.artist_len; + buf_size -= data.artist_len; + + /* album names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, data.album_len) == 0) + goto failure; + + data.album_names = buf; + buf = (char *)buf + data.album_len; + buf_size -= data.album_len; + + /* index of album names */ + ALIGN_BUFFER(buf, buf_size, 4); + if (read2buf(fr, buf, album_idx_sz) == 0) + goto failure; + + data.album_index = buf; + buf = (char *)buf + album_idx_sz; + buf_size -= album_idx_sz; + + rb->close(fr); + + /* sanity check loaded data */ + for (i = 0; i < data.album_ct; i++) + { + album_idx = data.album_index[i].name_idx; + artist_idx = data.album_index[i].artist_idx; + if (album_idx >= (int) data.album_len || + artist_idx >= (int) data.artist_len) + { + goto failure; + } + } + + memcpy(&pf_idx, &data, sizeof(struct pf_index_t)); + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + + return 0; + } + } } + +failure: + rb->splash(HZ/2, "Failed to load index"); + if (fr >= 0) + rb->close(fr); + + pf_idx.buf = bufstart; + pf_idx.buf_sz = bufstart_sz; + pf_idx.artist_ct = 0; + pf_idx.album_ct = 0; return -1; + } /** @@ -985,7 +1467,18 @@ static int load_album_index(void){ */ static char* get_album_name(const int slide_index) { - return album_names + album[slide_index].name_idx; + char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx; + return name; +} + +/** + Return a pointer to the album name of the given slide_index + */ +static char* get_album_name_idx(const int slide_index, int *idx) +{ + *idx = pf_idx.album_index[slide_index].name_idx; + char *name = pf_idx.album_names + pf_idx.album_index[slide_index].name_idx; + return name; } /** @@ -993,13 +1486,14 @@ static char* get_album_name(const int slide_index) */ static char* get_album_artist(const int slide_index) { - if (slide_index < album_count && slide_index >= 0){ - int artist_pos = album[slide_index].artist_idx; - if (artist_pos < artist_count && artist_pos >= 0){ - return artist_names + artist[artist_pos].name_idx; + if (slide_index < pf_idx.album_ct && slide_index >= 0){ + int idx = pf_idx.album_index[slide_index].artist_idx; + if (idx >= 0 && idx < (int) pf_idx.artist_len) { + char *name = pf_idx.artist_names + idx; + return name; } } - return NULL; + return "?"; } @@ -1009,34 +1503,54 @@ static char* get_album_artist(const int slide_index) */ static char* get_track_name(const int track_index) { - if ( track_index < track_count ) - return track_names + tracks[track_index].name_idx; + if (track_index >= 0 && track_index < pf_tracks.count ) + return pf_tracks.names + pf_tracks.index[track_index].name_idx; return 0; } #if PF_PLAYBACK_CAPABLE static char* get_track_filename(const int track_index) { - if ( track_index < track_count ) - return track_names + tracks[track_index].filename_idx; + if ( track_index < pf_tracks.count ) + return pf_tracks.names + pf_tracks.index[track_index].filename_idx; return 0; } #endif static int get_wps_current_index(void) { + char* current_artist = UNTAGGED; + char* current_album = UNTAGGED; struct mp3entry *id3 = rb->audio_current_track(); - if(id3 && id3->album) { + if(id3) + { + /* we could be looking for the artist in either field */ + if(id3->albumartist) + current_artist = id3->albumartist; + else if(id3->artist) + current_artist = id3->artist; + + if (id3->album && rb->strlen(id3->album) > 0) + current_album = id3->album; + + //rb->splashf(1000, "%s, %s", current_album, current_artist); + int i; - for( i=0; i < album_count; i++ ) + int album_idx, artist_idx; + + for (i = 0; i < pf_idx.album_ct; i++ ) { - if(!rb->strcmp(album_names + album[i].name_idx, id3->album) && - !rb->strcmp(artist_names + artist[album[i].artist_idx].name_idx, - id3->albumartist)) + album_idx = pf_idx.album_index[i].name_idx; + artist_idx = pf_idx.album_index[i].artist_idx; + + if(!rb->strcmp(pf_idx.album_names + album_idx, current_album) && + !rb->strcmp(pf_idx.artist_names + artist_idx, current_artist)) return i; } + } - return last_album; + rb->splash(HZ/2, "Album Not Found!"); + return pf_cfg.last_album; } /** @@ -1054,50 +1568,81 @@ static int compare_tracks (const void *a_v, const void *b_v) */ static void create_track_index(const int slide_index) { - if ( slide_index == track_index ) + char temp[MAX_PATH + 1]; + if ( slide_index == pf_tracks.cur_idx ) return; - track_index = slide_index; if (!rb->tagcache_search(&tcs, tag_title)) goto fail; - rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); - rb->tagcache_search_add_filter(&tcs, tag_albumartist, - artist[album[slide_index].artist_idx].seek); + rb->tagcache_search_add_filter(&tcs, tag_album, + pf_idx.album_index[slide_index].seek); + + if (pf_idx.album_index[slide_index].artist_idx >= 0) + { + rb->tagcache_search_add_filter(&tcs, tag_albumartist, + pf_idx.album_index[slide_index].artist_seek); + } - track_count=0; int string_index = 0, track_num; int disc_num; + + char* result = NULL; size_t out = 0; - track_names = rb->buflib_buffer_out(&buf_ctx, &out); - borrowed += out; - int avail = borrowed; - tracks = (struct track_data*)(track_names + borrowed); + + pf_tracks.count = 0; + pf_tracks.names = rb->buflib_buffer_out(&buf_ctx, &out); + pf_tracks.borrowed += out; + int avail = pf_tracks.borrowed; + pf_tracks.index = (struct track_data*)(pf_tracks.names + pf_tracks.borrowed); while (rb->tagcache_get_next(&tcs)) { + result = NULL; + if (rb->strcmp(UNTAGGED, tcs.result) == 0) + { + /* show filename instead of */ + if (!rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, + temp, sizeof(temp) - 1)) + { + goto fail; + } + result = temp; + } + int len = 0, fn_idx = 0; avail -= sizeof(struct track_data); track_num = rb->tagcache_get_numeric(&tcs, tag_tracknumber); disc_num = rb->tagcache_get_numeric(&tcs, tag_discnumber); + if (result) + { + /* if filename remove the '/' */ + result = rb->strrchr(result, PATH_SEPCH); + if (result) + result++; + } + + if (!result) + result = tcs.result; + if (disc_num < 0) disc_num = 0; retry: if (track_num > 0) { if (disc_num) - fn_idx = 1 + rb->snprintf(track_names + string_index , avail, - "%d.%02d: %s", disc_num, track_num, tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%d.%02d: %s", disc_num, track_num, result); else - fn_idx = 1 + rb->snprintf(track_names + string_index , avail, - "%d: %s", track_num, tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%d: %s", track_num, result); } else { track_num = 0; - fn_idx = 1 + rb->snprintf(track_names + string_index, avail, - "%s", tcs.result); + fn_idx = 1 + rb->snprintf(pf_tracks.names + string_index, avail, + "%s", result); } if (fn_idx <= 0) goto fail; @@ -1106,11 +1651,12 @@ retry: if (remain >= MAX_PATH) { /* retrieve filename for building the playlist */ rb->tagcache_retrieve(&tcs, tcs.idx_id, tag_filename, - track_names + string_index + fn_idx, remain); - len = fn_idx + rb->strlen(track_names + string_index + fn_idx) + 1; + pf_tracks.names + string_index + fn_idx, remain); + + len = fn_idx + rb->strlen(pf_tracks.names + string_index + fn_idx) + 1; /* make sure track name and file name are really split by a \0, else * get_track_name might fail */ - *(track_names + string_index + fn_idx -1) = '\0'; + *(pf_tracks.names + string_index + fn_idx -1) = '\0'; } else /* request more buffer so that track and filename fit */ @@ -1127,38 +1673,43 @@ retry: out = 0; rb->buflib_buffer_out(&buf_ctx, &out); avail += out; - borrowed += out; + pf_tracks.borrowed += out; - struct track_data *new_tracks = - (struct track_data *)(out + (uintptr_t)tracks); + struct track_data *new_tracks; + new_tracks = (struct track_data *)(out + (uintptr_t)pf_tracks.index); - unsigned int bytes = track_count * sizeof(struct track_data); - if (track_count) - rb->memmove(new_tracks, tracks, bytes); - tracks = new_tracks; + unsigned int bytes = pf_tracks.count * sizeof(struct track_data); + if (pf_tracks.count) + rb->memmove(new_tracks, pf_tracks.index, bytes); + pf_tracks.index = new_tracks; } goto retry; } avail -= len; - tracks--; - tracks->sort = (disc_num << 24) + (track_num << 14) + track_count; - tracks->name_idx = string_index; - tracks->seek = tcs.result_seek; + pf_tracks.index--; + pf_tracks.index->sort = (disc_num << 24) + (track_num << 14); + pf_tracks.index->sort += pf_tracks.count; + pf_tracks.index->name_idx = string_index; + pf_tracks.index->seek = tcs.result_seek; #if PF_PLAYBACK_CAPABLE - tracks->filename_idx = fn_idx + string_index; + pf_tracks.index->filename_idx = fn_idx + string_index; #endif - track_count++; + pf_tracks.count++; string_index += len; } rb->tagcache_search_finish(&tcs); /* now fix the track list order */ - rb->qsort(tracks, track_count, sizeof(struct track_data), compare_tracks); + rb->qsort(pf_tracks.index, pf_tracks.count, + sizeof(struct track_data), compare_tracks); + + pf_tracks.cur_idx = slide_index; return; fail: - track_count = 0; + rb->tagcache_search_finish(&tcs); + pf_tracks.count = 0; return; } @@ -1176,14 +1727,16 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, rb->strlcpy( buf, EMPTY_SLIDE, buflen ); } - if (!rb->tagcache_search(&tcs, tag_filename)) + if (tcs.valid || !rb->tagcache_search(&tcs, tag_filename)) return false; bool result; /* find the first track of the album */ - rb->tagcache_search_add_filter(&tcs, tag_album, album[slide_index].seek); + rb->tagcache_search_add_filter(&tcs, tag_album, + pf_idx.album_index[slide_index].seek); + rb->tagcache_search_add_filter(&tcs, tag_albumartist, - artist[album[slide_index].artist_idx].seek); + pf_idx.album_index[slide_index].artist_seek); if ( rb->tagcache_get_next(&tcs) ) { struct mp3entry id3; @@ -1198,9 +1751,12 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, #endif { fd = rb->open(tcs.result, O_RDONLY); - rb->get_metadata(&id3, fd, tcs.result); - rb->close(fd); + if (fd) { + rb->get_metadata(&id3, fd, tcs.result); + rb->close(fd); + } } + if ( search_albumart_files(&id3, ":", buf, buflen) ) result = true; else @@ -1217,10 +1773,8 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, /** Draw the PictureFlow logo */ -static void draw_splashscreen(void) +static void draw_splashscreen(unsigned char * buf_tmp, size_t buf_tmp_size) { - unsigned char * buf_tmp = buf; - size_t buf_tmp_size = buf_size; struct screen* display = rb->screens[SCREEN_MAIN]; #if FB_DATA_SZ > 1 ALIGN_BUFFER(buf_tmp, buf_tmp_size, sizeof(fb_data)); @@ -1264,27 +1818,28 @@ static void draw_splashscreen(void) /** Draw a simple progress bar */ -static void draw_progressbar(int step) +static void draw_progressbar(int step, int count, char *msg) { - int txt_w, txt_h; + static int txt_w, txt_h; const int bar_height = 22; const int w = LCD_WIDTH - 20; const int x = 10; - + static int y; + if (msg != NULL) + { #if LCD_DEPTH > 1 - rb->lcd_set_background(N_BRIGHT(0)); - rb->lcd_set_foreground(N_BRIGHT(255)); + rb->lcd_set_background(N_BRIGHT(0)); + rb->lcd_set_foreground(N_BRIGHT(255)); #else - rb->lcd_set_drawmode(PICTUREFLOW_DRMODE); + rb->lcd_set_drawmode(PICTUREFLOW_DRMODE); #endif - rb->lcd_clear_display(); - rb->lcd_getstringsize("Preparing album artwork", &txt_w, &txt_h); - - int y = (LCD_HEIGHT - txt_h)/2; + rb->lcd_getstringsize(msg, &txt_w, &txt_h); - rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, "Preparing album artwork"); - y += (txt_h + 5); + y = (LCD_HEIGHT - txt_h)/2; + rb->lcd_putsxy((LCD_WIDTH - txt_w)/2, y, msg); + y += (txt_h + 5); + } #if LCD_DEPTH > 1 rb->lcd_set_foreground(N_BRIGHT(100)); #endif @@ -1293,7 +1848,7 @@ static void draw_progressbar(int step) rb->lcd_set_foreground(N_PIX(165, 231, 82)); #endif - rb->lcd_fillrect(x+1, y+1, step * w / album_count, bar_height-2); + rb->lcd_fillrect(x+1, y+1, step * w / count, bar_height-2); #if LCD_DEPTH > 1 rb->lcd_set_foreground(N_BRIGHT(255)); #endif @@ -1327,7 +1882,7 @@ static bool save_pfraw(char* filename, struct bitmap *bm) struct pfraw_header bmph; bmph.width = bm->width; bmph.height = bm->height; - int fh = rb->creat( filename , 0666); + int fh = rb->open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666); if( fh < 0 ) return false; rb->write( fh, &bmph, sizeof( struct pfraw_header ) ); pix_t *data = (pix_t*)( bm->data ); @@ -1341,62 +1896,99 @@ static bool save_pfraw(char* filename, struct bitmap *bm) return true; } -/** - Precomupte the album art images and store them in CACHE_PREFIX. - Use the "?" bitmap if image is not found. - */ -static bool create_albumart_cache(void) +static bool incremental_albumart_cache(bool verbose) { - int ret; + if (!aa_cache.buf) + goto aa_failure; - int i, slides = 0; - struct bitmap input_bmp; + if (aa_cache.inspected >= pf_idx.album_ct) + return false; - char pfraw_file[MAX_PATH]; - char albumart_file[MAX_PATH]; + int idx, ret; + unsigned int hash_artist, hash_album; unsigned int format = FORMAT_NATIVE; - bool update = (cache_version == CACHE_UPDATE); - if (resize) + + bool update = (pf_cfg.cache_version == CACHE_UPDATE); + + if (pf_cfg.resize) format |= FORMAT_RESIZE|FORMAT_KEEP_ASPECT; - for (i=0; i < album_count; i++) - { - draw_progressbar(i); - rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", - mfnv(get_album_name(i)),mfnv(get_album_artist(i))); - /* delete existing cache, so it's a true rebuild */ - if(rb->file_exists(pfraw_file)) { - if(update) { - slides++; - continue; - } - rb->remove(pfraw_file); - } - if (!get_albumart_for_index_from_db(i, albumart_file, MAX_PATH)) - rb->strcpy(albumart_file, EMPTY_SLIDE_BMP); - - input_bmp.data = buf; - input_bmp.width = DISPLAY_WIDTH; - input_bmp.height = DISPLAY_HEIGHT; - ret = read_image_file(albumart_file, &input_bmp, buf_size, - format, &format_transposed); - if (ret <= 0) { - rb->splashf(HZ, "Album art is bad: %s", get_album_name(i)); - rb->strcpy(albumart_file, EMPTY_SLIDE_BMP); - ret = read_image_file(albumart_file, &input_bmp, buf_size, - format, &format_transposed); - if(ret <= 0) - continue; + + idx = aa_cache.idx; + if (idx >= pf_idx.album_ct || idx < 0) { idx = 0; } /* Rollover */ + + + aa_cache.idx++; + aa_cache.inspected++; + if (aa_cache.idx >= pf_idx.album_ct) { aa_cache.idx = 0; } /* Rollover */ + + if (!get_albumart_for_index_from_db(idx, aa_cache.file, sizeof(aa_cache.file))) + goto aa_failure; //rb->strcpy(aa_cache.file, EMPTY_SLIDE_BMP); + + hash_artist = mfnv(get_album_artist(idx)); + hash_album = mfnv(get_album_name(idx)); + + rb->snprintf(aa_cache.pfraw_file, sizeof(aa_cache.pfraw_file), + CACHE_PREFIX "/%x%x.pfraw", hash_album, hash_artist); + + if(rb->file_exists(aa_cache.pfraw_file)) { + if(update) { + aa_cache.slides++; + goto aa_success; } - if (!save_pfraw(pfraw_file, &input_bmp)) - { - rb->splash(HZ, "Could not write bmp"); - continue; + } + + aa_cache.input_bmp.data = aa_cache.buf; + aa_cache.input_bmp.width = DISPLAY_WIDTH; + aa_cache.input_bmp.height = DISPLAY_HEIGHT; + + ret = read_image_file(aa_cache.file, &aa_cache.input_bmp, + aa_cache.buf_sz, format, &format_transposed); + if (ret <= 0) { + if (verbose) { + rb->splashf(HZ, "Album art is bad: %s", get_album_name(idx)); } - slides++; - if ( rb->button_get(false) == PF_MENU ) return false; + + goto aa_failure; + } + rb->remove(aa_cache.pfraw_file); + + if (!save_pfraw(aa_cache.pfraw_file, &aa_cache.input_bmp)) + { + if (verbose) { rb->splash(HZ, "Could not write bmp"); } + goto aa_failure; + } + aa_cache.slides++; + +aa_failure: + if (verbose) + return false; + +aa_success: + if (aa_cache.inspected >= pf_idx.album_ct) + free_all_slide_prio(0); + + if(verbose)/* direct interaction with user */ + return true; + + return false; +} + +/** + Precomupte the album art images and store them in CACHE_PREFIX. + Use the "?" bitmap if image is not found. + */ +static bool create_albumart_cache(void) +{ + draw_splashscreen(pf_idx.buf, pf_idx.buf_sz); + draw_progressbar(0, pf_idx.album_ct, "Preparing artwork"); + for (int i=0; i < pf_idx.album_ct; i++) + { + incremental_albumart_cache(true); + draw_progressbar(aa_cache.inspected, pf_idx.album_ct, NULL); + if (rb->button_get(false) > BUTTON_NONE) + return true; } - draw_progressbar(i); - if ( slides == 0 ) { + if ( aa_cache.slides == 0 ) { /* Warn the user that we couldn't find any albumart */ rb->splash(2*HZ, ID2P(LANG_NO_ALBUMART_FOUND)); return false; @@ -1410,19 +2002,23 @@ static bool create_albumart_cache(void) */ static int create_empty_slide(bool force) { + const unsigned int format = FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT; + + if (!aa_cache.buf) + return false; + if ( force || ! rb->file_exists( EMPTY_SLIDE ) ) { - struct bitmap input_bmp; - input_bmp.width = DISPLAY_WIDTH; - input_bmp.height = DISPLAY_HEIGHT; + aa_cache.input_bmp.width = DISPLAY_WIDTH; + aa_cache.input_bmp.height = DISPLAY_HEIGHT; #if LCD_DEPTH > 1 - input_bmp.format = FORMAT_NATIVE; + aa_cache.input_bmp.format = FORMAT_NATIVE; #endif - input_bmp.data = (char*)buf; - scaled_read_bmp_file(EMPTY_SLIDE_BMP, &input_bmp, - buf_size, - FORMAT_NATIVE|FORMAT_RESIZE|FORMAT_KEEP_ASPECT, - &format_transposed); - if (!save_pfraw(EMPTY_SLIDE, &input_bmp)) + aa_cache.input_bmp.data = (char*)aa_cache.buf; + + scaled_read_bmp_file(EMPTY_SLIDE_BMP, &aa_cache.input_bmp, + aa_cache.buf_sz, format, &format_transposed); + + if (!save_pfraw(EMPTY_SLIDE, &aa_cache.input_bmp)) return false; } @@ -1502,23 +2098,23 @@ static bool create_pf_thread(void) * the LRU cache of slides, and the list of free cache slots. */ -#define seek_right_while(start, cond) \ +#define _SEEK_RIGHT_WHILE(start, cond) \ ({ \ int ind_, next_ = (start); \ do { \ ind_ = next_; \ - next_ = cache[ind_].next; \ - } while (next_ != cache_used && (cond)); \ + next_ = pf_sldcache.cache[ind_].next; \ + } while (next_ != pf_sldcache.used && (cond)); \ ind_; \ }) -#define seek_left_while(start, cond) \ +#define _SEEK_LEFT_WHILE(start, cond) \ ({ \ int ind_, next_ = (start); \ do { \ ind_ = next_; \ - next_ = cache[ind_].prev; \ - } while (ind_ != cache_used && (cond)); \ + next_ = pf_sldcache.cache[ind_].prev; \ + } while (ind_ != pf_sldcache.used && (cond)); \ ind_; \ }) @@ -1528,8 +2124,8 @@ static bool create_pf_thread(void) */ static inline int lla_pop_item (int *head, int i) { - int prev = cache[i].prev; - int next = cache[i].next; + int prev = pf_sldcache.cache[i].prev; + int next = pf_sldcache.cache[i].next; if (i == next) { *head = -1; @@ -1537,8 +2133,8 @@ static inline int lla_pop_item (int *head, int i) } else if (i == *head) *head = next; - cache[next].prev = prev; - cache[prev].next = next; + pf_sldcache.cache[next].prev = prev; + pf_sldcache.cache[prev].next = next; return next; } @@ -1561,11 +2157,11 @@ static inline int lla_pop_head (int *head) static inline void lla_insert (int i, int p) { int next = p; - int prev = cache[next].prev; - cache[next].prev = i; - cache[prev].next = i; - cache[i].next = next; - cache[i].prev = prev; + int prev = pf_sldcache.cache[next].prev; + pf_sldcache.cache[next].prev = i; + pf_sldcache.cache[prev].next = i; + pf_sldcache.cache[i].next = next; + pf_sldcache.cache[i].prev = prev; } @@ -1577,8 +2173,8 @@ static inline void lla_insert_tail (int *head, int i) if (*head == -1) { *head = i; - cache[i].next = i; - cache[i].prev = i; + pf_sldcache.cache[i].next = i; + pf_sldcache.cache[i].prev = i; } else lla_insert(i, *head); } @@ -1588,7 +2184,7 @@ static inline void lla_insert_tail (int *head, int i) */ static inline void lla_insert_after(int i, int p) { - p = cache[p].next; + p = pf_sldcache.cache[p].next; lla_insert(i, p); } @@ -1611,16 +2207,16 @@ static inline void lla_insert_before(int *head, int i, int p) */ static inline void free_slide(int i) { - if (cache[i].hid != empty_slide_hid) - rb->buflib_free(&buf_ctx, cache[i].hid); - cache[i].index = -1; - lla_pop_item(&cache_used, i); - lla_insert_tail(&cache_free, i); - if (cache_used == -1) + if (pf_sldcache.cache[i].hid != empty_slide_hid) + rb->buflib_free(&buf_ctx, pf_sldcache.cache[i].hid); + pf_sldcache.cache[i].index = -1; + lla_pop_item(&pf_sldcache.used, i); + lla_insert_tail(&pf_sldcache.free, i); + if (pf_sldcache.used == -1) { - cache_right_index = -1; - cache_left_index = -1; - cache_center_index = -1; + pf_sldcache.right_idx = -1; + pf_sldcache.left_idx = -1; + pf_sldcache.center_idx = -1; } } @@ -1631,13 +2227,17 @@ static inline void free_slide(int i) */ static bool free_slide_prio(int prio) { - if (cache_used == -1) + if (pf_sldcache.used == -1) return false; - int i, l = cache_used, r = cache[cache_used].prev, prio_max; - int prio_l = cache[l].index < center_index ? - center_index - cache[l].index : 0; - int prio_r = cache[r].index > center_index ? - cache[r].index - center_index : 0; + + int i, prio_max; + int l = pf_sldcache.used; + int r = pf_sldcache.cache[pf_sldcache.used].prev; + + int prio_l = pf_sldcache.cache[l].index < center_index ? + center_index - pf_sldcache.cache[l].index : 0; + int prio_r = pf_sldcache.cache[r].index > center_index ? + pf_sldcache.cache[r].index - center_index : 0; if (prio_l > prio_r) { i = l; @@ -1648,16 +2248,27 @@ static bool free_slide_prio(int prio) } if (prio_max > prio) { - if (i == cache_left_index) - cache_left_index = cache[i].next; - if (i == cache_right_index) - cache_right_index = cache[i].prev; + if (i == pf_sldcache.left_idx) + pf_sldcache.left_idx = pf_sldcache.cache[i].next; + if (i == pf_sldcache.right_idx) + pf_sldcache.right_idx = pf_sldcache.cache[i].prev; free_slide(i); return true; } else return false; } + +/** + Free all slides ranked above the given priority. +*/ +static void free_all_slide_prio(int prio) +{ + while (free_slide_prio(prio)) + ;; +} + + /** Read the pfraw image given as filename and return the hid of the buffer */ @@ -1666,7 +2277,7 @@ static int read_pfraw(char* filename, int prio) struct pfraw_header bmph; int fh = rb->open(filename, O_RDONLY); if( fh < 0 ) { - cache_version = CACHE_UPDATE; + /* pf_cfg.cache_version = CACHE_UPDATE; -- don't invalidate on missing pfraw */ return empty_slide_hid; } else @@ -1711,19 +2322,20 @@ static inline bool load_and_prepare_surface(const int slide_index, const int prio) { char pfraw_file[MAX_PATH]; - + unsigned int hash_artist = mfnv(get_album_artist(slide_index)); + unsigned int hash_album = mfnv(get_album_name(slide_index)); rb->snprintf(pfraw_file, sizeof(pfraw_file), CACHE_PREFIX "/%x%x.pfraw", - mfnv(get_album_name(slide_index)),mfnv(get_album_artist(slide_index))); + hash_album, hash_artist); int hid = read_pfraw(pfraw_file, prio); if (!hid) return false; - cache[cache_index].hid = hid; + pf_sldcache.cache[cache_index].hid = hid; if ( cache_index < SLIDE_CACHE_SIZE ) { - cache[cache_index].index = slide_index; + pf_sldcache.cache[cache_index].index = slide_index; } return true; @@ -1737,107 +2349,121 @@ static inline bool load_and_prepare_surface(const int slide_index, bool load_new_slide(void) { int i = -1; - if (cache_center_index != -1) + + if (pf_sldcache.center_idx != -1) { int next, prev; - if (cache[cache_center_index].index != center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index) { - if (cache[cache_center_index].index < center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index < center_index) { - cache_center_index = seek_right_while(cache_center_index, - cache[next_].index <= center_index); - prev = cache_center_index; - next = cache[cache_center_index].next; + pf_sldcache.center_idx = _SEEK_RIGHT_WHILE(pf_sldcache.center_idx, + pf_sldcache.cache[next_].index <= center_index); + + prev = pf_sldcache.center_idx; + next = pf_sldcache.cache[pf_sldcache.center_idx].next; } else { - cache_center_index = seek_left_while(cache_center_index, - cache[next_].index >= center_index); - next = cache_center_index; - prev = cache[cache_center_index].prev; + pf_sldcache.center_idx = _SEEK_LEFT_WHILE(pf_sldcache.center_idx, + pf_sldcache.cache[next_].index >= center_index); + + next = pf_sldcache.center_idx; + prev = pf_sldcache.cache[pf_sldcache.center_idx].prev; } - if (cache[cache_center_index].index != center_index) + if (pf_sldcache.cache[pf_sldcache.center_idx].index != center_index) { - if (cache_free == -1) + if (pf_sldcache.free == -1) free_slide_prio(0); - i = lla_pop_head(&cache_free); + + i = lla_pop_head(&pf_sldcache.free); if (!load_and_prepare_surface(center_index, i, 0)) goto fail_and_refree; - if (cache[next].index == -1) + + if (pf_sldcache.cache[next].index == -1) { - if (cache[prev].index == -1) + if (pf_sldcache.cache[prev].index == -1) goto insert_first_slide; else - next = cache[prev].next; + next = pf_sldcache.cache[prev].next; } lla_insert(i, next); - if (cache[i].index < cache[cache_used].index) - cache_used = i; - cache_center_index = i; - cache_left_index = i; - cache_right_index = i; + if (pf_sldcache.cache[i].index < pf_sldcache.cache[pf_sldcache.used].index) + pf_sldcache.used = i; + + pf_sldcache.center_idx = i; + pf_sldcache.left_idx = i; + pf_sldcache.right_idx = i; return true; } } - if (cache[cache_left_index].index > - cache[cache_center_index].index) - cache_left_index = cache_center_index; - if (cache[cache_right_index].index < - cache[cache_center_index].index) - cache_right_index = cache_center_index; - cache_left_index = seek_left_while(cache_left_index, - cache[ind_].index - 1 == cache[next_].index); - cache_right_index = seek_right_while(cache_right_index, - cache[ind_].index - 1 == cache[next_].index); - int prio_l = cache[cache_center_index].index - - cache[cache_left_index].index + 1; - int prio_r = cache[cache_right_index].index - - cache[cache_center_index].index + 1; - if ((prio_l < prio_r || - cache[cache_right_index].index >= number_of_slides) && - cache[cache_left_index].index > 0) + int left, center, right; + left = pf_sldcache.cache[pf_sldcache.left_idx].index; + center = pf_sldcache.cache[pf_sldcache.center_idx].index; + right = pf_sldcache.cache[pf_sldcache.right_idx].index; + + if (left > center) + pf_sldcache.left_idx = pf_sldcache.center_idx; + if (right < center) + pf_sldcache.right_idx = pf_sldcache.center_idx; + + pf_sldcache.left_idx = _SEEK_LEFT_WHILE(pf_sldcache.left_idx, + pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index); + + pf_sldcache.right_idx = _SEEK_RIGHT_WHILE(pf_sldcache.right_idx, + pf_sldcache.cache[ind_].index - 1 == pf_sldcache.cache[next_].index); + + + /* update indices */ + left = pf_sldcache.cache[pf_sldcache.left_idx].index; + center = pf_sldcache.cache[pf_sldcache.center_idx].index; + right = pf_sldcache.cache[pf_sldcache.right_idx].index; + + int prio_l = center - left + 1; + int prio_r = right - center + 1; + if ((prio_l < prio_r || right >= number_of_slides) && left > 0) { - if (cache_free == -1 && !free_slide_prio(prio_l)) + if (pf_sldcache.free == -1 && !free_slide_prio(prio_l)) return false; - i = lla_pop_head(&cache_free); - if (load_and_prepare_surface(cache[cache_left_index].index - - 1, i, prio_l)) + + i = lla_pop_head(&pf_sldcache.free); + if (load_and_prepare_surface(left - 1, i, prio_l)) { - lla_insert_before(&cache_used, i, cache_left_index); - cache_left_index = i; + lla_insert_before(&pf_sldcache.used, i, pf_sldcache.left_idx); + pf_sldcache.left_idx = i; return true; } - } else if(cache[cache_right_index].index < number_of_slides - 1) + } else if(right < number_of_slides - 1) { - if (cache_free == -1 && !free_slide_prio(prio_r)) + if (pf_sldcache.free == -1 && !free_slide_prio(prio_r)) return false; - i = lla_pop_head(&cache_free); - if (load_and_prepare_surface(cache[cache_right_index].index - + 1, i, prio_r)) + + i = lla_pop_head(&pf_sldcache.free); + if (load_and_prepare_surface(right + 1, i, prio_r)) { - lla_insert_after(i, cache_right_index); - cache_right_index = i; + lla_insert_after(i, pf_sldcache.right_idx); + pf_sldcache.right_idx = i; return true; } } } else { - i = lla_pop_head(&cache_free); + i = lla_pop_head(&pf_sldcache.free); if (load_and_prepare_surface(center_index, i, 0)) { insert_first_slide: - cache[i].next = i; - cache[i].prev = i; - cache_center_index = i; - cache_left_index = i; - cache_right_index = i; - cache_used = i; + pf_sldcache.cache[i].next = i; + pf_sldcache.cache[i].prev = i; + pf_sldcache.center_idx = i; + pf_sldcache.left_idx = i; + pf_sldcache.right_idx = i; + pf_sldcache.used = i; return true; } } fail_and_refree: if (i != -1) { - lla_insert_tail(&cache_free, i); + lla_insert_tail(&pf_sldcache.free, i); } return false; } @@ -1869,13 +2495,13 @@ static inline struct dim *surface(const int slide_index) if (slide_index >= number_of_slides) return 0; int i; - if ((i = cache_used ) != -1) + if ((i = pf_sldcache.used ) != -1) { do { - if (cache[i].index == slide_index) - return get_slide(cache[i].hid); - i = cache[i].next; - } while (i != cache_used); + if (pf_sldcache.cache[i].index == slide_index) + return get_slide(pf_sldcache.cache[i].hid); + i = pf_sldcache.cache[i].next; + } while (i != pf_sldcache.used); } return get_slide(empty_slide_hid); } @@ -1892,19 +2518,19 @@ static void reset_slides(void) center_slide.slide_index = center_index; int i; - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &left_slides[i]; si->angle = itilt; - si->cx = -(offsetX + slide_spacing * i * PFREAL_ONE); + si->cx = -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE); si->cy = offsetY; si->slide_index = center_index - 1 - i; si->distance = 0; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &right_slides[i]; si->angle = -itilt; - si->cx = offsetX + slide_spacing * i * PFREAL_ONE; + si->cx = offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE; si->cy = offsetY; si->slide_index = center_index + 1 + i; si->distance = 0; @@ -1928,14 +2554,14 @@ static void recalc_offsets(void) { PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF; PFreal zo; - PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + center_margin * - PFREAL_ONE) * zoom / 100; + PFreal xp = (DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + + pf_cfg.center_margin * PFREAL_ONE) * pf_cfg.zoom / 100; PFreal cosr, sinr; itilt = 70 * IANGLE_MAX / 360; /* approx. 70 degrees tilted */ cosr = fcos(-itilt); sinr = fsin(-itilt); - zo = CAM_DIST_R * 100 / zoom - CAM_DIST_R + + zo = CAM_DIST_R * 100 / pf_cfg.zoom - CAM_DIST_R + fmuln(MAXSLIDE_LEFT_R, sinr, PFREAL_SHIFT - 2, 0); offsetX = xp - fmul(xs, cosr) + fmuln(xp, 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) PFreal cosr = fcos(slide->angle); PFreal sinr = fsin(slide->angle); - PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / zoom + PFreal zo = PFREAL_ONE * slide->distance + CAM_DIST_R * 100 / pf_cfg.zoom - CAM_DIST_R - fmuln(MAXSLIDE_LEFT_R, fabs(sinr), PFREAL_SHIFT - 2, 0); PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni; 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) } /** - Jump the the given slide_index + Jump to the given slide_index */ static inline void set_current_slide(const int slide_index) { @@ -2202,8 +2828,8 @@ static void render_all_slides(void) /* TODO: Optimizes this by e.g. invalidating rects */ mylcd_clear_display(); - int nleft = num_slides; - int nright = num_slides; + int nleft = pf_cfg.num_slides; + int nright = pf_cfg.num_slides; int alpha; int index; @@ -2242,7 +2868,7 @@ static void render_all_slides(void) } } alpha = 256; - if (step != 0 && num_slides <= 2) /* fading out center slide */ + if (step != 0 && pf_cfg.num_slides <= 2) /* fading out center slide */ alpha = (step > 0) ? 256 - fade / 2 : 128 + fade / 2; render_slide(¢er_slide, alpha); } @@ -2291,9 +2917,9 @@ static void update_scroll_animation(void) rb->queue_post(&thread_q, EV_WAKEUP, 0); slide_frame = index << 16; center_slide.slide_index = center_index; - for (i = 0; i < num_slides; i++) + for (i = 0; i < pf_cfg.num_slides; i++) left_slides[i].slide_index = center_index - 1 - i; - for (i = 0; i < num_slides; i++) + for (i = 0; i < pf_cfg.num_slides; i++) right_slides[i].slide_index = center_index + 1 + i; } @@ -2310,21 +2936,21 @@ static void update_scroll_animation(void) return; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &left_slides[i]; si->angle = itilt; si->cx = - -(offsetX + slide_spacing * i * PFREAL_ONE + step - * slide_spacing * ftick); + -(offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE + step + * pf_cfg.slide_spacing * ftick); si->cy = offsetY; } - for (i = 0; i < num_slides; i++) { + for (i = 0; i < pf_cfg.num_slides; i++) { struct slide_data *si = &right_slides[i]; si->angle = -itilt; si->cx = - offsetX + slide_spacing * i * PFREAL_ONE - step - * slide_spacing * ftick; + offsetX + pf_cfg.slide_spacing * i * PFREAL_ONE - step + * pf_cfg.slide_spacing * ftick; si->cy = offsetY; } @@ -2409,13 +3035,13 @@ static int settings_menu(void) selection=rb->do_menu(&settings_menu,&selection, NULL, false); switch(selection) { case 0: - rb->set_bool(rb->str(LANG_DISPLAY_FPS), &show_fps); + rb->set_bool(rb->str(LANG_DISPLAY_FPS), &pf_cfg.show_fps); reset_track_list(); break; case 1: rb->set_int(rb->str(LANG_SPACING), "", 1, - &slide_spacing, + &pf_cfg.slide_spacing, NULL, 1, 0, 100, NULL ); recalc_offsets(); reset_slides(); @@ -2423,57 +3049,59 @@ static int settings_menu(void) case 2: rb->set_int(rb->str(LANG_CENTRE_MARGIN), "", 1, - ¢er_margin, + &pf_cfg.center_margin, NULL, 1, 0, 80, NULL ); recalc_offsets(); reset_slides(); break; case 3: - rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, &num_slides, - NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); + rb->set_int(rb->str(LANG_NUMBER_OF_SLIDES), "", 1, + &pf_cfg.num_slides, NULL, 1, 1, MAX_SLIDES_COUNT, NULL ); recalc_offsets(); reset_slides(); break; case 4: - rb->set_int(rb->str(LANG_ZOOM), "", 1, &zoom, + rb->set_int(rb->str(LANG_ZOOM), "", 1, &pf_cfg.zoom, NULL, 1, 10, 300, NULL ); recalc_offsets(); reset_slides(); break; case 5: - rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), &show_album_name, - INT, album_name_options, 5, NULL); + rb->set_option(rb->str(LANG_SHOW_ALBUM_TITLE), + &pf_cfg.show_album_name, INT, album_name_options, 5, NULL); reset_track_list(); recalc_offsets(); reset_slides(); break; case 6: - old_val = resize; - rb->set_bool(rb->str(LANG_RESIZE_COVERS), &resize); - if (old_val == resize) /* changed? */ + old_val = pf_cfg.resize; + rb->set_bool(rb->str(LANG_RESIZE_COVERS), &pf_cfg.resize); + if (old_val == pf_cfg.resize) /* changed? */ break; /* fallthrough if changed, since cache needs to be rebuilt */ case 7: - cache_version = CACHE_REBUILD; + pf_cfg.cache_version = CACHE_REBUILD; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); break; case 8: - cache_version = CACHE_UPDATE; + pf_cfg.cache_version = CACHE_UPDATE; rb->remove(EMPTY_SLIDE); configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); rb->splash(HZ, ID2P(LANG_CACHE_REBUILT_NEXT_RESTART)); break; case 9: - rb->set_option(rb->str(LANG_WPS_INTEGRATION), &auto_wps, INT, wps_options, 3, NULL); + rb->set_option(rb->str(LANG_WPS_INTEGRATION), + &pf_cfg.auto_wps, INT, wps_options, 3, NULL); break; case 10: - rb->set_option(rb->str(LANG_BACKLIGHT), &backlight_mode, INT, backlight_options, 2, NULL); + rb->set_option(rb->str(LANG_BACKLIGHT), + &pf_cfg.backlight_mode, INT, backlight_options, 2, NULL); break; case MENU_ATTACHED_USB: @@ -2596,8 +3224,8 @@ static inline void draw_gradient(int y, int h) int r, inc, c; inc = (100 << 8) / h; c = 0; - selected_track_pulse = (selected_track_pulse+1) % 10; - int c2 = selected_track_pulse - 5; + pf_tracks.sel_pulse = (pf_tracks.sel_pulse+1) % 10; + int c2 = pf_tracks.sel_pulse - 5; for (r=0; r> 9), c2+100-(c >> 9), @@ -2616,30 +3244,30 @@ static inline void draw_gradient(int y, int h) static void track_list_yh(int char_height) { - switch (show_album_name) + switch (pf_cfg.show_album_name) { case ALBUM_NAME_HIDE: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y; + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y; break; case ALBUM_NAME_BOTTOM: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3); break; case ALBUM_AND_ARTIST_TOP: - track_list_y = char_height * 3; - track_list_h = LCD_HEIGHT - track_list_y - - (show_fps ? char_height : 0); + pf_tracks.list_y = char_height * 3; + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - + (pf_cfg.show_fps ? char_height : 0); break; case ALBUM_AND_ARTIST_BOTTOM: - track_list_y = (show_fps ? char_height : 0); - track_list_h = LCD_HEIGHT - track_list_y - (char_height * 3); + pf_tracks.list_y = (pf_cfg.show_fps ? char_height : 0); + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - (char_height * 3); break; case ALBUM_NAME_TOP: default: - track_list_y = char_height * 3; - track_list_h = LCD_HEIGHT - track_list_y - - (show_fps ? char_height : 0); + pf_tracks.list_y = char_height * 3; + pf_tracks.list_h = LCD_HEIGHT - pf_tracks.list_y - + (pf_cfg.show_fps ? char_height : 0); break; } } @@ -2652,18 +3280,20 @@ void reset_track_list(void) int char_height = rb->screens[SCREEN_MAIN]->getcharheight(); int total_height; track_list_yh(char_height); - track_list_visible_entries = fmin( track_list_h/char_height , track_count ); - start_index_track_list = 0; - selected_track = 0; - last_selected_track = -1; + pf_tracks.list_visible = + fmin( pf_tracks.list_h/char_height , pf_tracks.count ); + + pf_tracks.list_start = 0; + pf_tracks.sel = 0; + pf_tracks.last_sel = -1; /* let the tracklist start more centered * if the screen isn't filled with tracks */ - total_height = track_count*char_height; - if (total_height < track_list_h) + total_height = pf_tracks.count*char_height; + if (total_height < pf_tracks.list_h) { - track_list_y += (track_list_h - total_height) / 2; - track_list_h = total_height; + pf_tracks.list_y += (pf_tracks.list_h - total_height) / 2; + pf_tracks.list_h = total_height; } } @@ -2673,24 +3303,25 @@ void reset_track_list(void) static void show_track_list(void) { mylcd_clear_display(); - if ( center_slide.slide_index != track_index ) { + if ( center_slide.slide_index != pf_tracks.cur_idx ) { create_track_index(center_slide.slide_index); reset_track_list(); } int titletxt_w, titletxt_x, color, titletxt_h; titletxt_h = rb->screens[SCREEN_MAIN]->getcharheight(); - int titletxt_y = track_list_y; + int titletxt_y = pf_tracks.list_y; int track_i; - track_i = start_index_track_list; - for (;track_i < track_list_visible_entries+start_index_track_list; - track_i++) + int fade; + + track_i = pf_tracks.list_start; + for (; track_i < pf_tracks.list_visible + pf_tracks.list_start; track_i++) { char *trackname = get_track_name(track_i); - if ( track_i == selected_track ) { - if (selected_track != last_selected_track) { + if ( track_i == pf_tracks.sel ) { + if (pf_tracks.sel != pf_tracks.last_sel) { set_scroll_line(trackname, PF_SCROLL_TRACK); - last_selected_track = selected_track; + pf_tracks.last_sel = pf_tracks.sel; } draw_gradient(titletxt_y, titletxt_h); titletxt_x = get_scroll_line_offset(PF_SCROLL_TRACK); @@ -2699,7 +3330,8 @@ static void show_track_list(void) else { titletxt_w = mylcd_getstringsize(trackname, NULL, NULL); titletxt_x = (LCD_WIDTH-titletxt_w)/2; - color = 250 - (abs(selected_track - track_i) * 200 / track_count); + fade = (abs(pf_tracks.sel - track_i) * 200 / pf_tracks.count); + color = 250 - fade; } mylcd_set_foreground(G_BRIGHT(color)); mylcd_putsxy(titletxt_x,titletxt_y,trackname); @@ -2709,18 +3341,26 @@ static void show_track_list(void) static void select_next_track(void) { - if ( selected_track < track_count - 1 ) { - selected_track++; - if (selected_track==(track_list_visible_entries+start_index_track_list)) - start_index_track_list++; + if ( pf_tracks.sel < pf_tracks.count - 1 ) { + pf_tracks.sel++; + if (pf_tracks.sel==(pf_tracks.list_visible+pf_tracks.list_start)) + pf_tracks.list_start++; + } else { + /* Rollover */ + pf_tracks.sel = 0; + pf_tracks.list_start = 0; } } static void select_prev_track(void) { - if (selected_track > 0 ) { - if (selected_track==start_index_track_list) start_index_track_list--; - selected_track--; + if (pf_tracks.sel > 0 ) { + if (pf_tracks.sel==pf_tracks.list_start) pf_tracks.list_start--; + pf_tracks.sel--; + } else { + /* Rolllover */ + pf_tracks.sel = pf_tracks.count - 1; + pf_tracks.list_start = pf_tracks.count - pf_tracks.list_visible; } } @@ -2732,7 +3372,7 @@ static void start_playback(bool append) { static int old_playlist = -1, old_shuffle = 0; int count = 0; - int position = selected_track; + int position = pf_tracks.sel; int shuffle = rb->global_settings->playlist_shuffle; /* reuse existing playlist if possible * regenerate if shuffle is on or changed, since playlist index and @@ -2751,14 +3391,14 @@ static void start_playback(bool append) if (rb->playlist_insert_track(NULL, get_track_filename(count), PLAYLIST_INSERT_LAST, false, true) < 0) break; - } while(++count < track_count); + } while(++count < pf_tracks.count); rb->playlist_sync(NULL); } else return; if (rb->global_settings->playlist_shuffle) - position = rb->playlist_shuffle(*rb->current_tick, selected_track); + position = rb->playlist_shuffle(*rb->current_tick, pf_tracks.sel); play: /* TODO: can we adjust selected_track if !play_selected ? * if shuffle, we can't predict the playing track easily, and for either @@ -2775,12 +3415,14 @@ play: */ static void draw_album_text(void) { - if (show_album_name == ALBUM_NAME_HIDE) + if (pf_cfg.show_album_name == ALBUM_NAME_HIDE) return; + static int prev_albumtxt_index = -1; int albumtxt_index; int char_height; int albumtxt_x, albumtxt_y, artisttxt_x; + int album_idx = 0; char *albumtxt; char *artisttxt; @@ -2802,7 +3444,7 @@ static void draw_album_text(void) albumtxt_index = center_index; c= 255; } - albumtxt = get_album_name(albumtxt_index); + albumtxt = get_album_name_idx(albumtxt_index, &album_idx); mylcd_set_foreground(G_BRIGHT(c)); if (albumtxt_index != prev_albumtxt_index) { @@ -2811,15 +3453,13 @@ static void draw_album_text(void) } char_height = rb->screens[SCREEN_MAIN]->getcharheight(); - switch(show_album_name){ + switch(pf_cfg.show_album_name){ case ALBUM_AND_ARTIST_TOP: albumtxt_y = 0; break; case ALBUM_NAME_BOTTOM: - albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 10); - break; case ALBUM_AND_ARTIST_BOTTOM: - albumtxt_y = (LCD_HEIGHT - char_height - char_height/2 - 20); + albumtxt_y = (LCD_HEIGHT - (char_height * 5 / 2)); break; case ALBUM_NAME_TOP: default: @@ -2828,15 +3468,21 @@ static void draw_album_text(void) } albumtxt_x = get_scroll_line_offset(PF_SCROLL_ALBUM); - mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); - if ((show_album_name == ALBUM_AND_ARTIST_TOP) - || (show_album_name == ALBUM_AND_ARTIST_BOTTOM)){ + + if ((pf_cfg.show_album_name == ALBUM_AND_ARTIST_TOP) + || (pf_cfg.show_album_name == ALBUM_AND_ARTIST_BOTTOM)){ + + if (album_idx != (int) pf_idx.album_untagged_idx) + mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); artisttxt = get_album_artist(albumtxt_index); set_scroll_line(artisttxt, PF_SCROLL_ARTIST); artisttxt_x = get_scroll_line_offset(PF_SCROLL_ARTIST); - mylcd_putsxy(artisttxt_x, albumtxt_y+20, artisttxt); + int y_offset = char_height + char_height/2; + mylcd_putsxy(artisttxt_x, albumtxt_y + y_offset, artisttxt); + } else { + mylcd_putsxy(albumtxt_x, albumtxt_y, albumtxt); } } @@ -2857,7 +3503,7 @@ static void error_wait(const char *message) */ static int pictureflow_main(void) { - int ret; + int ret = SUCCESS; rb->lcd_setfont(FONT_UI); @@ -2868,10 +3514,13 @@ static int pictureflow_main(void) } } + rb->memset(&aa_cache, 0, sizeof(struct albumart_t)); + config_set_defaults(&pf_cfg); + configfile_load(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); - if(auto_wps == 0) - draw_splashscreen(); - if(backlight_mode == 0) { + if(pf_cfg.auto_wps == 0) + draw_splashscreen(pf_idx.buf, pf_idx.buf_sz); + if(pf_cfg.backlight_mode == 0) { /* Turn off backlight timeout */ backlight_ignore_timeout(); } @@ -2879,19 +3528,20 @@ static int pictureflow_main(void) init_scroll_lines(); init_reflect_table(); - ALIGN_BUFFER(buf, buf_size, 4); + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); /*Scan will trigger when no file is found or the option was activated*/ - if ((cache_version != CACHE_VERSION)||(load_album_index() < 0)){ - rb->splash(HZ/2,"Creating album index, please wait"); + if ((pf_cfg.cache_version != CACHE_VERSION)||(load_album_index() < 0)){ + rb->splash(HZ/2,"Creating index, please wait"); ret = create_album_index(); + if (ret == 0){ - save_album_index(); + pf_cfg.cache_version = CACHE_REBUILD; + if (save_album_index() < 0) { + rb->splash(HZ, "Could not write index"); + }; } } - else{ - ret = 0; - } if (ret == ERROR_BUFFER_FULL) { error_wait("Not enough memory for album names"); @@ -2899,30 +3549,47 @@ static int pictureflow_main(void) } else if (ret == ERROR_NO_ALBUMS) { error_wait("No albums found. Please enable database"); return PLUGIN_ERROR; + } else if (ret == ERROR_USER_ABORT) { + error_wait("User aborted."); + return PLUGIN_ERROR; } - ALIGN_BUFFER(buf, buf_size, 4); - number_of_slides = album_count; - if ((cache_version != CACHE_VERSION) && !create_albumart_cache()) { - cache_version = CACHE_REBUILD; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); - error_wait("Could not create album art cache"); + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); + number_of_slides = pf_idx.album_ct; + + size_t aa_bufsz = ALIGN_DOWN(pf_idx.buf_sz / 4, 0x4); + + if (aa_bufsz < DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(pix_t)) + { + error_wait("Not enough memory for album art cache"); return PLUGIN_ERROR; } - if (!create_empty_slide(cache_version != CACHE_VERSION)) { - cache_version = CACHE_REBUILD; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); + pf_idx.buf_sz -= aa_bufsz; + ALIGN_BUFFER(pf_idx.buf, pf_idx.buf_sz, 4); + aa_cache.buf = (char*) pf_idx.buf + aa_bufsz; + aa_cache.buf_sz = aa_bufsz; + ALIGN_BUFFER(aa_cache.buf, aa_cache.buf_sz, 4); + + if (!create_empty_slide(pf_cfg.cache_version != CACHE_VERSION)) { + config_save(CACHE_REBUILD); error_wait("Could not load the empty slide"); return PLUGIN_ERROR; } - if (cache_version != CACHE_VERSION) + + if ((pf_cfg.cache_version != CACHE_VERSION) && !create_albumart_cache()) { + config_save(CACHE_REBUILD); + error_wait("Could not create album art cache"); + } else if(aa_cache.inspected < pf_idx.album_ct) { + rb->splash(HZ * 2, "Updating album art cache in background"); + } + + if (pf_cfg.cache_version != CACHE_VERSION) { - cache_version = CACHE_VERSION; - configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, CONFIG_VERSION); + config_save(CACHE_VERSION); } - rb->buflib_init(&buf_ctx, (void *)buf, buf_size); + rb->buflib_init(&buf_ctx, (void *)pf_idx.buf, pf_idx.buf_sz); if (!(empty_slide_hid = read_pfraw(EMPTY_SLIDE, 0))) { @@ -2939,19 +3606,25 @@ static int pictureflow_main(void) /* initialize */ for (i = 0; i < SLIDE_CACHE_SIZE; i++) { - cache[i].hid = 0; - cache[i].index = 0; - cache[i].next = i + 1; - cache[i].prev = i - 1; - } - cache[0].prev = i - 1; - cache[i - 1].next = 0; - cache_free = 0; + pf_sldcache.cache[i].hid = 0; + pf_sldcache.cache[i].index = 0; + pf_sldcache.cache[i].next = i + 1; + pf_sldcache.cache[i].prev = i - 1; + } + pf_sldcache.cache[0].prev = i - 1; + pf_sldcache.cache[i - 1].next = 0; + + pf_sldcache.free = 0; + pf_sldcache.used = -1; + pf_sldcache.left_idx = -1; + pf_sldcache.right_idx = -1; + pf_sldcache.center_idx = -1; + buffer = LCD_BUF; pf_state = pf_idle; - track_index = -1; + pf_tracks.cur_idx = -1; extra_fade = 0; slide_frame = 0; step = 0; @@ -3009,6 +3682,7 @@ static int pictureflow_main(void) break; case pf_idle: render_all_slides(); + incremental_albumart_cache(false); break; } @@ -3019,7 +3693,7 @@ static int pictureflow_main(void) frames = 0; } /* Draw FPS */ - if (show_fps) + if (pf_cfg.show_fps) { #ifdef USEGSLIB mylcd_set_foreground(G_BRIGHT(255)); @@ -3027,7 +3701,7 @@ static int pictureflow_main(void) mylcd_set_foreground(G_PIX(255,0,0)); #endif rb->snprintf(fpstxt, sizeof(fpstxt), "FPS: %d", fps); - if (show_album_name == ALBUM_NAME_TOP) + if (pf_cfg.show_album_name == ALBUM_NAME_TOP) fpstxt_y = LCD_HEIGHT - rb->screens[SCREEN_MAIN]->getcharheight(); else @@ -3057,9 +3731,9 @@ static int pictureflow_main(void) case PF_BACK: if ( pf_state == pf_show_tracks ) { - rb->buflib_buffer_in(&buf_ctx, borrowed); - borrowed = 0; - track_index = -1; + rb->buflib_buffer_in(&buf_ctx, pf_tracks.borrowed); + pf_tracks.borrowed = 0; + pf_tracks.cur_idx = -1; pf_state = pf_cover_out; } if (pf_state == pf_idle || pf_state == pf_scrolling) @@ -3096,7 +3770,7 @@ static int pictureflow_main(void) break; #if PF_PLAYBACK_CAPABLE case PF_CONTEXT: - if ( auto_wps != 0 ) { + if ( pf_cfg.auto_wps != 0 ) { if( pf_state == pf_idle ) { create_track_index(center_slide.slide_index); reset_track_list(); @@ -3104,7 +3778,7 @@ static int pictureflow_main(void) rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); } else if( pf_state == pf_show_tracks ) { - rb->playlist_insert_track(NULL, get_track_filename(selected_track), + rb->playlist_insert_track(NULL, get_track_filename(pf_tracks.sel), PLAYLIST_INSERT_LAST, false, true); rb->playlist_sync(NULL); rb->splash(HZ*2, ID2P(LANG_ADDED_TO_PLAYLIST)); @@ -3113,18 +3787,18 @@ static int pictureflow_main(void) break; #endif case PF_TRACKLIST: - if ( auto_wps == 1 && pf_state == pf_idle ) { + if ( pf_cfg.auto_wps == 1 && pf_state == pf_idle ) { pf_state = pf_cover_in; break; } case PF_SELECT: if ( pf_state == pf_idle ) { #if PF_PLAYBACK_CAPABLE - if(auto_wps == 1) { + if(pf_cfg.auto_wps == 1) { create_track_index(center_slide.slide_index); reset_track_list(); start_playback(false); - last_album = center_index; + pf_cfg.last_album = center_index; return PLUGIN_GOTO_WPS; } else @@ -3134,8 +3808,8 @@ static int pictureflow_main(void) else if ( pf_state == pf_show_tracks ) { #if PF_PLAYBACK_CAPABLE start_playback(false); - if(auto_wps != 0) { - last_album = center_index; + if(pf_cfg.auto_wps != 0) { + pf_cfg.last_album = center_index; return PLUGIN_GOTO_WPS; } #endif @@ -3154,6 +3828,10 @@ enum plugin_status plugin_start(const void *parameter) { int ret; (void) parameter; + + void * buf; + size_t buf_size; + atexit(cleanup); #ifdef HAVE_ADJUSTABLE_CPU_FREQ @@ -3171,11 +3849,6 @@ enum plugin_status plugin_start(const void *parameter) } #endif #endif - /* create unique entry buffer with 1/4 of the plugin buffer */ - uniqbuf = buf; - uniqbuf_size = ALIGN_DOWN(buf_size / 4, 0x8); - buf += uniqbuf_size; - buf_size -= uniqbuf_size; #ifdef USEGSLIB long grey_buf_used; @@ -3190,6 +3863,10 @@ enum plugin_status plugin_start(const void *parameter) buf = (void*)(grey_buf_used + (char*)buf); #endif + /* store buffer pointers and sizes */ + pf_idx.buf = buf; + pf_idx.buf_sz = buf_size; + ret = pictureflow_main(); if ( ret == PLUGIN_OK || ret == PLUGIN_GOTO_WPS) { if (configfile_save(CONFIG_FILE, config, CONFIG_NUM_ITEMS, -- cgit v1.2.3