Document new %mp values that were introduced with the sbs change
[kugel-rb.git] / apps / enc_config.c
blob48ad18f7715359411dbf2ef2129ce4330383d7f7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Michael Sevakis
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdio.h>
22 #include <sprintf.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "config.h"
26 #include "action.h"
27 #include "lang.h"
28 #include "misc.h"
29 #include "talk.h"
30 #include "general.h"
31 #include "codecs.h"
32 #include "menu.h"
33 #include "settings.h"
34 #include "audio.h"
35 #include "pcm_record.h"
36 #include "enc_config.h"
37 #include "splash.h"
40 #define CALL_FN_(fn, ...) \
41 if (fn) fn(__VA_ARGS__)
43 static int enc_menuitem_callback(int action,
44 const struct menu_item_ex *this_item);
45 static int enc_menuitem_enteritem(int action,
46 const struct menu_item_ex *this_item);
47 static void enc_rec_settings_changed(struct encoder_config *cfg);
48 /* this is used by all encoder menu items,
49 MUST be initialised before the call to do_menu() */
50 static struct menucallback_data {
51 struct encoder_config *cfg;
52 bool global;
53 } menu_callback_data;
55 /** Function definitions for each codec - add these to enc_data
56 list following the definitions **/
58 /** aiff_enc.codec **/
60 /** mp3_enc.codec **/
61 /* mp3_enc: return encoder capabilities */
62 static void mp3_enc_get_caps(const struct encoder_config *cfg,
63 struct encoder_caps *caps,
64 bool for_config)
66 int i;
67 unsigned long bitr;
69 if (!for_config)
71 /* Overall encoder capabilities */
72 caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS;
73 caps->channel_caps = CHN_CAP_ALL;
74 return;
77 /* Restrict caps based on config */
78 i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
79 MP3_ENC_NUM_BITR, false);
80 bitr = mp3_enc_bitr[i];
82 /* sample rate caps */
84 /* check if MPEG1 sample rates are available */
85 if ((bitr >= 32 && bitr <= 128) || bitr >= 160)
86 caps->samplerate_caps |= MPEG1_SAMPR_CAPS;
88 /* check if MPEG2 sample rates and mono are available */
89 if (bitr <= 160)
91 caps->samplerate_caps |= MPEG2_SAMPR_CAPS;
92 caps->channel_caps |= CHN_CAP_MONO;
95 /* check if stereo is available */
96 if (bitr >= 32)
97 caps->channel_caps |= CHN_CAP_STEREO;
98 } /* mp3_enc_get_caps */
100 /* mp3_enc: return the default configuration */
101 static void mp3_enc_default_config(struct encoder_config *cfg)
103 cfg->mp3_enc.bitrate = 128; /* default that works for all types */
104 } /* mp3_enc_default_config */
106 static void mp3_enc_convert_config(struct encoder_config *cfg,
107 bool global)
109 if (global)
111 global_settings.mp3_enc_config.bitrate =
112 round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
113 MP3_ENC_NUM_BITR, false);
115 else
117 if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
118 global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
119 cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
121 } /* mp3_enc_convert_config */
123 /* mp3_enc: show the bitrate setting options */
124 static bool mp3_enc_bitrate(struct menucallback_data *data)
126 struct encoder_config *cfg = data->cfg;
127 static const struct opt_items items[] =
129 /* Available in MPEG Version: */
130 #ifdef HAVE_MPEG2_SAMPR
131 #if 0
132 /* this sounds awful no matter what */
133 { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */
134 #endif
135 /* mono only */
136 { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */
137 { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */
138 #endif /* HAVE_MPEG2_SAMPR */
139 /* stereo/mono */
140 { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */
141 { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */
142 { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */
143 { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */
144 { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */
145 { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */
146 { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */
147 { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */
148 { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */
149 /* Leave out 144 when there is both MPEG 1 and 2 */
150 #if defined(HAVE_MPEG2_SAMPR) && !defined (HAVE_MPEG1_SAMPR)
151 /* oddball MPEG2-only rate stuck in the middle */
152 { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */
153 #endif
154 { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */
155 #ifdef HAVE_MPEG1_SAMPR
156 /* stereo only */
157 { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */
158 { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */
159 { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */
160 { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */
161 #endif
164 unsigned long rate_list[ARRAYLEN(items)];
166 /* This is rather constant based upon the build but better than
167 storing and maintaining yet another list of numbers */
168 int n_rates = make_list_from_caps32(
169 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr,
171 #ifdef HAVE_MPEG1_SAMPR
172 | MPEG1_BITR_CAPS
173 #endif
174 #ifdef HAVE_MPEG2_SAMPR
175 #ifdef HAVE_MPEG1_SAMPR
176 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8))
177 #else
178 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_8))
179 #endif
180 #endif /* HAVE_MPEG2_SAMPR */
181 , rate_list);
183 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
184 n_rates, false);
185 bool res = set_option(str(LANG_BITRATE), &index, INT,
186 items, n_rates, NULL);
187 index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
188 MP3_ENC_NUM_BITR, false);
189 cfg->mp3_enc.bitrate = mp3_enc_bitr[index];
191 return res;
192 } /* mp3_enc_bitrate */
194 /* mp3_enc configuration menu */
195 MENUITEM_FUNCTION(mp3_bitrate, MENU_FUNC_USEPARAM, ID2P(LANG_BITRATE),
196 mp3_enc_bitrate,
197 &menu_callback_data, enc_menuitem_callback, Icon_NOICON);
198 MAKE_MENU( mp3_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
199 enc_menuitem_enteritem, Icon_NOICON,
200 &mp3_bitrate);
203 /** wav_enc.codec **/
204 /* wav_enc: show the configuration menu */
205 #if 0
206 MAKE_MENU( wav_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
207 enc_menuitem_enteritem, Icon_NOICON,
209 #endif
211 /** wavpack_enc.codec **/
212 /* wavpack_enc: show the configuration menu */
213 #if 0
214 MAKE_MENU( wavpack_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
215 enc_menuitem_enteritem, Icon_NOICON,
217 #endif
219 /** config function pointers and/or data for each codec **/
220 static const struct encoder_data
222 void (*get_caps)(const struct encoder_config *cfg,
223 struct encoder_caps *caps, bool for_config);
224 void (*default_cfg)(struct encoder_config *cfg);
225 void (*convert_cfg)(struct encoder_config *cfg , bool global);
226 const struct menu_item_ex *menu;
227 } enc_data[REC_NUM_FORMATS] =
229 /* aiff_enc.codec */
230 [REC_FORMAT_AIFF] = {
231 NULL,
232 NULL,
233 NULL,
234 NULL,
236 /* mp3_enc.codec */
237 [REC_FORMAT_MPA_L3] = {
238 mp3_enc_get_caps,
239 mp3_enc_default_config,
240 mp3_enc_convert_config,
241 &mp3_enc_menu,
243 /* wav_enc.codec */
244 [REC_FORMAT_PCM_WAV] = {
245 NULL,
246 NULL,
247 NULL,
248 NULL,
250 /* wavpack_enc.codec */
251 [REC_FORMAT_WAVPACK] = {
252 NULL,
253 NULL,
254 NULL,
255 NULL,
259 static inline bool rec_format_ok(int rec_format)
261 return (unsigned)rec_format < REC_NUM_FORMATS;
263 /* This is called before entering the menu with the encoder settings
264 Its needed to make sure the settings can take effect. */
265 static int enc_menuitem_enteritem(int action,
266 const struct menu_item_ex *this_item)
268 (void)this_item;
269 /* this struct must be init'ed before calling do_menu() so this is safe */
270 struct menucallback_data *data = &menu_callback_data;
271 if (action == ACTION_STD_OK) /* entering the item */
273 if (data->global)
274 global_to_encoder_config(data->cfg);
276 return action;
278 /* this is called when a encoder setting is exited
279 It is used to update the status bar and save the setting */
280 static int enc_menuitem_callback(int action,
281 const struct menu_item_ex *this_item)
283 struct menucallback_data *data =
284 (struct menucallback_data*)this_item->function->param;
286 if (action == ACTION_EXIT_MENUITEM)
288 /* If the setting being configured is global, it must be placed
289 in global_settings before updating the status bar for the
290 change to show upon exiting the item. */
291 if (data->global)
293 enc_rec_settings_changed(data->cfg);
294 encoder_config_to_global(data->cfg);
298 return action;
301 /* update settings dependent upon encoder settings */
302 static void enc_rec_settings_changed(struct encoder_config *cfg)
304 struct encoder_config enc_config;
305 struct encoder_caps caps;
306 long table[MAX(CHN_NUM_MODES, REC_NUM_FREQ)];
307 int n;
309 if (cfg == NULL)
311 cfg = &enc_config;
312 cfg->rec_format = global_settings.rec_format;
313 global_to_encoder_config(cfg);
316 /* have to sync other settings when encoder settings change */
317 if (!enc_get_caps(cfg, &caps, true))
318 return;
320 /* rec_channels */
321 n = make_list_from_caps32(CHN_CAP_ALL, NULL,
322 caps.channel_caps, table);
324 /* no zero check needed: encoder must support at least one
325 sample rate that recording supports or it shouldn't be in
326 available in the recording options */
327 n = round_value_to_list32(global_settings.rec_channels,
328 table, n, true);
329 global_settings.rec_channels = table[n];
331 /* rec_frequency */
332 n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
333 caps.samplerate_caps, table);
335 n = round_value_to_list32(
336 rec_freq_sampr[global_settings.rec_frequency],
337 table, n, false);
339 global_settings.rec_frequency = round_value_to_list32(
340 table[n], rec_freq_sampr, REC_NUM_FREQ, false);
341 } /* enc_rec_settings_changed */
343 /** public stuff **/
344 void global_to_encoder_config(struct encoder_config *cfg)
346 const struct encoder_data *data = &enc_data[cfg->rec_format];
347 CALL_FN_(data->convert_cfg, cfg, false);
348 } /* global_to_encoder_config */
350 void encoder_config_to_global(const struct encoder_config *cfg)
352 const struct encoder_data *data = &enc_data[cfg->rec_format];
353 CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, true);
354 } /* encoder_config_to_global */
356 bool enc_get_caps(const struct encoder_config *cfg,
357 struct encoder_caps *caps,
358 bool for_config)
360 /* get_caps expects caps to be zeroed first */
361 memset(caps, 0, sizeof (*caps));
363 if (!rec_format_ok(cfg->rec_format))
364 return false;
366 if (enc_data[cfg->rec_format].get_caps)
368 enc_data[cfg->rec_format].get_caps(cfg, caps, for_config);
370 else
372 /* If no function provided...defaults to all */
373 caps->samplerate_caps = SAMPR_CAP_ALL;
374 caps->channel_caps = CHN_CAP_ALL;
377 return true;
378 } /* enc_get_caps */
380 /* Initializes the config struct with default values */
381 bool enc_init_config(struct encoder_config *cfg)
383 if (!rec_format_ok(cfg->rec_format))
384 return false;
385 CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg);
386 return true;
387 } /* enc_init_config */
389 /** Encoder Menus **/
390 #if 0
391 bool enc_config_menu(struct encoder_config *cfg)
393 if (!rec_format_ok(cfg->rec_format))
394 return false;
395 if (enc_data[cfg->rec_format].menu)
397 menu_callback_data.cfg = &cfg;
398 menu_callback_data.global = false;
399 return do_menu(enc_data[cfg->rec_format].menu, NULL, NULL, false)
400 == MENU_ATTACHED_USB;
402 else
404 splash(HZ, str(LANG_NO_SETTINGS));
405 return false;
407 } /* enc_config_menu */
408 #endif
410 /** Global Settings **/
412 /* Reset all codecs to defaults */
413 void enc_global_settings_reset(void)
415 struct encoder_config cfg;
416 cfg.rec_format = 0;
420 global_to_encoder_config(&cfg);
421 enc_init_config(&cfg);
422 encoder_config_to_global(&cfg);
423 if (cfg.rec_format == global_settings.rec_format)
424 enc_rec_settings_changed(&cfg);
426 while (++cfg.rec_format < REC_NUM_FORMATS);
427 } /* enc_global_settings_reset */
429 /* Apply new settings */
430 void enc_global_settings_apply(void)
432 struct encoder_config cfg;
433 if (!rec_format_ok(global_settings.rec_format))
434 global_settings.rec_format = REC_FORMAT_DEFAULT;
436 cfg.rec_format = global_settings.rec_format;
437 global_to_encoder_config(&cfg);
438 enc_rec_settings_changed(&cfg);
439 encoder_config_to_global(&cfg);
440 } /* enc_global_settings_apply */
442 /* Show an encoder's config menu based on the global_settings.
443 Modified settings are placed in global_settings.enc_config. */
444 bool enc_global_config_menu(void)
446 struct encoder_config cfg;
448 if (!rec_format_ok(global_settings.rec_format))
449 global_settings.rec_format = REC_FORMAT_DEFAULT;
451 cfg.rec_format = global_settings.rec_format;
453 if (enc_data[cfg.rec_format].menu)
455 menu_callback_data.cfg = &cfg;
456 menu_callback_data.global = true;
457 return do_menu(enc_data[cfg.rec_format].menu, NULL, NULL, false)
458 == MENU_ATTACHED_USB;
460 else
462 splash(HZ, str(LANG_NO_SETTINGS));
463 return false;
465 } /* enc_global_config_menu */