summaryrefslogtreecommitdiff
path: root/apps/enc_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/enc_config.c')
-rw-r--r--apps/enc_config.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/apps/enc_config.c b/apps/enc_config.c
new file mode 100644
index 0000000000..384e679c42
--- /dev/null
+++ b/apps/enc_config.c
@@ -0,0 +1,432 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 Michael Sevakis
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <sprintf.h>
21#include <string.h>
22#include "config.h"
23#include "atoi.h"
24#include "lang.h"
25#include "misc.h"
26#include "talk.h"
27#include "general.h"
28#include "codecs.h"
29#include "menu.h"
30#include "statusbar.h"
31#include "settings.h"
32#include "audio.h"
33#include "pcm_record.h"
34#include "enc_config.h"
35
36#define MENU_ITEM_FN(fn) \
37 ((bool (*)(void))fn)
38
39#define ENC_MENU_ITEM_FN(fn) \
40 ((bool (*)(struct encoder_config *))fn)
41
42#define CALL_FN_(fn, ...) \
43 if (fn) fn(__VA_ARGS__)
44
45static bool enc_run_menu(int m, const struct menu_item items[],
46 struct encoder_config *cfg);
47static bool enc_no_config_menu(struct encoder_config *cfg);
48
49/** Function definitions for each codec - add these to enc_data
50 list following the definitions **/
51
52/** mp3_enc.codec **/
53/* mp3_enc: return encoder capabilities */
54static void mp3_enc_get_caps(const struct encoder_config *cfg,
55 struct encoder_caps *caps,
56 bool for_config)
57{
58 int i;
59 unsigned long bitr;
60
61 if (!for_config)
62 {
63 /* Overall encoder capabilities */
64 caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS;
65 caps->channel_caps = CHN_CAP_ALL;
66 return;
67 }
68
69 /* Restrict caps based on config */
70 i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
71 MP3_ENC_NUM_BITR, false);
72 bitr = mp3_enc_bitr[i];
73
74 /* sample rate caps */
75
76 /* check if MPEG1 sample rates are available */
77 if ((bitr >= 32 && bitr <= 128) || bitr >= 160)
78 caps->samplerate_caps |= MPEG1_SAMPR_CAPS;
79
80 /* check if MPEG2 sample rates and mono are available */
81 if (bitr <= 160)
82 {
83 caps->samplerate_caps |= MPEG2_SAMPR_CAPS;
84 caps->channel_caps |= CHN_CAP_MONO;
85 }
86
87 /* check if stereo is available */
88 if (bitr >= 32)
89 caps->channel_caps |= CHN_CAP_STEREO;
90} /* mp3_enc_get_caps */
91
92/* mp3_enc: return the default configuration */
93static void mp3_enc_default_config(struct encoder_config *cfg)
94{
95 cfg->mp3_enc.bitrate = 128; /* default that works for all types */
96} /* mp3_enc_default_config */
97
98static void mp3_enc_convert_config(struct encoder_config *cfg,
99 bool to_encoder)
100{
101 if (to_encoder)
102 {
103 if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
104 global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
105 cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
106 }
107 else
108 {
109 global_settings.mp3_enc_config.bitrate =
110 round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
111 MP3_ENC_NUM_BITR, false);
112 }
113} /* mp3_enc_convert_config */
114
115/* mp3_enc: show the bitrate setting options */
116static bool mp3_enc_bitrate(struct encoder_config *cfg)
117{
118 static const struct opt_items items[] =
119 {
120 /* Available in MPEG Version: */
121#ifdef HAVE_MPEG2_SAMPR
122#if 0
123 /* this sounds awful no matter what */
124 { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */
125#endif
126 /* mono only */
127 { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */
128 { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */
129#endif
130 /* stereo/mono */
131 { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */
132 { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */
133 { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */
134 { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */
135 { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */
136 { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */
137 { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */
138 { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */
139 { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */
140#if 0
141 /* oddball MPEG2-only rate stuck in the middle */
142 { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */
143#endif
144 { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */
145 /* stereo only */
146 { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */
147 { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */
148 { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */
149 { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */
150 };
151
152 unsigned long rate_list[ARRAYLEN(items)];
153
154 /* This is rather constant based upon the build but better than
155 storing and maintaining yet another list of numbers */
156 int n_rates = make_list_from_caps32(
157 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr,
158 MPEG1_BITR_CAPS
159#ifdef HAVE_MPEG2_SAMPR
160 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8)),
161#endif
162 rate_list);
163
164 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
165 n_rates, false);
166 bool res = set_option(str(LANG_BITRATE), &index, INT,
167 items, n_rates, NULL);
168 index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
169 MP3_ENC_NUM_BITR, false);
170 cfg->mp3_enc.bitrate = mp3_enc_bitr[index];
171
172 return res;
173} /* mp3_enc_bitrate */
174
175/* mp3_enc: show the configuration menu */
176static bool mp3_enc_menu(struct encoder_config *cfg)
177{
178 static const struct menu_item items[] =
179 {
180 { ID2P(LANG_BITRATE), MENU_ITEM_FN(mp3_enc_bitrate) }
181 };
182
183 bool result;
184 int m = menu_init(items, ARRAYLEN(items), NULL, NULL, NULL, NULL);
185 result = enc_run_menu(m, items, cfg);
186 menu_exit(m);
187 return result;
188} /* mp3_enc_menu */
189
190/** wav_enc.codec **/
191/* wav_enc: show the configuration menu */
192#if 0
193static bool wav_enc_menu(struct encoder_config *cfg);
194#endif
195
196/** wavpack_enc.codec **/
197/* wavpack_enc: show the configuration menu */
198#if 0
199static bool wavpack_enc_menu(struct encoder_config *cfg);
200#endif
201
202/** config function pointers and/or data for each codec **/
203static const struct encoder_data
204{
205 void (*get_caps)(const struct encoder_config *, struct encoder_caps *,
206 bool);
207 void (*default_cfg)(struct encoder_config *);
208 void (*convert_cfg)(struct encoder_config *, bool to_encoder);
209 bool (*menu)(struct encoder_config *);
210} enc_data[REC_NUM_FORMATS] =
211{
212 /* mp3_enc.codec */
213 [REC_FORMAT_MPA_L3] = {
214 mp3_enc_get_caps,
215 mp3_enc_default_config,
216 mp3_enc_convert_config,
217 mp3_enc_menu,
218 },
219 /* wav_enc.codec */
220 [REC_FORMAT_PCM_WAV] = {
221 NULL,
222 NULL,
223 NULL,
224 enc_no_config_menu,
225 },
226 /* wavpack_enc.codec */
227 [REC_FORMAT_WAVPACK] = {
228 NULL,
229 NULL,
230 NULL,
231 enc_no_config_menu,
232 },
233};
234
235static inline bool rec_format_ok(int rec_format)
236{
237 return (unsigned)rec_format < REC_NUM_FORMATS;
238}
239
240static bool enc_run_menu(int m, const struct menu_item items[],
241 struct encoder_config *cfg)
242{
243 int selected;
244 while (1)
245 {
246 switch (selected=menu_show(m))
247 {
248 case MENU_SELECTED_EXIT:
249 return false;
250
251 case MENU_ATTACHED_USB:
252 return true;
253
254 default:
255 if (items[selected].function &&
256 ENC_MENU_ITEM_FN(items[selected].function)(cfg))
257 return true;
258 gui_syncstatusbar_draw(&statusbars, true);
259 }
260 }
261} /* enc_run_menu */
262
263/* menu created when encoder has no configuration options */
264static bool enc_no_config_menu(struct encoder_config *cfg)
265{
266 static const struct menu_item items[] =
267 {
268 { ID2P(LANG_NO_SETTINGS), NULL }
269 };
270 int m;
271 bool result;
272
273 m = menu_init(items, ARRAYLEN(items), NULL, NULL, NULL, NULL);
274 result = enc_run_menu(m, items, NULL);
275 menu_exit(m);
276
277 return result;
278 (void)cfg;
279} /* enc_no_config_menu */
280
281/* update settings dependent upon encoder settings */
282static void enc_rec_settings_changed(struct encoder_config *cfg)
283{
284 struct encoder_config enc_config;
285 struct encoder_caps caps;
286 long table[MAX(CHN_NUM_MODES, REC_NUM_FREQ)];
287 int n;
288
289 if (cfg == NULL)
290 {
291 cfg = &enc_config;
292 cfg->rec_format = global_settings.rec_format;
293 global_to_encoder_config(cfg);
294 }
295
296 /* have to sync other settings when encoder settings change */
297 if (!enc_get_caps(cfg, &caps, true))
298 return;
299
300 /* rec_channels */
301 n = make_list_from_caps32(CHN_CAP_ALL, NULL,
302 caps.channel_caps, table);
303
304 /* no zero check needed: encoder must support at least one
305 sample rate that recording supports or it shouldn't be in
306 available in the recording options */
307 n = round_value_to_list32(global_settings.rec_channels,
308 table, n, true);
309 global_settings.rec_channels = table[n];
310
311 /* rec_frequency */
312 n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
313 caps.samplerate_caps, table);
314
315 n = round_value_to_list32(
316 rec_freq_sampr[global_settings.rec_frequency],
317 table, n, false);
318
319 global_settings.rec_frequency = round_value_to_list32(
320 table[n], rec_freq_sampr, REC_NUM_FREQ, false);
321} /* enc_rec_settings_changed */
322
323/** public stuff **/
324void global_to_encoder_config(struct encoder_config *cfg)
325{
326 const struct encoder_data *data = &enc_data[cfg->rec_format];
327 CALL_FN_(data->convert_cfg, cfg, true);
328} /* global_to_encoder_config */
329
330void encoder_config_to_global(const struct encoder_config *cfg)
331{
332 const struct encoder_data *data = &enc_data[cfg->rec_format];
333 CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, false);
334} /* encoder_config_to_global */
335
336bool enc_get_caps(const struct encoder_config *cfg,
337 struct encoder_caps *caps,
338 bool for_config)
339{
340 /* get_caps expects caps to be zeroed first */
341 memset(caps, 0, sizeof (*caps));
342
343 if (!rec_format_ok(cfg->rec_format))
344 return false;
345
346 if (enc_data[cfg->rec_format].get_caps)
347 {
348 enc_data[cfg->rec_format].get_caps(cfg, caps, for_config);
349 }
350 else
351 {
352 /* If no function provided...defaults to all */
353 caps->samplerate_caps = SAMPR_CAP_ALL;
354 caps->channel_caps = CHN_CAP_ALL;
355 }
356
357 return true;
358} /* enc_get_caps */
359
360/* Initializes the config struct with default values */
361bool enc_init_config(struct encoder_config *cfg)
362{
363 if (!rec_format_ok(cfg->rec_format))
364 return false;
365 CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg);
366 return true;
367} /* enc_init_config */
368
369/** Encoder Menus **/
370bool enc_config_menu(struct encoder_config *cfg)
371{
372 if (!rec_format_ok(cfg->rec_format))
373 return false;
374 return enc_data[cfg->rec_format].menu(cfg);
375} /* enc_config_menu */
376
377/** Global Settings **/
378
379/* Reset all codecs to defaults */
380void enc_global_settings_reset(void)
381{
382 struct encoder_config cfg;
383 cfg.rec_format = 0;
384
385 do
386 {
387 global_to_encoder_config(&cfg);
388 enc_init_config(&cfg);
389 encoder_config_to_global(&cfg);
390 if (cfg.rec_format == global_settings.rec_format)
391 enc_rec_settings_changed(&cfg);
392 }
393 while (++cfg.rec_format < REC_NUM_FORMATS);
394} /* enc_global_settings_reset */
395
396/* Apply new settings */
397void enc_global_settings_apply(void)
398{
399 struct encoder_config cfg;
400 if (!rec_format_ok(global_settings.rec_format))
401 global_settings.rec_format = REC_FORMAT_DEFAULT;
402
403 cfg.rec_format = global_settings.rec_format;
404 global_to_encoder_config(&cfg);
405 enc_rec_settings_changed(&cfg);
406 encoder_config_to_global(&cfg);
407} /* enc_global_settings_apply */
408
409/* Show an encoder's config menu based on the global_settings.
410 Modified settings are placed in global_settings.enc_config. */
411bool enc_global_config_menu(void)
412{
413 struct encoder_config cfg;
414
415 bool res;
416
417 if (!rec_format_ok(global_settings.rec_format))
418 global_settings.rec_format = REC_FORMAT_DEFAULT;
419
420 cfg.rec_format = global_settings.rec_format;
421
422 global_to_encoder_config(&cfg);
423
424 res = enc_config_menu(&cfg);
425 if (!res)
426 {
427 enc_rec_settings_changed(&cfg);
428 encoder_config_to_global(&cfg);
429 }
430
431 return res;
432} /* enc_global_config_menu */