From c748985f3df3171a5221e42b3742b86e08d820af Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 23 Nov 2025 21:12:09 +0900 Subject: [PATCH] wip --- mauplay/CMakeLists.txt | 1 + mauplay/audio.c | 59 ++++++++++++ mauplay/db.c | 76 +++++++++++++++- mauplay/main.c | 13 ++- mauplay/mauplay.h | 37 +++++++- mauplay/ui.c | 201 +++++++++++++++++++++++++++++++++++++---- 6 files changed, 363 insertions(+), 24 deletions(-) create mode 100644 mauplay/audio.c diff --git a/mauplay/CMakeLists.txt b/mauplay/CMakeLists.txt index 819fa47..de27701 100644 --- a/mauplay/CMakeLists.txt +++ b/mauplay/CMakeLists.txt @@ -4,6 +4,7 @@ setup_project(mauplay ${CMAKE_INSTALL_BINDIR}) pkg_config_add(mauplay sqlite3) pkg_config_add(mauplay sndfile) +pkg_config_add(mauplay samplerate) target_link_libraries( mauplay diff --git a/mauplay/audio.c b/mauplay/audio.c new file mode 100644 index 0000000..b945d8a --- /dev/null +++ b/mauplay/audio.c @@ -0,0 +1,59 @@ +#include "mauplay.h" + +#include +#include + +static void* audio; +pthread_mutex_t audio_mutex; +queue_t* queue = NULL; + +static void handler(void* handle, void* user, void* data, int frames) { + memset(data, 0, frames * 2 * 2); + + pthread_mutex_lock(&audio_mutex); + if(arrlen(queue) > 0) { + int from_frames = frames * queue[0].sfi.samplerate / MDEAudioRate; + float* from = malloc(from_frames * sizeof(*from) * 2); + float* to = malloc(frames * sizeof(*to) * 2); + SRC_DATA d; + int f; + + d.data_in = from; + d.data_out = to; + d.input_frames = from_frames; + d.output_frames = frames; + d.src_ratio = (double)MDEAudioRate / queue[0].sfi.samplerate; + + f = sf_readf_float(queue[0].sf, from, from_frames); + src_simple(&d, SRC_SINC_BEST_QUALITY, 2); + src_float_to_short_array(to, data, frames * 2); + queue[0].frames += f; + + free(from); + free(to); + + if(f < from_frames) { + arrdel(queue, 0); + } + } + pthread_mutex_unlock(&audio_mutex); +} + +void audio_init(void) { + audio = MDEAudioOpen(handler, NULL); + + pthread_mutex_init(&audio_mutex, NULL); + + MDEAudioStart(audio); +} + +void audio_queue(const char* path) { + queue_t q; + q.path = MDEFileAbsolutePath(path); + q.sf = sf_open(q.path, SFM_READ, &q.sfi); + q.frames = 0; + + pthread_mutex_lock(&audio_mutex); + arrput(queue, q); + pthread_mutex_unlock(&audio_mutex); +} diff --git a/mauplay/db.c b/mauplay/db.c index 75a287b..e292ea1 100644 --- a/mauplay/db.c +++ b/mauplay/db.c @@ -1,10 +1,13 @@ #include "mauplay.h" #include -#include #include static sqlite3* db; +numkv_t* db_musics = NULL; +numkv_t* db_albums = NULL; +numkv_t* db_artists = NULL; +numkv_t* db_genres = NULL; int db_exec(const char* s) { sqlite3_stmt* stmt; @@ -114,14 +117,83 @@ void db_add(const char* path) { void db_scan(void) { sqlite3_stmt* stmt; + int total = 0; + int i; + + for(i = 0; i < shlen(db_musics); i++) { + free(db_musics[i].title); + free(db_musics[i].album); + free(db_musics[i].artist); + free(db_musics[i].genre); + } + + shfree(db_musics); + shfree(db_albums); + shfree(db_artists); + shfree(db_genres); + + sh_new_strdup(db_musics); + sh_new_strdup(db_albums); + sh_new_strdup(db_artists); + sh_new_strdup(db_genres); + + shdefault(db_musics, 0); + shdefault(db_albums, 0); + shdefault(db_artists, 0); + shdefault(db_genres, 0); if(sqlite3_prepare_v2(db, "SELECT * FROM cache", -1, &stmt, NULL) != SQLITE_OK) { return; } while(sqlite3_step(stmt) == SQLITE_ROW) { - printf("!\n"); + char* s_path = MDEStringDuplicate(sqlite3_column_text(stmt, 0)); + char* s_title = MDEStringDuplicate(sqlite3_column_text(stmt, 1)); + char* s_album = MDEStringDuplicate(sqlite3_column_text(stmt, 3)); + char* s_artist = MDEStringDuplicate(sqlite3_column_text(stmt, 2)); + char* s_genre = MDEStringDuplicate(sqlite3_column_text(stmt, 4)); + int s_length = sqlite3_column_int(stmt, 5); + int ind; + + shput(db_musics, s_path, 0); + ind = shgeti(db_musics, s_path); + db_musics[ind].title = s_title; + db_musics[ind].album = s_album; + db_musics[ind].artist = s_artist; + db_musics[ind].genre = s_genre; + db_musics[ind].length = s_length; + + shput(db_albums, s_album, shget(db_albums, s_album) + 1); + ind = shgeti(db_albums, s_album); + if(shget(db_albums, s_album) == 1) { + db_albums[ind].length = s_length; + } else { + db_albums[ind].length += s_length; + } + + shput(db_artists, s_artist, shget(db_artists, s_artist) + 1); + ind = shgeti(db_artists, s_artist); + if(shget(db_artists, s_artist) == 1) { + db_artists[ind].length = s_length; + } else { + db_artists[ind].length += s_length; + } + + shput(db_genres, s_genre, shget(db_genres, s_genre) + 1); + ind = shgeti(db_genres, s_genre); + if(shget(db_genres, s_genre) == 1) { + db_genres[ind].length = s_length; + } else { + db_genres[ind].length += s_length; + } } sqlite3_finalize(stmt); + + ui_set_all_music(shlen(db_musics)); + ui_set_albums(shlen(db_albums)); + ui_set_artists(shlen(db_artists)); + ui_set_genres(shlen(db_genres)); + + MwDispatchUserHandler(tree, MwNactivateHandler, ui_last); } diff --git a/mauplay/main.c b/mauplay/main.c index 43fd1cc..955e88f 100644 --- a/mauplay/main.c +++ b/mauplay/main.c @@ -201,16 +201,17 @@ int main() { MwNorientation, MwHORIZONTAL, NULL); eltime = MwVaCreateWidget(MwLabelClass, "eltime", window, 0, 0, 0, 0, - MwNalignment, MwALIGNMENT_BEGINNING, - MwNtext, "00:00", + MwNalignment, MwALIGNMENT_END, + MwNtext, "0:00", NULL); seekbar = MwVaCreateWidget(MwScrollBarClass, "seekbar", window, 0, 0, 0, 0, MwNorientation, MwHORIZONTAL, MwNareaShown, 15, + MwNshowArrows, 0, NULL); rmtime = MwVaCreateWidget(MwLabelClass, "rmtime", window, 0, 0, 0, 0, - MwNalignment, MwALIGNMENT_BEGINNING, - MwNtext, "00:00", + MwNalignment, MwALIGNMENT_END, + MwNtext, "0:00", NULL); tree = MwCreateWidget(MwTreeViewClass, "tree", window, 0, 0, 0, 0); list = MwVaCreateWidget(MwListBoxClass, "list", window, 0, 0, 0, 0, @@ -251,7 +252,11 @@ int main() { ui_init(); db_add("test.mp3"); + db_add("test2.mp3"); db_scan(); + audio_init(); + audio_queue("test2.mp3"); + MwLoop(window); } diff --git a/mauplay/mauplay.h b/mauplay/mauplay.h index 563c205..7a6ba1d 100644 --- a/mauplay/mauplay.h +++ b/mauplay/mauplay.h @@ -8,6 +8,7 @@ #include /* External */ +#include /* Standard */ #include @@ -15,6 +16,25 @@ #include #include #include +#include + +typedef struct numkv { + char* key; + int value; + + char* title; + char* album; + char* artist; + char* genre; + int length; +} numkv_t; + +typedef struct queue { + char* path; + SNDFILE* sf; + SF_INFO sfi; + int frames; +} queue_t; /* main.c */ extern MwWidget window; @@ -25,13 +45,20 @@ extern MwWidget tree, list; extern MwLLPixmap pxalbum; /* db.c */ +extern numkv_t* db_musics; +extern numkv_t* db_albums; +extern numkv_t* db_artists; +extern numkv_t* db_genres; + int db_exec(const char* s); int db_init(void); void db_add(const char* path); void db_scan(void); /* ui.c */ -void ui_list_reset(void); +extern void* ui_last; + +void ui_list_reset(const char* merge); void ui_tree_reset(void); void ui_init(void); void ui_set_play_queue(int v); @@ -39,6 +66,12 @@ void ui_set_all_music(int v); void ui_set_albums(int v); void ui_set_artists(int v); void ui_set_genres(int v); -void ui_set_playlists(int v); + +/* audio.c */ +extern pthread_mutex_t audio_mutex; +extern queue_t* queue; + +void audio_init(void); +void audio_queue(const char* path); #endif diff --git a/mauplay/ui.c b/mauplay/ui.c index b668710..32dd313 100644 --- a/mauplay/ui.c +++ b/mauplay/ui.c @@ -1,13 +1,15 @@ #include "mauplay.h" +#include + static void* play_queue; static void* all_music; static void* albums; static void* artists; static void* genres; -static void* playlists; +void* ui_last; -void ui_list_reset(void) { +void ui_list_reset(const char* merge) { void* p; MwListBoxReset(list); @@ -15,17 +17,27 @@ void ui_list_reset(void) { p = MwListBoxCreatePacket(); MwListBoxPacketInsert(p, -1); MwListBoxPacketSet(p, 0, 0, "#"); - MwListBoxPacketSet(p, 0, 1, "Title"); - MwListBoxPacketSet(p, 0, 2, "Artist"); - MwListBoxPacketSet(p, 0, 3, "Length"); + if(merge != NULL) { + MwListBoxPacketSet(p, 0, 1, merge); + MwListBoxPacketSet(p, 0, 2, "Length"); + } else { + MwListBoxPacketSet(p, 0, 1, "Title"); + MwListBoxPacketSet(p, 0, 2, "Artist"); + MwListBoxPacketSet(p, 0, 3, "Length"); + } MwListBoxInsert(list, -1, p); MwListBoxDestroyPacket(p); MwListBoxSetWidth(list, 0, 48); - MwListBoxSetWidth(list, 1, -48 - 128); - MwListBoxSetWidth(list, 2, 64); - MwListBoxSetWidth(list, 3, 64); + if(merge != NULL) { + MwListBoxSetWidth(list, 1, -48 - 64); + MwListBoxSetWidth(list, 2, 64); + } else { + MwListBoxSetWidth(list, 1, -48 - 128); + MwListBoxSetWidth(list, 2, 64); + MwListBoxSetWidth(list, 3, 64); + } MwListBoxSetAlignment(list, 0, MwALIGNMENT_CENTER); MwListBoxSetAlignment(list, 2, MwALIGNMENT_END); @@ -44,8 +56,6 @@ void ui_tree_reset(void) { albums = MwTreeViewAdd(tree, t, NULL, "Albums (?)"); artists = MwTreeViewAdd(tree, t, NULL, "Artists (?)"); genres = MwTreeViewAdd(tree, t, NULL, "Genres (?)"); - - playlists = MwTreeViewAdd(tree, NULL, NULL, "Playlists (?)"); } void ui_set_play_queue(int v) { @@ -78,14 +88,170 @@ void ui_set_genres(int v) { MwTreeViewSetLabel(tree, genres, buf); } -void ui_set_playlists(int v) { - char buf[64]; - sprintf(buf, "Playlists (%d)", v); - MwTreeViewSetLabel(tree, playlists, buf); +static void tree_activate(MwWidget handle, void* user, void* client) { + if(client == play_queue || client == all_music || client == albums || client == artists || client == genres) { + void* p = MwListBoxCreatePacket(); + int i; + if(client == play_queue) { + pthread_mutex_lock(&audio_mutex); + for(i = 0; i < arrlen(queue); i++) { + char buf[64]; + int ind = shgeti(db_musics, queue[i].path); + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_musics[ind].title); + MwListBoxPacketSet(p, index, 2, db_musics[ind].artist); + + sprintf(buf, "%d:%02d", db_musics[ind].length / 60, db_musics[ind].length % 60); + + MwListBoxPacketSet(p, index, 3, buf); + } + pthread_mutex_unlock(&audio_mutex); + } + if(client == all_music) { + for(i = 0; i < shlen(db_musics); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_musics[i].title); + MwListBoxPacketSet(p, index, 2, db_musics[i].artist); + + sprintf(buf, "%d:%02d", db_musics[i].length / 60, db_musics[i].length % 60); + + MwListBoxPacketSet(p, index, 3, buf); + } + } + if(client == albums) { + for(i = 0; i < shlen(db_albums); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_albums[i].key); + + sprintf(buf, "%d:%02d", db_musics[i].length / 60, db_albums[i].length % 60); + + MwListBoxPacketSet(p, index, 2, buf); + } + } + if(client == artists) { + for(i = 0; i < shlen(db_artists); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_artists[i].key); + + sprintf(buf, "%d:%02d", db_artists[i].length / 60, db_artists[i].length % 60); + + MwListBoxPacketSet(p, index, 2, buf); + } + } + if(client == genres) { + for(i = 0; i < shlen(db_genres); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_genres[i].key); + + sprintf(buf, "%d:%02d", db_genres[i].length / 60, db_genres[i].length % 60); + + MwListBoxPacketSet(p, index, 2, buf); + } + } + + if(client == albums) { + ui_list_reset("Album"); + } else if(client == artists) { + ui_list_reset("Artist"); + } else if(client == genres) { + ui_list_reset("Genre"); + } else { + ui_list_reset(NULL); + } + MwListBoxInsert(list, -1, p); + MwListBoxDestroyPacket(p); + + ui_last = client; + } +} + +int queue_last = 0; + +static void window_tick(MwWidget handle, void* user, void* client) { + pthread_mutex_lock(&audio_mutex); + if(queue_last != arrlen(queue)) { + if(ui_last == play_queue) { + pthread_mutex_unlock(&audio_mutex); + MwDispatchUserHandler(tree, MwNactivateHandler, ui_last); + pthread_mutex_lock(&audio_mutex); + } + + ui_set_play_queue(arrlen(queue)); + + if(arrlen(queue) == 0) { + MwVaApply(info, + MwNtext, "", + NULL); + } else { + int ind = shgeti(db_musics, queue[0].path); + char* buf = malloc(strlen(db_musics[ind].title) + 1 + strlen(db_musics[ind].artist) + 1); + + buf[0] = 0; + strcpy(buf, db_musics[ind].title); + strcat(buf, "\n"); + strcat(buf, db_musics[ind].artist); + + MwVaApply(info, + MwNtext, buf, + NULL); + MwVaApply(seekbar, + MwNmaxValue, queue[0].sfi.frames / queue[0].sfi.samplerate, + NULL); + + free(buf); + } + } + if(arrlen(queue) > 0) { + int elsec = queue[0].frames / queue[0].sfi.samplerate; + int rmsec = (queue[0].sfi.frames / queue[0].sfi.samplerate) - elsec; + char buf[64]; + + sprintf(buf, "%d:%02d", elsec / 60, elsec % 60); + MwVaApply(eltime, + MwNtext, buf, + NULL); + + sprintf(buf, "%d:%02d", rmsec / 60, rmsec % 60); + MwVaApply(rmtime, + MwNtext, buf, + NULL); + + MwVaApply(seekbar, + MwNvalue, elsec, + NULL); + } else { + MwVaApply(eltime, + MwNtext, "0:00", + NULL); + MwVaApply(rmtime, + MwNtext, "0:00", + NULL); + } + queue_last = arrlen(queue); + pthread_mutex_unlock(&audio_mutex); } void ui_init(void) { - ui_list_reset(); + ui_list_reset(NULL); ui_tree_reset(); ui_set_play_queue(0); @@ -93,5 +259,8 @@ void ui_init(void) { ui_set_albums(0); ui_set_artists(0); ui_set_genres(0); - ui_set_playlists(0); + + ui_last = all_music; + MwAddUserHandler(tree, MwNactivateHandler, tree_activate, NULL); + MwAddUserHandler(window, MwNtickHandler, window_tick, NULL); }