autodetection: convert path to native separators before displaying it.
[Rockbox.git] / firmware / sound.c
blob2cf6ad08e906b2130ffdb0e602a75e354c296499
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 #error define for VOLUME_MIN and VOLUME_MAX is missing!
44 #endif
46 /* volume/balance/treble/bass interdependency main part */
47 #define VOLUME_RANGE (VOLUME_MAX - VOLUME_MIN)
49 #ifndef SIMULATOR
50 extern bool audio_is_initialized;
52 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
53 extern unsigned long shadow_io_control_main;
54 extern unsigned shadow_codec_reg0;
55 #endif
56 #endif /* SIMULATOR */
58 #ifdef SIMULATOR
59 /* dummy for sim */
60 const struct sound_settings_info audiohw_settings[] = {
61 [SOUND_VOLUME] = {"dB", 0, 1, VOLUME_MIN / 10, VOLUME_MAX / 10, -25},
62 [SOUND_BASS] = {"dB", 0, 1, -24, 24, 0},
63 [SOUND_TREBLE] = {"dB", 0, 1, -24, 24, 0},
64 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
65 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
66 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
67 #if defined(HAVE_RECORDING)
68 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
69 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
70 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
71 #endif
72 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
73 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
74 #endif
75 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
76 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
77 #endif
78 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
79 [SOUND_LOUDNESS] = {"dB", 0, 1, 0, 17, 0},
80 [SOUND_AVC] = {"", 0, 1, -1, 4, 0},
81 [SOUND_MDB_STRENGTH] = {"dB", 0, 1, 0, 127, 48},
82 [SOUND_MDB_HARMONICS] = {"%", 0, 1, 0, 100, 50},
83 [SOUND_MDB_CENTER] = {"Hz", 0, 10, 20, 300, 60},
84 [SOUND_MDB_SHAPE] = {"Hz", 0, 10, 50, 300, 90},
85 [SOUND_MDB_ENABLE] = {"", 0, 1, 0, 1, 0},
86 [SOUND_SUPERBASS] = {"", 0, 1, 0, 1, 0},
87 #endif
89 #endif
91 const char *sound_unit(int setting)
93 return audiohw_settings[setting].unit;
96 int sound_numdecimals(int setting)
98 return audiohw_settings[setting].numdecimals;
101 int sound_steps(int setting)
103 return audiohw_settings[setting].steps;
106 int sound_min(int setting)
108 return audiohw_settings[setting].minval;
111 int sound_max(int setting)
113 return audiohw_settings[setting].maxval;
116 int sound_default(int setting)
118 return audiohw_settings[setting].defaultval;
121 sound_set_type* sound_get_fn(int setting)
123 sound_set_type* result = NULL;
125 switch (setting) {
126 case SOUND_VOLUME:
127 result = sound_set_volume;
128 break;
130 case SOUND_BASS:
131 result = sound_set_bass;
132 break;
134 case SOUND_TREBLE:
135 result = sound_set_treble;
136 break;
138 case SOUND_BALANCE:
139 result = sound_set_balance;
140 break;
142 case SOUND_CHANNELS:
143 result = sound_set_channels;
144 break;
146 case SOUND_STEREO_WIDTH:
147 result = sound_set_stereo_width;
148 break;
150 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
151 case SOUND_BASS_CUTOFF:
152 result = sound_set_bass_cutoff;
153 break;
154 #endif
156 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
157 case SOUND_TREBLE_CUTOFF:
158 result = sound_set_treble_cutoff;
159 break;
160 #endif
162 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
163 case SOUND_LOUDNESS:
164 result = sound_set_loudness;
165 break;
167 case SOUND_AVC:
168 result = sound_set_avc;
169 break;
171 case SOUND_MDB_STRENGTH:
172 result = sound_set_mdb_strength;
173 break;
175 case SOUND_MDB_HARMONICS:
176 result = sound_set_mdb_harmonics;
177 break;
179 case SOUND_MDB_CENTER:
180 result = sound_set_mdb_center;
181 break;
183 case SOUND_MDB_SHAPE:
184 result = sound_set_mdb_shape;
185 break;
187 case SOUND_MDB_ENABLE:
188 result = sound_set_mdb_enable;
189 break;
191 case SOUND_SUPERBASS:
192 result = sound_set_superbass;
193 break;
194 #endif
197 return result;
200 #if CONFIG_CODEC == SWCODEC
201 /* Copied from dsp.h, nasty nasty, but we don't want to include dsp.h */
202 enum {
203 DSP_CALLBACK_SET_PRESCALE = 0,
204 DSP_CALLBACK_SET_BASS,
205 DSP_CALLBACK_SET_TREBLE,
206 DSP_CALLBACK_SET_CHANNEL_CONFIG,
207 DSP_CALLBACK_SET_STEREO_WIDTH
210 static int (*dsp_callback)(int, intptr_t) = NULL;
212 void sound_set_dsp_callback(int (*func)(int, intptr_t))
214 dsp_callback = func;
216 #endif
218 #ifndef SIMULATOR
219 #if CONFIG_CODEC == MAS3507D
220 /* convert tenth of dB volume (-780..+180) to dac3550 register value */
221 static int tenthdb2reg(int db)
223 if (db < -540) /* 3 dB steps */
224 return (db + 780) / 30;
225 else /* 1.5 dB steps */
226 return (db + 660) / 15;
228 #endif
231 #if !defined(AUDIOHW_HAVE_CLIPPING)
233 * The prescaler compensates for any kind of boosts, to prevent clipping.
235 * It's basically just a measure to make sure that audio does not clip during
236 * tone controls processing, like if i want to boost bass 12 dB, i can decrease
237 * the audio amplitude by -12 dB before processing, then increase master gain
238 * by 12 dB after processing.
241 /* all values in tenth of dB MAS3507D UDA1380 */
242 int current_volume = 0; /* -780..+180 -840.. 0 */
243 int current_balance = 0; /* -960..+960 -840..+840 */
244 int current_treble = 0; /* -150..+150 0.. +60 */
245 int current_bass = 0; /* -150..+150 0..+240 */
247 static void set_prescaled_volume(void)
249 int prescale = 0;
250 int l, r;
252 /* The WM codecs listed don't have suitable prescaler functionality, so we let
253 * the prescaler stay at 0 for these unless SW tone controls are in use */
254 #if defined(HAVE_SW_TONE_CONTROLS) || !(defined(HAVE_WM8975) \
255 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
256 || defined(HAVE_WM8758) || defined(HAVE_WM8985)) || defined(HAVE_TSC2100)
258 prescale = MAX(current_bass, current_treble);
259 if (prescale < 0)
260 prescale = 0; /* no need to prescale if we don't boost
261 bass or treble */
263 /* Gain up the analog volume to compensate the prescale gain reduction,
264 * but if this would push the volume over the top, reduce prescaling
265 * instead (might cause clipping). */
266 if (current_volume + prescale > VOLUME_MAX)
267 prescale = VOLUME_MAX - current_volume;
268 #endif
270 #if defined(AUDIOHW_HAVE_PRESCALER)
271 audiohw_set_prescaler(prescale);
272 #else
273 dsp_callback(DSP_CALLBACK_SET_PRESCALE, prescale);
274 #endif
276 if (current_volume == VOLUME_MIN)
277 prescale = 0; /* Make sure the chip gets muted at VOLUME_MIN */
279 l = r = current_volume + prescale;
281 if (current_balance > 0)
283 l -= current_balance;
284 if (l < VOLUME_MIN)
285 l = VOLUME_MIN;
287 if (current_balance < 0)
289 r += current_balance;
290 if (r < VOLUME_MIN)
291 r = VOLUME_MIN;
294 #if CONFIG_CODEC == MAS3507D
295 dac_volume(tenthdb2reg(l), tenthdb2reg(r), false);
296 #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \
297 || defined(HAVE_WM8731) || defined(HAVE_WM8721) || defined(HAVE_WM8751) \
298 || defined(HAVE_AS3514) || defined(HAVE_TSC2100)
299 audiohw_set_master_vol(tenthdb2master(l), tenthdb2master(r));
300 #if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
301 || (defined(HAVE_WM8751) && !defined(MROBE_100)) \
302 || defined(HAVE_TSC2100)
303 audiohw_set_lineout_vol(tenthdb2master(0), tenthdb2master(0));
304 #endif
306 #elif defined(HAVE_TLV320) || defined(HAVE_WM8978)
307 audiohw_set_headphone_vol(tenthdb2master(l), tenthdb2master(r));
308 #endif
310 #endif /* (CONFIG_CODEC == MAS3507D) || defined HAVE_UDA1380 */
311 #endif /* !SIMULATOR */
314 #ifndef SIMULATOR
316 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
317 unsigned long mdb_shape_shadow = 0;
318 unsigned long loudness_shadow = 0;
319 #endif
321 void sound_set_volume(int value)
323 if(!audio_is_initialized)
324 return;
326 #if defined(AUDIOHW_HAVE_CLIPPING)
327 audiohw_set_volume(value);
328 #elif CONFIG_CPU == PNX0101
329 int tmp = (60 - value * 4) & 0xff;
330 CODECVOL = tmp | (tmp << 8);
331 #else
332 current_volume = value * 10; /* tenth of dB */
333 set_prescaled_volume();
334 #endif
337 void sound_set_balance(int value)
339 if(!audio_is_initialized)
340 return;
342 #ifdef AUDIOHW_HAVE_BALANCE
343 audiohw_set_balance(value);
344 #else
345 current_balance = value * VOLUME_RANGE / 100; /* tenth of dB */
346 set_prescaled_volume();
347 #endif
350 void sound_set_bass(int value)
352 if(!audio_is_initialized)
353 return;
355 #if !defined(AUDIOHW_HAVE_CLIPPING)
356 #if defined(HAVE_WM8751)
357 current_bass = value;
358 #else
359 current_bass = value * 10;
360 #endif
361 #endif
363 #if defined(AUDIOHW_HAVE_BASS)
364 audiohw_set_bass(value);
365 #else
366 dsp_callback(DSP_CALLBACK_SET_BASS, current_bass);
367 #endif
369 #if !defined(AUDIOHW_HAVE_CLIPPING)
370 set_prescaled_volume();
371 #endif
374 void sound_set_treble(int value)
376 if(!audio_is_initialized)
377 return;
379 #if !defined(AUDIOHW_HAVE_CLIPPING)
380 #if defined(HAVE_WM8751)
381 current_treble = value;
382 #else
383 current_treble = value * 10;
384 #endif
385 #endif
387 #if defined(AUDIOHW_HAVE_TREBLE)
388 audiohw_set_treble(value);
389 #else
390 dsp_callback(DSP_CALLBACK_SET_TREBLE, current_treble);
391 #endif
393 #if !defined(AUDIOHW_HAVE_CLIPPING)
394 set_prescaled_volume();
395 #endif
398 void sound_set_channels(int value)
400 if(!audio_is_initialized)
401 return;
403 #if CONFIG_CODEC == SWCODEC
404 dsp_callback(DSP_CALLBACK_SET_CHANNEL_CONFIG, value);
405 #else
406 audiohw_set_channel(value);
407 #endif
410 void sound_set_stereo_width(int value)
412 if(!audio_is_initialized)
413 return;
415 #if CONFIG_CODEC == SWCODEC
416 dsp_callback(DSP_CALLBACK_SET_STEREO_WIDTH, value);
417 #else
418 audiohw_set_stereo_width(value);
419 #endif
422 #if defined(AUDIOHW_HAVE_BASS_CUTOFF)
423 void sound_set_bass_cutoff(int value)
425 if(!audio_is_initialized)
426 return;
428 audiohw_set_bass_cutoff(value);
430 #endif
432 #if defined(AUDIOHW_HAVE_TREBLE_CUTOFF)
433 void sound_set_treble_cutoff(int value)
435 if(!audio_is_initialized)
436 return;
438 audiohw_set_treble_cutoff(value);
440 #endif
442 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
443 void sound_set_loudness(int value)
445 if(!audio_is_initialized)
446 return;
447 loudness_shadow = (loudness_shadow & 0x04) |
448 (MAX(MIN(value * 4, 0x44), 0) << 8);
449 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
452 void sound_set_avc(int value)
454 if(!audio_is_initialized)
455 return;
456 int tmp;
457 switch (value) {
458 case 1: /* 20ms */
459 tmp = (0x1 << 8) | (0x8 << 12);
460 break;
461 case 2: /* 2s */
462 tmp = (0x2 << 8) | (0x8 << 12);
463 break;
464 case 3: /* 4s */
465 tmp = (0x4 << 8) | (0x8 << 12);
466 break;
467 case 4: /* 8s */
468 tmp = (0x8 << 8) | (0x8 << 12);
469 break;
470 case -1: /* turn off and then turn on again to decay quickly */
471 tmp = mas_codec_readreg(MAS_REG_KAVC);
472 mas_codec_writereg(MAS_REG_KAVC, 0);
473 break;
474 default: /* off */
475 tmp = 0;
476 break;
478 mas_codec_writereg(MAS_REG_KAVC, tmp);
481 void sound_set_mdb_strength(int value)
483 if(!audio_is_initialized)
484 return;
485 mas_codec_writereg(MAS_REG_KMDB_STR, (value & 0x7f) << 8);
488 void sound_set_mdb_harmonics(int value)
490 if(!audio_is_initialized)
491 return;
492 int tmp = value * 127 / 100;
493 mas_codec_writereg(MAS_REG_KMDB_HAR, (tmp & 0x7f) << 8);
496 void sound_set_mdb_center(int value)
498 if(!audio_is_initialized)
499 return;
500 mas_codec_writereg(MAS_REG_KMDB_FC, (value/10) << 8);
503 void sound_set_mdb_shape(int value)
505 if(!audio_is_initialized)
506 return;
507 mdb_shape_shadow = (mdb_shape_shadow & 0x02) | ((value/10) << 8);
508 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
511 void sound_set_mdb_enable(int value)
513 if(!audio_is_initialized)
514 return;
515 mdb_shape_shadow = (mdb_shape_shadow & ~0x02) | (value?2:0);
516 mas_codec_writereg(MAS_REG_KMDB_SWITCH, mdb_shape_shadow);
519 void sound_set_superbass(int value)
521 if(!audio_is_initialized)
522 return;
523 loudness_shadow = (loudness_shadow & ~0x04) | (value?4:0);
524 mas_codec_writereg(MAS_REG_KLOUDNESS, loudness_shadow);
526 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
528 #else /* SIMULATOR */
529 int sim_volume;
530 void sound_set_volume(int value)
532 /* 128 is SDL_MIX_MAXVOLUME */
533 sim_volume = 128 * (value - VOLUME_MIN / 10) / (VOLUME_RANGE / 10);
536 void sound_set_balance(int value)
538 (void)value;
541 void sound_set_bass(int value)
543 (void)value;
546 void sound_set_treble(int value)
548 (void)value;
551 void sound_set_channels(int value)
553 (void)value;
556 void sound_set_stereo_width(int value)
558 (void)value;
561 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
562 void sound_set_loudness(int value)
564 (void)value;
567 void sound_set_avc(int value)
569 (void)value;
572 void sound_set_mdb_strength(int value)
574 (void)value;
577 void sound_set_mdb_harmonics(int value)
579 (void)value;
582 void sound_set_mdb_center(int value)
584 (void)value;
587 void sound_set_mdb_shape(int value)
589 (void)value;
592 void sound_set_mdb_enable(int value)
594 (void)value;
597 void sound_set_superbass(int value)
599 (void)value;
601 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */
603 #if defined(HAVE_WM8758) || defined(HAVE_WM8985)
604 void sound_set_bass_cutoff(int value)
606 (void) value;
609 void sound_set_treble_cutoff(int value)
611 (void) value;
613 #endif /* HAVE_WM8758 */
615 #endif /* SIMULATOR */
617 void sound_set(int setting, int value)
619 sound_set_type* sound_set_val = sound_get_fn(setting);
620 if (sound_set_val)
621 sound_set_val(value);
624 #if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined(HAVE_TSC2100)) \
625 || defined(SIMULATOR)
626 int sound_val2phys(int setting, int value)
628 #if CONFIG_CODEC == MAS3587F
629 int result = 0;
631 switch(setting)
633 case SOUND_LEFT_GAIN:
634 case SOUND_RIGHT_GAIN:
635 result = (value - 2) * 15;
636 break;
638 case SOUND_MIC_GAIN:
639 result = value * 15 + 210;
640 break;
642 default:
643 result = value;
644 break;
646 return result;
647 #elif defined(HAVE_UDA1380)
648 int result = 0;
650 switch(setting)
652 case SOUND_LEFT_GAIN:
653 case SOUND_RIGHT_GAIN:
654 case SOUND_MIC_GAIN:
655 result = value * 5; /* (1/2) * 10 */
656 break;
658 default:
659 result = value;
660 break;
662 return result;
663 #elif defined(HAVE_TLV320) || defined(HAVE_WM8731)
664 int result = 0;
666 switch(setting)
668 #ifdef HAVE_RECORDING
669 case SOUND_LEFT_GAIN:
670 case SOUND_RIGHT_GAIN:
671 result = (value - 23) * 15; /* (x - 23)/1.5 *10 */
672 break;
674 case SOUND_MIC_GAIN:
675 result = value * 200; /* 0 or 20 dB */
676 break;
677 #endif
678 default:
679 result = value;
680 break;
682 return result;
683 #elif defined(HAVE_AS3514)
684 /* This is here for the sim only and the audio driver has its own */
685 int result;
687 switch(setting)
689 case SOUND_LEFT_GAIN:
690 case SOUND_RIGHT_GAIN:
691 case SOUND_MIC_GAIN:
692 result = (value - 23) * 15;
693 break;
695 default:
696 result = value;
697 break;
700 return result;
701 #else
702 (void)setting;
703 return value;
704 #endif
706 #endif /* !defined(HAVE_AS3514) || defined(SIMULATOR) */
708 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
709 #ifndef SIMULATOR
710 /* This function works by telling the decoder that we have another
711 crystal frequency than we actually have. It will adjust its internal
712 parameters and the result is that the audio is played at another pitch.
714 The pitch value is in tenths of percent.
716 static int last_pitch = 1000;
718 void sound_set_pitch(int pitch)
720 unsigned long val;
722 if (pitch != last_pitch)
724 /* Calculate the new (bogus) frequency */
725 val = 18432 * 1000 / pitch;
727 mas_writemem(MAS_BANK_D0, MAS_D0_OFREQ_CONTROL, &val, 1);
729 /* We must tell the MAS that the frequency has changed.
730 * This will unfortunately cause a short silence. */
731 mas_writemem(MAS_BANK_D0, MAS_D0_IO_CONTROL_MAIN, &shadow_io_control_main, 1);
733 last_pitch = pitch;
737 int sound_get_pitch(void)
739 return last_pitch;
741 #else /* SIMULATOR */
742 void sound_set_pitch(int pitch)
744 (void)pitch;
747 int sound_get_pitch(void)
749 return 1000;
751 #endif /* SIMULATOR */
752 #endif /* (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) */