summaryrefslogtreecommitdiff
path: root/apps/replaygain.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/replaygain.c')
-rw-r--r--apps/replaygain.c222
1 files changed, 0 insertions, 222 deletions
diff --git a/apps/replaygain.c b/apps/replaygain.c
deleted file mode 100644
index a178321385..0000000000
--- a/apps/replaygain.c
+++ /dev/null
@@ -1,222 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Magnus Holmgren
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <ctype.h>
23#include <math.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include "strlcpy.h"
29#include "strcasecmp.h"
30#include "system.h"
31#include "metadata.h"
32#include "debug.h"
33#include "replaygain.h"
34#include "fixedpoint.h"
35
36#define FP_BITS (12)
37#define FP_ONE (1 << FP_BITS)
38#define FP_MIN (-48 * FP_ONE)
39#define FP_MAX ( 17 * FP_ONE)
40
41void replaygain_itoa(char* buffer, int length, long int_gain)
42{
43 /* int_gain uses Q19.12 format. */
44 int one = abs(int_gain) >> FP_BITS;
45 int cent = ((abs(int_gain) & 0x0fff) * 100 + (FP_ONE/2)) >> FP_BITS;
46 snprintf(buffer, length, "%s%d.%02d dB", (int_gain<0) ? "-":"", one, cent);
47}
48
49static long fp_atof(const char* s, int precision)
50{
51 long int_part = 0;
52 long int_one = BIT_N(precision);
53 long frac_part = 0;
54 long frac_count = 0;
55 long frac_max = ((precision * 4) + 12) / 13;
56 long frac_max_int = 1;
57 long sign = 1;
58 bool point = false;
59
60 while ((*s != '\0') && isspace(*s))
61 {
62 s++;
63 }
64
65 if (*s == '-')
66 {
67 sign = -1;
68 s++;
69 }
70 else if (*s == '+')
71 {
72 s++;
73 }
74
75 while (*s != '\0')
76 {
77 if (*s == '.')
78 {
79 if (point)
80 {
81 break;
82 }
83
84 point = true;
85 }
86 else if (isdigit(*s))
87 {
88 if (point)
89 {
90 if (frac_count < frac_max)
91 {
92 frac_part = frac_part * 10 + (*s - '0');
93 frac_count++;
94 frac_max_int *= 10;
95 }
96 }
97 else
98 {
99 int_part = int_part * 10 + (*s - '0');
100 }
101 }
102 else
103 {
104 break;
105 }
106
107 s++;
108 }
109
110 while (frac_count < frac_max)
111 {
112 frac_part *= 10;
113 frac_count++;
114 frac_max_int *= 10;
115 }
116
117 return sign * ((int_part * int_one)
118 + (((int64_t) frac_part * int_one) / frac_max_int));
119}
120
121static long convert_gain(long gain)
122{
123 /* Don't allow unreasonably low or high gain changes.
124 * Our math code can't handle it properly anyway. :) */
125 gain = MAX(gain, FP_MIN);
126 gain = MIN(gain, FP_MAX);
127
128 return fp_factor(gain, FP_BITS) << (24 - FP_BITS);
129}
130
131/* Get the sample scale factor in Q19.12 format from a gain value. Returns 0
132 * for no gain.
133 *
134 * str Gain in dB as a string. E.g., "-3.45 dB"; the "dB" part is ignored.
135 */
136static long get_replaygain(const char* str)
137{
138 return fp_atof(str, FP_BITS);
139}
140
141/* Get the peak volume in Q7.24 format.
142 *
143 * str Peak volume. Full scale is specified as "1.0". Returns 0 for no peak.
144 */
145static long get_replaypeak(const char* str)
146{
147 return fp_atof(str, 24);
148}
149
150/* Get a sample scale factor in Q7.24 format from a gain value.
151 *
152 * int_gain Gain in dB, multiplied by 100.
153 */
154long get_replaygain_int(long int_gain)
155{
156 return convert_gain(int_gain * FP_ONE / 100);
157}
158
159/* Parse a ReplayGain tag conforming to the "VorbisGain standard". If a
160 * valid tag is found, update mp3entry struct accordingly. Existing values
161 * are not overwritten.
162 *
163 * key Name of the tag.
164 * value Value of the tag.
165 * entry mp3entry struct to update.
166 */
167void parse_replaygain(const char* key, const char* value,
168 struct mp3entry* entry)
169{
170 if (((strcasecmp(key, "replaygain_track_gain") == 0) ||
171 (strcasecmp(key, "rg_radio") == 0)) &&
172 !entry->track_gain)
173 {
174 entry->track_level = get_replaygain(value);
175 entry->track_gain = convert_gain(entry->track_level);
176 }
177 else if (((strcasecmp(key, "replaygain_album_gain") == 0) ||
178 (strcasecmp(key, "rg_audiophile") == 0)) &&
179 !entry->album_gain)
180 {
181 entry->album_level = get_replaygain(value);
182 entry->album_gain = convert_gain(entry->album_level);
183 }
184 else if (((strcasecmp(key, "replaygain_track_peak") == 0) ||
185 (strcasecmp(key, "rg_peak") == 0)) &&
186 !entry->track_peak)
187 {
188 entry->track_peak = get_replaypeak(value);
189 }
190 else if ((strcasecmp(key, "replaygain_album_peak") == 0) &&
191 !entry->album_peak)
192 {
193 entry->album_peak = get_replaypeak(value);
194 }
195}
196
197/* Set ReplayGain values from integers. Existing values are not overwritten.
198 *
199 * album If true, set album values, otherwise set track values.
200 * gain Gain value in dB, multiplied by 512. 0 for no gain.
201 * peak Peak volume in Q7.24 format, where 1.0 is full scale. 0 for no
202 * peak volume.
203 * entry mp3entry struct to update.
204 */
205void parse_replaygain_int(bool album, long gain, long peak,
206 struct mp3entry* entry)
207{
208 gain = gain * FP_ONE / 512;
209
210 if (album)
211 {
212 entry->album_level = gain;
213 entry->album_gain = convert_gain(gain);
214 entry->album_peak = peak;
215 }
216 else
217 {
218 entry->track_level = gain;
219 entry->track_gain = convert_gain(gain);
220 entry->track_peak = peak;
221 }
222}