More feature designation corrections
[kugel-rb.git] / firmware / sound.c
blobd66a93a70d97433c97082f58227f777b3dfd1ec8
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 * const 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 static int (*dsp_callback)(int, intptr_t) = NULL;
163 void sound_set_dsp_callback(int (*func)(int, intptr_t))
165 dsp_callback = func;
167 #endif
169 #ifndef SIMULATOR
170 #if CONFIG_CODEC == MAS3507D
171 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
172 static int tenthdb2reg(int db)
174 if (db < -540) /* 3 dB steps */
175 return (db + 780) / 30;
176 else /* 1.5 dB steps */
177 return (db + 660) / 15;
179 #endif
182 #if !defined(AUDIOHW_HAVE_CLIPPING)
184 * The prescaler compensates for any kind of boosts, to prevent clipping.
186 * It's basically just a measure to make sure that audio does not clip during
187 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
188 * the audio amplitude by -12 dB before processing, then increase master gain
189 * by 12 dB after processing.
192 /* all values in tenth of dB MAS3507D UDA1380 */
193 int current_volume = 0; /* -780..+180 -840.. 0 */
194 int current_balance = 0; /* -960..+960 -840..+840 */
195 int current_treble = 0; /* -150..+150 0.. +60 */
196 int current_bass = 0; /* -150..+150 0..+240 */
198 static void set_prescaled_volume(void)
200 int prescale = 0;
201 int l, r;
203 /* The WM codecs listed don't have suitable prescaler functionality, so we let
204 * the prescaler stay at 0 for these unless SW tone controls are in use */
205 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
206 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
207 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
208 || defined(HAVE_TSC2100) || defined(HAVE_UDA1341)
210 prescale = MAX(current_bass, current_treble);
211 if (prescale < 0)
212 prescale = 0; /* no need to prescale if we don't boost
213 bass or treble */
215 /* Gain up the analog volume to compensate the prescale gain reduction,
216 * but if this would push the volume over the top, reduce prescaling
217 * instead (might cause clipping). */
218 if (current_volume + prescale > VOLUME_MAX)
219 prescale = VOLUME_MAX - current_volume;
220 #endif
222 #if defined(AUDIOHW_HAVE_PRESCALER)
223 audiohw_set_prescaler(prescale);
224 #else
225 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
226 #endif
228 if (current_volume == VOLUME_MIN)
229 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
231 l = r = current_volume + prescale;
233 /* Balance the channels scaled by the current volume and min volume. */
234 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
235 if (current_balance > 0)
237 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
239 else if (current_balance < 0)
241 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
244 #ifdef HAVE_SW_VOLUME_CONTROL
245 dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0);
246 #endif
248 #if CONFIG_CODEC == MAS3507D
249 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
250 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
251 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
252 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100) \
253 || defined(HAVE_AK4537) || defined(HAVE_UDA1341)
254 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
255 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
256 || (defined(HAVE_WM8751) && !defined(MROBE_100)) || defined(HAVE_WM8985)
257 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
258 #endif
260 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
261 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
262 #elif defined(HAVE_JZ4740_CODEC)
263 audiohw_set_volume(current_volume);
264 #endif
266 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
267 #endif /* !SIMULATOR */
270 #ifndef SIMULATOR
272 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
273 unsigned long mdb_shape_shadow = 0;
274 unsigned long loudness_shadow = 0;
275 #endif
277 void sound_set_volume(int value)
279 if(!audio_is_initialized)
280 return;
282 #if defined(AUDIOHW_HAVE_CLIPPING)
283 audiohw_set_volume(value);
284 #elif CONFIG_CPU == PNX0101
285 int tmp = (60 - value * 4) & 0xff;
286 CODECVOL = tmp | (tmp << 8);
287 #else
288 current_volume = value * 10; /* tenth of dB */
289 set_prescaled_volume();
290 #endif
293 void sound_set_balance(int value)
295 if(!audio_is_initialized)
296 return;
298 #ifdef AUDIOHW_HAVE_BALANCE
299 audiohw_set_balance(value);
300 #else
301 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
302 set_prescaled_volume();
303 #endif
306 void sound_set_bass(int value)
308 if(!audio_is_initialized)
309 return;
311 #if !defined(AUDIOHW_HAVE_CLIPPING)
312 #if defined(HAVE_WM8751)
313 current_bass = value;
314 #else
315 current_bass = value * 10;
316 #endif
317 #endif
319 #if defined(AUDIOHW_HAVE_BASS)
320 audiohw_set_bass(value);
321 #else
322 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
323 #endif
325 #if !defined(AUDIOHW_HAVE_CLIPPING)
326 set_prescaled_volume();
327 #endif
330 void sound_set_treble(int value)
332 if(!audio_is_initialized)
333 return;
335 #if !defined(AUDIOHW_HAVE_CLIPPING)
336 #if defined(HAVE_WM8751)
337 current_treble = value;
338 #else
339 current_treble = value * 10;
340 #endif
341 #endif
343 #if defined(AUDIOHW_HAVE_TREBLE)
344 audiohw_set_treble(value);
345 #else
346 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
347 #endif
349 #if !defined(AUDIOHW_HAVE_CLIPPING)
350 set_prescaled_volume();
351 #endif
354 void sound_set_channels(int value)
356 if(!audio_is_initialized)
357 return;
359 #if CONFIG_CODEC == SWCODEC
360 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
361 #else
362 audiohw_set_channel(value);
363 #endif
366 void sound_set_stereo_width(int value)
368 if(!audio_is_initialized)
369 return;
371 #if CONFIG_CODEC == SWCODEC
372 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
373 #else
374 audiohw_set_stereo_width(value);
375 #endif
378 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
379 void sound_set_bass_cutoff(int value)
381 if(!audio_is_initialized)
382 return;
384 audiohw_set_bass_cutoff(value);
386 #endif
388 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
389 void sound_set_treble_cutoff(int value)
391 if(!audio_is_initialized)
392 return;
394 audiohw_set_treble_cutoff(value);
396 #endif
398 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
399 void sound_set_loudness(int value)
401 if(!audio_is_initialized)
402 return;
403 loudness_shadow = (loudness_shadow & 0x04) |
404 (MAX(MIN(value * 4, 0x44), 0) << 8);
405 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
408 void sound_set_avc(int value)
410 if(!audio_is_initialized)
411 return;
412 int tmp;
414 static const uint16_t avc_vals[] =
416 (0x1 << 8) | (0x8 << 12), /* 20ms */
417 (0x2 << 8) | (0x8 << 12), /* 2s */
418 (0x4 << 8) | (0x8 << 12), /* 4s */
419 (0x8 << 8) | (0x8 << 12), /* 8s */
421 switch (value) {
422 case 1:
423 case 2:
424 case 3:
425 case 4:
426 tmp = avc_vals[value -1];
427 break;
428 case -1: /* turn off and then turn on again to decay quickly */
429 tmp = mas_codec_readreg(MAS_REG_KAVC);
430 mas_codec_writereg(MAS_REG_KAVC, 0);
431 break;
432 default: /* off */
433 tmp = 0;
434 break;
436 mas_codec_writereg(MAS_REG_KAVC, tmp);
439 void sound_set_mdb_strength(int value)
441 if(!audio_is_initialized)
442 return;
443 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
446 void sound_set_mdb_harmonics(int value)
448 if(!audio_is_initialized)
449 return;
450 int tmp = value * 127 / 100;
451 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
454 void sound_set_mdb_center(int value)
456 if(!audio_is_initialized)
457 return;
458 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
461 void sound_set_mdb_shape(int value)
463 if(!audio_is_initialized)
464 return;
465 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
466 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
469 void sound_set_mdb_enable(int value)
471 if(!audio_is_initialized)
472 return;
473 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
474 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
477 void sound_set_superbass(int value)
479 if(!audio_is_initialized)
480 return;
481 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
482 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
484 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
486 #else /* SIMULATOR */
487 int sim_volume;
488 void sound_set_volume(int value)
490 /* 128 is SDL_MIX_MAXVOLUME */
491 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
494 void sound_set_balance(int value)
496 (void)value;
499 void sound_set_bass(int value)
501 (void)value;
504 void sound_set_treble(int value)
506 (void)value;
509 void sound_set_channels(int value)
511 (void)value;
514 void sound_set_stereo_width(int value)
516 (void)value;
519 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
520 void sound_set_loudness(int value)
522 (void)value;
525 void sound_set_avc(int value)
527 (void)value;
530 void sound_set_mdb_strength(int value)
532 (void)value;
535 void sound_set_mdb_harmonics(int value)
537 (void)value;
540 void sound_set_mdb_center(int value)
542 (void)value;
545 void sound_set_mdb_shape(int value)
547 (void)value;
550 void sound_set_mdb_enable(int value)
552 (void)value;
555 void sound_set_superbass(int value)
557 (void)value;
559 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
561 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
562 void sound_set_bass_cutoff(int value)
564 (void) value;
567 void sound_set_treble_cutoff(int value)
569 (void) value;
571 #endif /* HAVE_WM8758 */
573 #endif /* SIMULATOR */
575 void sound_set(int setting, int value)
577 sound_set_type* sound_set_val = sound_get_fn(setting);
578 if (sound_set_val)
579 sound_set_val(value);
582 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
583 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
584 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
585 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
586 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
587 int sound_val2phys(int setting, int value)
589 #if CONFIG_CODEC == MAS3587F
590 int result = 0;
592 switch(setting)
594 case SOUND_LEFT_GAIN:
595 case SOUND_RIGHT_GAIN:
596 result = (value - 2) * 15;
597 break;
599 case SOUND_MIC_GAIN:
600 result = value * 15 + 210;
601 break;
603 default:
604 result = value;
605 break;
607 return result;
608 #elif defined(HAVE_UDA1380)
609 int result = 0;
611 switch(setting)
613 #ifdef HAVE_RECORDING
614 case SOUND_LEFT_GAIN:
615 case SOUND_RIGHT_GAIN:
616 case SOUND_MIC_GAIN:
617 result = value * 5; /* (1/2) * 10 */
618 break;
619 #endif
620 default:
621 result = value;
622 break;
624 return result;
625 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
626 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
627 int result = 0;
629 switch(setting)
631 #ifdef HAVE_RECORDING
632 case SOUND_LEFT_GAIN:
633 case SOUND_RIGHT_GAIN:
634 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
635 break;
637 case SOUND_MIC_GAIN:
638 result = value * 200; /* 0 or 20 dB */
639 break;
640 #endif
641 default:
642 result = value;
643 break;
645 return result;
646 #elif defined(HAVE_AS3514)
647 /* This is here for the sim only and the audio driver has its own */
648 int result;
650 switch(setting)
652 #ifdef HAVE_RECORDING
653 case SOUND_LEFT_GAIN:
654 case SOUND_RIGHT_GAIN:
655 case SOUND_MIC_GAIN:
656 result = (value - 23) * 15;
657 break;
658 #endif
659 default:
660 result = value;
661 break;
664 return result;
665 #elif defined(HAVE_WM8978)
666 int result;
668 switch (setting)
670 #ifdef HAVE_RECORDING
671 case SOUND_LEFT_GAIN:
672 case SOUND_RIGHT_GAIN:
673 case SOUND_MIC_GAIN:
674 result = value * 5;
675 break;
676 #endif
678 default:
679 result = value;
682 return result;
683 #else
684 (void)setting;
685 return value;
686 #endif
688 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
690 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
691 #ifndef SIMULATOR
692 /* This function works by telling the decoder that we have another
693 crystal frequency than we actually have. It will adjust its internal
694 parameters and the result is that the audio is played at another pitch.
696 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
698 static int last_pitch = PITCH_SPEED_100;
700 void sound_set_pitch(int32_t pitch)
702 unsigned long val;
704 if (pitch != last_pitch)
706 /* Calculate the new (bogus) frequency */
707 val = 18432 * PITCH_SPEED_100 / pitch;
709 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
711 /* We must tell the MAS that the frequency has changed.
712 * This will unfortunately cause a short silence. */
713 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
715 last_pitch = pitch;
719 int32_t sound_get_pitch(void)
721 return last_pitch;
723 #else /* SIMULATOR */
724 void sound_set_pitch(int32_t pitch)
726 (void)pitch;
729 int32_t sound_get_pitch(void)
731 return PITCH_SPEED_100;
733 #endif /* SIMULATOR */
734 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */