1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
33 #include "statusbar.h"
36 #include "pcm_record.h"
37 #include "enc_config.h"
41 #define CALL_FN_(fn, ...) \
42 if (fn) fn(__VA_ARGS__)
44 static int enc_menuitem_callback(int action
,
45 const struct menu_item_ex
*this_item
);
46 static int enc_menuitem_enteritem(int action
,
47 const struct menu_item_ex
*this_item
);
48 static 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() */
51 static struct menucallback_data
{
52 struct encoder_config
*cfg
;
56 /** Function definitions for each codec - add these to enc_data
57 list following the definitions **/
59 /** aiff_enc.codec **/
62 /* mp3_enc: return encoder capabilities */
63 static void mp3_enc_get_caps(const struct encoder_config
*cfg
,
64 struct encoder_caps
*caps
,
72 /* Overall encoder capabilities */
73 caps
->samplerate_caps
= MPEG1_SAMPR_CAPS
| MPEG2_SAMPR_CAPS
;
74 caps
->channel_caps
= CHN_CAP_ALL
;
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
];
83 /* sample rate caps */
85 /* check if MPEG1 sample rates are available */
86 if ((bitr
>= 32 && bitr
<= 128) || bitr
>= 160)
87 caps
->samplerate_caps
|= MPEG1_SAMPR_CAPS
;
89 /* check if MPEG2 sample rates and mono are available */
92 caps
->samplerate_caps
|= MPEG2_SAMPR_CAPS
;
93 caps
->channel_caps
|= CHN_CAP_MONO
;
96 /* check if stereo is available */
98 caps
->channel_caps
|= CHN_CAP_STEREO
;
99 } /* mp3_enc_get_caps */
101 /* mp3_enc: return the default configuration */
102 static void mp3_enc_default_config(struct encoder_config
*cfg
)
104 cfg
->mp3_enc
.bitrate
= 128; /* default that works for all types */
105 } /* mp3_enc_default_config */
107 static void mp3_enc_convert_config(struct encoder_config
*cfg
,
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);
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
];
122 } /* mp3_enc_convert_config */
124 /* mp3_enc: show the bitrate setting options */
125 static bool mp3_enc_bitrate(struct menucallback_data
*data
)
127 struct encoder_config
*cfg
= data
->cfg
;
128 static const struct opt_items items
[] =
130 /* Available in MPEG Version: */
131 #ifdef HAVE_MPEG2_SAMPR
133 /* this sounds awful no matter what */
134 { "8 kBit/s", TALK_ID(8, UNIT_KBIT
) }, /* 2 */
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 */
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 */
155 { "160 kBit/s", TALK_ID(160, UNIT_KBIT
) }, /* 1,2 */
156 #ifdef HAVE_MPEG1_SAMPR
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 */
165 unsigned long rate_list
[ARRAYLEN(items
)];
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
,
172 #ifdef HAVE_MPEG1_SAMPR
175 #ifdef HAVE_MPEG2_SAMPR
176 #ifdef HAVE_MPEG1_SAMPR
177 | (MPEG2_BITR_CAPS
& ~(MP3_BITR_CAP_144
| MP3_BITR_CAP_8
))
179 | (MPEG2_BITR_CAPS
& ~(MP3_BITR_CAP_8
))
181 #endif /* HAVE_MPEG2_SAMPR */
184 int index
= round_value_to_list32(cfg
->mp3_enc
.bitrate
, rate_list
,
186 bool res
= set_option(str(LANG_BITRATE
), &index
, 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
];
193 } /* mp3_enc_bitrate */
195 /* mp3_enc configuration menu */
196 MENUITEM_FUNCTION(mp3_bitrate
, MENU_FUNC_USEPARAM
, ID2P(LANG_BITRATE
),
198 &menu_callback_data
, enc_menuitem_callback
, Icon_NOICON
);
199 MAKE_MENU( mp3_enc_menu
, ID2P(LANG_ENCODER_SETTINGS
),
200 enc_menuitem_enteritem
, Icon_NOICON
,
204 /** wav_enc.codec **/
205 /* wav_enc: show the configuration menu */
207 MAKE_MENU( wav_enc_menu
, ID2P(LANG_ENCODER_SETTINGS
),
208 enc_menuitem_enteritem
, Icon_NOICON
,
212 /** wavpack_enc.codec **/
213 /* wavpack_enc: show the configuration menu */
215 MAKE_MENU( wavpack_enc_menu
, ID2P(LANG_ENCODER_SETTINGS
),
216 enc_menuitem_enteritem
, Icon_NOICON
,
220 /** config function pointers and/or data for each codec **/
221 static const struct encoder_data
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
] =
231 [REC_FORMAT_AIFF
] = {
238 [REC_FORMAT_MPA_L3
] = {
240 mp3_enc_default_config
,
241 mp3_enc_convert_config
,
245 [REC_FORMAT_PCM_WAV
] = {
251 /* wavpack_enc.codec */
252 [REC_FORMAT_WAVPACK
] = {
260 static inline bool rec_format_ok(int rec_format
)
262 return (unsigned)rec_format
< REC_NUM_FORMATS
;
264 /* This is called before entering the menu with the encoder settings
265 Its needed to make sure the settings can take effect. */
266 static int enc_menuitem_enteritem(int action
,
267 const struct menu_item_ex
*this_item
)
270 /* this struct must be init'ed before calling do_menu() so this is safe */
271 struct menucallback_data
*data
= &menu_callback_data
;
272 if (action
== ACTION_STD_OK
) /* entering the item */
275 global_to_encoder_config(data
->cfg
);
279 /* this is called when a encoder setting is exited
280 It is used to update the status bar and save the setting */
281 static int enc_menuitem_callback(int action
,
282 const struct menu_item_ex
*this_item
)
284 struct menucallback_data
*data
=
285 (struct menucallback_data
*)this_item
->function
->param
;
287 if (action
== ACTION_EXIT_MENUITEM
)
289 /* If the setting being configured is global, it must be placed
290 in global_settings before updating the status bar for the
291 change to show upon exiting the item. */
294 enc_rec_settings_changed(data
->cfg
);
295 encoder_config_to_global(data
->cfg
);
298 gui_syncstatusbar_draw(&statusbars
, true);
303 /* update settings dependent upon encoder settings */
304 static void enc_rec_settings_changed(struct encoder_config
*cfg
)
306 struct encoder_config enc_config
;
307 struct encoder_caps caps
;
308 long table
[MAX(CHN_NUM_MODES
, REC_NUM_FREQ
)];
314 cfg
->rec_format
= global_settings
.rec_format
;
315 global_to_encoder_config(cfg
);
318 /* have to sync other settings when encoder settings change */
319 if (!enc_get_caps(cfg
, &caps
, true))
323 n
= make_list_from_caps32(CHN_CAP_ALL
, NULL
,
324 caps
.channel_caps
, table
);
326 /* no zero check needed: encoder must support at least one
327 sample rate that recording supports or it shouldn't be in
328 available in the recording options */
329 n
= round_value_to_list32(global_settings
.rec_channels
,
331 global_settings
.rec_channels
= table
[n
];
334 n
= make_list_from_caps32(REC_SAMPR_CAPS
, rec_freq_sampr
,
335 caps
.samplerate_caps
, table
);
337 n
= round_value_to_list32(
338 rec_freq_sampr
[global_settings
.rec_frequency
],
341 global_settings
.rec_frequency
= round_value_to_list32(
342 table
[n
], rec_freq_sampr
, REC_NUM_FREQ
, false);
343 } /* enc_rec_settings_changed */
346 void global_to_encoder_config(struct encoder_config
*cfg
)
348 const struct encoder_data
*data
= &enc_data
[cfg
->rec_format
];
349 CALL_FN_(data
->convert_cfg
, cfg
, false);
350 } /* global_to_encoder_config */
352 void encoder_config_to_global(const struct encoder_config
*cfg
)
354 const struct encoder_data
*data
= &enc_data
[cfg
->rec_format
];
355 CALL_FN_(data
->convert_cfg
, (struct encoder_config
*)cfg
, true);
356 } /* encoder_config_to_global */
358 bool enc_get_caps(const struct encoder_config
*cfg
,
359 struct encoder_caps
*caps
,
362 /* get_caps expects caps to be zeroed first */
363 memset(caps
, 0, sizeof (*caps
));
365 if (!rec_format_ok(cfg
->rec_format
))
368 if (enc_data
[cfg
->rec_format
].get_caps
)
370 enc_data
[cfg
->rec_format
].get_caps(cfg
, caps
, for_config
);
374 /* If no function provided...defaults to all */
375 caps
->samplerate_caps
= SAMPR_CAP_ALL
;
376 caps
->channel_caps
= CHN_CAP_ALL
;
382 /* Initializes the config struct with default values */
383 bool enc_init_config(struct encoder_config
*cfg
)
385 if (!rec_format_ok(cfg
->rec_format
))
387 CALL_FN_(enc_data
[cfg
->rec_format
].default_cfg
, cfg
);
389 } /* enc_init_config */
391 /** Encoder Menus **/
393 bool enc_config_menu(struct encoder_config
*cfg
)
395 if (!rec_format_ok(cfg
->rec_format
))
397 if (enc_data
[cfg
->rec_format
].menu
)
399 menu_callback_data
.cfg
= &cfg
;
400 menu_callback_data
.global
= false;
401 return do_menu(enc_data
[cfg
->rec_format
].menu
, NULL
, NULL
, false)
402 == MENU_ATTACHED_USB
;
406 gui_syncsplash(HZ
, str(LANG_NO_SETTINGS
));
409 } /* enc_config_menu */
412 /** Global Settings **/
414 /* Reset all codecs to defaults */
415 void enc_global_settings_reset(void)
417 struct encoder_config cfg
;
422 global_to_encoder_config(&cfg
);
423 enc_init_config(&cfg
);
424 encoder_config_to_global(&cfg
);
425 if (cfg
.rec_format
== global_settings
.rec_format
)
426 enc_rec_settings_changed(&cfg
);
428 while (++cfg
.rec_format
< REC_NUM_FORMATS
);
429 } /* enc_global_settings_reset */
431 /* Apply new settings */
432 void enc_global_settings_apply(void)
434 struct encoder_config cfg
;
435 if (!rec_format_ok(global_settings
.rec_format
))
436 global_settings
.rec_format
= REC_FORMAT_DEFAULT
;
438 cfg
.rec_format
= global_settings
.rec_format
;
439 global_to_encoder_config(&cfg
);
440 enc_rec_settings_changed(&cfg
);
441 encoder_config_to_global(&cfg
);
442 } /* enc_global_settings_apply */
444 /* Show an encoder's config menu based on the global_settings.
445 Modified settings are placed in global_settings.enc_config. */
446 bool enc_global_config_menu(void)
448 struct encoder_config cfg
;
450 if (!rec_format_ok(global_settings
.rec_format
))
451 global_settings
.rec_format
= REC_FORMAT_DEFAULT
;
453 cfg
.rec_format
= global_settings
.rec_format
;
455 if (enc_data
[cfg
.rec_format
].menu
)
457 menu_callback_data
.cfg
= &cfg
;
458 menu_callback_data
.global
= true;
459 return do_menu(enc_data
[cfg
.rec_format
].menu
, NULL
, NULL
, false)
460 == MENU_ATTACHED_USB
;
464 gui_syncsplash(HZ
, str(LANG_NO_SETTINGS
));
467 } /* enc_global_config_menu */