A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 283 lines 7.4 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2009, 2010 Wincent Balin 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include "plugin.h" 23#include "pdbox.h" 24 25#include "lib/helper.h" 26 27#include "PDa/src/m_pd.h" 28#include "PDa/src/s_stuff.h" 29 30/* Welcome to the PDBox plugin */ 31 32/* Name of the file to open. */ 33char* filename; 34 35/* Running time. */ 36uint64_t runningtime IBSS_ATTR = 0; 37 38/* Variables for Pure Data. */ 39int sys_verbose; 40int sys_noloadbang; 41t_symbol *sys_libdir; 42t_namelist *sys_openlist; 43int sys_soundindevlist[MAXAUDIOINDEV]; 44int sys_chinlist[MAXAUDIOINDEV]; 45int sys_soundoutdevlist[MAXAUDIOOUTDEV]; 46int sys_choutlist[MAXAUDIOOUTDEV]; 47t_binbuf* inbinbuf; 48 49/* References for scheduler variables and functions. */ 50extern t_time sys_time; 51extern t_time sys_time_per_dsp_tick; 52extern void sched_tick(t_time next_sys_time); 53 54/* LATER consider making this variable. It's now the LCM of all sample 55rates we expect to see: 32000, 44100, 48000, 88200, 96000. */ 56#define TIMEUNITPERSEC (32.*441000.) 57 58 59/* Quit flag. */ 60bool quit IBSS_ATTR = false; 61 62/* Stack sizes for threads. */ 63#define CORESTACKSIZE (1 * 1024 * 1024) 64#define GUISTACKSIZE (512 * 1024) 65 66/* Thread stacks. */ 67void* core_stack IBSS_ATTR; 68void* gui_stack IBSS_ATTR; 69 70/* Thread IDs. */ 71unsigned int core_thread_id IBSS_ATTR; 72unsigned int gui_thread_id IBSS_ATTR; 73 74 75/* GUI thread */ 76void gui_thread(void) 77{ 78 struct pd_widget widget[128]; 79 unsigned int widgets = 0; 80 struct datagram dg; 81 bool update; 82 83 /* Initialize GUI. */ 84 pd_gui_init(); 85 86 /* Load PD patch. */ 87 widgets = pd_gui_load_patch(widget, 88 sizeof(widget) / sizeof(struct pd_widget)); 89 90 /* Draw initial state of UI. */ 91 pd_gui_draw(widget, widgets); 92 93 /* GUI loop */ 94 while(!quit) 95 { 96 /* Reset update flag. */ 97 update = false; 98 99 /* Apply timer to widgets. */ 100 update |= 101 pd_gui_apply_timeouts(widget, widgets); 102 103 /* Process buttons. */ 104 update |= 105 pd_gui_parse_buttons(widgets); 106 107 /* Receive and parse datagrams. */ 108 while(RECEIVE_FROM_CORE(&dg)) 109 { 110 update = true; 111 pd_gui_parse_message(&dg, widget, widgets); 112 } 113 114 /* If there is something to update in GUI, do so. */ 115 if(update) 116 pd_gui_draw(widget, widgets); 117 118 rb->sleep(1); 119 } 120 121 rb->thread_exit(); 122} 123 124/* Core thread */ 125void core_thread(void) 126{ 127 /* Add the directory the called .pd file resides in to lib directories. */ 128 sys_findlibdir(filename); 129 130 /* Open the PD design file. */ 131 sys_openlist = namelist_append(sys_openlist, filename); 132 133 /* Fake a GUI start. */ 134 sys_startgui(NULL); 135 136 /* Core scheduler loop */ 137 while(!quit) 138 { 139 /* Receive datagrams. */ 140 struct datagram dg; 141 142 while(RECEIVE_TO_CORE(&dg)) 143 rockbox_receive_callback(&dg); 144 145 /* Use sys_send_dacs() function as timer. */ 146 while(sys_send_dacs() != SENDDACS_NO) 147 sched_tick(sys_time + sys_time_per_dsp_tick); 148 149 rb->sleep(1); 150 } 151 152 rb->thread_exit(); 153} 154 155 156 157/* Plug-in entry point */ 158enum plugin_status plugin_start(const void* parameter) 159{ 160 /* Memory pool variables. */ 161 size_t mem_size; 162 void* mem_pool; 163 164 /* Get the file name; check whether parameter contains no file name. */ 165 filename = (char*) parameter; 166 if(strlen(filename) == 0) 167 { 168 rb->splash(HZ, "Play a .pd file!"); 169 return PLUGIN_ERROR; 170 } 171 172 /* Initialize memory pool. */ 173 mem_pool = rb->plugin_get_audio_buffer(&mem_size); 174 if(mem_size < MIN_MEM_SIZE) 175 { 176 rb->splash(HZ, "Not enough memory!"); 177 return PLUGIN_ERROR; 178 } 179 180 init_memory_pool(mem_size, mem_pool); 181 182 /* Initialize net. */ 183 net_init(); 184 185 /* Initialize Pure Data, as does sys_main in s_main.c */ 186 pd_init(); 187 188 /* Set audio API. */ 189 sys_set_audio_api(API_ROCKBOX); 190 191 /* Initialize audio subsystem. */ 192 sys_open_audio(0, /* No sound input yet */ 193 sys_soundindevlist, 194 0, /* No sound input yet */ 195 sys_chinlist, 196 1, /* One sound output device */ 197 sys_soundoutdevlist, 198 -1, /* Use the default amount (2) of channels */ 199 sys_choutlist, 200 PD_SAMPLERATE, /* Sample rate */ 201 DEFAULTADVANCE, /* Scheduler advance */ 202 1 /* Enable */); 203 204 /* Initialize scheduler time variables. */ 205 sys_time = 0; 206 sys_time_per_dsp_tick = (TIMEUNITPERSEC) * 207 ((double) sys_schedblocksize) / sys_dacsr; 208 209 210 /* Create stacks for threads. */ 211 core_stack = getbytes(CORESTACKSIZE); 212 gui_stack = getbytes(GUISTACKSIZE); 213 if(core_stack == NULL || gui_stack == NULL) 214 { 215 rb->splash(HZ, "Not enough memory!"); 216 return PLUGIN_ERROR; 217 } 218 219#ifdef HAVE_SCHEDULER_BOOSTCTRL 220 /* Boost CPU. */ 221 rb->trigger_cpu_boost(); 222#endif 223 224 /* Start threads. */ 225 core_thread_id = 226 rb->create_thread(&core_thread, 227 core_stack, 228 CORESTACKSIZE, 229 0, /* FIXME Which flags? */ 230 "PD core" 231 IF_PRIO(, PRIORITY_REALTIME) 232 IF_COP(, CPU)); 233 234 gui_thread_id = 235 rb->create_thread(&gui_thread, 236 gui_stack, 237 GUISTACKSIZE, 238 0, /* FIXME Which flags? */ 239 "PD GUI" 240 IF_PRIO(, PRIORITY_USER_INTERFACE) 241 IF_COP(, CPU)); 242 243 /* If having an error creating threads, bail out. */ 244 if(core_thread_id == 0 || gui_thread_id == 0) 245 return PLUGIN_ERROR; 246 247 /* Make backlight remain on -- making music requires attention. */ 248 backlight_ignore_timeout(); 249 250 /* Main loop. */ 251 while(!quit) 252 { 253 /* Add time slice in milliseconds. */ 254 runningtime += (1000 / HZ); 255 256 /* Sleep to the next time slice. */ 257 rb->sleep(1); 258 } 259 260 /* Restore backlight. */ 261 backlight_use_settings(); 262 263 /* Wait for threads to complete. */ 264 rb->thread_wait(gui_thread_id); 265 rb->thread_wait(core_thread_id); 266 267#ifdef HAVE_SCHEDULER_BOOSTCTRL 268 /* Unboost CPU. */ 269 rb->cancel_cpu_boost(); 270#endif 271 272 /* Close audio subsystem. */ 273 sys_close_audio(); 274 275 /* Destroy net. */ 276 net_destroy(); 277 278 /* Clear memory pool. */ 279 destroy_memory_pool(mem_pool); 280 281 return PLUGIN_OK; 282} 283