diff options
Diffstat (limited to 'lib/rbcodec/dsp/dsp_misc.c')
-rw-r--r-- | lib/rbcodec/dsp/dsp_misc.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/lib/rbcodec/dsp/dsp_misc.c b/lib/rbcodec/dsp/dsp_misc.c new file mode 100644 index 0000000000..7b4589151c --- /dev/null +++ b/lib/rbcodec/dsp/dsp_misc.c | |||
@@ -0,0 +1,238 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Miika Pekkarinen | ||
11 | * Copyright (C) 2005 Magnus Holmgren | ||
12 | * Copyright (C) 2007 Thom Johansen | ||
13 | * Copyright (C) 2012 Michael Sevakis | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version 2 | ||
18 | * of the License, or (at your option) any later version. | ||
19 | * | ||
20 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
21 | * KIND, either express or implied. | ||
22 | * | ||
23 | ****************************************************************************/ | ||
24 | #include "config.h" | ||
25 | #include "system.h" | ||
26 | #include "dsp.h" | ||
27 | #include "dsp_sample_io.h" | ||
28 | #include "replaygain.h" | ||
29 | #include "sound.h" | ||
30 | #include "settings.h" | ||
31 | #include "fixedpoint.h" | ||
32 | #include <string.h> | ||
33 | #include "dsp_proc_entry.h" | ||
34 | |||
35 | /** Firmware callback interface **/ | ||
36 | |||
37 | /* Hook back from firmware/ part of audio, which can't/shouldn't call apps/ | ||
38 | * code directly. */ | ||
39 | int dsp_callback(int msg, intptr_t param) | ||
40 | { | ||
41 | switch (msg) | ||
42 | { | ||
43 | #ifdef HAVE_SW_TONE_CONTROLS | ||
44 | case DSP_CALLBACK_SET_PRESCALE: | ||
45 | tone_set_prescale(param); | ||
46 | break; | ||
47 | case DSP_CALLBACK_SET_BASS: | ||
48 | tone_set_bass(param); | ||
49 | break; | ||
50 | case DSP_CALLBACK_SET_TREBLE: | ||
51 | tone_set_treble(param); | ||
52 | break; | ||
53 | /* FIXME: This must be done by bottom-level PCM driver so it works with | ||
54 | all PCM, not here and not in mixer. I won't fully support it | ||
55 | here with all streams. -- jethead71 */ | ||
56 | #ifdef HAVE_SW_VOLUME_CONTROL | ||
57 | case DSP_CALLBACK_SET_SW_VOLUME: | ||
58 | if (global_settings.volume < SW_VOLUME_MAX || | ||
59 | global_settings.volume > SW_VOLUME_MIN) | ||
60 | { | ||
61 | int vol_gain = get_replaygain_int(global_settings.volume * 100); | ||
62 | pga_set_gain(PGA_VOLUME, vol_gain); | ||
63 | } | ||
64 | break; | ||
65 | #endif /* HAVE_SW_VOLUME_CONTROL */ | ||
66 | #endif /* HAVE_SW_TONE_CONTROLS */ | ||
67 | case DSP_CALLBACK_SET_CHANNEL_CONFIG: | ||
68 | channel_mode_set_config(param); | ||
69 | break; | ||
70 | case DSP_CALLBACK_SET_STEREO_WIDTH: | ||
71 | channel_mode_custom_set_width(param); | ||
72 | break; | ||
73 | default: | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /** Replaygain settings **/ | ||
81 | static struct dsp_replay_gains current_rpgains; | ||
82 | |||
83 | static void dsp_replaygain_update(const struct dsp_replay_gains *gains) | ||
84 | { | ||
85 | if (gains == NULL) | ||
86 | { | ||
87 | /* Use defaults */ | ||
88 | memset(¤t_rpgains, 0, sizeof (current_rpgains)); | ||
89 | gains = ¤t_rpgains; | ||
90 | } | ||
91 | else | ||
92 | { | ||
93 | current_rpgains = *gains; /* Stash settings */ | ||
94 | } | ||
95 | |||
96 | int32_t gain = PGA_UNITY; | ||
97 | |||
98 | if (global_settings.replaygain_type != REPLAYGAIN_OFF || | ||
99 | global_settings.replaygain_noclip) | ||
100 | { | ||
101 | bool track_mode = | ||
102 | get_replaygain_mode(gains->track_gain != 0, | ||
103 | gains->album_gain != 0) == REPLAYGAIN_TRACK; | ||
104 | |||
105 | int32_t peak = (track_mode || gains->album_peak == 0) ? | ||
106 | gains->track_peak : gains->album_peak; | ||
107 | |||
108 | if (global_settings.replaygain_type != REPLAYGAIN_OFF) | ||
109 | { | ||
110 | gain = (track_mode || gains->album_gain == 0) ? | ||
111 | gains->track_gain : gains->album_gain; | ||
112 | |||
113 | if (global_settings.replaygain_preamp) | ||
114 | { | ||
115 | int32_t preamp = get_replaygain_int( | ||
116 | global_settings.replaygain_preamp * 10); | ||
117 | |||
118 | gain = fp_mul(gain, preamp, 24); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | if (gain == 0) | ||
123 | { | ||
124 | /* So that noclip can work even with no gain information. */ | ||
125 | gain = PGA_UNITY; | ||
126 | } | ||
127 | |||
128 | if (global_settings.replaygain_noclip && peak != 0 && | ||
129 | fp_mul(gain, peak, 24) >= PGA_UNITY) | ||
130 | { | ||
131 | gain = fp_div(PGA_UNITY, peak, 24); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | pga_set_gain(PGA_REPLAYGAIN, gain); | ||
136 | pga_enable_gain(PGA_REPLAYGAIN, gain != PGA_UNITY); | ||
137 | } | ||
138 | |||
139 | int get_replaygain_mode(bool have_track_gain, bool have_album_gain) | ||
140 | { | ||
141 | bool track = false; | ||
142 | |||
143 | switch (global_settings.replaygain_type) | ||
144 | { | ||
145 | case REPLAYGAIN_TRACK: | ||
146 | track = true; | ||
147 | break; | ||
148 | |||
149 | case REPLAYGAIN_SHUFFLE: | ||
150 | track = global_settings.playlist_shuffle; | ||
151 | break; | ||
152 | } | ||
153 | |||
154 | return (!track && have_album_gain) ? | ||
155 | REPLAYGAIN_ALBUM : (have_track_gain ? REPLAYGAIN_TRACK : -1); | ||
156 | } | ||
157 | |||
158 | void dsp_set_replaygain(void) | ||
159 | { | ||
160 | dsp_replaygain_update(¤t_rpgains); | ||
161 | } | ||
162 | |||
163 | |||
164 | /** Pitch Settings **/ | ||
165 | |||
166 | #ifdef HAVE_PITCHSCREEN | ||
167 | static int32_t pitch_ratio = PITCH_SPEED_100; | ||
168 | |||
169 | static void dsp_pitch_update(struct dsp_config *dsp) | ||
170 | { | ||
171 | /* Account for playback speed adjustment when setting dsp->frequency | ||
172 | if we're called from the main audio thread. Voice playback thread | ||
173 | does not support this feature. */ | ||
174 | struct sample_io_data *data = (void *)dsp; | ||
175 | data->format.frequency = | ||
176 | (int64_t)pitch_ratio * data->format.codec_frequency / PITCH_SPEED_100; | ||
177 | } | ||
178 | |||
179 | int32_t sound_get_pitch(void) | ||
180 | { | ||
181 | return pitch_ratio; | ||
182 | } | ||
183 | |||
184 | void sound_set_pitch(int32_t percent) | ||
185 | { | ||
186 | pitch_ratio = percent > 0 ? percent : PITCH_SPEED_100; | ||
187 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); | ||
188 | struct sample_io_data *data = (void *)dsp; | ||
189 | dsp_configure(dsp, DSP_SWITCH_FREQUENCY, data->format.codec_frequency); | ||
190 | } | ||
191 | #endif /* HAVE_PITCHSCREEN */ | ||
192 | |||
193 | /* This is a null-processing stage that monitors as an enabled stage but never | ||
194 | * becomes active in processing samples. It only hooks messages. */ | ||
195 | |||
196 | /* DSP message hook */ | ||
197 | static intptr_t misc_handler_configure(struct dsp_proc_entry *this, | ||
198 | struct dsp_config *dsp, | ||
199 | unsigned setting, | ||
200 | intptr_t value) | ||
201 | { | ||
202 | switch (setting) | ||
203 | { | ||
204 | case DSP_INIT: | ||
205 | /* Enable us for the audio DSP at startup */ | ||
206 | if (value == CODEC_IDX_AUDIO) | ||
207 | dsp_proc_enable(dsp, DSP_PROC_MISC_HANDLER, true); | ||
208 | break; | ||
209 | |||
210 | case DSP_PROC_CLOSE: | ||
211 | /* This stage should be enabled at all times */ | ||
212 | DEBUGF("DSP_PROC_MISC_HANDLER - Error: Closing!\n"); | ||
213 | break; | ||
214 | |||
215 | case DSP_RESET: | ||
216 | #ifdef HAVE_PITCHSCREEN | ||
217 | dsp_pitch_update(dsp); | ||
218 | #endif | ||
219 | value = (intptr_t)NULL; /* Default gains */ | ||
220 | case REPLAYGAIN_SET_GAINS: | ||
221 | dsp_replaygain_update((void *)value); | ||
222 | break; | ||
223 | |||
224 | #ifdef HAVE_PITCHSCREEN | ||
225 | case DSP_SET_FREQUENCY: | ||
226 | dsp_pitch_update(dsp); | ||
227 | break; | ||
228 | #endif | ||
229 | } | ||
230 | |||
231 | return 1; | ||
232 | (void)this; | ||
233 | } | ||
234 | |||
235 | /* Database entry */ | ||
236 | DSP_PROC_DB_ENTRY( | ||
237 | MISC_HANDLER, | ||
238 | misc_handler_configure); | ||