1 /*
2   This file is part of Deadbeef Player source code
3   http://deadbeef.sourceforge.net
4 
5   replaygain support
6 
7   Copyright (C) 2009-2013 Alexey Yakovenko
8 
9   This software is provided 'as-is', without any express or implied
10   warranty.  In no event will the authors be held liable for any damages
11   arising from the use of this software.
12 
13   Permission is granted to anyone to use this software for any purpose,
14   including commercial applications, and to alter it and redistribute it
15   freely, subject to the following restrictions:
16 
17   1. The origin of this software must not be misrepresented; you must not
18      claim that you wrote the original software. If you use this software
19      in a product, an acknowledgment in the product documentation would be
20      appreciated but is not required.
21   2. Altered source versions must be plainly marked as such, and must not be
22      misrepresented as being the original software.
23   3. This notice may not be removed or altered from any source distribution.
24 
25   Alexey Yakovenko waker@users.sourceforge.net
26 */
27 #include "playlist.h"
28 #include "volume.h"
29 #include "replaygain.h"
30 
31 static int conf_replaygain_mode = 0;
32 static int conf_replaygain_scale = 1;
33 static float conf_replaygain_preamp = 0;
34 static float conf_global_preamp = 0;
35 
36 static float rg_albumgain = 1;
37 static float rg_albumpeak = 1;
38 static float rg_trackgain = 1;
39 static float rg_trackpeak = 1;
40 static float rg_albumgain_full_preamp = 1;
41 static float rg_trackgain_full_preamp = 1;
42 static float rg_albumgain_global_preamp = 1;
43 static float rg_trackgain_global_preamp = 1;
44 
45 void
replaygain_apply(ddb_waveformat_t * fmt,playItem_t * it,char * bytes,int bytesread)46 replaygain_apply (ddb_waveformat_t *fmt, playItem_t *it, char *bytes, int bytesread) {
47     // FIXME: separate replaygain DSP plugin?
48     if (fmt->bps == 16) {
49         apply_replay_gain_int16 (it, bytes, bytesread);
50     }
51     else if (fmt->bps == 24) {
52         apply_replay_gain_int24 (it, bytes, bytesread);
53     }
54     else if (fmt->bps == 8) {
55         apply_replay_gain_int16 (it, bytes, bytesread);
56     }
57     else if (fmt->bps == 32 && !fmt->is_float) {
58         apply_replay_gain_int32 (it, bytes, bytesread);
59     }
60     else if (fmt->bps == 32 && fmt->is_float) {
61         apply_replay_gain_float32 (it, bytes, bytesread);
62     }
63 }
64 
65 void
replaygain_set(int mode,int scale,float preamp,float global_preamp)66 replaygain_set (int mode, int scale, float preamp, float global_preamp) {
67     conf_replaygain_mode = mode;
68     conf_replaygain_scale = scale;
69     conf_replaygain_preamp = db_to_amp (preamp);
70     conf_global_preamp = db_to_amp (global_preamp);
71     rg_albumgain_full_preamp = rg_albumgain * conf_replaygain_preamp * conf_global_preamp;
72     rg_trackgain_full_preamp = rg_trackgain * conf_replaygain_preamp * conf_global_preamp;
73     rg_albumgain_global_preamp = rg_albumgain * conf_global_preamp;
74     rg_trackgain_global_preamp = rg_trackgain * conf_global_preamp;
75 }
76 
77 void
replaygain_set_values(float albumgain,float albumpeak,float trackgain,float trackpeak)78 replaygain_set_values (float albumgain, float albumpeak, float trackgain, float trackpeak) {
79     if (albumgain > 100 && trackgain <= 100) {
80         albumgain = trackgain;
81         albumpeak = trackpeak;
82     }
83     else if (albumgain <= 100 && trackgain > 100) {
84         trackgain = albumgain;
85         trackpeak = albumpeak;
86     }
87     else if (albumgain > 100 && trackgain > 100) {
88         trackgain = albumgain = 0;
89     }
90     rg_albumgain = db_to_amp (albumgain);
91     rg_trackgain = db_to_amp (trackgain);
92     rg_albumgain_full_preamp = rg_albumgain * conf_replaygain_preamp * conf_global_preamp;
93     rg_trackgain_full_preamp = rg_trackgain * conf_replaygain_preamp * conf_global_preamp;
94     rg_albumgain_global_preamp = rg_albumgain * conf_global_preamp;
95     rg_trackgain_global_preamp = rg_trackgain * conf_global_preamp;
96     rg_albumpeak = albumpeak;
97     rg_trackpeak = trackpeak;
98 }
99 
100 static inline int
get_int_volume(void)101 get_int_volume (void) {
102     int vol = 1000;
103     if (conf_replaygain_mode == 1) {
104         if (rg_trackgain == 1) {
105             vol = rg_trackgain_global_preamp * 1000;
106         } else {
107             vol = rg_trackgain_full_preamp * 1000;
108         }
109         if (conf_replaygain_scale) {
110             if (vol * rg_trackpeak > 1000) {
111                 vol = 1000 / rg_trackpeak;
112             }
113         }
114     }
115     else if (conf_replaygain_mode == 2) {
116         if (rg_albumgain == 1) {
117             vol = rg_albumgain_global_preamp * 1000;
118         } else {
119             vol = rg_albumgain_full_preamp * 1000;
120         }
121         if (conf_replaygain_scale) {
122             if (vol * rg_albumpeak > 1000) {
123                 vol = 1000 / rg_albumpeak;
124             }
125         }
126     }
127     return vol;
128 }
129 
130 void
apply_replay_gain_int8(playItem_t * it,char * bytes,int size)131 apply_replay_gain_int8 (playItem_t *it, char *bytes, int size) {
132     if (!conf_replaygain_mode) {
133         return;
134     }
135     int vol = get_int_volume ();
136     if (vol < 0) {
137         return;
138     }
139     int8_t *s = (int8_t*)bytes;
140     for (int j = 0; j < size; j++) {
141         int32_t sample = ((int8_t)(*s)) * vol / 1000;
142         if (sample > 0x7f) {
143             sample = 0x7f;
144         }
145         else if (sample < -0x80) {
146             sample = -0x80;
147         }
148         *s = (int8_t)sample;
149         s++;
150     }
151 }
152 
153 void
apply_replay_gain_int16(playItem_t * it,char * bytes,int size)154 apply_replay_gain_int16 (playItem_t *it, char *bytes, int size) {
155     if (!conf_replaygain_mode) {
156         return;
157     }
158     int vol = get_int_volume ();
159     if (vol < 0) {
160         return;
161     }
162     int16_t *s = (int16_t*)bytes;
163     for (int j = 0; j < size/2; j++) {
164         int32_t sample = ((int32_t)(*s)) * vol / 1000;
165         if (sample > 0x7fff) {
166             sample = 0x7fff;
167         }
168         else if (sample < -0x8000) {
169             sample = -0x8000;
170         }
171         *s = (int16_t)sample;
172         s++;
173     }
174 }
175 
176 void
apply_replay_gain_int24(playItem_t * it,char * bytes,int size)177 apply_replay_gain_int24 (playItem_t *it, char *bytes, int size) {
178     if (!conf_replaygain_mode) {
179         return;
180     }
181     int64_t vol = get_int_volume ();
182     if (vol < 0) {
183         return;
184     }
185     char *s = (char*)bytes;
186     for (int j = 0; j < size/3; j++) {
187         int32_t sample = ((unsigned char)s[0]) | ((unsigned char)s[1]<<8) | (s[2]<<16);
188         sample = sample * vol / 1000;
189         if (sample > 0x7fffff) {
190             sample = 0x7fffff;
191         }
192         else if (sample < -0x800000) {
193             sample = -0x800000;
194         }
195         s[0] = (sample&0x0000ff);
196         s[1] = (sample&0x00ff00)>>8;
197         s[2] = (sample&0xff0000)>>16;
198         s += 3;
199     }
200 }
201 
202 void
apply_replay_gain_int32(playItem_t * it,char * bytes,int size)203 apply_replay_gain_int32 (playItem_t *it, char *bytes, int size) {
204     if (!conf_replaygain_mode) {
205         return;
206     }
207     int64_t vol = get_int_volume ();
208     if (vol < 0) {
209         return;
210     }
211     int32_t *s = (int32_t*)bytes;
212     for (int j = 0; j < size/4; j++) {
213         int64_t sample = ((int32_t)(*s)) * vol / 1000;
214         *s = (int32_t)sample;
215         s++;
216     }
217 }
218 
219 void
apply_replay_gain_float32(playItem_t * it,char * bytes,int size)220 apply_replay_gain_float32 (playItem_t *it, char *bytes, int size) {
221     if (!conf_replaygain_mode) {
222         return;
223     }
224     float vol = 1.f;
225     if (conf_replaygain_mode == 1) {
226         if (rg_trackgain == 1) {
227             vol = rg_trackgain_global_preamp;
228         } else {
229             vol = rg_trackgain_full_preamp;
230         }
231         if (conf_replaygain_scale) {
232             if (vol * rg_trackpeak > 1.f) {
233                 vol = 1.f / rg_trackpeak;
234             }
235         }
236     }
237     else if (conf_replaygain_mode == 2) {
238         if (rg_albumgain == 1) {
239             vol = rg_albumgain_global_preamp;
240         } else {
241             vol = rg_albumgain_full_preamp;
242         }
243         if (conf_replaygain_scale) {
244             if (vol * rg_albumpeak > 1.f) {
245                 vol = 1.f / rg_albumpeak;
246             }
247         }
248     }
249     float *s = (float*)bytes;
250     for (int j = 0; j < size/4; j++) {
251         float sample = ((float)*s) * vol;
252         if (sample > 1.f) {
253             sample = 1.f;
254         }
255         else if (sample < -1.f) {
256             sample = -1.f;
257         }
258         *s = sample;
259         s++;
260     }
261 }
262