f8b31404b2684aa53f374e7c41ab539bb252f84f — Gregory Mullen 11 months ago d43fbcc
rewrite music search code
M Makefile => Makefile +1 -1
@@ 15,7 15,7 @@ OBJ += audio.o audio_search.o
 
 OBJ += gui/root.o gui/nav.o gui/notifier.o gui/onscreenkeys.o
 OBJ += gui/gps_gui.o
-OBJ += gui/music.o gui/music_tracks.o gui/music_buttons.o
+OBJ += gui/music.o gui/music_tracks.o gui/music_buttons.o gui/music_artists.o gui/music_albums.o
 
 
 

M audio.c => audio.c +22 -195
@@ 32,10 32,8 @@
 
 #define _10_mSECS 1000 * 1000 * 10
 #define _10_uSECS 1000 * 10
-
 #define _100_uSECS 1000 * 100
 
-
 #define DEFAULT_CHANNELS    2
 #define DEFAULT_SAMPLE_FMT  AV_SAMPLE_FMT_S16
 #define DEFAULT_SAMPLE_RATE 48000


@@ 43,11 41,15 @@
 static char *device = "default";
 static snd_pcm_format_t pcm_format = SND_PCM_FORMAT_S16;
 static snd_pcm_t *pcm;
+static struct track_data *current_track = NULL;
 
 
-static struct audio_track *current_track = NULL;
-// static struct music_dir *music_dir = NULL;
-static struct music_db *m_db = NULL;
+struct playback_data {
+    struct track_data *track;
+    bool running;
+    bool paused;
+    bool clean_exit;
+};
 
 
 static void init_pcm(void)


@@ 64,8 66,6 @@ static void init_pcm(void)
         LOG_E("Playback open error: %s\n", snd_strerror(snd_err));
         return;
     }
-
-
     return;
 }
 


@@ 93,7 93,6 @@ static int pcm_play(uint8_t *buffer, long count)
 
 static AUDIO_MSG next_amsg_msg = 0;
 static void *next_amsg_data = NULL;
-
 void postmsg_audio(AUDIO_MSG msg, void *data)
 {
     if (msg && next_amsg_msg) {


@@ 106,7 105,7 @@ void postmsg_audio(AUDIO_MSG msg, void *data)
 }
 
 
-static AVFormatContext *open_audio_track(char *filename, bool debug, int *stream_id)
+static AVFormatContext *open_audio_track(char *filename, int *stream_id)
 {
     LOG_D("getting format context\n");
     AVFormatContext *fcontext = avformat_alloc_context();


@@ 121,10 120,6 @@ static AVFormatContext *open_audio_track(char *filename, bool debug, int *stream
         return NULL;
     }
 
-    if (debug || 1) {
-        av_dump_format(fcontext, 0, filename, false);
-    }
-
     LOG_D("searching streams\n");
     for (uint32_t i = 0; i < fcontext->nb_streams; i++) {
         if (fcontext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {


@@ 163,40 158,33 @@ static AVCodecContext *init_codec(AVCodecContext *ctx, AVDictionary **metadata)
 }
 
 
-struct playback_data {
-    struct audio_track *track;
-    bool running;
-    bool paused;
-    bool clean_exit;
-};
-
-
 #define AUDIO_BUF_SIZE 20480
 static void *playback_thread(void *d)
 {
     struct playback_data *data = d;
 
     LOG_N("Playing %s\n", data->track->filename);
-    char *dirname  = expand_dirname(data->track->dirname, data->track->filename);
-    LOG_N("location %s\n", dirname);
+
+    const struct directory_data *dir = find_dir(data->track->dir_id, NULL);
+    char *filename  = expand_dirname(dir->dirname, data->track->filename);
+    LOG_N("location %s\n", filename);
 
     int stream_id = -1;
-    AVFormatContext *fcon = open_audio_track(dirname, false, &stream_id);
+    // So... I'm pretty sure filename only needs to exist until this function returns
+    // if you get odd crashes... that obviously not correct!
+    AVFormatContext *fcon = open_audio_track(filename, &stream_id);
     if (!fcon) {
         data->clean_exit = true;
-        free(dirname);
+        free(filename);
         return NULL;
     }
-
-    if (!data->track->file_read) {
-        audio_track_add_metadata(data->track);
-    }
+    free(filename);
+    filename = NULL;
 
     AVCodecContext *c_ctx = init_codec(fcon->streams[stream_id]->codec, &fcon->metadata);
     if (!c_ctx) {
         LOG_E("Could not allocate init codec\n");
         data->clean_exit = true;
-        free(dirname);
         return NULL;
     }
 


@@ 212,7 200,6 @@ static void *playback_thread(void *d)
     if (!avframe) {
         LOG_E("Could not allocate audio frame\n");
         data->clean_exit = true;
-        free(dirname);
         return NULL;
     }
 


@@ 225,7 212,6 @@ static void *playback_thread(void *d)
     if (!swr) {
         LOG_E("SWR alloc set opts failed\n;");
         data->clean_exit = true;
-        free(dirname);
         return NULL;
     }
     swr_init(swr);


@@ 279,7 265,6 @@ static void *playback_thread(void *d)
     LOG_E("files done\n");
 
     free(output);
-    free(dirname);
     avcodec_close(c_ctx);
     avformat_close_input(&fcon);
     avformat_free_context(fcon);


@@ 314,7 299,7 @@ static void *audio_thread(void *p)
                 return NULL;
             }
             case AMSG_NONE: {
-                LOG_T("AMSG_THREAD UNHANDLED msg AMSG_NONE\n");
+                // LOG_T("AMSG_THREAD UNHANDLED msg AMSG_NONE\n");
                 break;
             }
             case AMSG_PLAY: {


@@ 389,7 374,6 @@ static void *audio_thread(void *p)
             }
             case AMSG_TRACK_SCAN_DONE: {
                 LOG_N("AMSG Track Scan done!\n");
-                m_db = cur_data;
                 break;
             }
         }


@@ 406,150 390,6 @@ static void *audio_thread(void *p)
 }
 
 
-static struct artist_db *artist_db = NULL;
-
-
-static int push_artist(const char *name)
-{
-    // TODO check for unused locations so array can shrink with deletions
-
-    if (!name) {
-        return -2;
-    }
-
-    int name_length = strlen(name);
-    if (name_length == 0) {
-        LOG_E("artist push Name length shouldn't be 0\n");
-        return -2;
-    }
-
-    for (int i = 0; i < artist_db->count; i++) {
-        if (artist_db->data[i].length != name_length) {
-            continue;
-        }
-
-        if (strcmp(name, artist_db->data[i].name) == 0) {
-            return i;
-        }
-    }
-
-    if (artist_db->count >= artist_db->capacity) {
-        struct artist_data *next = realloc(artist_db->data, sizeof(struct artist_data) * (artist_db->capacity + 10));
-        if (!next) {
-            LOG_F("Realloc failed for push artist %s", name);
-            exit(2);
-        }
-        artist_db->data = next;
-        artist_db->capacity += 10;
-    }
-
-    artist_db->data[artist_db->count].length = name_length;
-    artist_db->data[artist_db->count].name = strdup(name);
-    if (!artist_db->data[artist_db->count].name) {
-        LOG_E("Strdup failed in push_artist\n");
-        exit(2);
-    }
-
-    artist_db->count++;
-    return artist_db->count - 1;
-
-    return -1;
-}
-
-
-const char *track_artist_get(const int id)
-{
-    if (id < 0 || id >= artist_db->count) {
-        return NULL;
-    }
-
-    return artist_db->data[id].name;
-}
-
-
-int audio_track_add_metadata(struct audio_track *track)
-{
-    LOG_T("Trying to add metadata for track ");
-    if (!track) {
-        LOG_W("Track give was null\n");
-        return 0;
-    }
-
-    if (!track->dirname || !track->filename) {
-        return -1;
-    }
-    LOG_T("dirname %s, filename %s\n", track->dirname, track->filename);
-
-    char *dirname  = expand_dirname(track->dirname, track->filename);
-    if (!dirname) {
-        LOG_F("Unable to expand dirname for track %s\n", track->filename);
-        exit(2);
-    }
-
-    AVFormatContext *file = avformat_alloc_context();
-    if (avformat_open_input(&file, dirname, NULL, NULL) < 0) {
-        LOG_E("Could not open file\n");
-        free(dirname);
-        return -2;
-    }
-
-    AVDictionaryEntry *dict = NULL;
-    if ((dict = av_dict_get(file->metadata, "album_artist", NULL, 0))) {
-        track->album_artist_id = push_artist(dict->value);
-    } else if ((dict = av_dict_get(file->metadata, "artist", NULL, 0))) {
-        track->album_artist_id = push_artist(dict->value);
-    }
-
-    if ((dict = av_dict_get(file->metadata, "artist", NULL, 0))) {
-        track->artist_id = push_artist(dict->value);
-    } else {
-        track->artist_id = track->album_artist_id;
-    }
-
-    if ((dict = av_dict_get(file->metadata, "title", NULL, 0))) {
-        LOG_E("%s title %s\n", track->filename, dict->value);
-        track->md_title = strdup(dict->value);
-    }
-
-    if ((dict = av_dict_get(file->metadata, "album", NULL, 0))) {
-        track->md_album = strdup(dict->value);
-    }
-
-    if ((dict = av_dict_get(file->metadata, "genre", NULL, 0))) {
-        track->md_genre = strdup(dict->value);
-    }
-
-    track->file_read = true;
-
-    avformat_close_input(&file);
-    avformat_free_context(file);
-    free(dirname);
-    LOG_T("metadata complete\n");
-    return 0;
-}
-
-
-void audio_track_free_metadata(struct audio_track *track)
-{
-    if (track->md_title) {
-        free(track->md_title);
-        track->md_title = NULL;
-    }
-
-    if (track->md_album) {
-        free(track->md_album);
-        track->md_album = NULL;
-    }
-
-    if (track->md_genre) {
-        free(track->md_genre);
-        track->md_genre = NULL;
-    }
-
-    track->file_read = false;
-}
-
-
 static void avlog_cb(void *ptr, int level, const char *fmt, va_list vl)
 {
     (void) ptr;


@@ 575,37 415,24 @@ static void audio_init(void)
 
     LOG_T("init pcm\n");
     init_pcm();
-
-    artist_db = calloc(1, sizeof (struct artist_db));
-    if (!artist_db) {
-        LOG_F("artist_db Calloc failed\n");
-        exit(2);
-    }
 }
 
 
-struct audio_track *audio_track_get_current(void)
+struct track_data *audio_track_get_current(void)
 {
     return current_track;
 }
 
 
-struct music_db *audio_db_get(void)
-{
-    return m_db;
-}
-
-
 void audio_thread_start(void)
 {
     LOG_N("audio_thread_start\n");
 
     audio_init();
 
-    struct music_db *music_db = calloc(1, sizeof (struct music_db));
     pthread_t ms;
-    pthread_create(&ms, NULL, find_files_thread, music_db);
+    pthread_create(&ms, NULL, find_files_thread, NULL);
 
     pthread_t a;
-    pthread_create(&a, NULL, audio_thread, (void *)NULL);
+    pthread_create(&a, NULL, audio_thread, NULL);
 }

M audio.h => audio.h +4 -35
@@ 1,6 1,9 @@
 #ifndef _HUD_AUDIO_H_
 #define _HUD_AUDIO_H_
 
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdint.h>
 #include <stdbool.h>
 
 typedef enum {


@@ 19,43 22,9 @@ typedef enum {
 } AUDIO_MSG;
 
 
-struct audio_track {
-    bool file_read;
-
-    char *filename;
-    char *dirname;
-
-    int artist_id;
-    int album_artist_id;
-    char *md_title;
-    char *md_album;
-    char *md_genre;
-};
-
-
-struct artist_data {
-    int length;
-    char *name;
-};
-
-struct artist_db {
-    int count;
-    int capacity;
-    struct artist_data *data;
-};
-
-
 void postmsg_audio(AUDIO_MSG msg, void *data);
-
 void audio_thread_start(void);
 
-struct audio_track *audio_track_get_current(void);
-struct music_db *audio_db_get(void);
-
-const char *track_artist_get(const int id);
-
-
-int audio_track_add_metadata(struct audio_track *track);
-void audio_track_free_metadata(struct audio_track *track);
+struct track_data *audio_track_get_current(void);
 
 #endif // _HUD_AUDIO_H_

M audio_search.c => audio_search.c +469 -95
@@ 16,16 16,33 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
+#include <libavformat/avformat.h>
+
+
 #define _10_mSECS 1000 * 1000 * 10
 
 
-const char *supported_ext[] = {
+static const char *supported_ext[] = {
     "mp3",
     "ogg",
     "flac",
 };
 
 
+static struct music_db *m_db = NULL;
+
+
+static struct track_data *track_get(int id)
+{
+    return &m_db->track_db.data[id];
+}
+
+static struct directory_data *directory_get(int id)
+{
+    return &m_db->dir_db.data[id];
+}
+
+
 static inline bool probably_music(char *filename)
 {
     for (unsigned int i = 0; i < 3; i++) {


@@ 42,41 59,198 @@ static inline bool probably_music(char *filename)
 }
 
 
-// static int add_file(struct music_db *m_dir, char *filename)
-// {
-//     (void) m_dir;
-//     if (probably_music(filename)) {
-//         LOG_D("Music %s\n", filename);
-//         return 1;
-//     }
-//     return 0;
-// }
+static int push_track(struct music_db *m_db, const char *name)
+{
+    // TODO check for unused locations so array can shrink with deletions
+    LOG_T("push_track called for %s\n", name);
+    if (!name) {
+        return -2;
+    }
+
+    uint32_t name_length = strlen(name);
+    if (name_length == 0) {
+        LOG_E("track push Name length shouldn't be 0\n");
+        return -2;
+    }
+
+    if (m_db->track_db.count >= m_db->track_db.capacity) {
+        struct track_data *next = realloc(m_db->track_db.data, sizeof(struct track_data) * (m_db->track_db.capacity + 10));
+        if (!next) {
+            LOG_F("Realloc failed for push track %s", name);
+            exit(2);
+        }
+
+        m_db->track_db.data = next;
+        m_db->track_db.capacity += 10;
+        memset(&m_db->track_db.data[m_db->track_db.count], 0, sizeof (struct track_data) * 10);
+    }
+
+    m_db->track_db.data[m_db->track_db.count].length = name_length;
+    m_db->track_db.data[m_db->track_db.count].filename = strdup(name);
+    if (!m_db->track_db.data[m_db->track_db.count].filename) {
+        LOG_E("Strdup failed in push_track\n");
+        exit(2);
+    }
+
+    m_db->track_db.count++;
+    return m_db->track_db.count - 1;
+}
+
+
+static int push_artist(struct music_db *m_db, const char *name)
+{
+    // TODO check for unused locations so array can shrink with deletions
+    LOG_T("push_artist called for %s\n", name);
+    if (!name) {
+        return -2;
+    }
+
+    uint32_t name_length = strlen(name);
+    if (name_length == 0) {
+        LOG_E("artist push Name length shouldn't be 0\n");
+        return -2;
+    }
+
+    for (int i = 0; i < m_db->artist_db.count; i++) {
+        if (m_db->artist_db.data[i].length != name_length) {
+            continue;
+        }
+
+        if (strcmp(name, m_db->artist_db.data[i].name) == 0) {
+            return i;
+        }
+    }
+
+    if (m_db->artist_db.count >= m_db->artist_db.capacity) {
+        struct artist_data *next = realloc(m_db->artist_db.data, sizeof(struct artist_data) * (m_db->artist_db.capacity + 10));
+        if (!next) {
+            LOG_F("Realloc failed for push artist %s", name);
+            exit(2);
+        }
+
+        m_db->artist_db.data = next;
+        m_db->artist_db.capacity += 10;
+        memset(&m_db->artist_db.data[m_db->artist_db.count], 0, sizeof (struct artist_data) * 10);
+    }
+
+    m_db->artist_db.data[m_db->artist_db.count].length = name_length;
+    m_db->artist_db.data[m_db->artist_db.count].name = strdup(name);
+    if (!m_db->artist_db.data[m_db->artist_db.count].name) {
+        LOG_E("Strdup failed in push_artist\n");
+        exit(2);
+    }
+
+    m_db->artist_db.count++;
+    return m_db->artist_db.count - 1;
+
+    return -1;
+}
+
+
+static int push_album(struct music_db *m_db, const char *name)
+{
+    // TODO check for unused locations so array can shrink with deletions
+    LOG_T("push_album called for %s\n", name);
+    if (!name) {
+        return -2;
+    }
+
+    uint32_t name_length = strlen(name);
+    if (name_length == 0) {
+        LOG_E("album push Name length shouldn't be 0\n");
+        return -2;
+    }
+
+    for (int i = 0; i < m_db->album_db.count; i++) {
+        if (m_db->album_db.data[i].length != name_length) {
+            continue;
+        }
+
+        if (strcmp(name, m_db->album_db.data[i].name) == 0) {
+            return i;
+        }
+    }
+
+    if (m_db->album_db.count >= m_db->album_db.capacity) {
+        struct album_data *next = realloc(m_db->album_db.data, sizeof(struct album_data) * (m_db->album_db.capacity + 10));
+        if (!next) {
+            LOG_F("Realloc failed for push album %s", name);
+            exit(2);
+        }
+
+        m_db->album_db.data = next;
+        m_db->album_db.capacity += 10;
+        memset(&m_db->album_db.data[m_db->album_db.count], 0, sizeof (struct album_data) * 10);
+    }
+
+    m_db->album_db.data[m_db->album_db.count].length = name_length;
+    m_db->album_db.data[m_db->album_db.count].name = strdup(name);
+    if (!m_db->album_db.data[m_db->album_db.count].name) {
+        LOG_E("Strdup failed in push_album\n");
+        exit(2);
+    }
+
+    m_db->album_db.count++;
+    return m_db->album_db.count - 1;
 
+    return -1;
+}
 
-static inline struct music_dir *ensure_dir(struct music_dir *dir)
+
+static int push_dir(struct music_db *m_db, const char *name)
 {
-    if (dir) {
-        return dir;
+    // TODO check for unused locations so array can shrink with deletions
+    LOG_T("push_dir called for %s\n", name);
+    if (!name) {
+        return -1;
     }
 
-    dir = calloc(1, sizeof (struct music_dir));
-    if (!dir) {
-        LOG_E("Unable to calloc for music_dir\n");
-        exit(10);
+    uint32_t name_length = strlen(name);
+    if (name_length == 0) {
+        LOG_E("dir push Name length shouldn't be 0\n");
+        return -2;
     }
-    return dir;
+
+    for (int i = 0; i < m_db->dir_db.count; i++) {
+        if (strcmp(name, m_db->dir_db.data[i].dirname) == 0) {
+            if (m_db->dir_db.data[i].length == name_length) {
+                return i;
+            }
+        }
+    }
+
+    if (m_db->dir_db.count >= m_db->dir_db.capacity) {
+        struct directory_data *next = realloc(m_db->dir_db.data, sizeof (struct directory_data) * (m_db->dir_db.capacity + 10));
+        if (!next) {
+            LOG_F("Realloc failed for push dir %s", name);
+            exit(2);
+        }
+        m_db->dir_db.data = next;
+        m_db->dir_db.capacity += 10;
+        memset(&m_db->dir_db.data[m_db->dir_db.count], 0, sizeof (struct directory_data) * 10);
+    }
+
+    m_db->dir_db.data[m_db->dir_db.count].length = name_length;
+    m_db->dir_db.data[m_db->dir_db.count].dirname = strdup(name);
+    if (!m_db->dir_db.data[m_db->dir_db.count].dirname) {
+        LOG_E("Strdup failed in push_dir\n");
+        exit(2);
+    }
+
+    m_db->dir_db.count++;
+    return m_db->dir_db.count - 1;
 }
 
 
 // TODO optimize
-static struct music_dir *search_dir(const char *dirname)
+static int search_dir(struct music_db *m_db, const char *dirname)
 {
     DIR *d = opendir(dirname);
     struct dirent *entry;
 
-    struct music_dir *thisdir = NULL;
+    int dir_id = -1;
 
-    while((entry = readdir(d))) {
+    while ((entry = readdir(d))) {
         if (entry->d_name[0] == '.') {
             continue;
         }


@@ 92,46 266,22 @@ static struct music_dir *search_dir(const char *dirname)
         if (!stat(filename, &s)) {
             if (S_ISREG(s.st_mode)) {
                 if (probably_music(filename)) {
-                    thisdir = ensure_dir(thisdir);
-
-                    if (!thisdir->track_count) {
-                        thisdir->tracks = calloc(1, sizeof(struct audio_track));
-                        if (!thisdir->tracks) {
-                            LOG_E("can't alloc for tracks\n");
-                            free(filename);
-                            return NULL;
-                        }
-                    } else {
-                        struct audio_track *next = realloc(thisdir->tracks,
-                            sizeof (struct audio_track) * (thisdir->track_count + 1));
-                        if (!next) {
-                            free(filename);
-                            return NULL;
-                        }
-                        thisdir->tracks = next;
+                    if (dir_id < 0) {
+                        dir_id = push_dir(m_db, dirname);
+                    }
+
+                    int track_id = push_track(m_db, entry->d_name);
+                    if (track_id >= 0 && dir_id >= 0) {
+                        struct track_data *track = track_get(track_id);
+                        track->dir_id = dir_id;
+                        // TODO increment directory total track count
                     }
-                    memset(&thisdir->tracks[thisdir->track_count], 0, sizeof (struct audio_track));
-                    thisdir->tracks[thisdir->track_count].filename = strdup(entry->d_name);
-                    thisdir->tracks[thisdir->track_count++].dirname = strdup(dirname);
-                    thisdir->total_track_count++;
                 }
             } else if (S_ISDIR(s.st_mode)) {
                 LOG_T("desending %s\n", filename);
-                struct music_dir *child = search_dir(filename);
-                if (child) {
-                    thisdir = ensure_dir(thisdir);
-                    if (child->dir_count || child->track_count) {
-                        struct music_dir *next = realloc(thisdir->subdirs,
-                            sizeof (struct music_dir) * (thisdir->dir_count + 1));
-                        if (!next) {
-                            free(filename);
-                            return NULL;
-                        }
-                        thisdir->subdirs = next;
-                        memcpy(&thisdir->subdirs[thisdir->dir_count++], child, sizeof (struct music_dir));
-                        thisdir->total_track_count += child->total_track_count;
-                        free(child);
-                    }
+                int child_id = search_dir(m_db, filename);
+                if (child_id >= 0 && dir_id < 0) {
+                    dir_id = push_dir(m_db, dirname);
                 }
             }
         }


@@ 139,13 289,7 @@ static struct music_dir *search_dir(const char *dirname)
     }
     closedir(d);
 
-    if (thisdir) {
-        thisdir->dirname = strdup(dirname);
-        LOG_T("Completed %s (with %i tracks and %i dirs)\n", dirname, thisdir->track_count, thisdir->dir_count);
-    } else {
-        LOG_T("Completed %s (with NO tracks)\n", dirname);
-    }
-    return thisdir;
+    return dir_id;
 }
 
 


@@ 166,64 310,294 @@ static bool dir_exists(const char *dirname)
 }
 
 
-void *find_files_thread(void *db_)
+static int metadata_add(struct track_data *track)
+{
+    LOG_T("Trying to add metadata for track ");
+    if (!track) {
+        LOG_W("Track give was null\n");
+        return 0;
+    }
+
+    if (!track->dir_id || !track->filename) {
+        return -1;
+    }
+
+    struct directory_data *dir = directory_get(track->dir_id);
+
+    LOG_T("dirname %s, filename %s\n", dir->dirname, track->filename);
+
+    char *dirname  = expand_dirname(dir->dirname, track->filename);
+    if (!dirname) {
+        LOG_F("Unable to expand dirname for track %s\n", track->filename);
+        exit(2);
+    }
+
+    AVFormatContext *file = avformat_alloc_context();
+    if (avformat_open_input(&file, dirname, NULL, NULL) < 0) {
+        LOG_E("Could not open file\n");
+        free(dirname);
+        return -2;
+    }
+
+    AVDictionaryEntry *dict = NULL;
+    if ((dict = av_dict_get(file->metadata, "album_artist", NULL, 0))) {
+        track->album_artist_id = push_artist(m_db, dict->value);
+    } else if ((dict = av_dict_get(file->metadata, "artist", NULL, 0))) {
+        track->album_artist_id = push_artist(m_db, dict->value);
+    }
+
+    if ((dict = av_dict_get(file->metadata, "artist", NULL, 0))) {
+        track->artist_id = push_artist(m_db, dict->value);
+    } else {
+        track->artist_id = track->album_artist_id;
+    }
+
+    if ((dict = av_dict_get(file->metadata, "title", NULL, 0))) {
+        track->md_title = strdup(dict->value);
+    }
+
+    if ((dict = av_dict_get(file->metadata, "album", NULL, 0))) {
+        track->album_id = push_album(m_db, dict->value);
+    }
+
+    if ((dict = av_dict_get(file->metadata, "genre", NULL, 0))) {
+        track->md_genre = strdup(dict->value);
+    }
+
+    track->file_read = true;
+
+    avformat_close_input(&file);
+    avformat_free_context(file);
+    free(dirname);
+    return 0;
+}
+
+
+static void metadata_free(struct track_data *track)
 {
+    if (track->md_title) {
+        free(track->md_title);
+        track->md_title = NULL;
+    }
+
+    if (track->md_genre) {
+        free(track->md_genre);
+        track->md_genre = NULL;
+    }
+
+    track->file_read = false;
+}
+
+
+void *find_files_thread(void *p)
+{
+    LOG_N("Audio search starting up\n");
+    (void) p;
+
+    m_db = calloc(1, sizeof (struct music_db));
+    if (!m_db) {
+        LOG_F("music_db Calloc failed\n");
+        exit(2);
+    }
+
     static const char *name = "/tmp/mnt/sda1";
-    LOG_E("Audio search starting up\n");
-    struct music_db *db = db_;
 
     if (!dir_exists(name)) {
         LOG_E("Error for dir %s, doesn't exist!\n", name);
         return NULL;
     }
 
-    db->dir_count = 1;
-    db->dirs = search_dir(name);
+    search_dir(m_db, name);
 
-    LOG_D("dir count %i\n", db->dir_count);
-    LOG_D("subdir %p \n", db->dirs);
-    LOG_D("dir name %s\n", db->dirs[0].dirname);
-    LOG_D("subdir count %i\n", db->dirs[0].dir_count);
-    LOG_D("subdir track count %i\n", db->dirs[0].track_count);
-    LOG_D("subdir track 0 name %s\n", db->dirs[0].tracks[0].filename);
-    // LOG_D("subdir track 0 location %s\n", expand_dirname(db->dirs[0].dirname, db->dirs[0].tracks[0].filename));
+    m_db->search_done = true;
+    postmsg_audio(AMSG_TRACK_SCAN_DONE, NULL);
 
 
-    db->search_done = true;
-    postmsg_audio(AMSG_TRACK_SCAN_DONE, db);
+    struct timespec __ts_nanosleep = { .tv_nsec = _10_mSECS };
+    const struct track_data *track;
+    uint32_t pos = 0;
 
-    // struct timespec __ts_nanosleep = { .tv_nsec = _10_mSECS };
-    // struct audio_track *track;
-    // uint32_t pos = 0;
+    while ((track = track_get(pos++))) {
+        metadata_add((struct track_data *)track);
+        nanosleep(&__ts_nanosleep, NULL);
+    }
+    return NULL;
+}
+
+
+const struct track_data *find_track(int skip, const char *search)
+{
+    if (!m_db) {
+        return NULL;
+    }
+
+    if (!m_db->track_db.count || !m_db->track_db.data) {
+        return NULL;
+    }
+
+    if (skip >= m_db->track_db.count || skip < 0) {
+        return NULL;
+    }
+
+    if (!search) {
+        return track_get(skip);
+    }
+
+    struct track_db *track = &m_db->track_db;
+
+    for (int i = 0; i < track->count; i++) {
+        if (!strcmp(search, track->data[i].filename)) {
+            // TODO or track name
+            if (strlen(search) <= track->data[i].length) {
+                if (skip--) {
+                    continue;
+                }
+
+                return &track->data[i];
+            }
+        }
+    }
 
-    // while ((track = find_track(pos++, db->dirs))) {
-    //     audio_track_add_metadata(track);
-    //     nanosleep(&__ts_nanosleep, NULL);
-    // }
     return NULL;
 }
 
 
-struct audio_track *find_track(uint32_t pos, struct music_dir *dir)
+const struct artist_data *find_artist(int skip, const char *search)
 {
-    if (pos > dir->total_track_count) {
+    if (!m_db) {
         return NULL;
     }
 
-    if (pos < dir->track_count) {
-        return &dir->tracks[pos];
+    struct artist_db *artists = &m_db->artist_db;
+
+    if (!search) {
+        if (skip < artists->count) {
+            return &artists->data[skip];
+        }
+        return NULL;
+    }
+
+    for (int i = 0; i < artists->count; i++) {
+        if (!strcmp(search, artists->data[i].name)) {
+            if (strlen(search) <= artists->data[i].length) {
+                if (skip--) {
+                    continue;
+                }
+                return &artists->data[i];
+            }
+            }
     }
 
-    pos -= dir->track_count;
+    return NULL;
+}
+
+
+const struct album_data *find_album(int skip, const char *search)
+{
+    struct album_db *album = &m_db->album_db;
 
-    for (uint32_t i = 0; i < dir->dir_count; i++) {
-        struct audio_track *track = find_track(pos, &dir->subdirs[i]);
-        if (track) {
-            return track;
+    if (!search) {
+        if (skip < album->count) {
+            return &album->data[skip];
         }
-        pos -= dir->subdirs[i].total_track_count;
+        return NULL;
     }
 
+    for (int i = 0; i < album->count; i++) {
+        if (!strcmp(search, album->data[i].name)) {
+            if (strlen(search) <= album->data[i].length) {
+                if (skip--) {
+                    continue;
+                }
+
+                return &album->data[i];
+            }
+        }
+    }
+
+    return NULL;
+}
+
+
+const struct directory_data *find_dir(int skip, const char *search)
+{
+    struct directory_db *dir = &m_db->dir_db;
+
+    if (!search) {
+        if (skip < dir->count) {
+            return directory_get(skip);
+        }
+        return NULL;
+    }
+
+    for (int i = 0; i < dir->count; i++) {
+        if (!strcmp(search, dir->data[i].dirname)) {
+            if (strlen(search) <= dir->data[i].length) {
+                if (skip--) {
+                    continue;
+                }
+
+                return &dir->data[i];
+            }
+        }
+    }
+
+    return NULL;
+}
+
+
+const struct track_data *audio_db_search_track(int skip, const char *search)
+{
+    (void) skip;
+    (void) search;
+    return NULL;
+}
+
+
+const struct track_data *audio_db_search_artist(int skip, const char *search)
+{
+    (void) skip;
+    (void) search;
     return NULL;
 }
 
+
+const struct track_data *audio_db_search_album(int skip, const char *search)
+{
+    (void) skip;
+    (void) search;
+    return NULL;
+}
+
+
+const char *track_artist_name(const int id)
+{
+    if (id < 0 || id >= m_db->artist_db.count) {
+        return NULL;
+    }
+
+    return m_db->artist_db.data[id].name;
+}
+
+
+const char *track_album_name(const int id)
+{
+    if (id < 0 || id >= m_db->album_db.count) {
+        return NULL;
+    }
+
+    return m_db->album_db.data[id].name;
+}
+
+
+bool track_delete(int track_id)
+{
+    // TODO input validation
+    struct track_data *track = track_get(track_id);
+    if (track) {
+        metadata_free(track);
+        return true;
+    }
+
+    return false;
+}

M audio_search.h => audio_search.h +67 -16
@@ 4,40 4,91 @@
 #include <stdint.h>
 #include <stdbool.h>
 
-extern const char *supported_ext[];
+struct track_data {
+    uint32_t length;
+    char *filename;
+    char *md_title;
+    char *md_genre;
+
+    int dir_id;
+    int artist_id;
+    int album_artist_id;
+    int album_id;
+    bool file_read;
+};
 
-struct music_dir {
-    char *dirname;
+struct artist_data {
+    uint32_t length;
+    char *name;
+};
 
-    uint32_t dir_count;
-    struct music_dir *subdirs;
+struct album_data {
+    uint32_t length;
+    char *name;
+};
+
+struct directory_data {
+    uint32_t length;
+    char *dirname;
 
     uint32_t track_count;
-    struct audio_track *tracks;
+    struct track_data **tracks;
+
+    // Includes all tracks in subdirectories.
+    uint32_t track_count_total;
+};
 
-    uint32_t total_track_count;
+struct track_db {
+    int count;
+    int capacity;
+    struct track_data *data;
 };
 
+struct artist_db {
+    int count;
+    int capacity;
+    struct artist_data *data;
+};
+
+struct album_db {
+    int count;
+    int capacity;
+    struct album_data *data;
+};
+
+struct directory_db {
+    int count;
+    int capacity;
+    struct directory_data *data;
+};
 
 struct music_db {
     bool search_done;
 
-    char *dir_name;
+    struct track_db     track_db;
+    struct artist_db    artist_db;
+    struct album_db     album_db;
+    struct directory_db dir_db;
+};
 
-    uint32_t dir_count;
-    struct music_dir *dirs;
 
-    uint32_t total_track_count;
+void *find_files_thread(void *db);
 
-    uint32_t artist_count;
-    char **artists;
-};
 
+struct music_db *audio_db_get(void);
 
+const struct track_data *find_track(int skip, const char *search);
+const struct artist_data *find_artist(int skip, const char *search);
+const struct album_data *find_album(int skip, const char *search);
+const struct directory_data *find_dir(int skip, const char *search);
 
-void *find_files_thread(void *db);
+const struct track_data *audio_db_search_track(int skip, const char *search);
+const struct track_data *audio_db_search_artist(int skip, const char *search);
+const struct track_data *audio_db_search_album(int skip, const char *search);
 
-struct audio_track *find_track(uint32_t pos, struct music_dir *dir);
+const char *track_artist_name(const int id);
+const char *track_album_name(const int id);
 
+bool track_delete(int track_id);
 
 #endif // _HUDTDS_AUDIO_SEARCH_H_

M gui/music.c => gui/music.c +4 -2
@@ 27,7 27,7 @@ static void draw_music_playing(struct ui_panel *p, int32_t x, int32_t y, int32_t
         draw_square_c(x, y, w, y + p->height, 0xff111111);
     }
 
-    struct audio_track *track = audio_track_get_current();
+    struct track_data *track = audio_track_get_current();
     if (track) {
         text_draw_string(track->filename, x + 3, y + 3);
     } else {


@@ 52,7 52,7 @@ static bool music_playing_kdn(struct ui_panel *p, const uint32_t key, const uint
 
 
 
-struct music_track music_track_playing = {
+struct music_track_panel music_track_playing = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry playing",


@@ 135,6 135,8 @@ struct ui_panel music_frame = {
         (struct ui_panel*)&music_track_playing,
         (struct ui_panel*)&music_buttons_frame,
         (struct ui_panel*)&music_tracks_frame,
+        (struct ui_panel*)&music_artists_frame,
+        (struct ui_panel*)&music_albums_frame,
         NULL
     }
 };

M gui/music.h => gui/music.h +4 -2
@@ 4,10 4,12 @@
 #include "../wl/ui.h"
 
 extern struct ui_panel music_frame;
-extern struct ui_panel music_tracks_frame;
 extern struct ui_panel music_buttons_frame;
+extern struct ui_panel music_tracks_frame;
+extern struct ui_panel music_artists_frame;
+extern struct ui_panel music_albums_frame;
 
-struct music_track {
+struct music_track_panel {
     struct ui_panel panel;
 
     uint32_t position;

A gui/music_albums.c => gui/music_albums.c +228 -0
@@ 0,0 1,228 @@
+#include "music.h"
+
+#include "../wl/ui.h"
+#include "../wl/draw.h"
+#include "../wl/text.h"
+#include "../wl/keyboard.h"
+
+#include "../log.h"
+#include "../audio.h"
+#include "../audio_search.h"
+
+#include <stdlib.h>
+
+
+static uint32_t albums_skip = 0;
+
+static const struct album_data *album_pos(uint32_t pos)
+{
+    pos += albums_skip;
+    return find_album(pos, NULL);
+}
+
+
+
+static void draw_music_album(struct ui_panel *p, int32_t x, int32_t y, int32_t w, int32_t h)
+{
+    x = p->pos_x < 0 ? w + p->pos_x : x + p->pos_x; \
+    y = p->pos_y < 0 ? h + p->pos_y : y + p->pos_y; \
+    w = p->width <= 0 ? w + p->width : x + p->width; \
+    h = p->height <= 0 ? h + p->height : y + p->height; \
+    draw_square_c(x, y, w, y + p->height, 0xff000000);
+
+    struct music_track *music = (struct music_track *)p;
+    const struct album_data *album = album_pos(music->position);
+
+    // LOG_E("Draw music entry (track: %s), %i %i %i %i (%i)\n", music->track_title, x, y, w, h, y + p->height);
+    if (music_albums_frame.focused && p->focused) {
+        draw_box_c(x, y, w, y + p->height, p->color);
+    }
+
+    text_draw_string(album->name, x + 3, y + 3);
+}
+
+
+struct music_track album_0 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_0",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 0,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 0
+};
+
+struct music_track album_1 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_1",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 40,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 1
+};
+
+struct music_track album_2 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_2",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 80,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 2
+};
+
+struct music_track album_3 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_3",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 120,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 3
+};
+
+struct music_track album_4 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_4",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 160,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 4
+};
+
+struct music_track album_5 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_5",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 200,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 5
+};
+
+struct music_track album_6 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music album_6",
+        .draw = draw_music_album,
+        .pos_x = 0,
+        .pos_y = 240,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 6
+};
+
+
+
+static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_t s)
+{
+    (void) s;
+    struct music_track **children = (struct music_track**)p->children;
+
+    if (!children) {
+        return false;
+    }
+    struct music_track *first = *children, *entry, *prev;
+
+    while ((entry = *children++)) {
+        if (entry->panel.focused) {
+            switch (key) {
+                case MZD_KEYMAP_ROTATE_LEFT: {
+                    if (entry != first) {
+                        LOG_T("move to prev\n");
+                        prev->panel.focused = true;
+                        entry->panel.focused = false;
+                    } else {
+                        LOG_D("already at beginning\n");
+                        if (albums_skip) {
+                            albums_skip--;
+                        }
+                    }
+                    break;
+                }
+                case MZD_KEYMAP_ROTATE_RIGHT: {
+                    if (*children) {
+                        LOG_T("move to next %s\n", (*children)->panel.name);
+                        (*children)->panel.focused = true;
+                        entry->panel.focused = false;
+                    } else {
+                        LOG_D("already at end\n");
+                        albums_skip++;
+                    }
+                    break;
+                }
+                case MZD_KEYMAP_DPAD_CENTER: {
+                    LOG_D("play this one %s\n", entry->panel.name);
+                    // if (track_get_pos(entry->position)) {
+                    //     postmsg_audio(AMSG_PLAY, track_get_pos(entry->position));
+                    // } else {
+                    //     LOG_E("No track found here %s\n", entry->panel.name);
+                    // }
+                    break;
+                }
+                default: {
+                    LOG_D("frame_key_down default case\n");
+                    return false;
+                }
+            }
+            p->draw_needed = true;
+            return true;
+        }
+
+        prev = entry;
+    }
+
+    LOG_D("focus not found\n");
+    first->panel.focused = true;
+    return false;
+}
+
+
+struct ui_panel music_albums_frame = {
+    .type = PANEL_LIST,
+    .name = "music artist frame",
+    .pos_x = 80,
+    .pos_y = 60,
+    .height = -80,
+    .k_dn = frame_key_down,
+    .focused = false,
+    .disabled = true,
+    .children = (struct ui_panel*[]) {
+        (struct ui_panel*)&album_0,
+        (struct ui_panel*)&album_1,
+        (struct ui_panel*)&album_2,
+        (struct ui_panel*)&album_3,
+        (struct ui_panel*)&album_4,
+        (struct ui_panel*)&album_5,
+        (struct ui_panel*)&album_6,
+        NULL
+    }
+};

A gui/music_artists.c => gui/music_artists.c +231 -0
@@ 0,0 1,231 @@
+#include "music.h"
+
+#include "../wl/ui.h"
+#include "../wl/draw.h"
+#include "../wl/text.h"
+#include "../wl/keyboard.h"
+
+#include "../log.h"
+#include "../audio_search.h"
+
+#include <stdlib.h>
+
+
+static uint32_t artist_skip = 0;
+
+
+static const struct artist_data *artist_pos(uint32_t pos)
+{
+    pos += artist_skip;
+
+    return find_artist(pos, NULL);
+}
+
+
+
+static void draw_music_track(struct ui_panel *p, int32_t x, int32_t y, int32_t w, int32_t h)
+{
+    x = p->pos_x < 0 ? w + p->pos_x : x + p->pos_x; \
+    y = p->pos_y < 0 ? h + p->pos_y : y + p->pos_y; \
+    w = p->width <= 0 ? w + p->width : x + p->width; \
+    h = p->height <= 0 ? h + p->height : y + p->height; \
+    draw_square_c(x, y, w, y + p->height, 0xff000000);
+
+    struct music_track *music = (struct music_track *)p;
+    const struct artist_data *artist = artist_pos(music->position);
+
+    // LOG_E("Draw music entry (track: %s), %i %i %i %i (%i)\n", music->track_title, x, y, w, h, y + p->height);
+    if (music_artists_frame.focused && p->focused) {
+        draw_box_c(x, y, w, y + p->height, p->color);
+    }
+
+    text_draw_string(artist->name, x + 3, y + 3);
+}
+
+
+struct music_track music_artist_0 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_0",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 0,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 0
+};
+
+struct music_track music_artist_1 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_1",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 40,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 1
+};
+
+struct music_track music_artist_2 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_2",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 80,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 2
+};
+
+struct music_track music_artist_3 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_3",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 120,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 3
+};
+
+struct music_track music_artist_4 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_4",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 160,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 4
+};
+
+struct music_track music_artist_5 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_5",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 200,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 5
+};
+
+struct music_track music_artist_6 = {
+    .panel = {
+        .type = PANEL_LIST_ENTRY,
+        .name = "music artist_6",
+        .draw = draw_music_track,
+        .pos_x = 0,
+        .pos_y = 240,
+        .height = 40,
+        .color = 0xffff0000,
+        .children = NULL,
+    },
+    .position = 6
+};
+
+
+
+static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_t s)
+{
+    (void) s;
+    struct music_track **children = (struct music_track**)p->children;
+
+    if (!children) {
+        return false;
+    }
+    struct music_track *first = *children, *entry, *prev;
+
+    while ((entry = *children++)) {
+        if (entry->panel.focused) {
+            switch (key) {
+                case MZD_KEYMAP_ROTATE_LEFT: {
+                    if (entry != first) {
+                        LOG_T("move to prev\n");
+                        prev->panel.focused = true;
+                        entry->panel.focused = false;
+                    } else {
+                        LOG_D("already at beginning\n");
+                        if (artist_skip) {
+                            artist_skip--;
+                        }
+                    }
+                    break;
+                }
+                case MZD_KEYMAP_ROTATE_RIGHT: {
+                    if (*children) {
+                        LOG_T("move to next %s\n", (*children)->panel.name);
+                        (*children)->panel.focused = true;
+                        entry->panel.focused = false;
+                    } else {
+                        LOG_D("already at end\n");
+                        artist_skip++;
+                    }
+                    break;
+                }
+                case MZD_KEYMAP_DPAD_CENTER: {
+                    LOG_D("play this one %s\n", entry->panel.name);
+                    if (artist_pos(entry->position)) {
+                        // Set search value,
+                        // reset focus to tracks
+                        // postmsg_audio(AMSG_PLAY, artist_pos(entry->position));
+                    } else {
+                        LOG_E("No track found here %s\n", entry->panel.name);
+                    }
+                    break;
+                }
+                default: {
+                    LOG_D("frame_key_down default case\n");
+                    return false;
+                }
+            }
+            p->draw_needed = true;
+            return true;
+        }
+
+        prev = entry;
+    }
+
+    LOG_D("focus not found\n");
+    first->panel.focused = true;
+    return false;
+}
+
+
+struct ui_panel music_artists_frame = {
+    .type = PANEL_LIST,
+    .name = "music artist frame",
+    .pos_x = 80,
+    .pos_y = 60,
+    .height = -80,
+    .k_dn = frame_key_down,
+    .focused = false,
+    .disabled = true,
+    .children = (struct ui_panel*[]) {
+        (struct ui_panel*)&music_artist_0,
+        (struct ui_panel*)&music_artist_1,
+        (struct ui_panel*)&music_artist_2,
+        (struct ui_panel*)&music_artist_3,
+        (struct ui_panel*)&music_artist_4,
+        (struct ui_panel*)&music_artist_5,
+        (struct ui_panel*)&music_artist_6,
+        NULL
+    }
+};

M gui/music_buttons.c => gui/music_buttons.c +29 -12
@@ 7,6 7,16 @@
 #include "../wl/keyboard.h"
 
 
+static void music_btn_disable_all(void)
+{
+    music_tracks_frame.disabled = true;
+    music_tracks_frame.focused = false;
+    music_artists_frame.disabled = true;
+    music_artists_frame.focused = false;
+
+    music_buttons_frame.focused = false;
+}
+
 
 static bool music_btn_tracks(struct ui_panel *p, const int mx, const int my, const int x, const int y, const uint32_t w, uint32_t h,
     const uint32_t id, const uint32_t serial)


@@ 20,7 30,11 @@ static bool music_btn_tracks(struct ui_panel *p, const int mx, const int my, con
     (void) h;
     (void) id;
     (void) serial;
-    LOG_E("Music show tracks\n");
+    LOG_N("Music show tracks\n");
+
+    music_btn_disable_all();
+    music_tracks_frame.disabled = false;
+    music_tracks_frame.focused = true;
     return true;
 }
 


@@ 37,7 51,15 @@ static bool music_btn_artists(struct ui_panel *p, const int mx, const int my, co
     (void) h;
     (void) id;
     (void) serial;
-    LOG_E("Music Show artists\n");
+    LOG_N("Music Show artists\n");
+
+    music_btn_disable_all();
+    music_artists_frame.disabled = false;
+    music_artists_frame.focused = true;
+
+    music_btn_disable_all();
+    music_artists_frame.disabled = false;
+    music_artists_frame.focused = true;
     return true;
 }
 


@@ 54,7 76,11 @@ static bool music_btn_albums(struct ui_panel *p, const int mx, const int my, con
     (void) h;
     (void) id;
     (void) serial;
-    LOG_E("Music Show Albums\n");
+    LOG_N("Music Show Albums\n");
+
+    music_btn_disable_all();
+    music_albums_frame.disabled = false;
+    music_albums_frame.focused = true;
     return true;
 }
 


@@ 142,9 168,6 @@ static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_
                         entry->panel.focused = false;
                     } else {
                         LOG_D("already at beginning\n");
-                        // if (cur_db_loc) {
-                        //     cur_db_loc--;
-                        // }
                     }
                     break;
                 }


@@ 155,17 178,11 @@ static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_
                         entry->panel.focused = false;
                     } else {
                         LOG_D("already at end\n");
-                        // cur_db_loc++;
                     }
                     break;
                 }
                 case MZD_KEYMAP_DPAD_CENTER: {
                     LOG_D("play this one %s\n", entry->panel.name);
-                    // if (track_pos_get(entry->position)) {
-                    //     postmsg_audio(AMSG_PLAY, track_pos_get(entry->position));
-                    // } else {
-                    //     LOG_E("No track found here %s\n", entry->panel.name);
-                    // }
                     break;
                 }
                 default: {

M gui/music_tracks.c => gui/music_tracks.c +26 -38
@@ 15,24 15,14 @@
 static uint32_t cur_db_loc = 0;
 
 
-static struct audio_track *track_get_pos(uint32_t pos)
+static const struct track_data *track_get_pos(uint32_t pos)
 {
     pos += cur_db_loc;
-    struct music_db *db = audio_db_get();
-    if (!db) {
-        return NULL;
-    }
-
-    struct music_dir *dir = db->dirs;
-    if (pos > dir->total_track_count) {
-        return NULL;
-    }
-
-    return find_track(pos, dir);
+    return find_track(pos, NULL);
 }
 
 
-static const char *entry_text(struct audio_track *t)
+static const char *entry_text(const struct track_data *t)
 {
     static char str[2048] = {0}; // because fuck memory safety!
     if (!t) {


@@ 41,20 31,18 @@ static const char *entry_text(struct audio_track *t)
     }
 
     int pos = 0;
-    if (!t->file_read) {
-        audio_track_add_metadata(t);
-    }
-
-    if (t->album_artist_id >= 0) {
-        pos += snprintf(str, 2048, "%s - ", track_artist_get(t->album_artist_id));
-    } else if (t->artist_id >= 0) {
-        pos += snprintf(str, 2048, "%s - ", track_artist_get(t->artist_id));
-    }
+    if (t->file_read) {
+        if (t->album_artist_id >= 0) {
+            pos += snprintf(str, 2048, "%s - ", track_artist_name(t->album_artist_id));
+        } else if (t->artist_id >= 0) {
+            pos += snprintf(str, 2048, "%s - ", track_artist_name(t->artist_id));
+        }
 
-    if (t->md_title) {
-        pos += snprintf(str + pos, 2048 - pos, "%s", t->md_title);
-    } else {
-        pos += snprintf(str + pos, 2048 - pos, "%s", t->filename);
+        if (t->md_title) {
+            pos += snprintf(str + pos, 2048 - pos, "%s", t->md_title);
+        } else {
+            pos += snprintf(str + pos, 2048 - pos, "%s", t->filename);
+        }
     }
 
     if (pos == 0) {


@@ 78,19 66,19 @@ static void draw_music_track(struct ui_panel *p, int32_t x, int32_t y, int32_t w
     h = p->height <= 0 ? h + p->height : y + p->height; \
     draw_square_c(x, y, w, y + p->height, 0xff000000);
 
-    struct music_track *music = (struct music_track *)p;
-    struct audio_track *track = track_get_pos(music->position);
+    struct music_track_panel *music = (struct music_track_panel *)p;
 
     // LOG_E("Draw music entry (track: %s), %i %i %i %i (%i)\n", music->track_title, x, y, w, h, y + p->height);
     if (music_tracks_frame.focused && p->focused) {
         draw_box_c(x, y, w, y + p->height, p->color);
     }
 
+    const struct track_data *track = track_get_pos(music->position);
     text_draw_string(entry_text(track), x + 3, y + 3);
 }
 
 
-struct music_track music_track_0 = {
+struct music_track_panel music_track_0 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_0",


@@ 104,7 92,7 @@ struct music_track music_track_0 = {
     .position = 0
 };
 
-struct music_track music_track_1 = {
+struct music_track_panel music_track_1 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_1",


@@ 118,7 106,7 @@ struct music_track music_track_1 = {
     .position = 1
 };
 
-struct music_track music_track_2 = {
+struct music_track_panel music_track_2 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_2",


@@ 132,7 120,7 @@ struct music_track music_track_2 = {
     .position = 2
 };
 
-struct music_track music_track_3 = {
+struct music_track_panel music_track_3 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_3",


@@ 146,7 134,7 @@ struct music_track music_track_3 = {
     .position = 3
 };
 
-struct music_track music_track_4 = {
+struct music_track_panel music_track_4 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_4",


@@ 160,7 148,7 @@ struct music_track music_track_4 = {
     .position = 4
 };
 
-struct music_track music_track_5 = {
+struct music_track_panel music_track_5 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_5",


@@ 174,7 162,7 @@ struct music_track music_track_5 = {
     .position = 5
 };
 
-struct music_track music_track_6 = {
+struct music_track_panel music_track_6 = {
     .panel = {
         .type = PANEL_LIST_ENTRY,
         .name = "music entry_6",


@@ 193,12 181,12 @@ struct music_track music_track_6 = {
 static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_t s)
 {
     (void) s;
-    struct music_track **children = (struct music_track**)p->children;
+    struct music_track_panel **children = (struct music_track_panel**)p->children;
 
     if (!children) {
         return false;
     }
-    struct music_track *first = *children, *entry, *prev;
+    struct music_track_panel *first = *children, *entry, *prev;
 
     while ((entry = *children++)) {
         if (entry->panel.focused) {


@@ 230,7 218,7 @@ static bool frame_key_down(struct ui_panel *p, const uint32_t key, const uint32_
                 case MZD_KEYMAP_DPAD_CENTER: {
                     LOG_D("play this one %s\n", entry->panel.name);
                     if (track_get_pos(entry->position)) {
-                        postmsg_audio(AMSG_PLAY, track_get_pos(entry->position));
+                        postmsg_audio(AMSG_PLAY, (void *)track_get_pos(entry->position));
                     } else {
                         LOG_E("No track found here %s\n", entry->panel.name);
                     }