blob: 07405cdac191d805bea308693d53c9e4d81ce8ab [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 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Michael Sevakis5efee7c2006-11-06 18:18:05 +000016 *
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>
Michael Sevakis5efee7c2006-11-06 18:18:05 +000022#include <string.h>
Bertrik Sikken28434692008-04-28 16:18:04 +000023#include <stdlib.h>
Michael Sevakis5efee7c2006-11-06 18:18:05 +000024#include "config.h"
Jonathan Gordon4eaddc32007-04-29 15:02:09 +000025#include "action.h"
Michael Sevakis5efee7c2006-11-06 18:18:05 +000026#include "lang.h"
27#include "misc.h"
28#include "talk.h"
29#include "general.h"
30#include "codecs.h"
31#include "menu.h"
Michael Sevakis5efee7c2006-11-06 18:18:05 +000032#include "settings.h"
33#include "audio.h"
34#include "pcm_record.h"
35#include "enc_config.h"
Jonathan Gordoncaea20e2007-04-29 13:26:56 +000036#include "splash.h"
Michael Sevakis5efee7c2006-11-06 18:18:05 +000037
Michael Sevakis5efee7c2006-11-06 18:18:05 +000038
39#define CALL_FN_(fn, ...) \
40 if (fn) fn(__VA_ARGS__)
41
Jonathan Gordon4eaddc32007-04-29 15:02:09 +000042static int enc_menuitem_callback(int action,
43 const struct menu_item_ex *this_item);
44static int enc_menuitem_enteritem(int action,
45 const struct menu_item_ex *this_item);
Michael Sevakisc7a1cec2007-02-10 07:08:25 +000046static void enc_rec_settings_changed(struct encoder_config *cfg);
Jonathan Gordon4eaddc32007-04-29 15:02:09 +000047/* this is used by all encoder menu items,
48 MUST be initialised before the call to do_menu() */
Bertrik Sikkendb2d61f2008-04-20 10:24:15 +000049static struct menucallback_data {
Jonathan Gordon4eaddc32007-04-29 15:02:09 +000050 struct encoder_config *cfg;
51 bool global;
52} menu_callback_data;
Michael Sevakis5efee7c2006-11-06 18:18:05 +000053
54/** Function definitions for each codec - add these to enc_data
55 list following the definitions **/
56
Michael Sevakis0729b922006-11-24 19:49:04 +000057/** aiff_enc.codec **/
58
Michael Sevakis5efee7c2006-11-06 18:18:05 +000059/** mp3_enc.codec **/
60/* mp3_enc: return encoder capabilities */
61static void mp3_enc_get_caps(const struct encoder_config *cfg,
62 struct encoder_caps *caps,
63 bool for_config)
64{
65 int i;
66 unsigned long bitr;
67
68 if (!for_config)
69 {
70 /* Overall encoder capabilities */
71 caps->samplerate_caps = MPEG1_SAMPR_CAPS | MPEG2_SAMPR_CAPS;
72 caps->channel_caps = CHN_CAP_ALL;
73 return;
74 }
75
76 /* Restrict caps based on config */
77 i = round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
78 MP3_ENC_NUM_BITR, false);
79 bitr = mp3_enc_bitr[i];
80
81 /* sample rate caps */
82
83 /* check if MPEG1 sample rates are available */
84 if ((bitr >= 32 && bitr <= 128) || bitr >= 160)
85 caps->samplerate_caps |= MPEG1_SAMPR_CAPS;
86
87 /* check if MPEG2 sample rates and mono are available */
88 if (bitr <= 160)
89 {
90 caps->samplerate_caps |= MPEG2_SAMPR_CAPS;
91 caps->channel_caps |= CHN_CAP_MONO;
92 }
93
94 /* check if stereo is available */
95 if (bitr >= 32)
96 caps->channel_caps |= CHN_CAP_STEREO;
97} /* mp3_enc_get_caps */
98
99/* mp3_enc: return the default configuration */
100static void mp3_enc_default_config(struct encoder_config *cfg)
101{
102 cfg->mp3_enc.bitrate = 128; /* default that works for all types */
103} /* mp3_enc_default_config */
104
105static void mp3_enc_convert_config(struct encoder_config *cfg,
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000106 bool global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000107{
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000108 if (global)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000109 {
110 global_settings.mp3_enc_config.bitrate =
111 round_value_to_list32(cfg->mp3_enc.bitrate, mp3_enc_bitr,
112 MP3_ENC_NUM_BITR, false);
113 }
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000114 else
115 {
116 if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
117 global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
118 cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
119 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000120} /* mp3_enc_convert_config */
121
122/* mp3_enc: show the bitrate setting options */
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000123static bool mp3_enc_bitrate(struct menucallback_data *data)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000124{
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000125 struct encoder_config *cfg = data->cfg;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000126 static const struct opt_items items[] =
127 {
128 /* Available in MPEG Version: */
129#ifdef HAVE_MPEG2_SAMPR
130#if 0
131 /* this sounds awful no matter what */
132 { "8 kBit/s", TALK_ID(8, UNIT_KBIT) }, /* 2 */
133#endif
134 /* mono only */
135 { "16 kBit/s", TALK_ID(16, UNIT_KBIT) }, /* 2 */
136 { "24 kBit/s", TALK_ID(24, UNIT_KBIT) }, /* 2 */
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000137#endif /* HAVE_MPEG2_SAMPR */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000138 /* stereo/mono */
139 { "32 kBit/s", TALK_ID(32, UNIT_KBIT) }, /* 1,2 */
140 { "40 kBit/s", TALK_ID(40, UNIT_KBIT) }, /* 1,2 */
141 { "48 kBit/s", TALK_ID(48, UNIT_KBIT) }, /* 1,2 */
142 { "56 kBit/s", TALK_ID(56, UNIT_KBIT) }, /* 1,2 */
143 { "64 kBit/s", TALK_ID(64, UNIT_KBIT) }, /* 1,2 */
144 { "80 kBit/s", TALK_ID(80, UNIT_KBIT) }, /* 1,2 */
145 { "96 kBit/s", TALK_ID(96, UNIT_KBIT) }, /* 1,2 */
146 { "112 kBit/s", TALK_ID(112, UNIT_KBIT) }, /* 1,2 */
147 { "128 kBit/s", TALK_ID(128, UNIT_KBIT) }, /* 1,2 */
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000148 /* Leave out 144 when there is both MPEG 1 and 2 */
149#if defined(HAVE_MPEG2_SAMPR) && !defined (HAVE_MPEG1_SAMPR)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000150 /* oddball MPEG2-only rate stuck in the middle */
151 { "144 kBit/s", TALK_ID(144, UNIT_KBIT) }, /* 2 */
152#endif
153 { "160 kBit/s", TALK_ID(160, UNIT_KBIT) }, /* 1,2 */
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000154#ifdef HAVE_MPEG1_SAMPR
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000155 /* stereo only */
156 { "192 kBit/s", TALK_ID(192, UNIT_KBIT) }, /* 1 */
157 { "224 kBit/s", TALK_ID(224, UNIT_KBIT) }, /* 1 */
158 { "256 kBit/s", TALK_ID(256, UNIT_KBIT) }, /* 1 */
159 { "320 kBit/s", TALK_ID(320, UNIT_KBIT) }, /* 1 */
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000160#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000161 };
162
163 unsigned long rate_list[ARRAYLEN(items)];
164
165 /* This is rather constant based upon the build but better than
166 storing and maintaining yet another list of numbers */
167 int n_rates = make_list_from_caps32(
168 MPEG1_BITR_CAPS | MPEG2_BITR_CAPS, mp3_enc_bitr,
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000169 0
170#ifdef HAVE_MPEG1_SAMPR
171 | MPEG1_BITR_CAPS
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000172#endif
Michael Sevakiseae3a6a2007-06-06 21:24:20 +0000173#ifdef HAVE_MPEG2_SAMPR
174#ifdef HAVE_MPEG1_SAMPR
175 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_144 | MP3_BITR_CAP_8))
176#else
177 | (MPEG2_BITR_CAPS & ~(MP3_BITR_CAP_8))
178#endif
179#endif /* HAVE_MPEG2_SAMPR */
Barry Wardelldf0dc222006-12-18 01:52:21 +0000180 , rate_list);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000181
182 int index = round_value_to_list32(cfg->mp3_enc.bitrate, rate_list,
183 n_rates, false);
184 bool res = set_option(str(LANG_BITRATE), &index, INT,
185 items, n_rates, NULL);
186 index = round_value_to_list32(rate_list[index], mp3_enc_bitr,
187 MP3_ENC_NUM_BITR, false);
188 cfg->mp3_enc.bitrate = mp3_enc_bitr[index];
189
190 return res;
191} /* mp3_enc_bitrate */
192
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000193/* mp3_enc configuration menu */
194MENUITEM_FUNCTION(mp3_bitrate, MENU_FUNC_USEPARAM, ID2P(LANG_BITRATE),
195 mp3_enc_bitrate,
196 &menu_callback_data, enc_menuitem_callback, Icon_NOICON);
197MAKE_MENU( mp3_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
198 enc_menuitem_enteritem, Icon_NOICON,
199 &mp3_bitrate);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000200
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000201
202/** wav_enc.codec **/
203/* wav_enc: show the configuration menu */
204#if 0
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000205MAKE_MENU( wav_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
206 enc_menuitem_enteritem, Icon_NOICON,
207 );
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000208#endif
209
210/** wavpack_enc.codec **/
211/* wavpack_enc: show the configuration menu */
212#if 0
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000213MAKE_MENU( wavpack_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
214 enc_menuitem_enteritem, Icon_NOICON,
215 );
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000216#endif
217
218/** config function pointers and/or data for each codec **/
219static const struct encoder_data
220{
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000221 void (*get_caps)(const struct encoder_config *cfg,
222 struct encoder_caps *caps, bool for_config);
223 void (*default_cfg)(struct encoder_config *cfg);
224 void (*convert_cfg)(struct encoder_config *cfg , bool global);
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000225 const struct menu_item_ex *menu;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000226} enc_data[REC_NUM_FORMATS] =
227{
Michael Sevakis0729b922006-11-24 19:49:04 +0000228 /* aiff_enc.codec */
229 [REC_FORMAT_AIFF] = {
230 NULL,
231 NULL,
232 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000233 NULL,
Michael Sevakis0729b922006-11-24 19:49:04 +0000234 },
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000235 /* mp3_enc.codec */
236 [REC_FORMAT_MPA_L3] = {
237 mp3_enc_get_caps,
238 mp3_enc_default_config,
239 mp3_enc_convert_config,
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000240 &mp3_enc_menu,
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000241 },
242 /* wav_enc.codec */
243 [REC_FORMAT_PCM_WAV] = {
244 NULL,
245 NULL,
246 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000247 NULL,
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000248 },
249 /* wavpack_enc.codec */
250 [REC_FORMAT_WAVPACK] = {
251 NULL,
252 NULL,
253 NULL,
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000254 NULL,
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000255 },
256};
257
258static inline bool rec_format_ok(int rec_format)
259{
260 return (unsigned)rec_format < REC_NUM_FORMATS;
261}
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000262/* This is called before entering the menu with the encoder settings
263 Its needed to make sure the settings can take effect. */
264static int enc_menuitem_enteritem(int action,
265 const struct menu_item_ex *this_item)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000266{
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000267 (void)this_item;
268 /* this struct must be init'ed before calling do_menu() so this is safe */
269 struct menucallback_data *data = &menu_callback_data;
270 if (action == ACTION_STD_OK) /* entering the item */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000271 {
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000272 if (data->global)
273 global_to_encoder_config(data->cfg);
274 }
275 return action;
276}
277/* this is called when a encoder setting is exited
278 It is used to update the status bar and save the setting */
279static int enc_menuitem_callback(int action,
280 const struct menu_item_ex *this_item)
281{
282 struct menucallback_data *data =
283 (struct menucallback_data*)this_item->function->param;
284
285 if (action == ACTION_EXIT_MENUITEM)
286 {
287 /* If the setting being configured is global, it must be placed
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000288 in global_settings before updating the status bar for the
289 change to show upon exiting the item. */
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000290 if (data->global)
291 {
292 enc_rec_settings_changed(data->cfg);
293 encoder_config_to_global(data->cfg);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000294 }
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000295
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000296 }
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000297 return action;
298}
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000299
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000300/* update settings dependent upon encoder settings */
301static void enc_rec_settings_changed(struct encoder_config *cfg)
302{
303 struct encoder_config enc_config;
304 struct encoder_caps caps;
Nils Wallménius4c046d02010-12-20 20:56:22 +0000305 long table[MAX((int)CHN_NUM_MODES, (int)REC_NUM_FREQ)];
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000306 int n;
307
308 if (cfg == NULL)
309 {
310 cfg = &enc_config;
311 cfg->rec_format = global_settings.rec_format;
312 global_to_encoder_config(cfg);
313 }
314
315 /* have to sync other settings when encoder settings change */
316 if (!enc_get_caps(cfg, &caps, true))
317 return;
318
319 /* rec_channels */
320 n = make_list_from_caps32(CHN_CAP_ALL, NULL,
321 caps.channel_caps, table);
322
323 /* no zero check needed: encoder must support at least one
324 sample rate that recording supports or it shouldn't be in
325 available in the recording options */
326 n = round_value_to_list32(global_settings.rec_channels,
327 table, n, true);
328 global_settings.rec_channels = table[n];
329
330 /* rec_frequency */
331 n = make_list_from_caps32(REC_SAMPR_CAPS, rec_freq_sampr,
332 caps.samplerate_caps, table);
333
334 n = round_value_to_list32(
335 rec_freq_sampr[global_settings.rec_frequency],
336 table, n, false);
337
338 global_settings.rec_frequency = round_value_to_list32(
339 table[n], rec_freq_sampr, REC_NUM_FREQ, false);
340} /* enc_rec_settings_changed */
341
342/** public stuff **/
343void global_to_encoder_config(struct encoder_config *cfg)
344{
345 const struct encoder_data *data = &enc_data[cfg->rec_format];
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000346 CALL_FN_(data->convert_cfg, cfg, false);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000347} /* global_to_encoder_config */
348
349void encoder_config_to_global(const struct encoder_config *cfg)
350{
351 const struct encoder_data *data = &enc_data[cfg->rec_format];
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000352 CALL_FN_(data->convert_cfg, (struct encoder_config *)cfg, true);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000353} /* encoder_config_to_global */
354
355bool enc_get_caps(const struct encoder_config *cfg,
356 struct encoder_caps *caps,
357 bool for_config)
358{
359 /* get_caps expects caps to be zeroed first */
360 memset(caps, 0, sizeof (*caps));
361
362 if (!rec_format_ok(cfg->rec_format))
363 return false;
364
365 if (enc_data[cfg->rec_format].get_caps)
366 {
367 enc_data[cfg->rec_format].get_caps(cfg, caps, for_config);
368 }
369 else
370 {
371 /* If no function provided...defaults to all */
372 caps->samplerate_caps = SAMPR_CAP_ALL;
373 caps->channel_caps = CHN_CAP_ALL;
374 }
375
376 return true;
377} /* enc_get_caps */
378
379/* Initializes the config struct with default values */
380bool enc_init_config(struct encoder_config *cfg)
381{
382 if (!rec_format_ok(cfg->rec_format))
383 return false;
384 CALL_FN_(enc_data[cfg->rec_format].default_cfg, cfg);
385 return true;
386} /* enc_init_config */
387
388/** Encoder Menus **/
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000389#if 0
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000390bool enc_config_menu(struct encoder_config *cfg)
391{
392 if (!rec_format_ok(cfg->rec_format))
393 return false;
Jonathan Gordon9270ada2007-04-29 13:33:15 +0000394 if (enc_data[cfg->rec_format].menu)
395 {
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000396 menu_callback_data.cfg = &cfg;
397 menu_callback_data.global = false;
Jonathan Gordon5ca15392008-03-26 03:35:24 +0000398 return do_menu(enc_data[cfg->rec_format].menu, NULL, NULL, false)
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000399 == MENU_ATTACHED_USB;
Jonathan Gordon9270ada2007-04-29 13:33:15 +0000400 }
401 else
402 {
Jonathan Gordon3af1bf02010-05-20 14:15:11 +0000403 splash(HZ, ID2P(LANG_NO_SETTINGS));
Jonathan Gordon9270ada2007-04-29 13:33:15 +0000404 return false;
405 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000406} /* enc_config_menu */
Michael Sevakisc7a1cec2007-02-10 07:08:25 +0000407#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000408
409/** Global Settings **/
410
411/* Reset all codecs to defaults */
412void enc_global_settings_reset(void)
413{
414 struct encoder_config cfg;
415 cfg.rec_format = 0;
416
417 do
418 {
419 global_to_encoder_config(&cfg);
420 enc_init_config(&cfg);
421 encoder_config_to_global(&cfg);
422 if (cfg.rec_format == global_settings.rec_format)
423 enc_rec_settings_changed(&cfg);
424 }
425 while (++cfg.rec_format < REC_NUM_FORMATS);
426} /* enc_global_settings_reset */
427
428/* Apply new settings */
429void enc_global_settings_apply(void)
430{
431 struct encoder_config cfg;
432 if (!rec_format_ok(global_settings.rec_format))
433 global_settings.rec_format = REC_FORMAT_DEFAULT;
434
435 cfg.rec_format = global_settings.rec_format;
436 global_to_encoder_config(&cfg);
437 enc_rec_settings_changed(&cfg);
438 encoder_config_to_global(&cfg);
439} /* enc_global_settings_apply */
440
441/* Show an encoder's config menu based on the global_settings.
442 Modified settings are placed in global_settings.enc_config. */
443bool enc_global_config_menu(void)
444{
445 struct encoder_config cfg;
446
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000447 if (!rec_format_ok(global_settings.rec_format))
448 global_settings.rec_format = REC_FORMAT_DEFAULT;
449
450 cfg.rec_format = global_settings.rec_format;
451
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000452 if (enc_data[cfg.rec_format].menu)
453 {
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000454 menu_callback_data.cfg = &cfg;
455 menu_callback_data.global = true;
Jonathan Gordon5ca15392008-03-26 03:35:24 +0000456 return do_menu(enc_data[cfg.rec_format].menu, NULL, NULL, false)
Jonathan Gordon4eaddc32007-04-29 15:02:09 +0000457 == MENU_ATTACHED_USB;
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000458 }
459 else
460 {
Jonathan Gordon3af1bf02010-05-20 14:15:11 +0000461 splash(HZ, ID2P(LANG_NO_SETTINGS));
Jonathan Gordoncaea20e2007-04-29 13:26:56 +0000462 return false;
463 }
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000464} /* enc_global_config_menu */