1 /* Copyright (C) 1999--2005 Chris Vaill
2    This file is part of normalize.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*/
17 
18 #define _POSIX_C_SOURCE 2
19 
20 #include "config.h"
21 
22 #include <stdio.h>
23 #if STDC_HEADERS
24 # include <stdlib.h>
25 # include <string.h>
26 #else
27 # if HAVE_STDLIB_H
28 #  include <stdlib.h>
29 # endif
30 # if HAVE_STRING_H
31 #  include <string.h>
32 # else
33 #  ifndef HAVE_STRCHR
34 #   define strchr index
35 #   define strrchr rindex
36 #  endif
37 #  ifndef HAVE_MEMCPY
38 #   define memcpy(d,s,n) bcopy((s),(d),(n))
39 #   define memmove(d,s,n) bcopy((s),(d),(n))
40 #  endif
41 # endif
42 #endif
43 #if HAVE_MATH_H
44 # include <math.h>
45 #endif
46 #if HAVE_ERRNO_H
47 # include <errno.h>
48 #endif
49 
50 #ifdef ENABLE_NLS
51 # define _(msgid) gettext (msgid)
52 # include <libintl.h>
53 #else
54 # define _(msgid) (msgid)
55 #endif
56 #define N_(msgid) (msgid)
57 
58 #include "common.h"
59 #include "nid3.h"
60 
61 extern void progress_callback(char *prefix, float fraction_completed);
62 extern char *basename(char *path);
63 extern void *xmalloc(size_t size);
64 
65 extern char *progname;
66 extern int verbose;
67 extern int id3_compat;
68 extern int id3_unsync;
69 extern double adjust_thresh;
70 extern int batch_mode; /* FIXME: remove */
71 
72 
73 /* adjust_id3() takes gain in decibels */
74 static int
adjust_id3(char * fname,double gain)75 adjust_id3(char *fname, double gain)
76 {
77   id3_t tag;
78   id3_frame_t fr;
79   int ret = 1;
80   char prefix_buf[18];
81 
82   /* initialize progress meter */
83   if (verbose >= VERBOSE_PROGRESS) {
84     strncpy(prefix_buf, basename(fname), 17);
85     prefix_buf[17] = '\0';
86     progress_callback(prefix_buf, 0.0);
87   }
88 
89   tag = id3_open(fname, ID3_RDWR);
90   if (tag == NULL)
91     return -1;
92 
93   if (fabs(gain) < adjust_thresh) {
94     /* gain is below the threshold, so we should *remove* any RVA2 frame */
95     fr = id3_get_frame_by_id(tag, "RVA2");
96     if (fr)
97       id3_frame_delete(fr);
98     fr = id3_get_frame_by_id(tag, "XRVA");
99     if (fr)
100       id3_frame_delete(fr);
101   } else if (id3_rva_set(tag, "normalize", ID3_CHANNEL_MASTER, gain) == -1) {
102     fprintf(stderr, _("%s: error reading ID3 tag\n"), progname);
103     ret = -1;
104     goto error_close;
105   }
106 
107   if (id3_compat) {
108     if (id3_set_version(tag, ID3_VERSION_2_3) == -1) {
109       fprintf(stderr, _("%s: error converting tag\n"), progname);
110       ret = -1;
111     }
112   } else {
113     if (id3_set_version(tag, ID3_VERSION_2_4) == -1) {
114       fprintf(stderr, _("%s: error converting tag\n"), progname);
115       ret = -1;
116     }
117   }
118   if (id3_unsync)
119     id3_set_unsync(tag, 1);
120   if (id3_write(tag) == -1) {
121     fprintf(stderr, _("%s: error writing ID3 tag\n"), progname);
122     ret = -1;
123   }
124 
125  error_close:
126   id3_close(tag);
127 
128   /* update progress meter */
129   if (verbose >= VERBOSE_PROGRESS)
130     progress_callback(prefix_buf, 1.0);
131 
132   return ret;
133 }
134 
135 
136 /*
137  * input is read from read_fd and output is written to write_fd:
138  * filename is used only for messages.
139  *
140  * The si pointer gives the peaks so we know if limiting is needed
141  * or not.  It may be specified as NULL if this information is not
142  * available.
143  */
144 int
apply_gain_mp3(char * filename,double gain,struct signal_info * si)145 apply_gain_mp3(char *filename, double gain, struct signal_info *si)
146 {
147   int ret = 0;
148 
149   gain = FRACTODB(gain); /* we want the gain in dB */
150 
151   if (!batch_mode && verbose >= VERBOSE_PROGRESS)
152     fprintf(stderr, _("Applying adjustment of %0.2fdB to %s...\n"),
153 	    gain, filename);
154 
155   /* either set RVA2 id3 tag or adjust scale factors */
156 #if 0
157   ret = adjust_scalefactors(filename, gain);
158 #else
159   ret = adjust_id3(filename, gain);
160 #endif
161 
162   return ret;
163 }
164