]> git.sesse.net Git - vlc/blob - src/audio_output/volume.c
input: treat negative deadline as no deadline in ControlPop()
[vlc] / src / audio_output / volume.c
1 /*****************************************************************************
2  * volume.c : audio output volume operations
3  *****************************************************************************
4  * Copyright (C) 2002-2004 VLC authors and VideoLAN
5  * Copyright (C) 2011-2012 RĂ©mi Denis-Courmont
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation; either version 2.1 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <stddef.h>
27 #include <math.h>
28
29 #include <vlc_common.h>
30 #include <libvlc.h>
31 #include <vlc_modules.h>
32 #include <vlc_aout.h>
33 #include <vlc_aout_volume.h>
34 #include "aout_internal.h"
35
36 struct aout_volume
37 {
38     audio_volume_t object;
39     audio_replay_gain_t replay_gain;
40     vlc_atomic_float gain_factor;
41     float output_factor;
42     module_t *module;
43 };
44
45 static int ReplayGainCallback (vlc_object_t *, char const *,
46                                vlc_value_t, vlc_value_t, void *);
47
48 #undef aout_volume_New
49 /**
50  * Creates a software amplifier.
51  */
52 aout_volume_t *aout_volume_New(vlc_object_t *parent,
53                                const audio_replay_gain_t *gain)
54 {
55     aout_volume_t *vol = vlc_custom_create(parent, sizeof (aout_volume_t),
56                                            "volume");
57     if (unlikely(vol == NULL))
58         return NULL;
59     vol->module = NULL;
60     vol->output_factor = 1.f;
61
62     //audio_volume_t *obj = &vol->object;
63
64     /* Gain */
65     if (gain != NULL)
66         memcpy(&vol->replay_gain, gain, sizeof (vol->replay_gain));
67     else
68         memset(&vol->replay_gain, 0, sizeof (vol->replay_gain));
69
70     var_AddCallback(parent, "audio-replay-gain-mode",
71                     ReplayGainCallback, vol);
72     var_TriggerCallback(parent, "audio-replay-gain-mode");
73
74     return vol;
75 }
76
77 /**
78  * Selects the current sample format for software amplification.
79  */
80 int aout_volume_SetFormat(aout_volume_t *vol, vlc_fourcc_t format)
81 {
82     if (unlikely(vol == NULL))
83         return -1;
84
85     audio_volume_t *obj = &vol->object;
86     if (vol->module != NULL)
87     {
88         if (obj->format == format)
89         {
90             msg_Dbg (obj, "retaining sample format");
91             return 0;
92         }
93         msg_Dbg (obj, "changing sample format");
94         module_unneed(obj, vol->module);
95     }
96
97     obj->format = format;
98     vol->module = module_need(obj, "audio volume", NULL, false);
99     if (vol->module == NULL)
100         return -1;
101     return 0;
102 }
103
104 /**
105  * Destroys a software amplifier.
106  */
107 void aout_volume_Delete(aout_volume_t *vol)
108 {
109     if (vol == NULL)
110         return;
111
112     audio_volume_t *obj = &vol->object;
113
114     if (vol->module != NULL)
115         module_unneed(obj, vol->module);
116     var_DelCallback(obj->p_parent, "audio-replay-gain-mode",
117                     ReplayGainCallback, vol);
118     vlc_object_release(obj);
119 }
120
121 void aout_volume_SetVolume(aout_volume_t *vol, float factor)
122 {
123     if (unlikely(vol == NULL))
124         return;
125
126     vol->output_factor = factor;
127 }
128
129 /**
130  * Applies replay gain and software volume to an audio buffer.
131  */
132 int aout_volume_Amplify(aout_volume_t *vol, block_t *block)
133 {
134     if (unlikely(vol == NULL) || vol->module == NULL)
135         return -1;
136
137     float amp = vol->output_factor
138               * vlc_atomic_load_float (&vol->gain_factor);
139
140     vol->object.amplify(&vol->object, block, amp);
141     return 0;
142 }
143
144 /*** Replay gain ***/
145 static float aout_ReplayGainSelect(vlc_object_t *obj, const char *str,
146                                    const audio_replay_gain_t *replay_gain)
147 {
148     unsigned mode = AUDIO_REPLAY_GAIN_MAX;
149
150     if (likely(str != NULL))
151     {   /* Find selectrf mode */
152         if (!strcmp (str, "track"))
153             mode = AUDIO_REPLAY_GAIN_TRACK;
154         else
155         if (!strcmp (str, "album"))
156             mode = AUDIO_REPLAY_GAIN_ALBUM;
157     }
158
159     /* */
160     float multiplier;
161
162     if (mode == AUDIO_REPLAY_GAIN_MAX)
163     {
164         multiplier = 1.f;
165     }
166     else
167     {
168         float gain;
169
170         /* If the selectrf mode is not available, prefer the other one */
171         if (!replay_gain->pb_gain[mode] && replay_gain->pb_gain[!mode])
172             mode = !mode;
173
174         if (replay_gain->pb_gain[mode])
175             gain = replay_gain->pf_gain[mode]
176                  + var_InheritFloat (obj, "audio-replay-gain-preamp");
177         else
178             gain = var_InheritFloat (obj, "audio-replay-gain-default");
179
180         multiplier = powf (10.f, gain / 20.f);
181
182         if (var_InheritBool (obj, "audio-replay-gain-peak-protection"))
183             multiplier = fminf (multiplier, replay_gain->pb_peak[mode]
184                                             ? 1.f / replay_gain->pf_peak[mode]
185                                             : 1.f);
186     }
187
188     /* Command line / configuration gain */
189     multiplier *= var_InheritFloat (obj, "gain");
190
191     return multiplier;
192 }
193
194 static int ReplayGainCallback (vlc_object_t *obj, char const *var,
195                                vlc_value_t oldval, vlc_value_t val, void *data)
196 {
197     aout_volume_t *vol = data;
198     float multiplier = aout_ReplayGainSelect(obj, val.psz_string,
199                                              &vol->replay_gain);
200     vlc_atomic_store_float (&vol->gain_factor, multiplier);
201     VLC_UNUSED(var); VLC_UNUSED(oldval);
202     return VLC_SUCCESS;
203 }