diff options
author | Christian Soffke <christian.soffke@gmail.com> | 2022-05-25 20:11:29 +0200 |
---|---|---|
committer | Christian Soffke <christian.soffke@gmail.com> | 2023-01-10 18:50:12 +0100 |
commit | a513cee8222006d5f970b4495ae7d1f1b6facf9b (patch) | |
tree | e6faa2e23a49b9dfd2eec38ef07aa899804ed39a /apps/plugins | |
parent | d5e38062ea6f1f4645f917b0d70e5001c48e9052 (diff) | |
download | rockbox-a513cee8222006d5f970b4495ae7d1f1b6facf9b.tar.gz rockbox-a513cee8222006d5f970b4495ae7d1f1b6facf9b.zip |
PictureFlow: Add 'Track Info' for tracks or whole albums
Context menu gains new option to view
metadata for individual tracks or albums.
Will display an album's length and total file size.
Other fields are displayed only if they are identical
across all tracks (except for the album year, which
is determined by the highest value encountered).
Change-Id: Ibc14cfaf2cb3d91b8d1cfbee05c6261db4975355
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/pictureflow/pictureflow.c | 258 |
1 files changed, 243 insertions, 15 deletions
diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index 54497d8306..61d0b64e94 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c | |||
@@ -397,6 +397,26 @@ struct track_data { | |||
397 | #endif | 397 | #endif |
398 | }; | 398 | }; |
399 | 399 | ||
400 | #if PF_PLAYBACK_CAPABLE | ||
401 | struct multiple_tracks_id3 { | ||
402 | unsigned long length; | ||
403 | unsigned long filesize; | ||
404 | unsigned long frequency; | ||
405 | unsigned int artist_hash; | ||
406 | unsigned int composer_hash; | ||
407 | unsigned int albumartist_hash; | ||
408 | unsigned int grouping_hash; | ||
409 | unsigned int comment_hash; | ||
410 | unsigned int album_hash; | ||
411 | unsigned int genre_hash; | ||
412 | unsigned int codectype; | ||
413 | unsigned int bitrate; | ||
414 | bool filesize_ovf; | ||
415 | bool length_ovf; | ||
416 | bool vbr; | ||
417 | }; | ||
418 | #endif | ||
419 | |||
400 | struct rect { | 420 | struct rect { |
401 | int left; | 421 | int left; |
402 | int right; | 422 | int right; |
@@ -558,6 +578,8 @@ static struct pf_index_t pf_idx; | |||
558 | 578 | ||
559 | static struct pf_track_t pf_tracks; | 579 | static struct pf_track_t pf_tracks; |
560 | 580 | ||
581 | static struct mp3entry id3; | ||
582 | |||
561 | void reset_track_list(void); | 583 | void reset_track_list(void); |
562 | 584 | ||
563 | static bool thread_is_running; | 585 | static bool thread_is_running; |
@@ -2093,7 +2115,6 @@ static bool get_albumart_for_index_from_db(const int slide_index, char *buf, | |||
2093 | pf_idx.album_index[slide_index].artist_seek); | 2115 | pf_idx.album_index[slide_index].artist_seek); |
2094 | 2116 | ||
2095 | if ( rb->tagcache_get_next(&tcs) ) { | 2117 | if ( rb->tagcache_get_next(&tcs) ) { |
2096 | struct mp3entry id3; | ||
2097 | int fd; | 2118 | int fd; |
2098 | 2119 | ||
2099 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 2120 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
@@ -2218,6 +2239,9 @@ static unsigned int mfnv(char *str) | |||
2218 | const unsigned int p = 16777619; | 2239 | const unsigned int p = 16777619; |
2219 | unsigned int hash = 0x811C9DC5; // 2166136261; | 2240 | unsigned int hash = 0x811C9DC5; // 2166136261; |
2220 | 2241 | ||
2242 | if (!str) | ||
2243 | return 0; | ||
2244 | |||
2221 | while(*str) | 2245 | while(*str) |
2222 | hash = (hash ^ *str++) * p; | 2246 | hash = (hash ^ *str++) * p; |
2223 | hash += hash << 13; | 2247 | hash += hash << 13; |
@@ -4010,6 +4034,169 @@ static void select_prev_album(void) | |||
4010 | } | 4034 | } |
4011 | 4035 | ||
4012 | #if PF_PLAYBACK_CAPABLE | 4036 | #if PF_PLAYBACK_CAPABLE |
4037 | static void collect_id3(struct multiple_tracks_id3 *mul_id3, bool is_first_track) | ||
4038 | { | ||
4039 | if (is_first_track) | ||
4040 | { | ||
4041 | mul_id3->artist_hash = mfnv(id3.artist); | ||
4042 | mul_id3->album_hash = mfnv(id3.album); | ||
4043 | mul_id3->genre_hash = mfnv(id3.genre_string); | ||
4044 | mul_id3->composer_hash = mfnv(id3.composer); | ||
4045 | mul_id3->albumartist_hash = mfnv(id3.albumartist); | ||
4046 | mul_id3->grouping_hash = mfnv(id3.grouping); | ||
4047 | mul_id3->comment_hash = mfnv(id3.comment); | ||
4048 | mul_id3->codectype = id3.codectype; | ||
4049 | mul_id3->vbr = id3.vbr; | ||
4050 | mul_id3->bitrate = id3.bitrate; | ||
4051 | mul_id3->frequency = id3.frequency; | ||
4052 | } | ||
4053 | else | ||
4054 | { | ||
4055 | if (mul_id3->artist_hash && (mfnv(id3.artist) != mul_id3->artist_hash)) | ||
4056 | mul_id3->artist_hash = 0; | ||
4057 | if (mul_id3->album_hash && (mfnv(id3.album) != mul_id3->album_hash)) | ||
4058 | mul_id3->album_hash = 0; | ||
4059 | if (mul_id3->genre_hash && (mfnv(id3.genre_string) != mul_id3->genre_hash)) | ||
4060 | mul_id3->genre_hash = 0; | ||
4061 | if (mul_id3->composer_hash && (mfnv(id3.composer) != mul_id3->composer_hash)) | ||
4062 | mul_id3->composer_hash = 0; | ||
4063 | if (mul_id3->albumartist_hash && (mfnv(id3.albumartist) != | ||
4064 | mul_id3->albumartist_hash)) | ||
4065 | mul_id3->albumartist_hash = 0; | ||
4066 | if (mul_id3->grouping_hash && (mfnv(id3.grouping) != mul_id3->grouping_hash)) | ||
4067 | mul_id3->grouping_hash = 0; | ||
4068 | if (mul_id3->comment_hash && (mfnv(id3.comment) != mul_id3->comment_hash)) | ||
4069 | mul_id3->comment_hash = 0; | ||
4070 | |||
4071 | if (mul_id3->codectype && (id3.codectype != mul_id3->codectype)) | ||
4072 | mul_id3->codectype = AFMT_UNKNOWN; | ||
4073 | if (mul_id3->bitrate && (id3.bitrate != mul_id3->bitrate || | ||
4074 | id3.vbr != mul_id3->vbr)) | ||
4075 | mul_id3->bitrate = 0; | ||
4076 | if (mul_id3->frequency && (id3.frequency != mul_id3->frequency)) | ||
4077 | mul_id3->frequency = 0; | ||
4078 | } | ||
4079 | |||
4080 | if (ULONG_MAX - mul_id3->length < id3.length) | ||
4081 | { | ||
4082 | mul_id3->length_ovf = true; | ||
4083 | mul_id3->length = 0; | ||
4084 | } | ||
4085 | else if (!mul_id3->length_ovf) | ||
4086 | mul_id3->length += id3.length; | ||
4087 | |||
4088 | if (INT_MAX - mul_id3->filesize < id3.filesize) /* output_dyn_value expects int */ | ||
4089 | { | ||
4090 | mul_id3->filesize_ovf = true; | ||
4091 | mul_id3->filesize = 0; | ||
4092 | } | ||
4093 | else if (!mul_id3->filesize_ovf) | ||
4094 | mul_id3->filesize += id3.filesize; | ||
4095 | } | ||
4096 | |||
4097 | |||
4098 | static void write_id3_mul_tracks(struct multiple_tracks_id3 *mul_id3) | ||
4099 | { | ||
4100 | id3.path[0] = '\0'; | ||
4101 | id3.title = NULL; | ||
4102 | if (!mul_id3->artist_hash) | ||
4103 | id3.artist = NULL; | ||
4104 | if (!mul_id3->album_hash) | ||
4105 | id3.album = NULL; | ||
4106 | if (!mul_id3->genre_hash) | ||
4107 | id3.genre_string = NULL; | ||
4108 | if (!mul_id3->composer_hash) | ||
4109 | id3.composer = NULL; | ||
4110 | if (!mul_id3->albumartist_hash) | ||
4111 | id3.albumartist = NULL; | ||
4112 | if (!mul_id3->grouping_hash) | ||
4113 | id3.grouping = NULL; | ||
4114 | if (!mul_id3->comment_hash) | ||
4115 | id3.comment = NULL; | ||
4116 | id3.disc_string = NULL; | ||
4117 | id3.track_string = NULL; | ||
4118 | id3.year_string = NULL; | ||
4119 | id3.year = pf_idx.album_index[center_index].year; | ||
4120 | id3.length = mul_id3->length; | ||
4121 | id3.filesize = mul_id3->filesize; | ||
4122 | id3.frequency = mul_id3->frequency; | ||
4123 | id3.bitrate = mul_id3->bitrate; | ||
4124 | id3.codectype = mul_id3->codectype; | ||
4125 | id3.vbr = mul_id3->vbr; | ||
4126 | id3.discnum = 0; | ||
4127 | id3.tracknum = 0; | ||
4128 | id3.track_level = 0; | ||
4129 | id3.album_level = 0; | ||
4130 | } | ||
4131 | |||
4132 | static void init_mul_id3(struct multiple_tracks_id3 *mul_id3) | ||
4133 | { | ||
4134 | mul_id3->artist_hash = 0; | ||
4135 | mul_id3->album_hash = 0; | ||
4136 | mul_id3->genre_hash = 0; | ||
4137 | mul_id3->composer_hash = 0; | ||
4138 | mul_id3->albumartist_hash = 0; | ||
4139 | mul_id3->grouping_hash = 0; | ||
4140 | mul_id3->comment_hash = 0; | ||
4141 | mul_id3->codectype = 0; | ||
4142 | mul_id3->vbr = false; | ||
4143 | mul_id3->bitrate = 0; | ||
4144 | mul_id3->frequency = 0; | ||
4145 | mul_id3->length = 0; | ||
4146 | mul_id3->filesize = 0; | ||
4147 | mul_id3->length_ovf = false; | ||
4148 | mul_id3->filesize_ovf = false; | ||
4149 | } | ||
4150 | |||
4151 | static int show_id3_info(const char *selected_file) | ||
4152 | { | ||
4153 | int fd, i; | ||
4154 | unsigned long last_tick; | ||
4155 | const char *file_name; | ||
4156 | bool id3_retrieval_successful; | ||
4157 | bool is_multiple_tracks = insert_whole_album && pf_tracks.count > 1; | ||
4158 | struct multiple_tracks_id3 mul_id3; | ||
4159 | |||
4160 | init_mul_id3(&mul_id3); | ||
4161 | |||
4162 | last_tick = *(rb->current_tick) + HZ/2; | ||
4163 | rb->splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ | ||
4164 | i = 0; | ||
4165 | do { | ||
4166 | id3_retrieval_successful = false; | ||
4167 | file_name = i == 0 ? selected_file : get_track_filename(i); | ||
4168 | fd = rb->open(file_name, O_RDONLY); | ||
4169 | if (fd >= 0) | ||
4170 | { | ||
4171 | if (rb->get_metadata(&id3, fd, file_name)) | ||
4172 | id3_retrieval_successful = true; | ||
4173 | rb->close(fd); | ||
4174 | } | ||
4175 | if (!id3_retrieval_successful) | ||
4176 | return 0; | ||
4177 | |||
4178 | if (is_multiple_tracks) | ||
4179 | { | ||
4180 | rb->splash_progress(i, pf_tracks.count, | ||
4181 | "%s (%s)", rb->str(LANG_WAIT), rb->str(LANG_OFF_ABORT)); | ||
4182 | if (TIME_AFTER(*(rb->current_tick), last_tick + HZ/4)) | ||
4183 | { | ||
4184 | if (rb->action_userabort(TIMEOUT_NOBLOCK)) | ||
4185 | return 0; | ||
4186 | last_tick = *(rb->current_tick); | ||
4187 | } | ||
4188 | |||
4189 | collect_id3(&mul_id3, i == 0); | ||
4190 | rb->yield(); | ||
4191 | } | ||
4192 | } while (++i < pf_tracks.count && is_multiple_tracks); | ||
4193 | |||
4194 | if (is_multiple_tracks) | ||
4195 | write_id3_mul_tracks(&mul_id3); | ||
4196 | |||
4197 | return rb->browse_id3(&id3, 0, 0, NULL) ? PLUGIN_USB_CONNECTED : 0; | ||
4198 | } | ||
4199 | |||
4013 | 4200 | ||
4014 | static bool playlist_insert(int position, bool queue, bool create_new) | 4201 | static bool playlist_insert(int position, bool queue, bool create_new) |
4015 | { | 4202 | { |
@@ -4061,14 +4248,8 @@ static bool track_list_ready(void) | |||
4061 | return true; | 4248 | return true; |
4062 | } | 4249 | } |
4063 | 4250 | ||
4064 | /** | ||
4065 | Brings up "Current Playlist" menu with first | ||
4066 | track of selection. | ||
4067 | 4251 | ||
4068 | Onplay menu code calls back playlist_insert for | 4252 | static bool context_menu_ready(void) |
4069 | adding all of the tracks. | ||
4070 | */ | ||
4071 | static void show_current_playlist_menu(void) | ||
4072 | { | 4253 | { |
4073 | #ifdef USEGSLIB | 4254 | #ifdef USEGSLIB |
4074 | grey_show(false); | 4255 | grey_show(false); |
@@ -4080,13 +4261,23 @@ static void show_current_playlist_menu(void) | |||
4080 | #ifdef USEGSLIB | 4261 | #ifdef USEGSLIB |
4081 | grey_show(true); | 4262 | grey_show(true); |
4082 | #endif | 4263 | #endif |
4083 | return; | 4264 | return false; |
4084 | } | 4265 | } |
4266 | #if LCD_DEPTH > 1 | ||
4267 | #ifdef USEGSLIB | ||
4268 | rb->lcd_set_foreground(N_BRIGHT(0)); | ||
4269 | rb->lcd_set_background(N_BRIGHT(255)); | ||
4270 | #endif | ||
4271 | #endif | ||
4085 | insert_whole_album = pf_state != pf_show_tracks; | 4272 | insert_whole_album = pf_state != pf_show_tracks; |
4086 | FOR_NB_SCREENS(i) | 4273 | FOR_NB_SCREENS(i) |
4087 | rb->viewportmanager_theme_enable(i, true, NULL); | 4274 | rb->viewportmanager_theme_enable(i, true, NULL); |
4088 | rb->onplay_show_playlist_menu(get_track_filename(pf_tracks.sel), | 4275 | |
4089 | &playlist_insert); | 4276 | return true; |
4277 | } | ||
4278 | |||
4279 | static void context_menu_cleanup(void) | ||
4280 | { | ||
4090 | FOR_NB_SCREENS(i) | 4281 | FOR_NB_SCREENS(i) |
4091 | rb->viewportmanager_theme_undo(i, false); | 4282 | rb->viewportmanager_theme_undo(i, false); |
4092 | if (insert_whole_album) | 4283 | if (insert_whole_album) |
@@ -4098,6 +4289,39 @@ static void show_current_playlist_menu(void) | |||
4098 | } | 4289 | } |
4099 | 4290 | ||
4100 | 4291 | ||
4292 | static int context_menu(void) | ||
4293 | { | ||
4294 | char *file_name = get_track_filename(pf_tracks.sel); | ||
4295 | |||
4296 | enum { | ||
4297 | PF_CURRENT_PLAYLIST = 0, | ||
4298 | PF_ID3_INFO | ||
4299 | }; | ||
4300 | MENUITEM_STRINGLIST(context_menu, ID2P(LANG_ONPLAY_MENU_TITLE), NULL, | ||
4301 | ID2P(LANG_PLAYING_NEXT), | ||
4302 | ID2P(LANG_MENU_SHOW_ID3_INFO)); | ||
4303 | |||
4304 | while (1) { | ||
4305 | switch (rb->do_menu(&context_menu, | ||
4306 | NULL, NULL, false)) { | ||
4307 | |||
4308 | case PF_CURRENT_PLAYLIST: | ||
4309 | rb->onplay_show_playlist_menu(file_name, | ||
4310 | &playlist_insert); | ||
4311 | return 0; | ||
4312 | case PF_ID3_INFO: | ||
4313 | return show_id3_info(file_name); | ||
4314 | case MENU_ATTACHED_USB: | ||
4315 | return PLUGIN_USB_CONNECTED; | ||
4316 | default: | ||
4317 | return 0; | ||
4318 | |||
4319 | } | ||
4320 | } | ||
4321 | } | ||
4322 | |||
4323 | |||
4324 | |||
4101 | /* | 4325 | /* |
4102 | * Puts selected album's tracks into a newly created playlist and starts playing | 4326 | * Puts selected album's tracks into a newly created playlist and starts playing |
4103 | */ | 4327 | */ |
@@ -4247,7 +4471,6 @@ static void set_initial_slide(const char* selected_file) | |||
4247 | pf_cfg.last_album); | 4471 | pf_cfg.last_album); |
4248 | else | 4472 | else |
4249 | { | 4473 | { |
4250 | static struct mp3entry id3; | ||
4251 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 4474 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
4252 | if (rb->tagcache_fill_tags(&id3, selected_file)) | 4475 | if (rb->tagcache_fill_tags(&id3, selected_file)) |
4253 | set_current_slide(id3_get_index(&id3)); | 4476 | set_current_slide(id3_get_index(&id3)); |
@@ -4601,8 +4824,8 @@ static int pictureflow_main(const char* selected_file) | |||
4601 | #if PF_PLAYBACK_CAPABLE | 4824 | #if PF_PLAYBACK_CAPABLE |
4602 | case PF_CONTEXT: | 4825 | case PF_CONTEXT: |
4603 | if (pf_state == pf_idle || pf_state == pf_scrolling || | 4826 | if (pf_state == pf_idle || pf_state == pf_scrolling || |
4604 | pf_state == pf_show_tracks || pf_state == pf_cover_out) { | 4827 | pf_state == pf_show_tracks || pf_state == pf_cover_out) |
4605 | 4828 | { | |
4606 | if ( pf_state == pf_scrolling) | 4829 | if ( pf_state == pf_scrolling) |
4607 | { | 4830 | { |
4608 | set_current_slide(target); | 4831 | set_current_slide(target); |
@@ -4611,7 +4834,12 @@ static int pictureflow_main(const char* selected_file) | |||
4611 | else if (pf_state == pf_cover_out) | 4834 | else if (pf_state == pf_cover_out) |
4612 | interrupt_cover_out_animation(); | 4835 | interrupt_cover_out_animation(); |
4613 | 4836 | ||
4614 | show_current_playlist_menu(); | 4837 | if (context_menu_ready()) |
4838 | { | ||
4839 | ret = context_menu(); | ||
4840 | context_menu_cleanup(); | ||
4841 | if ( ret != 0 ) return ret; | ||
4842 | } | ||
4615 | } | 4843 | } |
4616 | break; | 4844 | break; |
4617 | #endif | 4845 | #endif |