Doom: re-add the missing modulus operation I removed in r22097
[kugel-rb.git] / firmware / sound.c
blob84ccd2b1bd75fd06dc1a46f12f693a5bc086a080
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 */
163 enum {
164 DSP_CALLBACK_SET_PRESCALE = 0,
165 DSP_CALLBACK_SET_BASS,
166 DSP_CALLBACK_SET_TREBLE,
167 DSP_CALLBACK_SET_CHANNEL_CONFIG,
168 DSP_CALLBACK_SET_STEREO_WIDTH
171 static int (*dsp_callback)(int, intptr_t) = NULL;
173 void sound_set_dsp_callback(int (*func)(int, intptr_t))
175 dsp_callback = func;
177 #endif
179 #ifndef SIMULATOR
180 #if CONFIG_CODEC == MAS3507D
181 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
182 static int tenthdb2reg(int db)
184 if (db < -540) /* 3 dB steps */
185 return (db + 780) / 30;
186 else /* 1.5 dB steps */
187 return (db + 660) / 15;
189 #endif
192 #if !defined(AUDIOHW_HAVE_CLIPPING)
194 * The prescaler compensates for any kind of boosts, to prevent clipping.
196 * It's basically just a measure to make sure that audio does not clip during
197 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
198 * the audio amplitude by -12 dB before processing, then increase master gain
199 * by 12 dB after processing.
202 /* all values in tenth of dB MAS3507D UDA1380 */
203 int current_volume = 0; /* -780..+180 -840.. 0 */
204 int current_balance = 0; /* -960..+960 -840..+840 */
205 int current_treble = 0; /* -150..+150 0.. +60 */
206 int current_bass = 0; /* -150..+150 0..+240 */
208 static void set_prescaled_volume(void)
210 int prescale = 0;
211 int l, r;
213 /* The WM codecs listed don't have suitable prescaler functionality, so we let
214 * the prescaler stay at 0 for these unless SW tone controls are in use */
215 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
216 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
217 || defined(HAVE_WM8751) || defined(HAVE_WM8758) || defined(HAVE_WM8985)) \
218 || defined(HAVE_TSC2100)
220 prescale = MAX(current_bass, current_treble);
221 if (prescale < 0)
222 prescale = 0; /* no need to prescale if we don't boost
223 bass or treble */
225 /* Gain up the analog volume to compensate the prescale gain reduction,
226 * but if this would push the volume over the top, reduce prescaling
227 * instead (might cause clipping). */
228 if (current_volume + prescale > VOLUME_MAX)
229 prescale = VOLUME_MAX - current_volume;
230 #endif
232 #if defined(AUDIOHW_HAVE_PRESCALER)
233 audiohw_set_prescaler(prescale);
234 #else
235 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
236 #endif
238 if (current_volume == VOLUME_MIN)
239 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
241 l = r = current_volume + prescale;
243 /* Balance the channels scaled by the current volume and min volume. */
244 /* Subtract a dB from VOLUME_MIN to get it to a mute level */
245 if (current_balance > 0)
247 l -= ((l - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
249 else if (current_balance < 0)
251 r += ((r - (VOLUME_MIN - ONE_DB)) * current_balance) / VOLUME_RANGE;
254 #if CONFIG_CODEC == MAS3507D
255 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
256 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
257 || defined(HAVE_WM8711) || defined(HAVE_WM8721) || defined(HAVE_WM8731) \
258 || defined(HAVE_WM8751) || defined(HAVE_AS3514) || defined(HAVE_TSC2100) \
259 || defined(HAVE_AK4537)
260 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
261 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
262 || (defined(HAVE_WM8751) && !defined(MROBE_100)) || defined(HAVE_WM8985)
263 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
264 #endif
266 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978) || defined(HAVE_WM8985)
267 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
268 #elif defined(HAVE_JZ4740_CODEC)
269 audiohw_set_volume(current_volume);
270 #endif
272 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
273 #endif /* !SIMULATOR */
276 #ifndef SIMULATOR
278 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
279 unsigned long mdb_shape_shadow = 0;
280 unsigned long loudness_shadow = 0;
281 #endif
283 void sound_set_volume(int value)
285 if(!audio_is_initialized)
286 return;
288 #if defined(AUDIOHW_HAVE_CLIPPING)
289 audiohw_set_volume(value);
290 #elif CONFIG_CPU == PNX0101
291 int tmp = (60 - value * 4) & 0xff;
292 CODECVOL = tmp | (tmp << 8);
293 #else
294 current_volume = value * 10; /* tenth of dB */
295 set_prescaled_volume();
296 #endif
299 void sound_set_balance(int value)
301 if(!audio_is_initialized)
302 return;
304 #ifdef AUDIOHW_HAVE_BALANCE
305 audiohw_set_balance(value);
306 #else
307 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
308 set_prescaled_volume();
309 #endif
312 void sound_set_bass(int value)
314 if(!audio_is_initialized)
315 return;
317 #if !defined(AUDIOHW_HAVE_CLIPPING)
318 #if defined(HAVE_WM8751)
319 current_bass = value;
320 #else
321 current_bass = value * 10;
322 #endif
323 #endif
325 #if defined(AUDIOHW_HAVE_BASS)
326 audiohw_set_bass(value);
327 #else
328 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
329 #endif
331 #if !defined(AUDIOHW_HAVE_CLIPPING)
332 set_prescaled_volume();
333 #endif
336 void sound_set_treble(int value)
338 if(!audio_is_initialized)
339 return;
341 #if !defined(AUDIOHW_HAVE_CLIPPING)
342 #if defined(HAVE_WM8751)
343 current_treble = value;
344 #else
345 current_treble = value * 10;
346 #endif
347 #endif
349 #if defined(AUDIOHW_HAVE_TREBLE)
350 audiohw_set_treble(value);
351 #else
352 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
353 #endif
355 #if !defined(AUDIOHW_HAVE_CLIPPING)
356 set_prescaled_volume();
357 #endif
360 void sound_set_channels(int value)
362 if(!audio_is_initialized)
363 return;
365 #if CONFIG_CODEC == SWCODEC
366 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
367 #else
368 audiohw_set_channel(value);
369 #endif
372 void sound_set_stereo_width(int value)
374 if(!audio_is_initialized)
375 return;
377 #if CONFIG_CODEC == SWCODEC
378 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
379 #else
380 audiohw_set_stereo_width(value);
381 #endif
384 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
385 void sound_set_bass_cutoff(int value)
387 if(!audio_is_initialized)
388 return;
390 audiohw_set_bass_cutoff(value);
392 #endif
394 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
395 void sound_set_treble_cutoff(int value)
397 if(!audio_is_initialized)
398 return;
400 audiohw_set_treble_cutoff(value);
402 #endif
404 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
405 void sound_set_loudness(int value)
407 if(!audio_is_initialized)
408 return;
409 loudness_shadow = (loudness_shadow & 0x04) |
410 (MAX(MIN(value * 4, 0x44), 0) << 8);
411 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
414 void sound_set_avc(int value)
416 if(!audio_is_initialized)
417 return;
418 int tmp;
420 static const uint16_t avc_vals[] =
422 (0x1 << 8) | (0x8 << 12), /* 20ms */
423 (0x2 << 8) | (0x8 << 12), /* 2s */
424 (0x4 << 8) | (0x8 << 12), /* 4s */
425 (0x8 << 8) | (0x8 << 12), /* 8s */
427 switch (value) {
428 case 1:
429 case 2:
430 case 3:
431 case 4:
432 tmp = avc_vals[value -1];
433 break;
434 case -1: /* turn off and then turn on again to decay quickly */
435 tmp = mas_codec_readreg(MAS_REG_KAVC);
436 mas_codec_writereg(MAS_REG_KAVC, 0);
437 break;
438 default: /* off */
439 tmp = 0;
440 break;
442 mas_codec_writereg(MAS_REG_KAVC, tmp);
445 void sound_set_mdb_strength(int value)
447 if(!audio_is_initialized)
448 return;
449 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
452 void sound_set_mdb_harmonics(int value)
454 if(!audio_is_initialized)
455 return;
456 int tmp = value * 127 / 100;
457 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
460 void sound_set_mdb_center(int value)
462 if(!audio_is_initialized)
463 return;
464 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
467 void sound_set_mdb_shape(int value)
469 if(!audio_is_initialized)
470 return;
471 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
472 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
475 void sound_set_mdb_enable(int value)
477 if(!audio_is_initialized)
478 return;
479 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
480 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
483 void sound_set_superbass(int value)
485 if(!audio_is_initialized)
486 return;
487 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
488 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
490 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
492 #else /* SIMULATOR */
493 int sim_volume;
494 void sound_set_volume(int value)
496 /* 128 is SDL_MIX_MAXVOLUME */
497 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
500 void sound_set_balance(int value)
502 (void)value;
505 void sound_set_bass(int value)
507 (void)value;
510 void sound_set_treble(int value)
512 (void)value;
515 void sound_set_channels(int value)
517 (void)value;
520 void sound_set_stereo_width(int value)
522 (void)value;
525 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
526 void sound_set_loudness(int value)
528 (void)value;
531 void sound_set_avc(int value)
533 (void)value;
536 void sound_set_mdb_strength(int value)
538 (void)value;
541 void sound_set_mdb_harmonics(int value)
543 (void)value;
546 void sound_set_mdb_center(int value)
548 (void)value;
551 void sound_set_mdb_shape(int value)
553 (void)value;
556 void sound_set_mdb_enable(int value)
558 (void)value;
561 void sound_set_superbass(int value)
563 (void)value;
565 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
567 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
568 void sound_set_bass_cutoff(int value)
570 (void) value;
573 void sound_set_treble_cutoff(int value)
575 (void) value;
577 #endif /* HAVE_WM8758 */
579 #endif /* SIMULATOR */
581 void sound_set(int setting, int value)
583 sound_set_type* sound_set_val = sound_get_fn(setting);
584 if (sound_set_val)
585 sound_set_val(value);
588 #if (!defined(HAVE_AS3514) && !defined(HAVE_WM8975) \
589 && !defined(HAVE_WM8758) && !defined(HAVE_TSC2100) \
590 && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \
591 && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \
592 && !defined(HAVE_AK4537)) || defined(SIMULATOR)
593 int sound_val2phys(int setting, int value)
595 #if CONFIG_CODEC == MAS3587F
596 int result = 0;
598 switch(setting)
600 case SOUND_LEFT_GAIN:
601 case SOUND_RIGHT_GAIN:
602 result = (value - 2) * 15;
603 break;
605 case SOUND_MIC_GAIN:
606 result = value * 15 + 210;
607 break;
609 default:
610 result = value;
611 break;
613 return result;
614 #elif defined(HAVE_UDA1380)
615 int result = 0;
617 switch(setting)
619 #ifdef HAVE_RECORDING
620 case SOUND_LEFT_GAIN:
621 case SOUND_RIGHT_GAIN:
622 case SOUND_MIC_GAIN:
623 result = value * 5; /* (1/2) * 10 */
624 break;
625 #endif
626 default:
627 result = value;
628 break;
630 return result;
631 #elif defined(HAVE_TLV320) || defined(HAVE_WM8711) \
632 || defined(HAVE_WM8721) || defined(HAVE_WM8731)
633 int result = 0;
635 switch(setting)
637 #ifdef HAVE_RECORDING
638 case SOUND_LEFT_GAIN:
639 case SOUND_RIGHT_GAIN:
640 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
641 break;
643 case SOUND_MIC_GAIN:
644 result = value * 200; /* 0 or 20 dB */
645 break;
646 #endif
647 default:
648 result = value;
649 break;
651 return result;
652 #elif defined(HAVE_AS3514)
653 /* This is here for the sim only and the audio driver has its own */
654 int result;
656 switch(setting)
658 #ifdef HAVE_RECORDING
659 case SOUND_LEFT_GAIN:
660 case SOUND_RIGHT_GAIN:
661 case SOUND_MIC_GAIN:
662 result = (value - 23) * 15;
663 break;
664 #endif
665 default:
666 result = value;
667 break;
670 return result;
671 #elif defined(HAVE_WM8978)
672 int result;
674 switch (setting)
676 #ifdef HAVE_RECORDING
677 case SOUND_LEFT_GAIN:
678 case SOUND_RIGHT_GAIN:
679 case SOUND_MIC_GAIN:
680 result = value * 5;
681 break;
682 #endif
684 default:
685 result = value;
688 return result;
689 #else
690 (void)setting;
691 return value;
692 #endif
694 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
696 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
697 #ifndef SIMULATOR
698 /* This function works by telling the decoder that we have another
699 crystal frequency than we actually have. It will adjust its internal
700 parameters and the result is that the audio is played at another pitch.
702 The pitch value precision is based on PITCH_SPEED_PRECISION (in dsp.h)
704 static int last_pitch = PITCH_SPEED_100;
706 void sound_set_pitch(int32_t pitch)
708 unsigned long val;
710 if (pitch != last_pitch)
712 /* Calculate the new (bogus) frequency */
713 val = 18432 * PITCH_SPEED_100 / pitch;
715 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
717 /* We must tell the MAS that the frequency has changed.
718 * This will unfortunately cause a short silence. */
719 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
721 last_pitch = pitch;
725 int32_t sound_get_pitch(void)
727 return last_pitch;
729 #else /* SIMULATOR */
730 void sound_set_pitch(int32_t pitch)
732 (void)pitch;
735 int32_t sound_get_pitch(void)
737 return PITCH_SPEED_100;
739 #endif /* SIMULATOR */
740 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */