changeset 97:a19f24790f3c trunk

[svn] It compiles now.
author chainsaw
date Sat, 21 Oct 2006 18:02:01 -0700
parents 63bde7ca7ad0
children 4b5ee7e23bd1
files ChangeLog src/flac/grabbag/replaygain.h src/flac/plugin.c src/flac/plugin_common/Makefile src/flac/plugin_common/Makefile.lite src/flac/plugin_common/README src/flac/plugin_common/plugin_common_static.dsp src/flac/plugin_common/replaygain.c src/flac/plugin_common/replaygain.h src/flac/replaygain.c src/flac/replaygain_analysis.h
diffstat 11 files changed, 215 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Oct 21 09:21:12 2006 -0700
+++ b/ChangeLog	Sat Oct 21 18:02:01 2006 -0700
@@ -1,3 +1,12 @@
+2006-10-21 16:21:12 +0000  Tony Vroon <chainsaw@gentoo.org>
+  revision [192]
+  First attempt at porting our FLAC plugin to API 1.1.3 (completely incompatible, as usual!). Needs more work and a version-sensitize FLAC checker.
+  trunk/src/flac/Makefile.lite |   39 ---
+  trunk/src/flac/fileinfo.c    |   71 +++++
+  trunk/src/flac/plugin.c      |  517 +++++++++++++++----------------------------
+  3 files changed, 255 insertions(+), 372 deletions(-)
+
+
 2006-10-20 07:59:45 +0000  Yoshiki Yazawa <yaz@cc.rim.or.jp>
   revision [190]
   - xspf now uses url encoding for location entry.
--- a/src/flac/grabbag/replaygain.h	Sat Oct 21 09:21:12 2006 -0700
+++ b/src/flac/grabbag/replaygain.h	Sat Oct 21 18:02:01 2006 -0700
@@ -1,5 +1,5 @@
 /* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ * Copyright (C) 2002,2003,2004,2005,2006 Josh Coalson
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -35,6 +35,12 @@
 
 extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
 
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
+
 FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
 
 FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
@@ -48,13 +54,15 @@
 /* These three functions return an error string on error, or NULL if successful */
 const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak);
 const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block);
 const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak);
 const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak);
 const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime);
 const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime);
 const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime);
 
-FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, double *gain, double *peak);
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak);
 double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping);
 
 #ifdef __cplusplus
--- a/src/flac/plugin.c	Sat Oct 21 09:21:12 2006 -0700
+++ b/src/flac/plugin.c	Sat Oct 21 18:02:01 2006 -0700
@@ -88,7 +88,7 @@
 
 static void *play_loop_(void *arg);
 
-static FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder);
+static FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder);
 static void safe_decoder_finish_(FLAC__StreamDecoder *decoder);
 static void safe_decoder_delete_(FLAC__StreamDecoder *decoder);
 
@@ -186,6 +186,7 @@
 {
 	ConfigDb *db;
 	FLAC__uint32 test = 1;
+	gchar *tmp;
 
 	is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true;
 
@@ -572,7 +573,7 @@
 	return 0; /* to silence the compiler warning about not returning a value */
 }
 
-FLAC__bool safe_decoder_init_(const char *filename, FLAC__StreamDecoder *decoder)
+FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder)
 {
 	if(decoder == 0)
 		return false;
--- a/src/flac/plugin_common/Makefile	Sat Oct 21 09:21:12 2006 -0700
+++ b/src/flac/plugin_common/Makefile	Sat Oct 21 18:02:01 2006 -0700
@@ -11,12 +11,14 @@
 	defs.h \
 	dither.h \
 	locale_hack.h \
-	tags.h
+	tags.h \
+	replaygain.h
 
 SOURCES = \
 	charset.c \
 	dither.c \
-	tags.c
+	tags.c \
+	replaygain.c
 
 OBJECTS = ${SOURCES:.c=.o}
 
--- a/src/flac/plugin_common/Makefile.lite	Sat Oct 21 09:21:12 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#  plugin_common - Routines common to several plugins
-#  Copyright (C) 2002,2003,2004,2005  Josh Coalson
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  This program is distributed in the hope that it will be useful,
-#  but WITHOUT ANY WARRANTY; without even the implied warranty of
-#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#  GNU General Public License for more details.
-#
-#  You should have received a copy of the GNU General Public License
-#  along with this program; if not, write to the Free Software
-#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#
-# GNU makefile
-#
-
-topdir = ../..
-
-LIB_NAME = libplugin_common
-INCLUDES = -I$(topdir)/include -I$(HOME)/local/include -I$(ICONV_INCLUDE_DIR)
-DEFINES  = 
-
-SRCS_C = \
-	charset.c \
-	dither.c \
-	tags.c
-
-include $(topdir)/build/lib.mk
-
-# DO NOT DELETE THIS LINE -- make depend depends on it.
--- a/src/flac/plugin_common/README	Sat Oct 21 09:21:12 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-This directory contains a convenience library of routines that are
-common to the plugins.
--- a/src/flac/plugin_common/plugin_common_static.dsp	Sat Oct 21 09:21:12 2006 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-# Microsoft Developer Studio Project File - Name="plugin_common_static" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Static Library" 0x0104
-
-CFG=plugin_common_static - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "plugin_common_static.mak".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "plugin_common_static.mak" CFG="plugin_common_static - Win32 Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "plugin_common_static - Win32 Release" (based on "Win32 (x86) Static Library")
-!MESSAGE "plugin_common_static - Win32 Debug" (based on "Win32 (x86) Static Library")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName "plugin_common"
-# PROP Scc_LocalPath "..\.."
-CPP=cl.exe
-RSC=rc.exe
-
-!IF  "$(CFG)" == "plugin_common_static - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "..\..\obj\release\lib"
-# PROP Intermediate_Dir "Release_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /WX /GX /Ox /Og /Oi /Os /Op /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /nodefaultlib
-
-!ELSEIF  "$(CFG)" == "plugin_common_static - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "..\..\obj\debug\lib"
-# PROP Intermediate_Dir "Debug_static"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\include" /I "..\..\include" /D "FLAC__NO_DLL" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LIB32=link.exe -lib
-# ADD BASE LIB32 /nologo
-# ADD LIB32 /nologo /nodefaultlib
-
-!ENDIF 
-
-# Begin Target
-
-# Name "plugin_common_static - Win32 Release"
-# Name "plugin_common_static - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp"
-# Begin Source File
-
-SOURCE=.\charset.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\dither.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\tags.c
-# End Source File
-# End Group
-# Begin Group "Public Header Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\all.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\charset.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\dither.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\locale_hack.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\tags.h
-# End Source File
-# End Group
-# End Target
-# End Project
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac/plugin_common/replaygain.c	Sat Oct 21 18:02:01 2006 -0700
@@ -0,0 +1,62 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "replaygain.h"
+#include "FLAC/ordinals.h"
+#include "FLAC/metadata.h"
+#include "grabbag.h"
+
+void FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set)
+{
+	FLAC__Metadata_SimpleIterator *iterator = FLAC__metadata_simple_iterator_new();
+
+	*track_gain_set = *album_gain_set = *track_peak_set = *album_peak_set = false;
+
+	if(0 != iterator) {
+		if(FLAC__metadata_simple_iterator_init(iterator, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+			FLAC__bool got_vorbis_comments = false;
+			do {
+				if(FLAC__metadata_simple_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+					FLAC__StreamMetadata *block = FLAC__metadata_simple_iterator_get_block(iterator);
+					if(0 != block) {
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/false, /*strict=*/true, reference, track_gain, track_peak)) {
+							*reference_set = *track_gain_set = *track_peak_set = true;
+						}
+						if(grabbag__replaygain_load_from_vorbiscomment(block, /*album_mode=*/true, /*strict=*/true, reference, album_gain, album_peak)) {
+							*reference_set = *album_gain_set = *album_peak_set = true;
+						}
+						FLAC__metadata_object_delete(block);
+						got_vorbis_comments = true;
+					}
+				}
+			} while (!got_vorbis_comments && FLAC__metadata_simple_iterator_next(iterator));
+		}
+		FLAC__metadata_simple_iterator_delete(iterator);
+	}
+	return;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/flac/plugin_common/replaygain.h	Sat Oct 21 18:02:01 2006 -0700
@@ -0,0 +1,32 @@
+/* plugin_common - Routines common to several plugins
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
+ * Copyright (C) 2003  Philip Jägenstedt
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+#define FLAC__PLUGIN_COMMON__REPLAYGAIN_H
+
+#include "FLAC/ordinals.h"
+
+void FLAC_plugin__replaygain_get_from_file(const char *filename,
+                                           double *reference, FLAC__bool *reference_set,
+                                           double *track_gain, FLAC__bool *track_gain_set,
+                                           double *album_gain, FLAC__bool *album_gain_set,
+                                           double *track_peak, FLAC__bool *track_peak_set,
+                                           double *album_peak, FLAC__bool *album_peak_set);
+
+#endif
--- a/src/flac/replaygain.c	Sat Oct 21 09:21:12 2006 -0700
+++ b/src/flac/replaygain.c	Sat Oct 21 18:02:01 2006 -0700
@@ -1,5 +1,5 @@
 /* grabbag - Convenience lib for various routines common to several tools
- * Copyright (C) 2002,2003,2004,2005  Josh Coalson
+ * Copyright (C) 2002,2003,2004,2005,2006  Josh Coalson
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -16,11 +16,15 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
 #include "grabbag.h"
 #include "replaygain_analysis.h"
 #include "FLAC/assert.h"
-#include "FLAC/file_decoder.h"
 #include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
 #include <locale.h>
 #include <math.h>
 #include <stdio.h>
@@ -41,23 +45,27 @@
 #endif
 #define local_max(a,b) ((a)>(b)?(a):(b))
 
-static const FLAC__byte *tag_title_gain_ = (FLAC__byte*)"REPLAYGAIN_TRACK_GAIN";
-static const FLAC__byte *tag_title_peak_ = (FLAC__byte*)"REPLAYGAIN_TRACK_PEAK";
-static const FLAC__byte *tag_album_gain_ = (FLAC__byte*)"REPLAYGAIN_ALBUM_GAIN";
-static const FLAC__byte *tag_album_peak_ = (FLAC__byte*)"REPLAYGAIN_ALBUM_PEAK";
+static const char *reference_format_ = "%s=%2.1f dB";
+static const char *gain_format_ = "%s=%+2.2f dB";
 static const char *peak_format_ = "%s=%1.8f";
-static const char *gain_format_ = "%s=%+2.2f dB";
 
 static double album_peak_, title_peak_;
 
-const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 148;
+const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
 /*
+	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
 	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
 	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
 	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
 	FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
 */
 
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
+
 
 static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
 {
@@ -82,8 +90,8 @@
 
 	FLAC__ASSERT(0 != block);
 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+	FLAC__ASSERT(0 != format);
 	FLAC__ASSERT(0 != name);
-	FLAC__ASSERT(0 != value);
 
 	buffer[sizeof(buffer)-1] = '\0';
 	/*
@@ -266,7 +274,7 @@
 	FLAC__bool error;
 } DecoderInstance;
 
-static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__FileDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
 {
 	DecoderInstance *instance = (DecoderInstance*)client_data;
 	const unsigned bits_per_sample = frame->header.bits_per_sample;
@@ -295,7 +303,7 @@
 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
 }
 
-static void metadata_callback_(const FLAC__FileDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
 {
 	DecoderInstance *instance = (DecoderInstance*)client_data;
 
@@ -318,7 +326,7 @@
 	}
 }
 
-static void error_callback_(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
 	DecoderInstance *instance = (DecoderInstance*)client_data;
 
@@ -330,7 +338,7 @@
 const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
 {
 	DecoderInstance instance;
-	FLAC__FileDecoder *decoder = FLAC__file_decoder_new();
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
 
 	if(0 == decoder)
 		return "memory allocation error";
@@ -338,27 +346,21 @@
 	instance.error = false;
 
 	/* It does these three by default but lets be explicit: */
-	FLAC__file_decoder_set_md5_checking(decoder, false);
-	FLAC__file_decoder_set_metadata_ignore_all(decoder);
-	FLAC__file_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
 
-	FLAC__file_decoder_set_filename(decoder, filename);
-	FLAC__file_decoder_set_write_callback(decoder, write_callback_);
-	FLAC__file_decoder_set_metadata_callback(decoder, metadata_callback_);
-	FLAC__file_decoder_set_error_callback(decoder, error_callback_);
-	FLAC__file_decoder_set_client_data(decoder, &instance);
-
-	if(FLAC__file_decoder_init(decoder) != FLAC__FILE_DECODER_OK) {
-		FLAC__file_decoder_delete(decoder);
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
 		return "initializing decoder";
 	}
 
-	if(!FLAC__file_decoder_process_until_end_of_file(decoder) || instance.error) {
-		FLAC__file_decoder_delete(decoder);
+	if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
+		FLAC__stream_decoder_delete(decoder);
 		return "decoding file";
 	}
 
-	FLAC__file_decoder_delete(decoder);
+	FLAC__stream_decoder_delete(decoder);
 
 	grabbag__replaygain_get_title(title_gain, title_peak);
 
@@ -369,6 +371,9 @@
 {
 	const char *error;
 
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
+		return error;
+
 	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
 		return error;
 
@@ -378,20 +383,34 @@
 	return 0;
 }
 
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
+{
+	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
+		return "memory allocation error";
+
+	if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
+		return "memory allocation error";
+
+	return 0;
+}
+
 const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
 {
 	FLAC__ASSERT(0 != block);
 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
 	if(
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_album_gain_) < 0 ||
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_album_peak_) < 0
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
 	)
 		return "memory allocation error";
 
 	if(
-		!append_tag_(block, peak_format_, tag_album_peak_, album_peak) ||
-		!append_tag_(block, gain_format_, tag_album_gain_, album_gain)
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
 	)
 		return "memory allocation error";
 
@@ -404,14 +423,14 @@
 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
 	if(
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_title_gain_) < 0 ||
-		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)tag_title_peak_) < 0
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
+		FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
 	)
 		return "memory allocation error";
 
 	if(
-		!append_tag_(block, peak_format_, tag_title_peak_, title_peak) ||
-		!append_tag_(block, gain_format_, tag_title_gain_, title_gain)
+		!append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
+		!append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
 	)
 		return "memory allocation error";
 
@@ -515,6 +534,26 @@
 	return 0;
 }
 
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
+{
+	FLAC__Metadata_Chain *chain;
+	FLAC__StreamMetadata *block;
+	const char *error;
+
+	if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+		return error;
+
+	if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
+		FLAC__metadata_chain_delete(chain);
+		return error;
+	}
+
+	if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+		return error;
+
+	return 0;
+}
+
 const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
 {
 	FLAC__Metadata_Chain *chain;
@@ -570,7 +609,7 @@
 		return false;
 	q++;
 	memset(s, 0, sizeof(s)-1);
-	strncpy(s, q, local_min(sizeof(s)-1, (size_t)(entry->length - (q-p))));
+	strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p)));
 
 	v = strtod(s, &end);
 	if(end == s)
@@ -580,22 +619,33 @@
 	return true;
 }
 
-FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, double *gain, double *peak)
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
 {
-	int gain_offset, peak_offset;
+	int reference_offset, gain_offset, peak_offset;
 
 	FLAC__ASSERT(0 != block);
+	FLAC__ASSERT(0 != reference);
+	FLAC__ASSERT(0 != gain);
+	FLAC__ASSERT(0 != peak);
 	FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
 
-	if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_gain_ : tag_title_gain_))))
-		return false;
-	if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? tag_album_peak_ : tag_title_peak_))))
-		return false;
+	/* Default to current level until overridden by a detected tag; this
+	 * will always be true until we change replaygain_analysis.c
+	 */
+	*reference = ReplayGainReferenceLoudness;
+
+	if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
+		(void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
+
+	if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+	if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
 
 	if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
-		return false;
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
 	if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
-		return false;
+		return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
 
 	return true;
 }
--- a/src/flac/replaygain_analysis.h	Sat Oct 21 09:21:12 2006 -0700
+++ b/src/flac/replaygain_analysis.h	Sat Oct 21 18:02:01 2006 -0700
@@ -43,6 +43,7 @@
 #endif
 
 typedef float   Float_t;         /* Type used for filtering */
+extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */
 
 int     InitGainAnalysis ( long samplefreq );
 int     AnalyzeSamples   ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels );