f8b31404b2684aa53f374e7c41ab539bb252f84f — Gregory Mullen 5 months ago d43fbcc
rewrite music search code
M Makefile => Makefile +1 -1
@@ 15,7 15,7 @@   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 @@ LOG_E("Playback open error: %s\n", snd_strerror(snd_err));
          return;
      }
- 
- 
      return;
  }
  


@@ 93,7 93,6 @@   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 @@ }
  
  
- 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 @@ 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 @@ }
  
  
- 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 @@ if (!avframe) {
          LOG_E("Could not allocate audio frame\n");
          data->clean_exit = true;
-         free(dirname);
          return NULL;
      }
  


@@ 225,7 212,6 @@ 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 @@ 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 @@ 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 @@ }
              case AMSG_TRACK_SCAN_DONE: {
                  LOG_N("AMSG Track Scan done!\n");
-                 m_db = cur_data;
                  break;
              }
          }


@@ 406,150 390,6 @@ }
  
  
- 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 @@       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 @@ } 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 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 @@ 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 @@ }
      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 @@ }
  
  
- 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 @@ 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 @@   
  
- 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_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 @@ (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 @@ (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 @@ (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 @@ entry->panel.focused = false;
                      } else {
                          LOG_D("already at beginning\n");
-                         // if (cur_db_loc) {
-                         //     cur_db_loc--;
-                         // }
                      }
                      break;
                  }


@@ 155,17 178,11 @@ 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 @@ }
  
      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 @@ 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 @@ .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 @@ .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 @@ .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 @@ .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 @@ .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 @@ .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 @@ 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 @@ 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);
                      }