1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2007 Nicolas Pennequin
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "buffering.h"
35 /* Strip filename from a full path
37 * buf - buffer to extract directory to.
38 * buf_size - size of buffer.
39 * fullpath - fullpath to extract from.
41 * Split the directory part of the given fullpath and store it in buf
42 * (including last '/').
43 * The function return parameter is a pointer to the filename
44 * inside the given fullpath.
46 static char* strip_filename(char* buf
, int buf_size
, const char* fullpath
)
51 if (!buf
|| buf_size
<= 0 || !fullpath
)
54 /* if 'fullpath' is only a filename return immediately */
55 sep
= strrchr(fullpath
, '/');
59 return (char*)fullpath
;
62 len
= MIN(sep
- fullpath
+ 1, buf_size
- 1);
63 strncpy(buf
, fullpath
, len
);
68 /* Make sure part of path only contain chars valid for a FAT32 long name.
69 * Double quotes are replaced with single quotes, other unsupported chars
70 * are replaced with an underscore.
72 * path - path to modify.
73 * offset - where in path to start checking.
74 * count - number of chars to check.
76 static void fix_path_part(char* path
, int offset
, int count
)
78 static const char invalid_chars
[] = "*/:<>?\\|";
83 for (i
= 0; i
<= count
; i
++, path
++)
89 else if (strchr(invalid_chars
, *path
))
94 #if defined(HAVE_JPEG) || defined(PLUGIN)
95 const char * extensions
[] = { "jpeg", "jpg", "bmp" };
96 int extension_lens
[] = { 4, 3, 3 };
97 /* Try checking for several file extensions, return true if a file is found and
98 * leaving the path modified to include the matching extension.
100 static bool try_exts(char *path
, int len
)
103 for (i
= 0; i
< 3; i
++)
105 if (extension_lens
[i
] + len
> MAX_PATH
)
107 strcpy(path
+ len
, extensions
[i
]);
108 if (file_exists(path
))
115 /* Look for the first matching album art bitmap in the following list:
116 * ./<trackname><size>.bmp
117 * ./<albumname><size>.bmp
119 * ../<albumname><size>.bmp
121 * ROCKBOX_DIR/albumart/<artist>-<albumname><size>.bmp
122 * <size> is the value of the size_string parameter, <trackname> and
123 * <albumname> are read from the ID3 metadata.
124 * If a matching bitmap is found, its filename is stored in buf.
125 * Return value is true if a bitmap was found, false otherwise.
127 bool search_albumart_files(const struct mp3entry
*id3
, const char *size_string
,
128 char *buf
, int buflen
)
130 char path
[MAX_PATH
+ 1];
131 char dir
[MAX_PATH
+ 1];
133 const char *trackname
;
137 #if defined(HAVE_JPEG) || defined(PLUGIN)
144 trackname
= id3
->path
;
146 if (strcmp(trackname
, "No file!") == 0)
149 strip_filename(dir
, sizeof(dir
), trackname
);
150 dirlen
= strlen(dir
);
151 albumlen
= id3
->album
? strlen(id3
->album
) : 0;
153 /* the first file we look for is one specific to the track playing */
154 strip_extension(path
, sizeof(path
) - strlen(size_string
) - 4, trackname
);
155 strcat(path
, size_string
);
156 #if defined(HAVE_JPEG) || defined(PLUGIN)
158 pathlen
= strlen(path
);
159 found
= try_exts(path
, pathlen
);
161 strcat(path
, ".bmp");
162 found
= file_exists(path
);
164 if (!found
&& albumlen
> 0)
166 /* if it doesn't exist,
167 * we look for a file specific to the track's album name */
168 #if defined(HAVE_JPEG) || defined(PLUGIN)
169 pathlen
= snprintf(path
, sizeof(path
),
170 "%s%s%s.", dir
, id3
->album
, size_string
);
171 fix_path_part(path
, dirlen
, albumlen
);
172 found
= try_exts(path
, pathlen
);
174 snprintf(path
, sizeof(path
),
175 "%s%s%s.bmp", dir
, id3
->album
, size_string
);
176 fix_path_part(path
, dirlen
, albumlen
);
177 found
= file_exists(path
);
183 /* if it still doesn't exist, we look for a generic file */
184 #if defined(HAVE_JPEG) || defined(PLUGIN)
185 pathlen
= snprintf(path
, sizeof(path
),
186 "%scover%s.", dir
, size_string
);
187 found
= try_exts(path
, pathlen
);
189 snprintf(path
, sizeof(path
),
190 "%scover%s.bmp", dir
, size_string
);
191 found
= file_exists(path
);
195 #if defined(HAVE_JPEG) || defined(PLUGIN)
198 snprintf (path
, sizeof(path
), "%sfolder.jpg", dir
);
199 found
= file_exists(path
);
203 artist
= id3
->albumartist
!= NULL
? id3
->albumartist
: id3
->artist
;
205 if (!found
&& artist
&& id3
->album
)
207 /* look in the albumart subdir of .rockbox */
208 #if defined(HAVE_JPEG) || defined(PLUGIN)
209 pathlen
= snprintf(path
, sizeof(path
),
210 ROCKBOX_DIR
"/albumart/%s-%s%s.",
214 fix_path_part(path
, strlen(ROCKBOX_DIR
"/albumart/"), MAX_PATH
);
215 found
= try_exts(path
, pathlen
);
217 snprintf(path
, sizeof(path
),
218 ROCKBOX_DIR
"/albumart/%s-%s%s.bmp",
222 fix_path_part(path
, strlen(ROCKBOX_DIR
"/albumart/"), MAX_PATH
);
223 found
= file_exists(path
);
229 /* if it still doesn't exist,
230 * we continue to search in the parent directory */
232 path
[dirlen
- 1] = 0;
233 strip_filename(dir
, sizeof(dir
), path
);
234 dirlen
= strlen(dir
);
237 /* only try parent if there is one */
240 if (!found
&& albumlen
> 0)
242 /* we look in the parent directory
243 * for a file specific to the track's album name */
244 #if defined(HAVE_JPEG) || defined(PLUGIN)
245 pathlen
= snprintf(path
, sizeof(path
),
246 "%s%s%s.", dir
, id3
->album
, size_string
);
247 fix_path_part(path
, dirlen
, albumlen
);
248 found
= try_exts(path
, pathlen
);
250 snprintf(path
, sizeof(path
),
251 "%s%s%s.bmp", dir
, id3
->album
, size_string
);
252 fix_path_part(path
, dirlen
, albumlen
);
253 found
= file_exists(path
);
259 /* if it still doesn't exist, we look in the parent directory
260 * for a generic file */
261 #if defined(HAVE_JPEG) || defined(PLUGIN)
262 pathlen
= snprintf(path
, sizeof(path
),
263 "%scover%s.", dir
, size_string
);
264 found
= try_exts(path
, pathlen
);
266 snprintf(path
, sizeof(path
),
267 "%scover%s.bmp", dir
, size_string
);
268 found
= file_exists(path
);
276 strncpy(buf
, path
, buflen
);
277 DEBUGF("Album art found: %s\n", path
);
282 /* Look for albumart bitmap in the same dir as the track and in its parent dir.
283 * Stores the found filename in the buf parameter.
284 * Returns true if a bitmap was found, false otherwise */
285 bool find_albumart(const struct mp3entry
*id3
, char *buf
, int buflen
)
291 struct wps_data
*data
= gui_wps
[0].data
;
296 DEBUGF("Looking for album art for %s\n", id3
->path
);
298 /* Write the size string, e.g. ".100x100". */
299 snprintf(size_string
, sizeof(size_string
), ".%dx%d",
300 data
->albumart_max_width
, data
->albumart_max_height
);
302 /* First we look for a bitmap of the right size */
303 if (search_albumart_files(id3
, size_string
, buf
, buflen
))
306 /* Then we look for generic bitmaps */
308 return search_albumart_files(id3
, size_string
, buf
, buflen
);
311 /* Draw the album art bitmap from the given handle ID onto the given WPS.
312 Call with clear = true to clear the bitmap instead of drawing it. */
313 void draw_album_art(struct gui_wps
*gwps
, int handle_id
, bool clear
)
315 if (!gwps
|| !gwps
->data
|| !gwps
->display
|| handle_id
< 0)
318 struct wps_data
*data
= gwps
->data
;
320 #ifdef HAVE_REMOTE_LCD
321 /* No album art on RWPS */
322 if (data
->remote_wps
)
327 if (bufgetdata(handle_id
, 0, (void *)&bmp
) <= 0)
330 short x
= data
->albumart_x
;
331 short y
= data
->albumart_y
;
332 short width
= bmp
->width
;
333 short height
= bmp
->height
;
335 if (data
->albumart_max_width
> 0)
337 /* Crop if the bitmap is too wide */
338 width
= MIN(bmp
->width
, data
->albumart_max_width
);
341 if (data
->albumart_xalign
& WPS_ALBUMART_ALIGN_RIGHT
)
342 x
+= data
->albumart_max_width
- width
;
343 else if (data
->albumart_xalign
& WPS_ALBUMART_ALIGN_CENTER
)
344 x
+= (data
->albumart_max_width
- width
) / 2;
347 if (data
->albumart_max_height
> 0)
349 /* Crop if the bitmap is too high */
350 height
= MIN(bmp
->height
, data
->albumart_max_height
);
353 if (data
->albumart_yalign
& WPS_ALBUMART_ALIGN_BOTTOM
)
354 y
+= data
->albumart_max_height
- height
;
355 else if (data
->albumart_yalign
& WPS_ALBUMART_ALIGN_CENTER
)
356 y
+= (data
->albumart_max_height
- height
) / 2;
361 /* Draw the bitmap */
362 gwps
->display
->bitmap_part((fb_data
*)bmp
->data
, 0, 0, bmp
->width
,
363 x
, y
, width
, height
);
364 #ifdef HAVE_LCD_INVERT
365 if (global_settings
.invert
) {
366 gwps
->display
->set_drawmode(DRMODE_COMPLEMENT
);
367 gwps
->display
->fillrect(x
, y
, width
, height
);
368 gwps
->display
->set_drawmode(DRMODE_SOLID
);
374 /* Clear the bitmap */
375 gwps
->display
->set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
376 gwps
->display
->fillrect(x
, y
, width
, height
);
377 gwps
->display
->set_drawmode(DRMODE_SOLID
);
381 void get_albumart_size(struct bitmap
*bmp
)
383 /* FIXME: What should we do with albumart on remote? */
384 struct wps_data
*data
= gui_wps
[0].data
;
386 bmp
->width
= data
->albumart_max_width
;
387 bmp
->height
= data
->albumart_max_height
;