A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 470 lines 15 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 Michael Sevakis 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#include <stdio.h> 22#include <string.h> 23#include <stdlib.h> 24#include "config.h" 25#include "action.h" 26#include "lang.h" 27#include "misc.h" 28#include "talk.h" 29#include "general.h" 30#include "codecs.h" 31#include "menu.h" 32#include "settings.h" 33#include "audio.h" 34#include "pcm_record.h" 35#include "enc_config.h" 36#include "splash.h" 37 38 39#define CALL_FN_(fn, ...) \ 40 if (fn) fn(__VA_ARGS__) 41 42static int enc_menuitem_callback(int action, 43 const struct menu_item_ex *this_item, 44 struct gui_synclist *this_list); 45static int enc_menuitem_enteritem(int action, 46 const struct menu_item_ex *this_item, 47 struct gui_synclist *this_list); 48static void enc_rec_settings_changed(struct encoder_config *cfg); 49/* this is used by all encoder menu items, 50 MUST be initialised before the call to do_menu() */ 51static struct menucallback_data { 52 struct encoder_config *cfg; 53 bool global; 54} menu_callback_data; 55 56/** Function definitions for each codec - add these to enc_data 57 list following the definitions **/ 58 59/** aiff_enc.codec **/ 60 61/** mp3_enc.codec **/ 62/* mp3_enc: return encoder capabilities */ 63static void mp3_enc_get_caps(const struct encoder_config *cfg, 64 struct encoder_caps *caps, 65 bool for_config) 66{ 67 int i; 68 unsigned long bitr; 69 70 if (!for_config) 71 { 72 /* Overall encoder capabilities */ 73 caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS; 74 caps->channel_caps = CHN_CAP_ALL; 75 return; 76 } 77 78 /* Restrict caps based on config */ 79 i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr, 80 MP3_ENC_NUM_BITR, false); 81 bitr = mp3_enc_bitr[i]; 82 83 /* sample rate caps */ 84 85 /* check if MPEG1 sample rates are available */ 86 if ((bitr >= 32 && bitr <= 128) || bitr >= 160) 87 caps->samplerate_caps |= MPEG1_SAMPR_CAPS; 88 89 /* check if MPEG2 sample rates and mono are available */ 90 if (bitr <= 160) 91 { 92 caps->samplerate_caps |= MPEG2_SAMPR_CAPS; 93 caps->channel_caps |= CHN_CAP_MONO; 94 } 95 96 /* check if stereo is available */ 97 if (bitr >= 32) 98 caps->channel_caps |= CHN_CAP_STEREO; 99} /* mp3_enc_get_caps */ 100 101/* mp3_enc: return the default configuration */ 102static void mp3_enc_default_config(struct encoder_config *cfg) 103{ 104 cfg->mp3_enc.bitrate = 128; /* default that works for all types */ 105} /* mp3_enc_default_config */ 106 107static void mp3_enc_convert_config(struct encoder_config *cfg, 108 bool global) 109{ 110 if (global) 111 { 112 global_settings.mp3_enc_config.bitrate = 113 round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr, 114 MP3_ENC_NUM_BITR, false); 115 } 116 else 117 { 118 if ((unsigned)global_settings.mp3_enc_config.bitrate >= MP3_ENC_NUM_BITR) 119 global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT; 120 cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate]; 121 } 122} /* mp3_enc_convert_config */ 123 124/* mp3_enc: show the bitrate setting options */ 125static bool mp3_enc_bitrate(struct menucallback_data *data) 126{ 127 struct encoder_config *cfg = data->cfg; 128 static const struct opt_items items[] = 129 { 130 /* Available in MPEG Version: */ 131#ifdef HAVE_MPEG2_SAMPR 132#if 0 133 /* this sounds awful no matter what */ 134 { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */ 135#endif 136 /* mono only */ 137 { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */ 138 { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */ 139#endif /* HAVE_MPEG2_SAMPR */ 140 /* stereo/mono */ 141 { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */ 142 { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */ 143 { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */ 144 { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */ 145 { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */ 146 { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */ 147 { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */ 148 { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */ 149 { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */ 150 /* Leave out 144 when there is both MPEG 1 and 2 */ 151#if defined(HAVE_MPEG2_SAMPR) && !defined (HAVE_MPEG1_SAMPR) 152 /* oddball MPEG2-only rate stuck in the middle */ 153 { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */ 154#endif 155 { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */ 156#ifdef HAVE_MPEG1_SAMPR 157 /* stereo only */ 158 { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */ 159 { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */ 160 { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */ 161 { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */ 162#endif 163 }; 164 165 unsigned long rate_list[ARRAYLEN(items)]; 166 167 /* This is rather constant based upon the build but better than 168 storing and maintaining yet another list of numbers */ 169 int n_rates = make_list_from_caps32( 170 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr, 171 0 172#ifdef HAVE_MPEG1_SAMPR 173 | MPEG1_BITR_CAPS 174#endif 175#ifdef HAVE_MPEG2_SAMPR 176#ifdef HAVE_MPEG1_SAMPR 177 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8)) 178#else 179 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_8)) 180#endif 181#endif /* HAVE_MPEG2_SAMPR */ 182 , rate_list); 183 184 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list, 185 n_rates, false); 186 bool res = set_option(str(LANG_BITRATE), &index, RB_INT, 187 items, n_rates, NULL); 188 index = round_value_to_list32(rate_list[index], mp3_enc_bitr, 189 MP3_ENC_NUM_BITR, false); 190 cfg->mp3_enc.bitrate = mp3_enc_bitr[index]; 191 192 return res; 193} /* mp3_enc_bitrate */ 194 195/* mp3_enc configuration menu */ 196MENUITEM_FUNCTION_W_PARAM(mp3_bitrate, 0, ID2P(LANG_BITRATE), 197 mp3_enc_bitrate, &menu_callback_data, 198 enc_menuitem_callback, Icon_NOICON); 199MAKE_MENU( mp3_enc_menu, ID2P(LANG_ENCODER_SETTINGS), 200 enc_menuitem_enteritem, Icon_NOICON, 201 &mp3_bitrate); 202 203 204/** wav_enc.codec **/ 205/* wav_enc: show the configuration menu */ 206#if 0 207MAKE_MENU( wav_enc_menu, ID2P(LANG_ENCODER_SETTINGS), 208 enc_menuitem_enteritem, Icon_NOICON, 209 ); 210#endif 211 212/** wavpack_enc.codec **/ 213/* wavpack_enc: show the configuration menu */ 214#if 0 215MAKE_MENU( wavpack_enc_menu, ID2P(LANG_ENCODER_SETTINGS), 216 enc_menuitem_enteritem, Icon_NOICON, 217 ); 218#endif 219 220/** config function pointers and/or data for each codec **/ 221static const struct encoder_data 222{ 223 void (*get_caps)(const struct encoder_config *cfg, 224 struct encoder_caps *caps, bool for_config); 225 void (*default_cfg)(struct encoder_config *cfg); 226 void (*convert_cfg)(struct encoder_config *cfg , bool global); 227 const struct menu_item_ex *menu; 228} enc_data[REC_NUM_FORMATS] = 229{ 230 /* aiff_enc.codec */ 231 [REC_FORMAT_AIFF] = { 232 NULL, 233 NULL, 234 NULL, 235 NULL, 236 }, 237 /* mp3_enc.codec */ 238 [REC_FORMAT_MPA_L3] = { 239 mp3_enc_get_caps, 240 mp3_enc_default_config, 241 mp3_enc_convert_config, 242 &mp3_enc_menu, 243 }, 244 /* wav_enc.codec */ 245 [REC_FORMAT_PCM_WAV] = { 246 NULL, 247 NULL, 248 NULL, 249 NULL, 250 }, 251 /* wavpack_enc.codec */ 252 [REC_FORMAT_WAVPACK] = { 253 NULL, 254 NULL, 255 NULL, 256 NULL, 257 }, 258}; 259 260static inline bool rec_format_ok(int rec_format) 261{ 262 return (unsigned)rec_format < REC_NUM_FORMATS; 263} 264/* This is called before entering the menu with the encoder settings 265 Its needed to make sure the settings can take effect. */ 266static int enc_menuitem_enteritem(int action, 267 const struct menu_item_ex *this_item, 268 struct gui_synclist *this_list) 269{ 270 (void)this_item; 271 (void)this_list; 272 /* this struct must be init'ed before calling do_menu() so this is safe */ 273 struct menucallback_data *data = &menu_callback_data; 274 if (action == ACTION_STD_OK) /* entering the item */ 275 { 276 if (data->global) 277 global_to_encoder_config(data->cfg); 278 } 279 return action; 280} 281/* this is called when a encoder setting is exited 282 It is used to update the status bar and save the setting */ 283static int enc_menuitem_callback(int action, 284 const struct menu_item_ex *this_item, 285 struct gui_synclist *this_list) 286{ 287 (void)this_list; 288 struct menucallback_data *data = 289 (struct menucallback_data*)this_item->function_param->param; 290 291 if (action == ACTION_EXIT_MENUITEM) 292 { 293 /* If the setting being configured is global, it must be placed 294 in global_settings before updating the status bar for the 295 change to show upon exiting the item. */ 296 if (data->global) 297 { 298 enc_rec_settings_changed(data->cfg); 299 encoder_config_to_global(data->cfg); 300 } 301 302 } 303 return action; 304} 305 306/* update settings dependent upon encoder settings */ 307static void enc_rec_settings_changed(struct encoder_config *cfg) 308{ 309 struct encoder_config enc_config; 310 struct encoder_caps caps; 311 long table[MAX((int)CHN_NUM_MODES, (int)REC_NUM_FREQ)]; 312 int n; 313 314 if (cfg == NULL) 315 { 316 cfg = &enc_config; 317 cfg->rec_format = global_settings.rec_format; 318 global_to_encoder_config(cfg); 319 } 320 321 /* have to sync other settings when encoder settings change */ 322 if (!enc_get_caps(cfg, &caps, true)) 323 return; 324 325 /* rec_channels */ 326 n = make_list_from_caps32(CHN_CAP_ALL, NULL, 327 caps.channel_caps, table); 328 329 /* no zero check needed: encoder must support at least one 330 sample rate that recording supports or it shouldn't be in 331 available in the recording options */ 332 n = round_value_to_list32(global_settings.rec_channels, 333 table, n, true); 334 global_settings.rec_channels = table[n]; 335 336 /* rec_frequency */ 337 n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr, 338 caps.samplerate_caps, table); 339 340 n = round_value_to_list32( 341 rec_freq_sampr[global_settings.rec_frequency], 342 table, n, false); 343 344 global_settings.rec_frequency = round_value_to_list32( 345 table[n], rec_freq_sampr, REC_NUM_FREQ, false); 346} /* enc_rec_settings_changed */ 347 348/** public stuff **/ 349void global_to_encoder_config(struct encoder_config *cfg) 350{ 351 const struct encoder_data *data = &enc_data[cfg->rec_format]; 352 CALL_FN_(data->convert_cfg, cfg, false); 353} /* global_to_encoder_config */ 354 355void encoder_config_to_global(const struct encoder_config *cfg) 356{ 357 const struct encoder_data *data = &enc_data[cfg->rec_format]; 358 CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, true); 359} /* encoder_config_to_global */ 360 361bool enc_get_caps(const struct encoder_config *cfg, 362 struct encoder_caps *caps, 363 bool for_config) 364{ 365 /* get_caps expects caps to be zeroed first */ 366 memset(caps, 0, sizeof (*caps)); 367 368 if (!rec_format_ok(cfg->rec_format)) 369 return false; 370 371 if (enc_data[cfg->rec_format].get_caps) 372 { 373 enc_data[cfg->rec_format].get_caps(cfg, caps, for_config); 374 } 375 else 376 { 377 /* If no function provided...defaults to all */ 378 caps->samplerate_caps = SAMPR_CAP_ALL_192; 379 caps->channel_caps = CHN_CAP_ALL; 380 } 381 382 return true; 383} /* enc_get_caps */ 384 385/* Initializes the config struct with default values */ 386bool enc_init_config(struct encoder_config *cfg) 387{ 388 if (!rec_format_ok(cfg->rec_format)) 389 return false; 390 CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg); 391 return true; 392} /* enc_init_config */ 393 394/** Encoder Menus **/ 395#if 0 396bool enc_config_menu(struct encoder_config *cfg) 397{ 398 if (!rec_format_ok(cfg->rec_format)) 399 return false; 400 if (enc_data[cfg->rec_format].menu) 401 { 402 menu_callback_data.cfg = &cfg; 403 menu_callback_data.global = false; 404 return do_menu(enc_data[cfg->rec_format].menu, NULL, NULL, false) 405 == MENU_ATTACHED_USB; 406 } 407 else 408 { 409 splash(HZ, ID2P(LANG_NO_SETTINGS)); 410 return false; 411 } 412} /* enc_config_menu */ 413#endif 414 415/** Global Settings **/ 416 417/* Reset all codecs to defaults */ 418void enc_global_settings_reset(void) 419{ 420 struct encoder_config cfg; 421 cfg.rec_format = 0; 422 423 do 424 { 425 global_to_encoder_config(&cfg); 426 enc_init_config(&cfg); 427 encoder_config_to_global(&cfg); 428 if (cfg.rec_format == global_settings.rec_format) 429 enc_rec_settings_changed(&cfg); 430 } 431 while (++cfg.rec_format < REC_NUM_FORMATS); 432} /* enc_global_settings_reset */ 433 434/* Apply new settings */ 435void enc_global_settings_apply(void) 436{ 437 struct encoder_config cfg; 438 if (!rec_format_ok(global_settings.rec_format)) 439 global_settings.rec_format = REC_FORMAT_DEFAULT; 440 441 cfg.rec_format = global_settings.rec_format; 442 global_to_encoder_config(&cfg); 443 enc_rec_settings_changed(&cfg); 444 encoder_config_to_global(&cfg); 445} /* enc_global_settings_apply */ 446 447/* Show an encoder's config menu based on the global_settings. 448 Modified settings are placed in global_settings.enc_config. */ 449int enc_global_config_menu(void) 450{ 451 struct encoder_config cfg; 452 453 if (!rec_format_ok(global_settings.rec_format)) 454 global_settings.rec_format = REC_FORMAT_DEFAULT; 455 456 cfg.rec_format = global_settings.rec_format; 457 458 if (enc_data[cfg.rec_format].menu) 459 { 460 menu_callback_data.cfg = &cfg; 461 menu_callback_data.global = true; 462 int retmenu = do_menu(enc_data[cfg.rec_format].menu, NULL, NULL, false); 463 return (retmenu == MENU_ATTACHED_USB) ? 1 : 0; 464 } 465 else 466 { 467 splash(HZ, ID2P(LANG_NO_SETTINGS)); 468 return 0; 469 } 470} /* enc_global_config_menu */