Use the new progressbar value slot instead of wrapping around it.
[Rockbox.git] / firmware / sound.c
blob7c862db515b40dc6f2ef6c8cfadbadfda4bd6ba1
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 -700
45 #define VOLUME_MAX 0
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 defined(HAVE_RECORDING)
70 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
71 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
72 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
73 #endif
74 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
75 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
76 #endif
77 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
78 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
79 #endif
80 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
81 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
82 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
83 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
84 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
85 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
86 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
87 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
88 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
89 #endif
91 #endif
93 const char *sound_unit(int setting)
95 return audiohw_settings[setting].unit;
98 int sound_numdecimals(int setting)
100 return audiohw_settings[setting].numdecimals;
103 int sound_steps(int setting)
105 return audiohw_settings[setting].steps;
108 int sound_min(int setting)
110 return audiohw_settings[setting].minval;
113 int sound_max(int setting)
115 return audiohw_settings[setting].maxval;
118 int sound_default(int setting)
120 return audiohw_settings[setting].defaultval;
123 sound_set_type* sound_get_fn(int setting)
125 sound_set_type* result = NULL;
127 switch (setting) {
128 case SOUND_VOLUME:
129 result = sound_set_volume;
130 break;
132 case SOUND_BASS:
133 result = sound_set_bass;
134 break;
136 case SOUND_TREBLE:
137 result = sound_set_treble;
138 break;
140 case SOUND_BALANCE:
141 result = sound_set_balance;
142 break;
144 case SOUND_CHANNELS:
145 result = sound_set_channels;
146 break;
148 case SOUND_STEREO_WIDTH:
149 result = sound_set_stereo_width;
150 break;
152 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
153 case SOUND_BASS_CUTOFF:
154 result = sound_set_bass_cutoff;
155 break;
156 #endif
158 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
159 case SOUND_TREBLE_CUTOFF:
160 result = sound_set_treble_cutoff;
161 break;
162 #endif
164 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
165 case SOUND_LOUDNESS:
166 result = sound_set_loudness;
167 break;
169 case SOUND_AVC:
170 result = sound_set_avc;
171 break;
173 case SOUND_MDB_STRENGTH:
174 result = sound_set_mdb_strength;
175 break;
177 case SOUND_MDB_HARMONICS:
178 result = sound_set_mdb_harmonics;
179 break;
181 case SOUND_MDB_CENTER:
182 result = sound_set_mdb_center;
183 break;
185 case SOUND_MDB_SHAPE:
186 result = sound_set_mdb_shape;
187 break;
189 case SOUND_MDB_ENABLE:
190 result = sound_set_mdb_enable;
191 break;
193 case SOUND_SUPERBASS:
194 result = sound_set_superbass;
195 break;
196 #endif
199 return result;
202 #if CONFIG_CODEC == SWCODEC
203 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
204 enum {
205 DSP_CALLBACK_SET_PRESCALE = 0,
206 DSP_CALLBACK_SET_BASS,
207 DSP_CALLBACK_SET_TREBLE,
208 DSP_CALLBACK_SET_CHANNEL_CONFIG,
209 DSP_CALLBACK_SET_STEREO_WIDTH
212 static int (*dsp_callback)(int, intptr_t) = NULL;
214 void sound_set_dsp_callback(int (*func)(int, intptr_t))
216 dsp_callback = func;
218 #endif
220 #ifndef SIMULATOR
221 #if CONFIG_CODEC == MAS3507D
222 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
223 static int tenthdb2reg(int db)
225 if (db < -540) /* 3 dB steps */
226 return (db + 780) / 30;
227 else /* 1.5 dB steps */
228 return (db + 660) / 15;
230 #endif
233 #if !defined(AUDIOHW_HAVE_CLIPPING)
235 * The prescaler compensates for any kind of boosts, to prevent clipping.
237 * It's basically just a measure to make sure that audio does not clip during
238 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
239 * the audio amplitude by -12 dB before processing, then increase master gain
240 * by 12 dB after processing.
243 /* all values in tenth of dB MAS3507D UDA1380 */
244 int current_volume = 0; /* -780..+180 -840.. 0 */
245 int current_balance = 0; /* -960..+960 -840..+840 */
246 int current_treble = 0; /* -150..+150 0.. +60 */
247 int current_bass = 0; /* -150..+150 0..+240 */
249 static void set_prescaled_volume(void)
251 int prescale = 0;
252 int l, r;
254 /* The WM codecs listed don't have suitable prescaler functionality, so we let
255 * the prescaler stay at 0 for these unless SW tone controls are in use */
256 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
257 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
258 || defined(HAVE_WM8758) || defined(HAVE_WM8985)) || defined(HAVE_TSC2100)
260 prescale = MAX(current_bass, current_treble);
261 if (prescale < 0)
262 prescale = 0; /* no need to prescale if we don't boost
263 bass or treble */
265 /* Gain up the analog volume to compensate the prescale gain reduction,
266 * but if this would push the volume over the top, reduce prescaling
267 * instead (might cause clipping). */
268 if (current_volume + prescale > VOLUME_MAX)
269 prescale = VOLUME_MAX - current_volume;
270 #endif
272 #if defined(AUDIOHW_HAVE_PRESCALER)
273 audiohw_set_prescaler(prescale);
274 #else
275 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
276 #endif
278 if (current_volume == VOLUME_MIN)
279 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
281 l = r = current_volume + prescale;
283 if (current_balance > 0)
285 l -= current_balance;
286 if (l < VOLUME_MIN)
287 l = VOLUME_MIN;
289 if (current_balance < 0)
291 r += current_balance;
292 if (r < VOLUME_MIN)
293 r = VOLUME_MIN;
296 #if CONFIG_CODEC == MAS3507D
297 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
298 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
299 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
300 || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
301 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
302 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
303 || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
304 || defined(HAVE_TSC2100)
305 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
306 #endif
308 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978)
309 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
310 #endif
312 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
313 #endif /* !SIMULATOR */
316 #ifndef SIMULATOR
318 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
319 unsigned long mdb_shape_shadow = 0;
320 unsigned long loudness_shadow = 0;
321 #endif
323 void sound_set_volume(int value)
325 if(!audio_is_initialized)
326 return;
328 #if defined(AUDIOHW_HAVE_CLIPPING)
329 audiohw_set_volume(value);
330 #elif CONFIG_CPU == PNX0101
331 int tmp = (60 - value * 4) & 0xff;
332 CODECVOL = tmp | (tmp << 8);
333 #else
334 current_volume = value * 10; /* tenth of dB */
335 set_prescaled_volume();
336 #endif
339 void sound_set_balance(int value)
341 if(!audio_is_initialized)
342 return;
344 #ifdef AUDIOHW_HAVE_BALANCE
345 audiohw_set_balance(value);
346 #else
347 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
348 set_prescaled_volume();
349 #endif
352 void sound_set_bass(int value)
354 if(!audio_is_initialized)
355 return;
357 #if !defined(AUDIOHW_HAVE_CLIPPING)
358 #if defined(HAVE_WM8751)
359 current_bass = value;
360 #else
361 current_bass = value * 10;
362 #endif
363 #endif
365 #if defined(AUDIOHW_HAVE_BASS)
366 audiohw_set_bass(value);
367 #else
368 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
369 #endif
371 #if !defined(AUDIOHW_HAVE_CLIPPING)
372 set_prescaled_volume();
373 #endif
376 void sound_set_treble(int value)
378 if(!audio_is_initialized)
379 return;
381 #if !defined(AUDIOHW_HAVE_CLIPPING)
382 #if defined(HAVE_WM8751)
383 current_treble = value;
384 #else
385 current_treble = value * 10;
386 #endif
387 #endif
389 #if defined(AUDIOHW_HAVE_TREBLE)
390 audiohw_set_treble(value);
391 #else
392 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
393 #endif
395 #if !defined(AUDIOHW_HAVE_CLIPPING)
396 set_prescaled_volume();
397 #endif
400 void sound_set_channels(int value)
402 if(!audio_is_initialized)
403 return;
405 #if CONFIG_CODEC == SWCODEC
406 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
407 #else
408 audiohw_set_channel(value);
409 #endif
412 void sound_set_stereo_width(int value)
414 if(!audio_is_initialized)
415 return;
417 #if CONFIG_CODEC == SWCODEC
418 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
419 #else
420 audiohw_set_stereo_width(value);
421 #endif
424 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
425 void sound_set_bass_cutoff(int value)
427 if(!audio_is_initialized)
428 return;
430 audiohw_set_bass_cutoff(value);
432 #endif
434 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
435 void sound_set_treble_cutoff(int value)
437 if(!audio_is_initialized)
438 return;
440 audiohw_set_treble_cutoff(value);
442 #endif
444 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
445 void sound_set_loudness(int value)
447 if(!audio_is_initialized)
448 return;
449 loudness_shadow = (loudness_shadow & 0x04) |
450 (MAX(MIN(value * 4, 0x44), 0) << 8);
451 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
454 void sound_set_avc(int value)
456 if(!audio_is_initialized)
457 return;
458 int tmp;
459 switch (value) {
460 case 1: /* 20ms */
461 tmp = (0x1 << 8) | (0x8 << 12);
462 break;
463 case 2: /* 2s */
464 tmp = (0x2 << 8) | (0x8 << 12);
465 break;
466 case 3: /* 4s */
467 tmp = (0x4 << 8) | (0x8 << 12);
468 break;
469 case 4: /* 8s */
470 tmp = (0x8 << 8) | (0x8 << 12);
471 break;
472 case -1: /* turn off and then turn on again to decay quickly */
473 tmp = mas_codec_readreg(MAS_REG_KAVC);
474 mas_codec_writereg(MAS_REG_KAVC, 0);
475 break;
476 default: /* off */
477 tmp = 0;
478 break;
480 mas_codec_writereg(MAS_REG_KAVC, tmp);
483 void sound_set_mdb_strength(int value)
485 if(!audio_is_initialized)
486 return;
487 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
490 void sound_set_mdb_harmonics(int value)
492 if(!audio_is_initialized)
493 return;
494 int tmp = value * 127 / 100;
495 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
498 void sound_set_mdb_center(int value)
500 if(!audio_is_initialized)
501 return;
502 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
505 void sound_set_mdb_shape(int value)
507 if(!audio_is_initialized)
508 return;
509 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
510 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
513 void sound_set_mdb_enable(int value)
515 if(!audio_is_initialized)
516 return;
517 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
518 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
521 void sound_set_superbass(int value)
523 if(!audio_is_initialized)
524 return;
525 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
526 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
528 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
530 #else /* SIMULATOR */
531 int sim_volume;
532 void sound_set_volume(int value)
534 /* 128 is SDL_MIX_MAXVOLUME */
535 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
538 void sound_set_balance(int value)
540 (void)value;
543 void sound_set_bass(int value)
545 (void)value;
548 void sound_set_treble(int value)
550 (void)value;
553 void sound_set_channels(int value)
555 (void)value;
558 void sound_set_stereo_width(int value)
560 (void)value;
563 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
564 void sound_set_loudness(int value)
566 (void)value;
569 void sound_set_avc(int value)
571 (void)value;
574 void sound_set_mdb_strength(int value)
576 (void)value;
579 void sound_set_mdb_harmonics(int value)
581 (void)value;
584 void sound_set_mdb_center(int value)
586 (void)value;
589 void sound_set_mdb_shape(int value)
591 (void)value;
594 void sound_set_mdb_enable(int value)
596 (void)value;
599 void sound_set_superbass(int value)
601 (void)value;
603 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
605 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
606 void sound_set_bass_cutoff(int value)
608 (void) value;
611 void sound_set_treble_cutoff(int value)
613 (void) value;
615 #endif /* HAVE_WM8758 */
617 #endif /* SIMULATOR */
619 void sound_set(int setting, int value)
621 sound_set_type* sound_set_val = sound_get_fn(setting);
622 if (sound_set_val)
623 sound_set_val(value);
626 #if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined(HAVE_TSC2100)) \
627 || defined(SIMULATOR)
628 int sound_val2phys(int setting, int value)
630 #if CONFIG_CODEC == MAS3587F
631 int result = 0;
633 switch(setting)
635 case SOUND_LEFT_GAIN:
636 case SOUND_RIGHT_GAIN:
637 result = (value - 2) * 15;
638 break;
640 case SOUND_MIC_GAIN:
641 result = value * 15 + 210;
642 break;
644 default:
645 result = value;
646 break;
648 return result;
649 #elif defined(HAVE_UDA1380)
650 int result = 0;
652 switch(setting)
654 case SOUND_LEFT_GAIN:
655 case SOUND_RIGHT_GAIN:
656 case SOUND_MIC_GAIN:
657 result = value * 5; /* (1/2) * 10 */
658 break;
660 default:
661 result = value;
662 break;
664 return result;
665 #elif defined(HAVE_TLV320) || defined(HAVE_WM8731)
666 int result = 0;
668 switch(setting)
670 #ifdef HAVE_RECORDING
671 case SOUND_LEFT_GAIN:
672 case SOUND_RIGHT_GAIN:
673 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
674 break;
676 case SOUND_MIC_GAIN:
677 result = value * 200; /* 0 or 20 dB */
678 break;
679 #endif
680 default:
681 result = value;
682 break;
684 return result;
685 #elif defined(HAVE_AS3514)
686 /* This is here for the sim only and the audio driver has its own */
687 int result;
689 switch(setting)
691 case SOUND_LEFT_GAIN:
692 case SOUND_RIGHT_GAIN:
693 case SOUND_MIC_GAIN:
694 result = (value - 23) * 15;
695 break;
697 default:
698 result = value;
699 break;
702 return result;
703 #else
704 (void)setting;
705 return value;
706 #endif
708 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
710 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
711 #ifndef SIMULATOR
712 /* This function works by telling the decoder that we have another
713 crystal frequency than we actually have. It will adjust its internal
714 parameters and the result is that the audio is played at another pitch.
716 The pitch value is in tenths of percent.
718 static int last_pitch = 1000;
720 void sound_set_pitch(int pitch)
722 unsigned long val;
724 if (pitch != last_pitch)
726 /* Calculate the new (bogus) frequency */
727 val = 18432 * 1000 / pitch;
729 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
731 /* We must tell the MAS that the frequency has changed.
732 * This will unfortunately cause a short silence. */
733 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
735 last_pitch = pitch;
739 int sound_get_pitch(void)
741 return last_pitch;
743 #else /* SIMULATOR */
744 void sound_set_pitch(int pitch)
746 (void)pitch;
749 int sound_get_pitch(void)
751 return 1000;
753 #endif /* SIMULATOR */
754 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */