FS#11263 - Radio Art support! %C and %Cl tags work in the radio screen and Base Skin when the radio is running.
put your station images in .rockbox/fmpresets/<preset name>.bmp or .jpg. Must be in preset mode and the preset name must match the filename


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26078 a1c6a512-1295-4272-9138-f99709370657
diff --git a/apps/appevents.h b/apps/appevents.h
index 91c45c5..fd578b9 100644
--- a/apps/appevents.h
+++ b/apps/appevents.h
@@ -31,7 +31,8 @@
 
 /** Playback events **/
 enum {
-    PLAYBACK_EVENT_TRACK_BUFFER = (EVENT_CLASS_PLAYBACK|1),
+    PLAYBACK_EVENT_START_PLAYBACK = (EVENT_CLASS_PLAYBACK|1),
+    PLAYBACK_EVENT_TRACK_BUFFER,
     PLAYBACK_EVENT_TRACK_FINISH,
     PLAYBACK_EVENT_TRACK_CHANGE,
     PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
@@ -53,6 +54,11 @@
     GUI_EVENT_THEME_CHANGED,
 };
 
+/** Recording events **/
+enum {
+    RECORDING_EVENT_START = (EVENT_CLASS_RECORDING|1),
+    RECORDING_EVENT_STOP,
+};
 #endif
 
 
diff --git a/apps/buffering.c b/apps/buffering.c
index f194e2b..371cf22 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -1007,7 +1007,6 @@
     }
 
     /* Other cases: there is a little more work. */
-
     int fd = open(file, O_RDONLY);
     if (fd < 0)
         return ERR_FILE_ERROR;
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index f7bc14d..5c2b118 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -443,8 +443,15 @@
     if (data->albumart && data->albumart->vp == vp
         && data->albumart->draw)
     {
-        draw_album_art(gwps, playback_current_aa_hid(data->playback_aa_slot),
-                        false);
+        int handle = playback_current_aa_hid(data->playback_aa_slot);
+#if CONFIG_TUNER
+        if (in_radio_screen())
+        {
+            struct dim dim = {data->albumart->width, data->albumart->height};
+            handle = radio_get_art_hid(&dim);
+        }
+#endif
+        draw_album_art(gwps, handle, false);
         data->albumart->draw = false;
     }
 #endif
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index 3d944a5..538f385 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -577,8 +577,18 @@
             return buf;
 #ifdef HAVE_ALBUMART
         case WPS_TOKEN_ALBUMART_FOUND:
-            if (data->albumart) {
-                if (playback_current_aa_hid(data->playback_aa_slot) >= 0)
+            if (data->albumart)
+            {
+                int handle = -1;
+                handle = playback_current_aa_hid(data->playback_aa_slot);
+#if CONFIG_TUNER
+                if (in_radio_screen() || (get_radio_status() != FMRADIO_OFF))
+                {
+                    struct dim dim = {data->albumart->width, data->albumart->height};
+                    handle = radio_get_art_hid(&dim);
+                }
+#endif
+                if (handle >= 0)    
                     return "C";
             }
             return NULL;
diff --git a/apps/playback.c b/apps/playback.c
index 390dd19..0be45b0 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -1709,6 +1709,7 @@
 {
     int i;
 
+    send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL);
 #if INPUT_SRC_CAPS != 0
     audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
     audio_set_output_source(AUDIO_SRC_PLAYBACK);
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index e5a5107..2567b56 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -31,6 +31,7 @@
 #include "audio.h"
 #include "sound.h"
 #include "metadata.h"
+#include "appevents.h"
 #ifdef HAVE_SPDIF_IN
 #include "spdif.h"
 #endif
@@ -1127,6 +1128,7 @@
 static void pcmrec_init(void)
 {
     unsigned char *buffer;
+    send_event(RECORDING_EVENT_START, NULL);
 
     /* warings and errors */
     warnings          =
@@ -1183,6 +1185,7 @@
     pcm_close_recording();
     reset_hardware();
     audio_remove_encoder();
+    send_event(RECORDING_EVENT_STOP, NULL);
 } /* pcmrec_close */
 
 /* PCMREC_OPTIONS */
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index 0265795..5425e8a 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -69,6 +69,7 @@
 #include "viewport.h"
 #include "skin_engine/skin_engine.h"
 #include "statusbar-skinned.h"
+#include "buffering.h"
 
 #if CONFIG_TUNER
 
@@ -199,10 +200,18 @@
     return ret;
 }
 
+#if defined(HAVE_RECORDING) && defined(HAVE_ALBUMART)
+static void recording_started_handler(void *data);
+static void recording_stopped_handler(void *data);
+#endif
 void radio_init(void)
 {
     tuner_init();
     radio_off();
+#if defined(HAVE_RECORDING) && defined(HAVE_ALBUMART)
+    add_event(RECORDING_EVENT_START, false, recording_started_handler);
+    add_event(RECORDING_EVENT_STOP, false, recording_stopped_handler);
+#endif
 }
 
 int get_radio_status(void)
@@ -504,6 +513,131 @@
 static struct wps_data      fms_skin_data[NB_SCREENS] = {{ .wps_loaded = 0 }};
 static struct wps_sync_data fms_skin_sync_data        = { .do_full_update = false };
 
+#ifdef HAVE_ALBUMART
+#define MAX_RADIOART_IMAGES 10
+struct radioart {
+    int handle;
+    long last_tick;
+    struct dim dim;
+    char name[MAX_FMPRESET_LEN+1];
+};
+
+static struct radioart radioart[MAX_RADIOART_IMAGES];
+#ifdef HAVE_RECORDING
+static bool allow_buffer_access = true; /* If we are recording dont touch the buffers! */
+#endif
+static int find_oldest_image(void)
+{
+    int i;
+    long oldest_tick = radioart[0].last_tick;
+    int oldest_idx = 0;
+    for(i=1;i<MAX_RADIOART_IMAGES;i++)
+    {
+        if (radioart[i].last_tick < oldest_tick)
+        {
+            oldest_tick = radioart[i].last_tick;
+            oldest_idx = i;
+        }
+    }
+    return oldest_idx;
+}
+static int load_radioart_image(struct radioart *ra, char* preset_name, struct dim *dim)
+{
+    char path[MAX_PATH];
+#ifndef HAVE_NOISY_IDLE_MODE
+    cpu_idle_mode(false);
+#endif
+    snprintf(path, sizeof(path), FMPRESET_PATH "/%s.bmp",preset_name);
+    if (!file_exists(path))
+        snprintf(path, sizeof(path), FMPRESET_PATH "/%s.jpg",preset_name);
+    if (!file_exists(path))
+    {
+#ifndef HAVE_NOISY_IDLE_MODE
+		cpu_idle_mode(true);
+#endif
+        return -1;
+	}
+    strlcpy(ra->name, preset_name, MAX_FMPRESET_LEN+1);
+    ra->dim.height = dim->height;
+    ra->dim.width = dim->width;
+    ra->last_tick = current_tick;
+    ra->handle = bufopen(path, 0, TYPE_BITMAP, &ra->dim);
+    if (ra->handle == ERR_BUFFER_FULL)
+    {
+        int i = find_oldest_image();
+        bufclose(i);
+        ra->handle = bufopen(path, 0, TYPE_BITMAP, &ra->dim);
+    }
+#ifndef HAVE_NOISY_IDLE_MODE
+    cpu_idle_mode(true);
+#endif
+    return ra->handle;    
+}
+int radio_get_art_hid(struct dim *requested_dim)
+{
+    int preset = radio_current_preset();
+    int i, free_idx = -1;
+    if ((radio_mode != RADIO_PRESET_MODE) || preset < 0)
+        return -1;
+#ifdef HAVE_RECORDING
+    if (!allow_buffer_access)
+        return -1;
+#endif
+    for(i=0;i<MAX_RADIOART_IMAGES;i++)
+    {
+        if (radioart[i].handle < 0)
+        {
+            free_idx = i;
+        }
+        else if (!strcmp(radioart[i].name, presets[preset].name) &&
+                 radioart[i].dim.width == requested_dim->width &&
+                 radioart[i].dim.height == requested_dim->height)
+        {
+            radioart[i].last_tick = current_tick;
+            return radioart[i].handle;
+        }
+    }
+    if (free_idx >= 0)
+    {
+        return load_radioart_image(&radioart[free_idx], 
+                                   presets[preset].name, requested_dim);
+    }
+    else
+    {
+        int i = find_oldest_image();
+        bufclose(radioart[i].handle);
+        return load_radioart_image(&radioart[i],
+                                   presets[preset].name, requested_dim);        
+    }
+        
+    return -1;
+}
+static void playback_restarting_handler(void *data)
+{
+    (void)data;
+    int i;
+    for(i=0;i<MAX_RADIOART_IMAGES;i++)
+    {
+        if (radioart[i].handle >= 0)
+            bufclose(radioart[i].handle);
+        radioart[i].handle = -1;
+        radioart[i].name[0] = '\0';
+    }
+}
+#ifdef HAVE_RECORDING
+static void recording_started_handler(void *data)
+{
+    (void)data;
+    allow_buffer_access = false;
+    playback_restarting_handler(NULL);
+}
+static void recording_stopped_handler(void *data)
+{
+    (void)data;
+    allow_buffer_access = true;
+}
+#endif
+#endif
 
 void fms_data_load(enum screen_type screen, const char *buf, bool isfile)
 {
@@ -613,9 +747,18 @@
     {
         radio_load_presets(global_settings.fmr_file);
     }
+#ifdef HAVE_ALBUMART
+    for(i=0;i<MAX_RADIOART_IMAGES;i++)
+    {
+        radioart[i].handle = -1;
+        radioart[i].name[0] = '\0';
+    }
+    add_event(PLAYBACK_EVENT_START_PLAYBACK, true, playback_restarting_handler);
+#endif    
 
     if(radio_status == FMRADIO_OFF)
         audio_stop();
+    
 #ifndef SIMULATOR
 
 #if CONFIG_CODEC != SWCODEC
diff --git a/apps/recorder/radio.h b/apps/recorder/radio.h
index 415de6f..d0a6053 100644
--- a/apps/recorder/radio.h
+++ b/apps/recorder/radio.h
@@ -59,6 +59,10 @@
     char name[MAX_FMPRESET_LEN+1];
 };
 
+#ifdef HAVE_ALBUMART
+int radio_get_art_hid(struct dim *requested_dim);
+#endif
+
 #endif /* CONFIG_TUNER */
 
 #endif /* RADIO_H */
diff --git a/firmware/export/events.h b/firmware/export/events.h
index 42ddf58..9e60fe7 100644
--- a/firmware/export/events.h
+++ b/firmware/export/events.h
@@ -37,6 +37,7 @@
 #define EVENT_CLASS_PLAYBACK   0x0200
 #define EVENT_CLASS_BUFFERING  0x0400
 #define EVENT_CLASS_GUI        0x0800
+#define EVENT_CLASS_RECORDING  0x1000
 #define EVENT_CLASS_LCD        0xf000
 
 bool add_event(unsigned short id, bool oneshot, void (*handler)(void *data));
diff --git a/tools/rockboxdev.sh b/tools/rockboxdev.sh
index 82f20ef..a139ed3 100755
--- a/tools/rockboxdev.sh
+++ b/tools/rockboxdev.sh
@@ -26,7 +26,7 @@
 if [ -f "`which gmake 2>/dev/null`" ]; then
     make="gmake"
 else
-    make="make"
+    make="make -j4"
 fi
 
 if [ -z $GNU_MIRROR ] ; then