blob: 864492669e5fd27f74c4075333e66f2167512326 [file] [log] [blame]
Michael Sevakis5efee7c2006-11-06 18:18:05 +00001/***************************************************************************
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"
Jonathan Gordoncaea20e2007-04-29 13:26:56 +000035#include "splash.h"
Michael Sevakis5efee7c2006-11-06 18:18:05 +000036
37#define MENU_ITEM_FN(fn) \
38 ((bool (*)(void))fn)
39
40#define ENC_MENU_ITEM_FN(fn) \
41 ((bool (*)(struct encoder_config *))fn)
42
43#define CALL_FN_(fn, ...) \
44 if (fn) fn(__VA_ARGS__)
45
46static bool enc_run_menu(int m, const struct menu_item items[],
Michael Sevakisc7a1cec2007-02-10 07:08:25 +000047 struct encoder_config *cfg, bool global);
Michael Sevakisc7a1cec2007-02-10 07:08:25 +000048static void enc_rec_settings_changed(struct encoder_config *cfg);
Michael Sevakis5efee7c2006-11-06 18:18:05 +000049
50/** Function definitions for each codec - add these to enc_data
51 list following the definitions **/
52
Michael Sevakis0729b922006-11-24 19:49:04 +000053/** aiff_enc.codec **/
54
Michael Sevakis5efee7c2006-11-06 18:18:05 +000055/** mp3_enc.codec **/
56/* mp3_enc: return encoder capabilities */
57static void mp3_enc_get_caps(const struct encoder_config *cfg,
58 struct encoder_caps *caps,
59 bool for_config)
60{
61 int i;
62 unsigned long bitr;
63
64 if (!for_config)
65 {
66 /* Overall encoder capabilities */
67 caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS;
68 caps->channel_caps = CHN_CAP_ALL;
69 return;
70 }
71
72 /* Restrict caps based on config */
73 i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
74 MP3_ENC_NUM_BITR, false);
75 bitr = mp3_enc_bitr[i];
76
77 /* sample rate caps */
78
79 /* check if MPEG1 sample rates are available */
80 if ((bitr >= 32 && bitr <= 128) || bitr >= 160)
81 caps->samplerate_caps |= MPEG1_SAMPR_CAPS;
82
83 /* check if MPEG2 sample rates and mono are available */
84 if (bitr <= 160)
85 {
86 caps->samplerate_caps |= MPEG2_SAMPR_CAPS;
87 caps->channel_caps |= CHN_CAP_MONO;
88 }
89
90 /* check if stereo is available */
91 if (bitr >= 32)
92 caps->channel_caps |= CHN_CAP_STEREO;
93} /* mp3_enc_get_caps */
94
95/* mp3_enc: return the default configuration */
96static void mp3_enc_default_config(struct encoder_config *cfg)
97{
98 cfg->mp3_enc.bitrate = 128; /* default that works for all types */
99} /* mp3_enc_default_config */
100
101static void mp3_enc_convert_config(struct encoder_config *cfg,
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000102 bool global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000103{
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000104 if (global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000105 {
106 global_settings.mp3_enc_config.bitrate =
107 round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
108 MP3_ENC_NUM_BITR, false);
109 }
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000110 else
111 {
112 if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
113 global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
114 cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
115 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000116} /* mp3_enc_convert_config */
117
118/* mp3_enc: show the bitrate setting options */
119static bool mp3_enc_bitrate(struct encoder_config *cfg)
120{
121 static const struct opt_items items[] =
122 {
123 /* Available in MPEG Version: */
124#ifdef HAVE_MPEG2_SAMPR
125#if 0
126 /* this sounds awful no matter what */
127 { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */
128#endif
129 /* mono only */
130 { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */
131 { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */
132#endif
133 /* stereo/mono */
134 { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */
135 { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */
136 { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */
137 { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */
138 { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */
139 { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */
140 { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */
141 { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */
142 { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */
143#if 0
144 /* oddball MPEG2-only rate stuck in the middle */
145 { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */
146#endif
147 { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */
148 /* stereo only */
149 { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */
150 { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */
151 { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */
152 { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */
153 };
154
155 unsigned long rate_list[ARRAYLEN(items)];
156
157 /* This is rather constant based upon the build but better than
158 storing and maintaining yet another list of numbers */
159 int n_rates = make_list_from_caps32(
160 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr,
161 MPEG1_BITR_CAPS
162#ifdef HAVE_MPEG2_SAMPR
Barry Wardelldf0dc222006-12-18 01:52:21 +0000163 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8))
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000164#endif
Barry Wardelldf0dc222006-12-18 01:52:21 +0000165 , rate_list);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000166
167 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
168 n_rates, false);
169 bool res = set_option(str(LANG_BITRATE), &index, INT,
170 items, n_rates, NULL);
171 index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
172 MP3_ENC_NUM_BITR, false);
173 cfg->mp3_enc.bitrate = mp3_enc_bitr[index];
174
175 return res;
176} /* mp3_enc_bitrate */
177
178/* mp3_enc: show the configuration menu */
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000179static bool mp3_enc_menu(struct encoder_config *cfg, bool global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000180{
181 static const struct menu_item items[] =
182 {
183 { ID2P(LANG_BITRATE), MENU_ITEM_FN(mp3_enc_bitrate) }
184 };
185
186 bool result;
187 int m = menu_init(items, ARRAYLEN(items), NULL, NULL, NULL, NULL);
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000188 result = enc_run_menu(m, items, cfg, global);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000189 menu_exit(m);
190 return result;
191} /* mp3_enc_menu */
192
193/** wav_enc.codec **/
194/* wav_enc: show the configuration menu */
195#if 0
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000196static bool wav_enc_menu(struct encoder_config *cfg, bool global);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000197#endif
198
199/** wavpack_enc.codec **/
200/* wavpack_enc: show the configuration menu */
201#if 0
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000202static bool wavpack_enc_menu(struct encoder_config *cfg, bool global);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000203#endif
204
205/** config function pointers and/or data for each codec **/
206static const struct encoder_data
207{
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000208 void (*get_caps)(const struct encoder_config *cfg,
209 struct encoder_caps *caps, bool for_config);
210 void (*default_cfg)(struct encoder_config *cfg);
211 void (*convert_cfg)(struct encoder_config *cfg , bool global);
212 bool (*menu)(struct encoder_config *cfg , bool global);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000213} enc_data[REC_NUM_FORMATS] =
214{
Michael Sevakis0729b922006-11-24 19:49:04 +0000215 /* aiff_enc.codec */
216 [REC_FORMAT_AIFF] = {
217 NULL,
218 NULL,
219 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000220 NULL,
Michael Sevakis0729b922006-11-24 19:49:04 +0000221 },
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000222 /* mp3_enc.codec */
223 [REC_FORMAT_MPA_L3] = {
224 mp3_enc_get_caps,
225 mp3_enc_default_config,
226 mp3_enc_convert_config,
227 mp3_enc_menu,
228 },
229 /* wav_enc.codec */
230 [REC_FORMAT_PCM_WAV] = {
231 NULL,
232 NULL,
233 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000234 NULL,
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000235 },
236 /* wavpack_enc.codec */
237 [REC_FORMAT_WAVPACK] = {
238 NULL,
239 NULL,
240 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000241 NULL,
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000242 },
243};
244
245static inline bool rec_format_ok(int rec_format)
246{
247 return (unsigned)rec_format < REC_NUM_FORMATS;
248}
249
250static bool enc_run_menu(int m, const struct menu_item items[],
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000251 struct encoder_config *cfg, bool global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000252{
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000253 while (1)
254 {
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000255 int selected = menu_show(m);
256
257 switch (selected)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000258 {
259 case MENU_SELECTED_EXIT:
260 return false;
261
262 case MENU_ATTACHED_USB:
263 return true;
264
265 default:
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000266 if (items[selected].function == NULL)
267 break;
268
269 /* If the setting being configured is global, it must be placed
270 in global_settings before updating the status bar for the
271 change to show upon exiting the item. */
272 if (global)
273 global_to_encoder_config(cfg);
274
275 if (ENC_MENU_ITEM_FN(items[selected].function)(cfg))
276 return true;
277
278 if (global)
279 {
280 enc_rec_settings_changed(cfg);
281 encoder_config_to_global(cfg);
282 }
283
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000284 gui_syncstatusbar_draw(&statusbars, true);
285 }
286 }
287} /* enc_run_menu */
288
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000289/* update settings dependent upon encoder settings */
290static void enc_rec_settings_changed(struct encoder_config *cfg)
291{
292 struct encoder_config enc_config;
293 struct encoder_caps caps;
294 long table[MAX(CHN_NUM_MODES, REC_NUM_FREQ)];
295 int n;
296
297 if (cfg == NULL)
298 {
299 cfg = &enc_config;
300 cfg->rec_format = global_settings.rec_format;
301 global_to_encoder_config(cfg);
302 }
303
304 /* have to sync other settings when encoder settings change */
305 if (!enc_get_caps(cfg, &caps, true))
306 return;
307
308 /* rec_channels */
309 n = make_list_from_caps32(CHN_CAP_ALL, NULL,
310 caps.channel_caps, table);
311
312 /* no zero check needed: encoder must support at least one
313 sample rate that recording supports or it shouldn't be in
314 available in the recording options */
315 n = round_value_to_list32(global_settings.rec_channels,
316 table, n, true);
317 global_settings.rec_channels = table[n];
318
319 /* rec_frequency */
320 n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
321 caps.samplerate_caps, table);
322
323 n = round_value_to_list32(
324 rec_freq_sampr[global_settings.rec_frequency],
325 table, n, false);
326
327 global_settings.rec_frequency = round_value_to_list32(
328 table[n], rec_freq_sampr, REC_NUM_FREQ, false);
329} /* enc_rec_settings_changed */
330
331/** public stuff **/
332void global_to_encoder_config(struct encoder_config *cfg)
333{
334 const struct encoder_data *data = &enc_data[cfg->rec_format];
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000335 CALL_FN_(data->convert_cfg, cfg, false);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000336} /* global_to_encoder_config */
337
338void encoder_config_to_global(const struct encoder_config *cfg)
339{
340 const struct encoder_data *data = &enc_data[cfg->rec_format];
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000341 CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, true);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000342} /* encoder_config_to_global */
343
344bool enc_get_caps(const struct encoder_config *cfg,
345 struct encoder_caps *caps,
346 bool for_config)
347{
348 /* get_caps expects caps to be zeroed first */
349 memset(caps, 0, sizeof (*caps));
350
351 if (!rec_format_ok(cfg->rec_format))
352 return false;
353
354 if (enc_data[cfg->rec_format].get_caps)
355 {
356 enc_data[cfg->rec_format].get_caps(cfg, caps, for_config);
357 }
358 else
359 {
360 /* If no function provided...defaults to all */
361 caps->samplerate_caps = SAMPR_CAP_ALL;
362 caps->channel_caps = CHN_CAP_ALL;
363 }
364
365 return true;
366} /* enc_get_caps */
367
368/* Initializes the config struct with default values */
369bool enc_init_config(struct encoder_config *cfg)
370{
371 if (!rec_format_ok(cfg->rec_format))
372 return false;
373 CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg);
374 return true;
375} /* enc_init_config */
376
377/** Encoder Menus **/
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000378#if 0
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000379bool enc_config_menu(struct encoder_config *cfg)
380{
381 if (!rec_format_ok(cfg->rec_format))
382 return false;
Jonathan Gordon9270ada2007-04-29 13:33:15 +0000383 if (enc_data[cfg->rec_format].menu)
384 {
385 return enc_data[cfg->rec_format].menu(cfg, false);
386 }
387 else
388 {
389 gui_syncsplash(HZ, str(LANG_NO_SETTINGS));
390 return false;
391 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000392} /* enc_config_menu */
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000393#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000394
395/** Global Settings **/
396
397/* Reset all codecs to defaults */
398void enc_global_settings_reset(void)
399{
400 struct encoder_config cfg;
401 cfg.rec_format = 0;
402
403 do
404 {
405 global_to_encoder_config(&cfg);
406 enc_init_config(&cfg);
407 encoder_config_to_global(&cfg);
408 if (cfg.rec_format == global_settings.rec_format)
409 enc_rec_settings_changed(&cfg);
410 }
411 while (++cfg.rec_format < REC_NUM_FORMATS);
412} /* enc_global_settings_reset */
413
414/* Apply new settings */
415void enc_global_settings_apply(void)
416{
417 struct encoder_config cfg;
418 if (!rec_format_ok(global_settings.rec_format))
419 global_settings.rec_format = REC_FORMAT_DEFAULT;
420
421 cfg.rec_format = global_settings.rec_format;
422 global_to_encoder_config(&cfg);
423 enc_rec_settings_changed(&cfg);
424 encoder_config_to_global(&cfg);
425} /* enc_global_settings_apply */
426
427/* Show an encoder's config menu based on the global_settings.
428 Modified settings are placed in global_settings.enc_config. */
429bool enc_global_config_menu(void)
430{
431 struct encoder_config cfg;
432
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000433 if (!rec_format_ok(global_settings.rec_format))
434 global_settings.rec_format = REC_FORMAT_DEFAULT;
435
436 cfg.rec_format = global_settings.rec_format;
437
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000438 if (enc_data[cfg.rec_format].menu)
439 {
440 return enc_data[cfg.rec_format].menu(&cfg, true);
441 }
442 else
443 {
444 gui_syncsplash(HZ, str(LANG_NO_SETTINGS));
445 return false;
446 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000447} /* enc_global_config_menu */