fix some small glitches for backup:
[Rockbox.git] / firmware / sound.c
blob45d3e4b1b6d076ef1a9e46550a2679ad87f933c2
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 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include "config.h"
23 #include "sound.h"
24 #include "logf.h"
25 #ifndef SIMULATOR
26 #include "i2c.h"
27 #include "mas.h"
28 #if CONFIG_CPU == PNX0101
29 #include "pnx0101.h"
30 #endif
31 #include "dac.h"
32 #include "system.h"
33 #if CONFIG_CODEC == SWCODEC
34 #include "pcm.h"
35 #endif
36 #endif
38 /* TODO
39 * find a nice way to handle 1.5db steps -> see wm8751 ifdef in sound_set_bass/treble
42 #if !defined(VOLUME_MIN) && !defined(VOLUME_MAX)
43 #warning define for VOLUME_MIN and VOLUME_MAX is missing
44 #define VOLUME_MIN -400
45 #define VOLUME_MAX 600
46 #endif
48 /* volume/balance/treble/bass interdependency main part */
49 #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
51 #ifndef SIMULATOR
52 extern bool audio_is_initialized;
54 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
55 extern unsigned long shadow_io_control_main;
56 extern unsigned shadow_codec_reg0;
57 #endif
58 #endif /* SIMULATOR */
60 #ifdef SIMULATOR
61 /* dummy for sim */
62 const struct sound_settings_info audiohw_settings[] = {
63 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
64 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
65 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
66 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
67 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
68 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
69 #if CONFIG_CODEC == MAS3587F || defined(HAVE_UDA1380) || defined(HAVE_TLV320)\
70 || defined(HAVE_WM8975) || defined(HAVE_WM8758) || defined(HAVE_WM8731)
71 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
72 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
73 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
74 #endif
75 #if defined(HAVE_WM8758)
76 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
77 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
78 #endif
79 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
80 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
81 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
82 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
83 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
84 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
85 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
86 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
87 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
88 #endif
90 #endif
92 const char *sound_unit(int setting)
94 return audiohw_settings[setting].unit;
97 int sound_numdecimals(int setting)
99 return audiohw_settings[setting].numdecimals;
102 int sound_steps(int setting)
104 return audiohw_settings[setting].steps;
107 int sound_min(int setting)
109 return audiohw_settings[setting].minval;
112 int sound_max(int setting)
114 return audiohw_settings[setting].maxval;
117 int sound_default(int setting)
119 return audiohw_settings[setting].defaultval;
122 sound_set_type* sound_get_fn(int setting)
124 sound_set_type* result = NULL;
126 switch (setting) {
127 case SOUND_VOLUME:
128 result = sound_set_volume;
129 break;
131 case SOUND_BASS:
132 result = sound_set_bass;
133 break;
135 case SOUND_TREBLE:
136 result = sound_set_treble;
137 break;
139 case SOUND_BALANCE:
140 result = sound_set_balance;
141 break;
143 case SOUND_CHANNELS:
144 result = sound_set_channels;
145 break;
147 case SOUND_STEREO_WIDTH:
148 result = sound_set_stereo_width;
149 break;
151 #ifdef HAVE_WM8758
152 case SOUND_BASS_CUTOFF:
153 result = sound_set_bass_cutoff;
154 break;
156 case SOUND_TREBLE_CUTOFF:
157 result = sound_set_treble_cutoff;
158 break;
159 #endif
161 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
162 case SOUND_LOUDNESS:
163 result = sound_set_loudness;
164 break;
166 case SOUND_AVC:
167 result = sound_set_avc;
168 break;
170 case SOUND_MDB_STRENGTH:
171 result = sound_set_mdb_strength;
172 break;
174 case SOUND_MDB_HARMONICS:
175 result = sound_set_mdb_harmonics;
176 break;
178 case SOUND_MDB_CENTER:
179 result = sound_set_mdb_center;
180 break;
182 case SOUND_MDB_SHAPE:
183 result = sound_set_mdb_shape;
184 break;
186 case SOUND_MDB_ENABLE:
187 result = sound_set_mdb_enable;
188 break;
190 case SOUND_SUPERBASS:
191 result = sound_set_superbass;
192 break;
193 #endif
196 return result;
199 #if CONFIG_CODEC == SWCODEC
200 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
201 enum {
202 DSP_CALLBACK_SET_PRESCALE = 0,
203 DSP_CALLBACK_SET_BASS,
204 DSP_CALLBACK_SET_TREBLE,
205 DSP_CALLBACK_SET_CHANNEL_CONFIG,
206 DSP_CALLBACK_SET_STEREO_WIDTH
209 static int (*dsp_callback)(int, intptr_t) = NULL;
211 void sound_set_dsp_callback(int (*func)(int, intptr_t))
213 dsp_callback = func;
215 #endif
217 #ifndef SIMULATOR
218 #if CONFIG_CODEC == MAS3507D
219 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
220 static int tenthdb2reg(int db)
222 if (db < -540) /* 3 dB steps */
223 return (db + 780) / 30;
224 else /* 1.5 dB steps */
225 return (db + 660) / 15;
227 #endif
230 /* MAS3587F and MAS3539F handle clipping prevention internally so we do not need
231 * the prescaler.
233 #if (CONFIG_CODEC != MAS3587F) && (CONFIG_CODEC != MAS3539F)
236 * The prescaler compensates for any kind of boosts, to prevent clipping.
238 * It's basically just a measure to make sure that audio does not clip during
239 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
240 * the audio amplitude by -12 dB before processing, then increase master gain
241 * by 12 dB after processing.
244 /* all values in tenth of dB MAS3507D UDA1380 */
245 int current_volume = 0; /* -780..+180 -840.. 0 */
246 int current_balance = 0; /* -960..+960 -840..+840 */
247 int current_treble = 0; /* -150..+150 0.. +60 */
248 int current_bass = 0; /* -150..+150 0..+240 */
250 static void set_prescaled_volume(void)
252 int prescale = 0;
253 int l, r;
255 /* The WM codecs listed don't have suitable prescaler functionality, so we let
256 * the prescaler stay at 0 for these unless SW tone controls are in use */
257 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
258 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
259 || defined(HAVE_WM8758) || defined(HAVE_WM8985)) || defined(HAVE_TSC2100)
261 prescale = MAX(current_bass, current_treble);
262 if (prescale < 0)
263 prescale = 0; /* no need to prescale if we don't boost
264 bass or treble */
266 /* Gain up the analog volume to compensate the prescale gain reduction,
267 * but if this would push the volume over the top, reduce prescaling
268 * instead (might cause clipping). */
269 if (current_volume + prescale > VOLUME_MAX)
270 prescale = VOLUME_MAX - current_volume;
271 #endif
273 #if defined(HAVE_SW_TONE_CONTROLS)
274 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
275 #elif CONFIG_CODEC == MAS3507D
276 mas_writereg(MAS_REG_KPRESCALE, prescale_table[prescale/10]);
277 #elif defined(HAVE_UDA1380)
278 audiohw_set_mixer_vol(tenthdb2mixer(-prescale), tenthdb2mixer(-prescale));
279 #endif
281 if (current_volume == VOLUME_MIN)
282 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
284 l = r = current_volume + prescale;
286 if (current_balance > 0)
288 l -= current_balance;
289 if (l < VOLUME_MIN)
290 l = VOLUME_MIN;
292 if (current_balance < 0)
294 r += current_balance;
295 if (r < VOLUME_MIN)
296 r = VOLUME_MIN;
299 #if CONFIG_CODEC == MAS3507D
300 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
301 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
302 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
303 || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
304 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
305 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
306 || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
307 || defined(HAVE_TSC2100)
308 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
309 #endif
311 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978)
312 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
313 #endif
315 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
316 #endif /* !SIMULATOR */
319 #ifndef SIMULATOR
321 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
322 unsigned long mdb_shape_shadow = 0;
323 unsigned long loudness_shadow = 0;
324 #endif
326 void sound_set_volume(int value)
328 if(!audio_is_initialized)
329 return;
330 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
331 unsigned tmp = ((unsigned)(value + 115) & 0xff) << 8;
332 mas_codec_writereg(0x10, tmp);
333 #elif (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 \
334 || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \
335 || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \
336 || defined(HAVE_AS3514) || defined(HAVE_WM8985) || defined(HAVE_TSC2100) \
337 || defined(HAVE_WM8978)
338 current_volume = value * 10; /* tenth of dB */
339 set_prescaled_volume();
340 #elif CONFIG_CPU == PNX0101
341 int tmp = (60 - value * 4) & 0xff;
342 CODECVOL = tmp | (tmp << 8);
343 #endif
344 (void)value;
347 void sound_set_balance(int value)
349 if(!audio_is_initialized)
350 return;
351 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
352 unsigned tmp = ((unsigned)(value * 127 / 100) & 0xff) << 8;
353 mas_codec_writereg(0x11, tmp);
354 #elif CONFIG_CODEC == MAS3507D || defined HAVE_UDA1380 \
355 || defined HAVE_WM8975 || defined HAVE_WM8758 || defined HAVE_WM8731 \
356 || defined(HAVE_WM8721) || defined(HAVE_TLV320) || defined(HAVE_WM8751) \
357 || defined(HAVE_AS3514) || defined(HAVE_WM8985) || defined(HAVE_TSC2100) \
358 || defined(HAVE_WM8978)
359 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
360 set_prescaled_volume();
361 #elif CONFIG_CPU == PNX0101
362 /* TODO: implement for iFP */
363 #endif
364 (void)value;
367 void sound_set_bass(int value)
369 if(!audio_is_initialized)
370 return;
372 #if defined(AUDIOHW_HAVE_BASS)
373 audiohw_set_bass(value);
374 #else
375 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
376 #endif
378 #if (CONFIG_CODEC != MAS3587F) && (CONFIG_CODEC != MAS3539F)
379 #if defined(HAVE_WM8751)
380 current_bass = value;
381 #else
382 current_bass = value * 10;
383 #endif
384 set_prescaled_volume();
385 #endif
388 void sound_set_treble(int value)
390 if(!audio_is_initialized)
391 return;
393 #if defined(AUDIOHW_HAVE_TREBLE)
394 audiohw_set_treble(value);
395 #else
396 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
397 #endif
399 #if (CONFIG_CODEC != MAS3587F) && (CONFIG_CODEC != MAS3539F)
400 #if defined(HAVE_WM8751)
401 current_treble = value;
402 #else
403 current_treble = value * 10;
404 #endif
405 set_prescaled_volume();
406 #endif
409 void sound_set_channels(int value)
411 if(!audio_is_initialized)
412 return;
414 #if CONFIG_CODEC == SWCODEC
415 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
416 #else
417 audiohw_set_channel(value);
418 #endif
421 void sound_set_stereo_width(int value)
423 if(!audio_is_initialized)
424 return;
426 #if CONFIG_CODEC == SWCODEC
427 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
428 #else
429 audiohw_set_stereo_width(value);
430 #endif
433 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
434 void sound_set_bass_cutoff(int value)
436 if(!audio_is_initialized)
437 return;
439 audiohw_set_bass_cutoff(value);
442 void sound_set_treble_cutoff(int value)
444 if(!audio_is_initialized)
445 return;
447 audiohw_set_treble_cutoff(value);
449 #endif
451 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
452 void sound_set_loudness(int value)
454 if(!audio_is_initialized)
455 return;
456 loudness_shadow = (loudness_shadow & 0x04) |
457 (MAX(MIN(value * 4, 0x44), 0) << 8);
458 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
461 void sound_set_avc(int value)
463 if(!audio_is_initialized)
464 return;
465 int tmp;
466 switch (value) {
467 case 1: /* 20ms */
468 tmp = (0x1 << 8) | (0x8 << 12);
469 break;
470 case 2: /* 2s */
471 tmp = (0x2 << 8) | (0x8 << 12);
472 break;
473 case 3: /* 4s */
474 tmp = (0x4 << 8) | (0x8 << 12);
475 break;
476 case 4: /* 8s */
477 tmp = (0x8 << 8) | (0x8 << 12);
478 break;
479 case -1: /* turn off and then turn on again to decay quickly */
480 tmp = mas_codec_readreg(MAS_REG_KAVC);
481 mas_codec_writereg(MAS_REG_KAVC, 0);
482 break;
483 default: /* off */
484 tmp = 0;
485 break;
487 mas_codec_writereg(MAS_REG_KAVC, tmp);
490 void sound_set_mdb_strength(int value)
492 if(!audio_is_initialized)
493 return;
494 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
497 void sound_set_mdb_harmonics(int value)
499 if(!audio_is_initialized)
500 return;
501 int tmp = value * 127 / 100;
502 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
505 void sound_set_mdb_center(int value)
507 if(!audio_is_initialized)
508 return;
509 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
512 void sound_set_mdb_shape(int value)
514 if(!audio_is_initialized)
515 return;
516 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
517 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
520 void sound_set_mdb_enable(int value)
522 if(!audio_is_initialized)
523 return;
524 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
525 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
528 void sound_set_superbass(int value)
530 if(!audio_is_initialized)
531 return;
532 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
533 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
535 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
537 #else /* SIMULATOR */
538 int sim_volume;
539 void sound_set_volume(int value)
541 /* 128 is SDL_MIX_MAXVOLUME */
542 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
545 void sound_set_balance(int value)
547 (void)value;
550 void sound_set_bass(int value)
552 (void)value;
555 void sound_set_treble(int value)
557 (void)value;
560 void sound_set_channels(int value)
562 (void)value;
565 void sound_set_stereo_width(int value)
567 (void)value;
570 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
571 void sound_set_loudness(int value)
573 (void)value;
576 void sound_set_avc(int value)
578 (void)value;
581 void sound_set_mdb_strength(int value)
583 (void)value;
586 void sound_set_mdb_harmonics(int value)
588 (void)value;
591 void sound_set_mdb_center(int value)
593 (void)value;
596 void sound_set_mdb_shape(int value)
598 (void)value;
601 void sound_set_mdb_enable(int value)
603 (void)value;
606 void sound_set_superbass(int value)
608 (void)value;
610 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
612 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
613 void sound_set_bass_cutoff(int value)
615 (void) value;
618 void sound_set_treble_cutoff(int value)
620 (void) value;
622 #endif /* HAVE_WM8758 */
624 #endif /* SIMULATOR */
626 void sound_set(int setting, int value)
628 sound_set_type* sound_set_val = sound_get_fn(setting);
629 if (sound_set_val)
630 sound_set_val(value);
633 #if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined(HAVE_TSC2100)) \
634 || defined(SIMULATOR)
635 int sound_val2phys(int setting, int value)
637 #if CONFIG_CODEC == MAS3587F
638 int result = 0;
640 switch(setting)
642 case SOUND_LEFT_GAIN:
643 case SOUND_RIGHT_GAIN:
644 result = (value - 2) * 15;
645 break;
647 case SOUND_MIC_GAIN:
648 result = value * 15 + 210;
649 break;
651 default:
652 result = value;
653 break;
655 return result;
656 #elif defined(HAVE_UDA1380)
657 int result = 0;
659 switch(setting)
661 case SOUND_LEFT_GAIN:
662 case SOUND_RIGHT_GAIN:
663 case SOUND_MIC_GAIN:
664 result = value * 5; /* (1/2) * 10 */
665 break;
667 default:
668 result = value;
669 break;
671 return result;
672 #elif defined(HAVE_TLV320) || defined(HAVE_WM8731)
673 int result = 0;
675 switch(setting)
677 case SOUND_LEFT_GAIN:
678 case SOUND_RIGHT_GAIN:
679 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
680 break;
682 case SOUND_MIC_GAIN:
683 result = value * 200; /* 0 or 20 dB */
684 break;
686 default:
687 result = value;
688 break;
690 return result;
691 #elif defined(HAVE_AS3514)
692 /* This is here for the sim only and the audio driver has its own */
693 int result;
695 switch(setting)
697 case SOUND_LEFT_GAIN:
698 case SOUND_RIGHT_GAIN:
699 case SOUND_MIC_GAIN:
700 result = (value - 23) * 15;
701 break;
703 default:
704 result = value;
705 break;
708 return result;
709 #else
710 (void)setting;
711 return value;
712 #endif
714 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
716 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
717 #ifndef SIMULATOR
718 /* This function works by telling the decoder that we have another
719 crystal frequency than we actually have. It will adjust its internal
720 parameters and the result is that the audio is played at another pitch.
722 The pitch value is in tenths of percent.
724 static int last_pitch = 1000;
726 void sound_set_pitch(int pitch)
728 unsigned long val;
730 if (pitch != last_pitch)
732 /* Calculate the new (bogus) frequency */
733 val = 18432 * 1000 / pitch;
735 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
737 /* We must tell the MAS that the frequency has changed.
738 * This will unfortunately cause a short silence. */
739 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
741 last_pitch = pitch;
745 int sound_get_pitch(void)
747 return last_pitch;
749 #else /* SIMULATOR */
750 void sound_set_pitch(int pitch)
752 (void)pitch;
755 int sound_get_pitch(void)
757 return 1000;
759 #endif /* SIMULATOR */
760 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */