1 diff --git a/Makefile b/Makefile
2 index 23bcb05..2187414 100644
6 # Mike Oliphant (oliphant@gtk.org)
12 -CFLAGS+= -Wall -DHAVE_MEMCPY
13 +CFLAGS+= -Wall -Wextra -DHAVE_MEMCPY
15 # all known MS Windows OS define the ComSpec environment variable
17 @@ -26,7 +26,7 @@ endif
19 # BeOS doesn't have libm (it's all in libroot)
20 ifneq ($(OSTYPE),beos)
24 # BeOS: without this it wants to use bcopy() :^)
25 CFLAGS+= -DHAVE_MEMCPY
26 @@ -37,7 +37,7 @@ ifeq ($(OSTYPE),win)
30 -OBJS= mp3gain.o apetag.o id3tag.o gain_analysis.o rg_error.o \
31 +OBJS= mp3gain.o apetag.o id3tag.o id3tag_foobar.o gain_analysis.o rg_error.o \
32 mpglibDBL/common.o mpglibDBL/dct64_i386.o \
33 mpglibDBL/decode_i386.o mpglibDBL/interface.o \
34 mpglibDBL/layer3.o mpglibDBL/tabinit.o
35 diff --git a/apetag.c b/apetag.c
36 index 1003059..aabf23d 100644
39 @@ -143,7 +143,6 @@ int ReadMP3APETag ( FILE *fp, struct MP3GainTagInfo *info, struct APETagStruct
43 - unsigned long flags;
44 unsigned long remaining;
47 @@ -154,7 +153,6 @@ int ReadMP3APETag ( FILE *fp, struct MP3GainTagInfo *info, struct APETagStruct
49 unsigned long TagCount;
50 unsigned long origTagCount, otherFieldsCount;
51 - unsigned long curFieldNum;
55 @@ -191,11 +189,10 @@ int ReadMP3APETag ( FILE *fp, struct MP3GainTagInfo *info, struct APETagStruct
58 end = buff + TagLen - sizeof (T);
60 for ( p = buff; p < end && TagCount--; ) {
61 if (end - p < 8) break;
62 vsize = Read_LE_Uint32 (p); p += 4;
63 - flags = Read_LE_Uint32 (p); p += 4;
64 + Read_LE_Uint32 (p); p += 4;
66 remaining = (unsigned long) (end - p);
67 isize = strlen_max (p, remaining);
68 diff --git a/gain_analysis.c b/gain_analysis.c
69 index e6e4e40..b29bed7 100644
72 @@ -105,13 +105,13 @@ typedef signed int Int32_t;
73 #define YULE_FILTER filterYule
74 #define BUTTER_FILTER filterButter
75 #define RMS_PERCENTILE 0.95 // percentile which is louder than the proposed level
76 -#define MAX_SAMP_FREQ 96000. // maximum allowed sample frequency [Hz]
77 -#define RMS_WINDOW_TIME 0.050 // Time slice size [s]
78 -#define STEPS_per_dB 100. // Table entries per dB
79 -#define MAX_dB 120. // Table entries for 0...MAX_dB (normal max. values are 70...80 dB)
80 +#define MAX_SAMP_FREQ 96000 // maximum allowed sample frequency [Hz]
81 +#define RMS_WINDOW_TIME 50/1000 // Time slice size [s]
82 +#define STEPS_per_dB 100 // Table entries per dB
83 +#define MAX_dB 120 // Table entries for 0...MAX_dB (normal max. values are 70...80 dB)
85 #define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
86 -#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1) // max. Samples per Time slice
87 +#define MAX_SAMPLES_PER_WINDOW (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1) // max. Samples per Time slice
88 #define PINK_REF 64.82 //298640883795 // calibration value
90 Float_t linprebuf [MAX_ORDER * 2];
91 diff --git a/id3tag.c b/id3tag.c
92 index c32b582..dd31150 100644
95 @@ -89,8 +89,8 @@ struct ID3v2FrameStruct {
98 struct upgrade_id3v22_struct {
105 static const struct upgrade_id3v22_struct upgrade_id3v22_table[] = {
106 @@ -224,8 +224,8 @@ static void id3_release_frames(struct ID3v2FrameStruct *frame)
110 - free(tframe->data);
112 + delete tframe->data;
117 @@ -272,13 +272,13 @@ static struct ID3v2FrameStruct * id3_make_frame(const char *frameid, const char
121 - frame = malloc(sizeof(struct ID3v2FrameStruct));
122 + frame = new (struct ID3v2FrameStruct);
124 strncpy(frame->frameid, frameid, 4);
128 - frame->data = malloc(k);
129 + frame->data = new unsigned char[k];
131 va_start(ap, format);
133 @@ -542,7 +542,7 @@ static int id3_parse_v2_tag(FILE *f, struct ID3v2TagStruct *tag)
134 DBG((" version=%04x length=%lu flags=%02x\n", tag->version, tag->length, tag->flags));
136 /* Read rest of the tag. */
137 - tagdata = malloc(dlen);
138 + tagdata = new unsigned char[dlen];
139 if (fread(tagdata, 1, dlen, f) != dlen)
142 @@ -677,7 +677,7 @@ static int id3_parse_v2_tag(FILE *f, struct ID3v2TagStruct *tag)
145 /* Allocate frame structure. */
146 - frame = malloc(sizeof(struct ID3v2FrameStruct));
147 + frame = new (struct ID3v2FrameStruct);
149 memcpy(frame->frameid, frameid, 4);
150 frame->flags = fflags;
151 @@ -688,13 +688,13 @@ static int id3_parse_v2_tag(FILE *f, struct ID3v2TagStruct *tag)
152 /* Copy frame data. */
153 if ((tag->version >> 8) == 4 && (fflags & FRAMEFL_UNSYNC) != 0) {
154 /* This frame is unsynchronized; decode it now. */
155 - frame->data = malloc(flen);
156 + frame->data = new unsigned char[flen];
157 k = id3_get_unsync_data(frame->data, tagdata + p, flen);
160 } else if ((tag->version >> 8) == 2 && memcmp(frameid, "APIC", 4) == 0) {
161 /* APIC frame format differs from PIC frame format */
162 - frame->data = malloc(flen + 12);
163 + frame->data = new unsigned char[flen + 12];
164 frame->data[0] = tagdata[p];
166 if (memcmp(tagdata + p + 1, "PNG", 3) == 0) {
167 @@ -713,7 +713,7 @@ static int id3_parse_v2_tag(FILE *f, struct ID3v2TagStruct *tag)
170 /* Normal case, just copy the data. */
171 - frame->data = malloc(flen);
172 + frame->data = new unsigned char[flen];
173 memcpy(frame->data, tagdata + p, flen);
176 @@ -735,11 +735,11 @@ static int id3_parse_v2_tag(FILE *f, struct ID3v2TagStruct *tag)
187 id3_release_frames(tag->frames);
188 return M3G_ERR_TAGFORMAT;
190 @@ -779,7 +779,7 @@ static int id3_write_tag(FILE *f, struct ID3v2TagStruct *tag)
191 DBG((" length=%lu\n", dlen));
193 /* Allocate buffer and fill with zeros. */
194 - tagdata = calloc(dlen, sizeof(unsigned char));
195 + tagdata = new unsigned char[dlen];
197 /* Prepare tag header. */
199 @@ -806,11 +806,11 @@ static int id3_write_tag(FILE *f, struct ID3v2TagStruct *tag)
201 /* Write the whole thing. */
202 if (fwrite(tagdata, 1, dlen, f) != dlen) {
205 return M3G_ERR_WRITE;
213 @@ -1024,7 +1024,7 @@ static int id3_copy_data(FILE *inf, FILE *outf, long offset, long count)
217 - buf = malloc(bufsize);
218 + buf = new char[bufsize];
220 if (fseek(inf, offset, SEEK_SET))
222 @@ -1045,7 +1045,7 @@ static int id3_copy_data(FILE *inf, FILE *outf, long offset, long count)
231 @@ -1152,8 +1152,8 @@ int WriteMP3GainID3Tag(char *filename, struct MP3GainTagInfo *info, int saveTime
232 /* This is a ReplayGain frame; kill it. */
234 *pframe = frame->next;
237 + delete frame->data;
240 pframe = &((*pframe)->next);
242 @@ -1204,14 +1204,14 @@ int WriteMP3GainID3Tag(char *filename, struct MP3GainTagInfo *info, int saveTime
245 /* Create temporary file. */
246 - tmpfilename = malloc(strlen(filename) + 5);
247 + tmpfilename = new char[strlen(filename) + 5];
248 strcpy(tmpfilename, filename);
249 strcat(tmpfilename, ".TMP");
250 outf = fopen(tmpfilename, "wb");
252 passError(MP3GAIN_UNSPECIFED_ERROR, 3, "Can not create temporary file ", tmpfilename, "\n");
255 + delete tmpfilename;
256 id3_release_frames(tag.frames);
257 return M3G_ERR_CANT_MAKE_TMP;
259 @@ -1249,7 +1249,7 @@ int WriteMP3GainID3Tag(char *filename, struct MP3GainTagInfo *info, int saveTime
261 /* Delete temp file after error. */
264 + delete tmpfilename;
268 @@ -1264,7 +1264,7 @@ int WriteMP3GainID3Tag(char *filename, struct MP3GainTagInfo *info, int saveTime
269 only _temporarily_ failed, and the original file will disappear soon, such as when
270 all handles on the file are closed. If it does disappear and we also
271 delete the tmp file, then the file is completely gone... */
273 + delete tmpfilename;
277 @@ -1278,7 +1278,7 @@ int WriteMP3GainID3Tag(char *filename, struct MP3GainTagInfo *info, int saveTime
278 fileTime(filename, setStoredTime);
282 + delete tmpfilename;
286 diff --git a/id3tag_foobar.c b/id3tag_foobar.c
288 index 0000000..9e95da2
290 +++ b/id3tag_foobar.c
293 + * File: id3tag_foobar.cpp
296 + * Created on 27 juillet 2009, 07:49
301 +#include <taglib/mpegfile.h>
302 +#include <taglib/id3v2tag.h>
303 +#include <taglib/id3v2frame.h>
305 +#include <taglib/textidentificationframe.h>
306 +#include <taglib/generalencapsulatedobjectframe.h>
308 +#include <taglib/tstring.h>
310 +#include <taglib/fileref.h>
312 +#include <taglib/unknownframe.h>
314 +#include <taglib/privateframe.h>
317 +#include "id3tag_foobar.h"
318 +#include "mp3gain.h"
320 +using namespace TagLib::ID3v2;
321 +using TagLib::String;
322 +using TagLib::ByteVector;
324 +PrivateFrame* findPrivateFrame(Tag* tag, const String &owner)
326 + FrameList l = tag->frameList("PRIV");
327 + for (FrameList::Iterator it = l.begin(); it != l.end(); ++it)
329 + PrivateFrame* f = dynamic_cast<PrivateFrame*> (*it);
330 + if (f && f->owner() == owner)
336 +void traitementTag(Tag* mp3Tag, const char* description, const int test, const char* stringTemplate, double val)
339 + // using TagLib::ID3v2::UserTextIdentificationFrame;
341 + String descriptionS = String(description, String::UTF8);
344 + UserTextIdentificationFrame* userFrame = UserTextIdentificationFrame::find(mp3Tag, descriptionS);
346 + if (userFrame == NULL && test)
348 + userFrame = new UserTextIdentificationFrame();
350 + userFrame->setDescription(descriptionS);
352 + // la memoire sera libéré tt seul !!
353 + mp3Tag->addFrame(userFrame);
358 + sprintf(sbuf, stringTemplate, val);
359 + String value = String(sbuf, String::UTF8);
360 + userFrame->setText(value);
362 + } else if (userFrame != NULL)
364 + // suppression automatique de la mem de userFrame avec true
365 + mp3Tag->removeFrame(userFrame, true);
370 + * Read gain information from an ID3v2 tag.
371 + * return 0 if nothing read
374 +int ReadMP3GainID3TagFoobar(char *filename, struct MP3GainTagInfo *info)
376 + if (access(filename, F_OK) != 0)
378 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " doesn't exist.\n");
379 + return M3G_ERR_FILEOPEN;
380 + } else if (access(filename, R_OK | W_OK) != 0)
382 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " can't be read or write.\n");
383 + return M3G_ERR_CANT_MODIFY_FILE;
386 + TagLib::MPEG::File file(filename);
388 + Tag* mp3Tag = file.ID3v2Tag(false);
390 + PrivateFrame* privateMp3GainFrame = findPrivateFrame(mp3Tag, "mp3gain");
391 + if (privateMp3GainFrame != 0)
393 + int dirty = info->dirty;
394 + int recalc = info->recalc;
395 + memcpy((char*) info, privateMp3GainFrame->data().data(), sizeof (MP3GainTagInfo));
396 + info->dirty = dirty;
397 + info->recalc = recalc;
407 + * Remove gain information from the ID3v2 tag.
408 + * Return 1 on success, 0 if no changes are needed, or a negative error code.
410 +int RemoveMP3GainID3TagFoobar(char *filename, int saveTimeStamp)
412 + if (access(filename, F_OK) != 0)
414 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " doesn't exist.\n");
415 + return M3G_ERR_FILEOPEN;
416 + } else if (access(filename, R_OK | W_OK) != 0)
418 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " can't be read or write.\n");
419 + return M3G_ERR_CANT_MODIFY_FILE;
423 + fileTime(filename, storeTime);
425 + TagLib::MPEG::File file(filename);
427 + Tag* mp3Tag = file.ID3v2Tag(false);
429 + if (mp3Tag == NULL)
434 + const char* listeDescription[4] = {"replaygain_track_gain", "replaygain_track_peak", "replaygain_album_gain", "replaygain_album_peak"};
436 + for (int i = 0; i < 4; ++i)
438 + String descriptionS(listeDescription[i]);
440 + UserTextIdentificationFrame* userFrame = UserTextIdentificationFrame::find(mp3Tag, descriptionS);
442 + if (userFrame != NULL)
444 + mp3Tag->removeFrame(userFrame, true);
448 + PrivateFrame* privateMp3GainFrame = findPrivateFrame(mp3Tag, "mp3gain");
449 + if (privateMp3GainFrame != 0)
451 + mp3Tag->removeFrame(privateMp3GainFrame, true);
457 + fileTime(filename, setStoredTime);
463 + * (Re-)Write gain information to an ID3v2 tag.
465 +int WriteMP3GainID3TagFoobar(char *filename, struct MP3GainTagInfo *info, int saveTimeStamp)
467 + if (access(filename, F_OK) != 0)
469 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " doesn't exist.\n");
470 + return M3G_ERR_FILEOPEN;
471 + } else if (access(filename, R_OK | W_OK) != 0)
473 + passError(MP3GAIN_UNSPECIFED_ERROR, 3, "File ", filename, " can't be read or write.\n");
474 + return M3G_ERR_CANT_MODIFY_FILE;
478 + fileTime(filename, storeTime);
480 + TagLib::MPEG::File file(filename);
482 + Tag* mp3Tag = file.ID3v2Tag(true);
484 + traitementTag(mp3Tag, "replaygain_track_gain", info->haveTrackGain, "%+.2f dB", info->trackGain);
485 + traitementTag(mp3Tag, "replaygain_track_peak", info->haveTrackPeak, "%.6f", info->trackPeak);
486 + traitementTag(mp3Tag, "replaygain_album_gain", info->haveAlbumGain, "%+.2f dB", info->albumGain);
487 + traitementTag(mp3Tag, "replaygain_album_peak", info->haveAlbumPeak, "%.6f", info->albumPeak);
489 + PrivateFrame* privateMp3GainFrame = findPrivateFrame(mp3Tag, "mp3gain");
490 + if (privateMp3GainFrame == 0)
492 + privateMp3GainFrame = new PrivateFrame();
493 + privateMp3GainFrame->setOwner("mp3gain");
496 + ByteVector data((const char*) info, sizeof (MP3GainTagInfo));
498 + privateMp3GainFrame->setData(data);
500 + mp3Tag->addFrame(privateMp3GainFrame);
505 + fileTime(filename, setStoredTime);
511 diff --git a/id3tag_foobar.h b/id3tag_foobar.h
513 index 0000000..dd3202f
515 +++ b/id3tag_foobar.h
518 + * File: id3tag_foobar.h
519 + * Author: Maxime de Roucy
521 + * Created on 27 juillet 2009, 07:49
524 +#ifndef _ID3TAG_FOOBAR_H
525 +#define _ID3TAG_FOOBAR_H
527 +int ReadMP3GainID3TagFoobar(char *filename, struct MP3GainTagInfo *info);
529 +int WriteMP3GainID3TagFoobar(char *filename, struct MP3GainTagInfo *info, int saveTimeStamp);
531 +int RemoveMP3GainID3TagFoobar(char *filename, int saveTimeStamp);
533 +#endif /* _ID3TAG_FOOBAR_H */
535 diff --git a/mp3gain.c b/mp3gain.c
536 index c575af0..04c657a 100644
543 +#include "id3tag_foobar.h"
547 @@ -145,6 +146,7 @@ int deleteTag = 0;
548 int forceRecalculateTag = 0;
549 int checkTagOnly = 0;
550 static int useId3 = 0;
551 +static int useId3_foobar = 0;
555 @@ -693,7 +695,6 @@ int changeGain(char *filename AACGAIN_ARG(AACGainHandle aacH), int leftgainchang
563 @@ -823,7 +824,6 @@ int changeGain(char *filename AACGAIN_ARG(AACGainHandle aacH), int leftgainchang
566 mpegver = (curframe[1] >> 3) & 0x03;
567 - freqidx = (curframe[2] >> 2) & 0x03;
569 bytesinframe = arrbytesinframe[bitridx] + ((curframe[2] >> 1) & 0x01);
571 @@ -857,7 +857,6 @@ int changeGain(char *filename AACGAIN_ARG(AACGainHandle aacH), int leftgainchang
573 mpegver = (curframe[1] >> 3) & 0x03;
574 crcflag = curframe[1] & 0x01;
575 - freqidx = (curframe[2] >> 2) & 0x03;
577 bytesinframe = arrbytesinframe[bitridx] + ((curframe[2] >> 1) & 0x01);
578 mode = (curframe[3] >> 6) & 0x03;
579 @@ -1118,6 +1117,9 @@ void WriteMP3GainTag(char *filename AACGAIN_ARG(AACGainHandle aacH), struct MP3G
580 /* Write ID3 tag; remove stale APE tag if it exists. */
581 if (WriteMP3GainID3Tag(filename, info, saveTimeStamp) >= 0)
582 RemoveMP3GainAPETag(filename, saveTimeStamp);
583 + } else if (useId3_foobar) {
584 + if (WriteMP3GainID3TagFoobar(filename, info, saveTimeStamp) >= 0)
585 + RemoveMP3GainAPETag(filename, saveTimeStamp);
588 WriteMP3GainAPETag(filename, info, fileTags, saveTimeStamp);
589 @@ -1346,6 +1348,7 @@ void fullUsage(char *progname) {
590 fprintf(stderr,"\t%cs s - skip (ignore) stored tag info (do not read or write tags)\n",SWITCH_CHAR);
591 fprintf(stderr,"\t%cs r - force re-calculation (do not read tag info)\n",SWITCH_CHAR);
592 fprintf(stderr,"\t%cs i - use ID3v2 tag for MP3 gain info\n",SWITCH_CHAR);
593 + fprintf(stderr,"\t%cs f - use ID3v2 tag (like foobar2000 : replaygain_track_*) for MP3 gain info\n",SWITCH_CHAR);
594 fprintf(stderr,"\t%cs a - use APE tag for MP3 gain info (default)\n",SWITCH_CHAR);
595 fprintf(stderr,"\t%cu - undo changes made (based on stored tag info)\n",SWITCH_CHAR);
596 fprintf(stderr,"\t%cw - \"wrap\" gain change if gain+change > 255 or gain+change < 0\n",SWITCH_CHAR);
597 @@ -1413,7 +1416,6 @@ int main(int argc, char **argv) {
602 unsigned char *Xingcheck;
605 @@ -1664,6 +1666,10 @@ int main(int argc, char **argv) {
616 @@ -1784,6 +1790,14 @@ int main(int argc, char **argv) {
617 tagInfo[mainloop].dirty = 1;
619 ReadMP3GainID3Tag(curfilename,&(tagInfo[mainloop]));
620 + } else if (useId3_foobar) {
621 + if (tagInfo[mainloop].haveTrackGain || tagInfo[mainloop].haveAlbumGain ||
622 + tagInfo[mainloop].haveMinMaxGain || tagInfo[mainloop].haveAlbumMinMaxGain ||
623 + tagInfo[mainloop].haveUndo) {
624 + /* Mark the file dirty to force upgrade to ID3v2 */
625 + tagInfo[mainloop].dirty = 1;
627 + ReadMP3GainID3TagFoobar(curfilename, &(tagInfo[mainloop]));
630 /*fprintf(stdout,"Read previous tags from %s\n",curfilename);
631 @@ -2037,7 +2051,9 @@ int main(int argc, char **argv) {
632 RemoveMP3GainAPETag(argv[mainloop], saveTime);
634 RemoveMP3GainID3Tag(argv[mainloop], saveTime);
636 + } else if (useId3_foobar) {
637 + RemoveMP3GainID3TagFoobar(argv[mainloop], saveTime);
640 if ((!QuietMode)&&(!databaseFormat))
641 fprintf(stderr,"Deleting tag info of %s...\n", argv[mainloop]);
642 @@ -2234,7 +2250,6 @@ int main(int argc, char **argv) {
645 mpegver = (curframe[1] >> 3) & 0x03;
646 - crcflag = curframe[1] & 0x01;
647 freqidx = (curframe[2] >> 2) & 0x03;
649 bytesinframe = arrbytesinframe[bitridx] + ((curframe[2] >> 1) & 0x01);