Merge the "Replaygain Off" option into the replaygain type; eliminate the "On/Off...
[kugel-rb/myfork.git] / firmware / sound.c
blobbca98b039ce10313f99ff343d566c7cc75538d8c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 by Linus Nielsen Feltzing
11 * Copyright (C) 2007 by Christian Gmeiner
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include <stdbool.h>
23 #include <stdio.h>
24 #include "config.h"
25 #include "sound.h"
26 #include "logf.h"
27 #include "system.h"
28 #ifndef SIMULATOR
29 #include "i2c.h"
30 #include "mas.h"
31 #if CONFIG_CPU == PNX0101
32 #include "pnx0101.h"
33 #endif
34 #include "dac.h"
35 #if CONFIG_CODEC == SWCODEC
36 #include "pcm.h"
37 #endif
38 #endif
40 /* TODO
41 * find a nice way to handle 1.5db steps -> see wm8751 ifdef in sound_set_bass/treble
44 #define ONE_DB 10
46 #if !defined(VOLUME_MIN) && !defined(VOLUME_MAX)
47 #warning define for VOLUME_MIN and VOLUME_MAX is missing
48 #define VOLUME_MIN -700
49 #define VOLUME_MAX 0
50 #endif
52 /* volume/balance/treble/bass interdependency main part */
53 #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
55 #ifndef SIMULATOR
56 extern bool audio_is_initialized;
58 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
59 extern unsigned long shadow_io_control_main;
60 extern unsigned shadow_codec_reg0;
61 #endif
62 #endif /* SIMULATOR */
64 #ifdef SIMULATOR
65 /* dummy for sim */
66 const struct sound_settings_info audiohw_settings[] = {
67 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
68 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
69 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
70 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
71 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
72 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
73 #if defined(HAVE_RECORDING)
74 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
75 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
76 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
77 #endif
78 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
79 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
80 #endif
81 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
82 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
83 #endif
84 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
85 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
86 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
87 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
88 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
89 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
90 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
91 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
92 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
93 #endif
95 #endif
97 const char *sound_unit(int setting)
99 return audiohw_settings[setting].unit;
102 int sound_numdecimals(int setting)
104 return audiohw_settings[setting].numdecimals;
107 int sound_steps(int setting)
109 return audiohw_settings[setting].steps;
112 int sound_min(int setting)
114 return audiohw_settings[setting].minval;
117 int sound_max(int setting)
119 return audiohw_settings[setting].maxval;
122 int sound_default(int setting)
124 return audiohw_settings[setting].defaultval;
127 static sound_set_type *sound_set_fns[] =
129 [0 ... SOUND_LAST_SETTING-1] = NULL,
130 [SOUND_VOLUME] = sound_set_volume,
131 [SOUND_BASS] = sound_set_bass,
132 [SOUND_TREBLE] = sound_set_treble,
133 [SOUND_BALANCE] = sound_set_balance,
134 [SOUND_CHANNELS] = sound_set_channels,
135 [SOUND_STEREO_WIDTH] = sound_set_stereo_width,
136 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
137 [SOUND_LOUDNESS] = sound_set_loudness,
138 [SOUND_AVC] = sound_set_avc,
139 [SOUND_MDB_STRENGTH] = sound_set_mdb_strength,
140 [SOUND_MDB_HARMONICS] = sound_set_mdb_harmonics,
141 [SOUND_MDB_CENTER] = sound_set_mdb_center,
142 [SOUND_MDB_SHAPE] = sound_set_mdb_shape,
143 [SOUND_MDB_ENABLE] = sound_set_mdb_enable,
144 [SOUND_SUPERBASS] = sound_set_superbass,
145 #endif
146 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
147 [SOUND_BASS_CUTOFF] = sound_set_bass_cutoff,
148 #endif
149 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
150 [SOUND_TREBLE_CUTOFF] = sound_set_treble_cutoff,
151 #endif
154 sound_set_type* sound_get_fn(int setting)
156 return ((unsigned)setting >= ARRAYLEN(sound_set_fns)?
157 NULL : sound_set_fns[setting]);
160 #if CONFIG_CODEC == SWCODEC
161 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
162 enum {
163 DSP_CALLBACK_SET_PRESCALE = 0,
164 DSP_CALLBACK_SET_BASS,
165 DSP_CALLBACK_SET_TREBLE,
166 DSP_CALLBACK_SET_CHANNEL_CONFIG,
167 DSP_CALLBACK_SET_STEREO_WIDTH
170 static int (*dsp_callback)(int, intptr_t) = NULL;
172 void sound_set_dsp_callback(int (*func)(int, intptr_t))
174 dsp_callback = func;
176 #endif
178 #ifndef SIMULATOR
179 #if CONFIG_CODEC == MAS3507D
180 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
181 static int tenthdb2reg(int db)
183 if (db < -540) /* 3 dB steps */
184 return (db + 780) / 30;
185 else /* 1.5 dB steps */
186 return (db + 660) / 15;
188 #endif
191 #if !defined(AUDIOHW_HAVE_CLIPPING)
193 * The prescaler compensates for any kind of boosts, to prevent clipping.
195 * It's basically just a measure to make sure that audio does not clip during
196 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
197 * the audio amplitude by -12 dB before processing, then increase master gain
198 * by 12 dB after processing.
201 /* all values in tenth of dB MAS3507D UDA1380 */
202 int current_volume = 0; /* -780..+180 -840.. 0 */
203 int current_balance = 0; /* -960..+960 -840..+840 */
204 int current_treble = 0; /* -150..+150 0.. +60 */
205 int current_bass = 0; /* -150..+150 0..+240 */
207 static void set_prescaled_volume(void)
209 int prescale = 0;
210 int l, r;
212 /* The WM codecs listed don't have suitable prescaler functionality, so we let
213 * the prescaler stay at 0 for these unless SW tone controls are in use */
214 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
215 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
216 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
217 || defined(HAVE_TSC2100)
219 prescale = MAX(current_bass, current_treble);
220 if (prescale < 0)
221 prescale = 0; /* no need to prescale if we don't boost
222 bass or treble */
224 /* Gain up the analog volume to compensate the prescale gain reduction,
225 * but if this would push the volume over the top, reduce prescaling
226 * instead (might cause clipping). */
227 if (current_volume + prescale > VOLUME_MAX)
228 prescale = VOLUME_MAX - current_volume;
229 #endif
231 #if defined(AUDIOHW_HAVE_PRESCALER)
232 audiohw_set_prescaler(prescale);
233 #else
234 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
235 #endif
237 if (current_volume == VOLUME_MIN)
238 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
240 l = r = current_volume + prescale;
242 /* Balance the channels scaled by the current volume and min volume. */
243 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
244 if (current_balance > 0)
246 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
248 else if (current_balance < 0)
250 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
253 #if CONFIG_CODEC == MAS3507D
254 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
255 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
256 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
257 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100) \
258 || defined(HAVE_AK4537)
259 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
260 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
261 || (defined(HAVE_WM8751) && !defined(MROBE_100)) || defined(HAVE_WM8985)
262 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
263 #endif
265 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
266 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
267 #elif defined(HAVE_JZ4740_CODEC)
268 audiohw_set_volume(current_volume);
269 #endif
271 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
272 #endif /* !SIMULATOR */
275 #ifndef SIMULATOR
277 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
278 unsigned long mdb_shape_shadow = 0;
279 unsigned long loudness_shadow = 0;
280 #endif
282 void sound_set_volume(int value)
284 if(!audio_is_initialized)
285 return;
287 #if defined(AUDIOHW_HAVE_CLIPPING)
288 audiohw_set_volume(value);
289 #elif CONFIG_CPU == PNX0101
290 int tmp = (60 - value * 4) & 0xff;
291 CODECVOL = tmp | (tmp << 8);
292 #else
293 current_volume = value * 10; /* tenth of dB */
294 set_prescaled_volume();
295 #endif
298 void sound_set_balance(int value)
300 if(!audio_is_initialized)
301 return;
303 #ifdef AUDIOHW_HAVE_BALANCE
304 audiohw_set_balance(value);
305 #else
306 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
307 set_prescaled_volume();
308 #endif
311 void sound_set_bass(int value)
313 if(!audio_is_initialized)
314 return;
316 #if !defined(AUDIOHW_HAVE_CLIPPING)
317 #if defined(HAVE_WM8751)
318 current_bass = value;
319 #else
320 current_bass = value * 10;
321 #endif
322 #endif
324 #if defined(AUDIOHW_HAVE_BASS)
325 audiohw_set_bass(value);
326 #else
327 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
328 #endif
330 #if !defined(AUDIOHW_HAVE_CLIPPING)
331 set_prescaled_volume();
332 #endif
335 void sound_set_treble(int value)
337 if(!audio_is_initialized)
338 return;
340 #if !defined(AUDIOHW_HAVE_CLIPPING)
341 #if defined(HAVE_WM8751)
342 current_treble = value;
343 #else
344 current_treble = value * 10;
345 #endif
346 #endif
348 #if defined(AUDIOHW_HAVE_TREBLE)
349 audiohw_set_treble(value);
350 #else
351 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
352 #endif
354 #if !defined(AUDIOHW_HAVE_CLIPPING)
355 set_prescaled_volume();
356 #endif
359 void sound_set_channels(int value)
361 if(!audio_is_initialized)
362 return;
364 #if CONFIG_CODEC == SWCODEC
365 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
366 #else
367 audiohw_set_channel(value);
368 #endif
371 void sound_set_stereo_width(int value)
373 if(!audio_is_initialized)
374 return;
376 #if CONFIG_CODEC == SWCODEC
377 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
378 #else
379 audiohw_set_stereo_width(value);
380 #endif
383 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
384 void sound_set_bass_cutoff(int value)
386 if(!audio_is_initialized)
387 return;
389 audiohw_set_bass_cutoff(value);
391 #endif
393 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
394 void sound_set_treble_cutoff(int value)
396 if(!audio_is_initialized)
397 return;
399 audiohw_set_treble_cutoff(value);
401 #endif
403 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
404 void sound_set_loudness(int value)
406 if(!audio_is_initialized)
407 return;
408 loudness_shadow = (loudness_shadow & 0x04) |
409 (MAX(MIN(value * 4, 0x44), 0) << 8);
410 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
413 void sound_set_avc(int value)
415 if(!audio_is_initialized)
416 return;
417 int tmp;
419 static const uint16_t avc_vals[] =
421 (0x1 << 8) | (0x8 << 12), /* 20ms */
422 (0x2 << 8) | (0x8 << 12), /* 2s */
423 (0x4 << 8) | (0x8 << 12), /* 4s */
424 (0x8 << 8) | (0x8 << 12), /* 8s */
426 switch (value) {
427 case 1:
428 case 2:
429 case 3:
430 case 4:
431 tmp = avc_vals[value -1];
432 break;
433 case -1: /* turn off and then turn on again to decay quickly */
434 tmp = mas_codec_readreg(MAS_REG_KAVC);
435 mas_codec_writereg(MAS_REG_KAVC, 0);
436 break;
437 default: /* off */
438 tmp = 0;
439 break;
441 mas_codec_writereg(MAS_REG_KAVC, tmp);
444 void sound_set_mdb_strength(int value)
446 if(!audio_is_initialized)
447 return;
448 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
451 void sound_set_mdb_harmonics(int value)
453 if(!audio_is_initialized)
454 return;
455 int tmp = value * 127 / 100;
456 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
459 void sound_set_mdb_center(int value)
461 if(!audio_is_initialized)
462 return;
463 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
466 void sound_set_mdb_shape(int value)
468 if(!audio_is_initialized)
469 return;
470 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
471 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
474 void sound_set_mdb_enable(int value)
476 if(!audio_is_initialized)
477 return;
478 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
479 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
482 void sound_set_superbass(int value)
484 if(!audio_is_initialized)
485 return;
486 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
487 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
489 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
491 #else /* SIMULATOR */
492 int sim_volume;
493 void sound_set_volume(int value)
495 /* 128 is SDL_MIX_MAXVOLUME */
496 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
499 void sound_set_balance(int value)
501 (void)value;
504 void sound_set_bass(int value)
506 (void)value;
509 void sound_set_treble(int value)
511 (void)value;
514 void sound_set_channels(int value)
516 (void)value;
519 void sound_set_stereo_width(int value)
521 (void)value;
524 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
525 void sound_set_loudness(int value)
527 (void)value;
530 void sound_set_avc(int value)
532 (void)value;
535 void sound_set_mdb_strength(int value)
537 (void)value;
540 void sound_set_mdb_harmonics(int value)
542 (void)value;
545 void sound_set_mdb_center(int value)
547 (void)value;
550 void sound_set_mdb_shape(int value)
552 (void)value;
555 void sound_set_mdb_enable(int value)
557 (void)value;
560 void sound_set_superbass(int value)
562 (void)value;
564 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
566 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
567 void sound_set_bass_cutoff(int value)
569 (void) value;
572 void sound_set_treble_cutoff(int value)
574 (void) value;
576 #endif /* HAVE_WM8758 */
578 #endif /* SIMULATOR */
580 void sound_set(int setting, int value)
582 sound_set_type* sound_set_val = sound_get_fn(setting);
583 if (sound_set_val)
584 sound_set_val(value);
587 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
588 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
589 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
590 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
591 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
592 int sound_val2phys(int setting, int value)
594 #if CONFIG_CODEC == MAS3587F
595 int result = 0;
597 switch(setting)
599 case SOUND_LEFT_GAIN:
600 case SOUND_RIGHT_GAIN:
601 result = (value - 2) * 15;
602 break;
604 case SOUND_MIC_GAIN:
605 result = value * 15 + 210;
606 break;
608 default:
609 result = value;
610 break;
612 return result;
613 #elif defined(HAVE_UDA1380)
614 int result = 0;
616 switch(setting)
618 case SOUND_LEFT_GAIN:
619 case SOUND_RIGHT_GAIN:
620 case SOUND_MIC_GAIN:
621 result = value * 5; /* (1/2) * 10 */
622 break;
624 default:
625 result = value;
626 break;
628 return result;
629 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
630 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
631 int result = 0;
633 switch(setting)
635 #ifdef HAVE_RECORDING
636 case SOUND_LEFT_GAIN:
637 case SOUND_RIGHT_GAIN:
638 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
639 break;
641 case SOUND_MIC_GAIN:
642 result = value * 200; /* 0 or 20 dB */
643 break;
644 #endif
645 default:
646 result = value;
647 break;
649 return result;
650 #elif defined(HAVE_AS3514)
651 /* This is here for the sim only and the audio driver has its own */
652 int result;
654 switch(setting)
656 #ifdef HAVE_RECORDING
657 case SOUND_LEFT_GAIN:
658 case SOUND_RIGHT_GAIN:
659 case SOUND_MIC_GAIN:
660 result = (value - 23) * 15;
661 break;
662 #endif
663 default:
664 result = value;
665 break;
668 return result;
669 #elif defined(HAVE_WM8978)
670 int result;
672 switch (setting)
674 #ifdef HAVE_RECORDING
675 case SOUND_LEFT_GAIN:
676 case SOUND_RIGHT_GAIN:
677 case SOUND_MIC_GAIN:
678 result = value * 5;
679 break;
680 #endif
682 default:
683 result = value;
686 return result;
687 #else
688 (void)setting;
689 return value;
690 #endif
692 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
694 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
695 #ifndef SIMULATOR
696 /* This function works by telling the decoder that we have another
697 crystal frequency than we actually have. It will adjust its internal
698 parameters and the result is that the audio is played at another pitch.
700 The pitch value is in tenths of percent.
702 static int last_pitch = 1000;
704 void sound_set_pitch(int pitch)
706 unsigned long val;
708 if (pitch != last_pitch)
710 /* Calculate the new (bogus) frequency */
711 val = 18432 * 1000 / pitch;
713 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
715 /* We must tell the MAS that the frequency has changed.
716 * This will unfortunately cause a short silence. */
717 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
719 last_pitch = pitch;
723 int sound_get_pitch(void)
725 return last_pitch;
727 #else /* SIMULATOR */
728 void sound_set_pitch(int pitch)
730 (void)pitch;
733 int sound_get_pitch(void)
735 return 1000;
737 #endif /* SIMULATOR */
738 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */