# HG changeset patch # User nenolod # Date 1161658299 25200 # Node ID 117bc56d906b760c013cf64280009ba38a55ff15 # Parent aff1cf3e86dd22063591c8b2c582759a8ce59fdf [svn] flac -> flac113 diff -r aff1cf3e86dd -r 117bc56d906b ChangeLog --- a/ChangeLog Mon Oct 23 19:46:25 2006 -0700 +++ b/ChangeLog Mon Oct 23 19:51:39 2006 -0700 @@ -1,3 +1,11 @@ +2006-10-24 02:46:25 +0000 William Pitcock + revision [204] + - revert to r198 + + trunk/src/flac/plugin_common/all.h | 7 ------- + 1 file changed, 7 deletions(-) + + 2006-10-24 02:21:36 +0000 William Pitcock revision [202] - plugin now builds on audacious 1.1.2, don't expect it to work diff -r aff1cf3e86dd -r 117bc56d906b src/flac/Makefile --- a/src/flac/Makefile Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -include ../../mk/rules.mk -include ../../mk/init.mk - -SUBDIRS = plugin_common - -noinst_HEADERS = \ - charset.h \ - configure.h \ - http.h \ - plugin.h \ - tag.h \ - fast_float_math_hack.h \ - replaygain_analysis.h \ - grabbag.h \ - replaygain_synthesis.h - -OBJECTIVE_LIBS = libflac$(SHARED_SUFFIX) - -LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR) - -LIBADD = $(LIBFLAC_LIBS) -L./plugin_common -lplugin_common - -SOURCES = \ - charset.c \ - configure.c \ - fileinfo.c \ - http.c \ - plugin.c \ - tag.c \ - replaygain_synthesis.c \ - replaygain.c \ - replaygain_analysis.c \ - file.c - -OBJECTS = ${SOURCES:.c=.o} - -CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../.. $(LIBFLAC_CFLAGS) - -include ../../mk/objective.mk diff -r aff1cf3e86dd -r 117bc56d906b src/flac/charset.c --- a/src/flac/charset.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,194 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura - * - * Almost from charset.c - * EasyTAG - Tag editor for MP3 and OGG files - * Copyright (C) 1999-2001 Håvard Kvålen - * - * 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. - */ - -#include -#include -#include -#include - -#include "plugin_common/charset.h" -#include "plugin_common/locale_hack.h" -#include "charset.h" -#include "configure.h" - - -/**************** - * Declarations * - ****************/ - -#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) ) -const CharsetInfo charset_trans_array[] = { - {N_("Arabic (IBM-864)"), "IBM864" }, - {N_("Arabic (ISO-8859-6)"), "ISO-8859-6" }, - {N_("Arabic (Windows-1256)"), "windows-1256" }, - {N_("Baltic (ISO-8859-13)"), "ISO-8859-13" }, - {N_("Baltic (ISO-8859-4)"), "ISO-8859-4" }, - {N_("Baltic (Windows-1257)"), "windows-1257" }, - {N_("Celtic (ISO-8859-14)"), "ISO-8859-14" }, - {N_("Central European (IBM-852)"), "IBM852" }, - {N_("Central European (ISO-8859-2)"), "ISO-8859-2" }, - {N_("Central European (Windows-1250)"), "windows-1250" }, - {N_("Chinese Simplified (GB18030)"), "gb18030" }, - {N_("Chinese Simplified (GB2312)"), "GB2312" }, - {N_("Chinese Traditional (Big5)"), "Big5" }, - {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS" }, - {N_("Cyrillic (IBM-855)"), "IBM855" }, - {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5" }, - {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111" }, - {N_("Cyrillic (KOI8-R)"), "KOI8-R" }, - {N_("Cyrillic (Windows-1251)"), "windows-1251" }, - {N_("Cyrillic/Russian (CP-866)"), "IBM866" }, - {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U" }, - {N_("English (US-ASCII)"), "us-ascii" }, - {N_("Greek (ISO-8859-7)"), "ISO-8859-7" }, - {N_("Greek (Windows-1253)"), "windows-1253" }, - {N_("Hebrew (IBM-862)"), "IBM862" }, - {N_("Hebrew (Windows-1255)"), "windows-1255" }, - {N_("Japanese (EUC-JP)"), "EUC-JP" }, - {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP" }, - {N_("Japanese (Shift_JIS)"), "Shift_JIS" }, - {N_("Korean (EUC-KR)"), "EUC-KR" }, - {N_("Nordic (ISO-8859-10)"), "ISO-8859-10" }, - {N_("South European (ISO-8859-3)"), "ISO-8859-3" }, - {N_("Thai (TIS-620)"), "TIS-620" }, - {N_("Turkish (IBM-857)"), "IBM857" }, - {N_("Turkish (ISO-8859-9)"), "ISO-8859-9" }, - {N_("Turkish (Windows-1254)"), "windows-1254" }, - {N_("Unicode (UTF-7)"), "UTF-7" }, - {N_("Unicode (UTF-8)"), "UTF-8" }, - {N_("Unicode (UTF-16BE)"), "UTF-16BE" }, - {N_("Unicode (UTF-16LE)"), "UTF-16LE" }, - {N_("Unicode (UTF-32BE)"), "UTF-32BE" }, - {N_("Unicode (UTF-32LE)"), "UTF-32LE" }, - {N_("Vietnamese (VISCII)"), "VISCII" }, - {N_("Vietnamese (Windows-1258)"), "windows-1258" }, - {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8" }, - {N_("Western (IBM-850)"), "IBM850" }, - {N_("Western (ISO-8859-1)"), "ISO-8859-1" }, - {N_("Western (ISO-8859-15)"), "ISO-8859-15" }, - {N_("Western (Windows-1252)"), "windows-1252" } - - /* - * From this point, character sets aren't supported by iconv - */ -#if 0 - {N_("Arabic (IBM-864-I)"), "IBM864i" }, - {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E" }, - {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I" }, - {N_("Arabic (MacArabic)"), "x-mac-arabic" }, - {N_("Armenian (ARMSCII-8)"), "armscii-8" }, - {N_("Central European (MacCE)"), "x-mac-ce" }, - {N_("Chinese Simplified (GBK)"), "x-gbk" }, - {N_("Chinese Simplified (HZ)"), "HZ-GB-2312" }, - {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw" }, - {N_("Croatian (MacCroatian)"), "x-mac-croatian" }, - {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic" }, - {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian" }, - {N_("Farsi (MacFarsi)"), "x-mac-farsi"}, - {N_("Greek (MacGreek)"), "x-mac-greek" }, - {N_("Gujarati (MacGujarati)"), "x-mac-gujarati" }, - {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi" }, - {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E" }, - {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I" }, - {N_("Hebrew (MacHebrew)"), "x-mac-hebrew" }, - {N_("Hindi (MacDevanagari)"), "x-mac-devanagari" }, - {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic" }, - {N_("Korean (JOHAB)"), "x-johab" }, - {N_("Korean (UHC)"), "x-windows-949" }, - {N_("Romanian (MacRomanian)"), "x-mac-romanian" }, - {N_("Turkish (MacTurkish)"), "x-mac-turkish" }, - {N_("User Defined"), "x-user-defined" }, - {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712" }, - {N_("Vietnamese (VPS)"), "x-viet-vps" }, - {N_("Western (MacRoman)"), "x-mac-roman" }, - /* charsets whithout posibly translatable names */ - {"T61.8bit", "T61.8bit" }, - {"x-imap4-modified-utf7", "x-imap4-modified-utf7"}, - {"x-u-escaped", "x-u-escaped" }, - {"windows-936", "windows-936" } -#endif -}; - -/************* - * Functions * - *************/ - -/* - * Commons conversion functions - */ -char *convert_from_utf8_to_user(const char *string) -{ - return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set); -} - -char *convert_from_user_to_utf8(const char *string) -{ - return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8"); -} - -GList *Charset_Create_List (void) -{ - GList *list = NULL; - guint i; - - for (i=0; i - * - * 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. - */ - - -#ifndef __CHARSET_H__ -#define __CHARSET_H__ - - -/*************** - * Declaration * - ***************/ - -typedef struct { - gchar *charset_title; - gchar *charset_name; -} CharsetInfo; - -/* translated charset titles */ -extern const CharsetInfo charset_trans_array[]; - -/************** - * Prototypes * - **************/ - -/* - * The returned strings are malloc()ed an must be free()d by the caller - */ -char *convert_from_utf8_to_user(const char *string); -char *convert_from_user_to_utf8(const char *string); - -GList *Charset_Create_List (void); -GList *Charset_Create_List_UTF8_Only (void); -gchar *Charset_Get_Name_From_Title (const gchar *charset_title); -gchar *Charset_Get_Title_From_Name (const gchar *charset_name); - -#endif /* __CHARSET_H__ */ - diff -r aff1cf3e86dd -r 117bc56d906b src/flac/configure.c --- a/src/flac/configure.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,685 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura - * - * Based on mpg123 plugin - * and prefs.c - 2000/05/06 - * EasyTAG - Tag editor for MP3 and OGG files - * Copyright (C) 2000-2002 Jerome Couderc - * - * 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. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "plugin_common/locale_hack.h" -#include "replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */ -#include "charset.h" -#include "configure.h" - -/* - * Initialize Global Valueable - */ -flac_config_t flac_cfg = { - /* title */ - { - FALSE, /* tag_override */ - NULL, /* tag_format */ - FALSE, /* convert_char_set */ - NULL /* user_char_set */ - }, - /* stream */ - { - 100 /* KB */, /* http_buffer_size */ - 50, /* http_prebuffer */ - FALSE, /* use_proxy */ - "", /* proxy_host */ - 0, /* proxy_port */ - FALSE, /* proxy_use_auth */ - "", /* proxy_user */ - "", /* proxy_pass */ - FALSE, /* save_http_stream */ - "", /* save_http_path */ - FALSE, /* cast_title_streaming */ - FALSE /* use_udp_channel */ - }, - /* output */ - { - /* replaygain */ - { - FALSE, /* enable */ - TRUE, /* album_mode */ - 0, /* preamp */ - FALSE /* hard_limit */ - }, - /* resolution */ - { - /* normal */ - { - TRUE /* dither_24_to_16 */ - }, - /* replaygain */ - { - TRUE, /* dither */ - NOISE_SHAPING_LOW, /* noise_shaping */ - 16 /* bps_out */ - } - } - } -}; - - -static GtkWidget *flac_configurewin = NULL; -static GtkWidget *vbox, *notebook; - -static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc; -static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry; -static GtkWidget *replaygain_enable, *replaygain_album_mode; -static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit; -static GtkObject *replaygain_preamp; -static GtkWidget *resolution_normal_dither_24_to_16; -static GtkWidget *resolution_replaygain_dither; -static GtkWidget *resolution_replaygain_noise_shaping_frame; -static GtkWidget *resolution_replaygain_noise_shaping_radio_none; -static GtkWidget *resolution_replaygain_noise_shaping_radio_low; -static GtkWidget *resolution_replaygain_noise_shaping_radio_medium; -static GtkWidget *resolution_replaygain_noise_shaping_radio_high; -static GtkWidget *resolution_replaygain_bps_out_frame; -static GtkWidget *resolution_replaygain_bps_out_radio_16bps; -static GtkWidget *resolution_replaygain_bps_out_radio_24bps; - -static GtkObject *streaming_size_adj, *streaming_pre_adj; -static GtkWidget *streaming_save_use, *streaming_save_entry; -#ifdef FLAC_ICECAST -static GtkWidget *streaming_cast_title, *streaming_udp_title; -#endif -static GtkWidget *streaming_save_dirbrowser; -static GtkWidget *streaming_save_hbox; - -static const gchar *gtk_entry_get_text_1 (GtkWidget *widget); -static void flac_configurewin_ok(GtkWidget * widget, gpointer data); -static void configure_destroy(GtkWidget * w, gpointer data); - -static void flac_configurewin_ok(GtkWidget * widget, gpointer data) -{ - ConfigDb *db; - - (void)widget, (void)data; /* unused arguments */ - g_free(flac_cfg.title.tag_format); - flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry))); - flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry)); - - db = bmp_cfg_db_open(); - /* title */ - bmp_cfg_db_set_bool(db, "flac", "title.tag_override", flac_cfg.title.tag_override); - bmp_cfg_db_set_string(db, "flac", "title.tag_format", flac_cfg.title.tag_format); - bmp_cfg_db_set_bool(db, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set); - bmp_cfg_db_set_string(db, "flac", "title.user_char_set", flac_cfg.title.user_char_set); - /* output */ - bmp_cfg_db_set_bool(db, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable); - bmp_cfg_db_set_bool(db, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode); - bmp_cfg_db_set_int(db, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp); - bmp_cfg_db_set_bool(db, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit); - bmp_cfg_db_set_bool(db, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16); - bmp_cfg_db_set_bool(db, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither); - bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping); - bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out); - /* streaming */ - flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value; - flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value; - - flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use)); - - if (flac_cfg.stream.save_http_path != NULL) - g_free(flac_cfg.stream.save_http_path); - - flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry))); - -#ifdef FLAC_ICECAST - flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title)); - flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title)); -#endif - - bmp_cfg_db_set_int(db, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size); - bmp_cfg_db_set_int(db, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer); - bmp_cfg_db_set_bool(db, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream); - bmp_cfg_db_set_string(db, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path); -#ifdef FLAC_ICECAST - bmp_cfg_db_set_bool(db, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming); - bmp_cfg_db_set_bool(db, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel); -#endif - - bmp_cfg_db_close(db); - gtk_widget_destroy(flac_configurewin); -} - -static void configure_destroy(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ -} - -static void title_tag_override_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override)); - - gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override); - gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override); - -} - -static void convert_char_set_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set)); - - gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE); - gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set); -} - -static void replaygain_enable_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable)); - - gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable); - gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable); - gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable); -} - -static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode)); -} - -static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit)); -} - -static void replaygain_preamp_cb(GtkWidget *widget, gpointer data) -{ - GString *gstring = g_string_new(""); - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5); - - g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp); - gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str)); -} - -static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16)); -} - -static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither)); - - gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither); -} - -static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.resolution.replaygain.noise_shaping = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 : - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 : - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 : - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 : - 0 - ; -} - -static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data) -{ - (void)widget, (void)data; /* unused arguments */ - flac_cfg.output.resolution.replaygain.bps_out = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 : - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 : - 16 - ; -} - -static void streaming_save_dirbrowser_cb(gchar * dir) -{ - gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir); -} - -static void streaming_save_browse_cb(GtkWidget * w, gpointer data) -{ - (void) w; - (void) data; - if (!streaming_save_dirbrowser) - { - streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"), - flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb); - gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser); - gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin)); - gtk_widget_show(streaming_save_dirbrowser); - } -} - -static void streaming_save_use_cb(GtkWidget * w, gpointer data) -{ - gboolean save_stream; - (void) w; - (void) data; - - save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use)); - - gtk_widget_set_sensitive(streaming_save_hbox, save_stream); -} - - -void FLAC_XMMS__configure(void) -{ - GtkWidget *title_frame, *title_tag_vbox, *title_tag_label; - GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame; - GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox; - GtkWidget *resolution_replaygain_noise_shaping_vbox; - GtkWidget *resolution_replaygain_bps_out_vbox; - GtkWidget *label, *hbox; - GtkWidget *bbox, *ok, *cancel; - GList *list; - - GtkWidget *streaming_vbox; - GtkWidget *streaming_buf_frame, *streaming_buf_hbox; - GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin; - GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin; - GtkWidget *streaming_save_frame, *streaming_save_vbox; - GtkWidget *streaming_save_label, *streaming_save_browse; -#ifdef FLAC_ICECAST - GtkWidget *streaming_cast_frame, *streaming_cast_vbox; -#endif - - if (flac_configurewin != NULL) { - gdk_window_raise(flac_configurewin->window); - return; - } - flac_configurewin = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin); - gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin); - gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration")); - gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE); - gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox); - - notebook = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); - - /* Title config.. */ - - title_frame = gtk_frame_new(_("Tag Handling")); - gtk_container_border_width(GTK_CONTAINER(title_frame), 5); - - title_tag_vbox = gtk_vbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5); - gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox); - - /* Convert Char Set */ - - convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set); - gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", (GCallback)convert_char_set_cb, NULL); - gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0); - /* Combo boxes... */ - hbox = gtk_hbox_new(FALSE,4); - gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox); - label = gtk_label_new(_("Convert character set from :")); - gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); - fileCharacterSetEntry = gtk_combo_new(); - gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0); - - label = gtk_label_new (_("to :")); - gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); - userCharacterSetEntry = gtk_combo_new(); - gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0); - - gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE); - gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE); - gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE); - gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE); - - list = Charset_Create_List(); - gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only()); - gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list); - gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set)); - gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE); - gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set); - - /* Override Tagging Format */ - - title_tag_override = gtk_check_button_new_with_label(_("Override generic titles")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override); - gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", (GCallback)title_tag_override_cb, NULL); - gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0); - - title_tag_box = gtk_hbox_new(FALSE, 5); - gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override); - gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0); - - title_tag_label = gtk_label_new(_("Title format:")); - gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0); - - title_tag_entry = gtk_entry_new(); - gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format); - gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0); - - title_desc = xmms_titlestring_descriptions("pafFetnygc", 2); - gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override); - gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title"))); - - /* Output config.. */ - - output_vbox = gtk_vbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(output_vbox), 5); - - /* replaygain */ - - replaygain_frame = gtk_frame_new(_("ReplayGain")); - gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5); - gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0); - - replaygain_vbox = gtk_vbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5); - gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox); - - replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable); - gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", (GCallback)replaygain_enable_cb, NULL); - gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0); - - replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode); - gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", (GCallback)replaygain_album_mode_cb, NULL); - gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0); - - hbox = gtk_hbox_new(FALSE,3); - gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox); - label = gtk_label_new(_("Preamp:")); - gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); - replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0); - gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", (GCallback)replaygain_preamp_cb, NULL); - replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp)); - gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE); - gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0); - replaygain_preamp_label = gtk_label_new(_("0 dB")); - gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0); - gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp)); - - replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit); - gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", (GCallback)replaygain_hard_limit_cb, NULL); - gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0); - - replaygain_enable_cb(replaygain_enable, NULL); - - /* resolution */ - - resolution_frame = gtk_frame_new(_("Resolution")); - gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5); - gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0); - - resolution_hbox = gtk_hbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5); - gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox); - - resolution_normal_frame = gtk_frame_new(_("Without ReplayGain")); - gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5); - gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0); - - resolution_normal_vbox = gtk_vbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5); - gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox); - - resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16); - gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", (GCallback)resolution_normal_dither_24_to_16_cb, NULL); - gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0); - - resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain")); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5); - gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0); - - resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox); - - resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", (GCallback)resolution_replaygain_dither_cb, NULL); - gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0); - - hbox = gtk_hbox_new(FALSE, 10); - gtk_container_border_width(GTK_CONTAINER(hbox), 5); - gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0); - - resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping")); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5); - gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0); - - resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new(); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox); - - resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none")); - if(flac_cfg.output.resolution.replaygain.noise_shaping == 0) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none); - - resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low")); - if(flac_cfg.output.resolution.replaygain.noise_shaping == 1) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low); - - resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium")); - if(flac_cfg.output.resolution.replaygain.noise_shaping == 2) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium); - - resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high")); - if(flac_cfg.output.resolution.replaygain.noise_shaping == 3) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high); - - resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to")); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5); - gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0); - - resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new(); - gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox); - - resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps")); - if(flac_cfg.output.resolution.replaygain.bps_out == 16) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps); - - resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps")); - if(flac_cfg.output.resolution.replaygain.bps_out == 24) - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE); - gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL); - gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps); - - resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output"))); - - /* Streaming */ - - streaming_vbox = gtk_vbox_new(FALSE, 0); - - streaming_buf_frame = gtk_frame_new(_("Buffering:")); - gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5); - gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0); - - streaming_buf_hbox = gtk_hbox_new(TRUE, 5); - gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5); - gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox); - - streaming_size_box = gtk_hbox_new(FALSE, 5); - /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */ - gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0); - streaming_size_label = gtk_label_new(_("Buffer size (kb):")); - gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0); - streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4); - streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0); - gtk_widget_set_usize(streaming_size_spin, 60, -1); - gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0); - - streaming_pre_box = gtk_hbox_new(FALSE, 5); - /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */ - gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0); - streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):")); - gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0); - streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1); - streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0); - gtk_widget_set_usize(streaming_pre_spin, 60, -1); - gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0); - - /* - * Save to disk config. - */ - streaming_save_frame = gtk_frame_new(_("Save stream to disk:")); - gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5); - gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0); - - streaming_save_vbox = gtk_vbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5); - gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox); - - streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream); - gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL); - gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0); - - streaming_save_hbox = gtk_hbox_new(FALSE, 5); - gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream); - gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0); - - streaming_save_label = gtk_label_new(_("Path:")); - gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0); - - streaming_save_entry = gtk_entry_new(); - gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path); - gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0); - - streaming_save_browse = gtk_button_new_with_label(_("Browse")); - gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL); - gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0); - -#ifdef FLAC_ICECAST - streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:")); - gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5); - gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0); - - streaming_cast_vbox = gtk_vbox_new(5, FALSE); - gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox); - - streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming); - gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0); - - streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel")); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel); - gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0); -#endif - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming"))); - - /* Buttons */ - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); - - ok = gtk_button_new_with_label(_("Ok")); - gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(flac_configurewin_ok), NULL); - GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); - gtk_widget_grab_default(ok); - - cancel = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(flac_configurewin)); - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); - - gtk_widget_show_all(flac_configurewin); -} - -void FLAC_XMMS__aboutbox() -{ - static GtkWidget *about_window; - - if (about_window) - gdk_window_raise(about_window->window); - else - { - about_window = xmms_show_message( - _("About Flac Plugin"), - _("Flac Plugin by Josh Coalson\n" - "contributions by\n" - "......\n" - "......\n" - "and\n" - "Daisuke Shimamura\n" - "Visit http://flac.sourceforge.net/"), - _("Ok"), FALSE, NULL, NULL); - gtk_signal_connect(GTK_OBJECT(about_window), "destroy", - GTK_SIGNAL_FUNC(gtk_widget_destroyed), - &about_window); - } -} - -/* - * Get text of an Entry or a ComboBox - */ -static const gchar *gtk_entry_get_text_1 (GtkWidget *widget) -{ - if (GTK_IS_COMBO(widget)) - { - return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry)); - }else if (GTK_IS_ENTRY(widget)) - { - return gtk_entry_get_text(GTK_ENTRY(widget)); - }else - { - return NULL; - } -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/configure.h --- a/src/flac/configure.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura - * - * Based on mpg123 plugin - * - * 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. - */ - -#ifndef __CONFIGURE_H__ -#define __CONFIGURE_H__ - -#include - -typedef struct { - struct { - gboolean tag_override; - gchar *tag_format; - gboolean convert_char_set; - gchar *user_char_set; - } title; - - struct { - gint http_buffer_size; - gint http_prebuffer; - gboolean use_proxy; - gchar *proxy_host; - gint proxy_port; - gboolean proxy_use_auth; - gchar *proxy_user; - gchar *proxy_pass; - gboolean save_http_stream; - gchar *save_http_path; - gboolean cast_title_streaming; - gboolean use_udp_channel; - } stream; - - struct { - struct { - gboolean enable; - gboolean album_mode; - gint preamp; - gboolean hard_limit; - } replaygain; - struct { - struct { - gboolean dither_24_to_16; - } normal; - struct { - gboolean dither; - gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */ - gint bps_out; - } replaygain; - } resolution; - } output; -} flac_config_t; - -extern flac_config_t flac_cfg; - -extern void FLAC_XMMS__configure(void); -extern void FLAC_XMMS__aboutbox(); - -#endif - - - diff -r aff1cf3e86dd -r 117bc56d906b src/flac/fast_float_math_hack.h --- a/src/flac/fast_float_math_hack.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -# ifdef __ICL /* only Intel C compiler has fmath ??? */ - - #include - -/* Nearest integer, absolute value, etc. */ - - #define ceil ceilf - #define fabs fabsf - #define floor floorf - #define fmod fmodf - #define rint rintf - #define hypot hypotf - -/* Power functions */ - - #define pow powf - #define sqrt sqrtf - -/* Exponential and logarithmic functions */ - - #define exp expf - #define log logf - #define log10 log10f - -/* Trigonometric functions */ - - #define acos acosf - #define asin asinf - #define atan atanf - #define cos cosf - #define sin sinf - #define tan tanf - -/* Hyperbolic functions */ - #define cosh coshf - #define sinh sinhf - #define tanh tanhf - -# endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/file.c --- a/src/flac/file.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,142 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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. - */ - -#if defined _MSC_VER || defined __MINGW32__ -#include /* for utime() */ -#include /* for chmod(), _setmode(), unlink() */ -#include /* for _O_BINARY */ -#else -#include /* some flavors of BSD (like OS X) require this to get time_t */ -#include /* for utime() */ -#endif -#ifdef __CYGWIN__ -#include /* for setmode(), O_BINARY */ -#include /* for _O_BINARY */ -#endif -#include /* for stat(), maybe chmod() */ -#if defined _WIN32 && !defined __CYGWIN__ -#else -#include /* for unlink() */ -#endif -#include -#include -#include /* for strrchr() */ -#include "grabbag.h" - - -void grabbag__file_copy_metadata(const char *srcpath, const char *destpath) -{ - struct stat srcstat; - struct utimbuf srctime; - - if(0 == stat(srcpath, &srcstat)) { - srctime.actime = srcstat.st_atime; - srctime.modtime = srcstat.st_mtime; - (void)chmod(destpath, srcstat.st_mode); - (void)utime(destpath, &srctime); - } -} - -off_t grabbag__file_get_filesize(const char *srcpath) -{ - struct stat srcstat; - - if(0 == stat(srcpath, &srcstat)) - return srcstat.st_size; - else - return -1; -} - -const char *grabbag__file_get_basename(const char *srcpath) -{ - const char *p; - - p = strrchr(srcpath, '/'); - if(0 == p) { - p = strrchr(srcpath, '\\'); - if(0 == p) - return srcpath; - } - return ++p; -} - -FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only) -{ - struct stat stats; - - if(0 == stat(filename, &stats)) { -#if !defined _MSC_VER && !defined __MINGW32__ - if(read_only) { - stats.st_mode &= ~S_IWUSR; - stats.st_mode &= ~S_IWGRP; - stats.st_mode &= ~S_IWOTH; - } - else { - stats.st_mode |= S_IWUSR; - } -#else - if(read_only) - stats.st_mode &= ~S_IWRITE; - else - stats.st_mode |= S_IWRITE; -#endif - if(0 != chmod(filename, stats.st_mode)) - return false; - } - else - return false; - - return true; -} - -FLAC__bool grabbag__file_remove_file(const char *filename) -{ - return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename); -} - -FILE *grabbag__file_get_binary_stdin() -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdin), _O_BINARY); -#elif defined __CYGWIN__ - /* almost certainly not needed for any modern Cygwin, but let's be safe... */ - setmode(_fileno(stdin), _O_BINARY); -#endif - - return stdin; -} - -FILE *grabbag__file_get_binary_stdout() -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdout), _O_BINARY); -#elif defined __CYGWIN__ - /* almost certainly not needed for any modern Cygwin, but let's be safe... */ - setmode(_fileno(stdout), _O_BINARY); -#endif - - return stdout; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/fileinfo.c --- a/src/flac/fileinfo.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,500 +0,0 @@ -/* XMMS - Cross-platform multimedia player - * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies - * Copyright (C) 1999,2000 Håvard Kvålen - * Copyright (C) 2002,2003,2004,2005,2006 Daisuke Shimamura - * - * 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. - */ - -#include -#include /* for strlen() */ -#include -#include -#include -#include -#include - -#include "audacious/util.h" -#include "FLAC/metadata.h" -#include "charset.h" -#include "configure.h" -#include "plugin_common/locale_hack.h" -#include "plugin_common/replaygain.h" -#include "plugin_common/tags.h" - -static GtkWidget *window = NULL; -static GList *genre_list = NULL; -static GtkWidget *filename_entry, *tag_frame; -static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry; -static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak; -static GtkWidget *genre_combo; -static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate; - -static gchar *current_filename = NULL; -static FLAC__StreamMetadata *tags_ = NULL; - -static const gchar *vorbis_genres[] = -{ - N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), - N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), - N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), - N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), - N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), - N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), - N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), - N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), - N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), - N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"), - N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), - N_("Meditative"), N_("Instrumental Pop"), - N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), - N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), - N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), - N_("Southern Rock"), N_("Comedy"), N_("Cult"), - N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), - N_("Pop/Funk"), N_("Jungle"), N_("Native American"), - N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), - N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), - N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), - N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), - N_("Folk/Rock"), N_("National Folk"), N_("Swing"), - N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), - N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), - N_("Gothic Rock"), N_("Progressive Rock"), - N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), - N_("Big Band"), N_("Chorus"), N_("Easy Listening"), - N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), - N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), - N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), - N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), - N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), - N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), - N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), - N_("Euro-House"), N_("Dance Hall"), N_("Goa"), - N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), - N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), - N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), - N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), - N_("Contemporary Christian"), N_("Christian Rock"), - N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), - N_("Anime"), N_("JPop"), N_("Synthpop") -}; - -static void label_set_text(GtkWidget * label, char *str, ...) -{ - va_list args; - gchar *tempstr; - - va_start(args, str); - tempstr = g_strdup_vprintf(str, args); - va_end(args); - - gtk_label_set_text(GTK_LABEL(label), tempstr); - g_free(tempstr); -} - -static void set_entry_tag(GtkEntry * entry, const char * utf8) -{ - if(utf8) { - if(flac_cfg.title.convert_char_set) { - char *text = convert_from_utf8_to_user(utf8); - gtk_entry_set_text(entry, text); - free(text); - } - else - gtk_entry_set_text(entry, utf8); - } - else - gtk_entry_set_text(entry, ""); -} - -static void get_entry_tag(GtkEntry * entry, const char *name) -{ - gchar *text; - char *utf8; - - text = g_strdup(gtk_entry_get_text(entry)); - if (!text || strlen(text) == 0) - { - g_free(text); - return; - } - if(flac_cfg.title.convert_char_set) - utf8 = convert_from_user_to_utf8(text); - else - utf8 = text; - - FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0); - - if(flac_cfg.title.convert_char_set) - free(utf8); - g_free(text); -} - -static void show_tag() -{ - set_entry_tag(GTK_ENTRY(title_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE")); - set_entry_tag(GTK_ENTRY(artist_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST")); - set_entry_tag(GTK_ENTRY(album_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM")); - set_entry_tag(GTK_ENTRY(date_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE")); - set_entry_tag(GTK_ENTRY(tracknum_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER")); - set_entry_tag(GTK_ENTRY(comment_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION")); - set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE")); -} - -static void save_tag(GtkWidget * w, gpointer data) -{ - (void)w; - (void)data; - - FLAC_plugin__tags_delete_tag(tags_, "TITLE"); - FLAC_plugin__tags_delete_tag(tags_, "ARTIST"); - FLAC_plugin__tags_delete_tag(tags_, "ALBUM"); - FLAC_plugin__tags_delete_tag(tags_, "DATE"); - FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER"); - FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION"); - FLAC_plugin__tags_delete_tag(tags_, "GENRE"); - - get_entry_tag(GTK_ENTRY(title_entry) , "TITLE"); - get_entry_tag(GTK_ENTRY(artist_entry) , "ARTIST"); - get_entry_tag(GTK_ENTRY(album_entry) , "ALBUM"); - get_entry_tag(GTK_ENTRY(date_entry) , "DATE"); - get_entry_tag(GTK_ENTRY(tracknum_entry) , "TRACKNUMBER"); - get_entry_tag(GTK_ENTRY(comment_entry) , "DESCRIPTION"); - get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE"); - - FLAC_plugin__tags_set(current_filename, tags_); - gtk_widget_destroy(window); -} - -static void remove_tag(GtkWidget * w, gpointer data) -{ - (void)w; - (void)data; - - FLAC_plugin__tags_delete_tag(tags_, "TITLE"); - FLAC_plugin__tags_delete_tag(tags_, "ARTIST"); - FLAC_plugin__tags_delete_tag(tags_, "ALBUM"); - FLAC_plugin__tags_delete_tag(tags_, "DATE"); - FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER"); - FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION"); - FLAC_plugin__tags_delete_tag(tags_, "GENRE"); - - FLAC_plugin__tags_set(current_filename, tags_); - gtk_widget_destroy(window); -} - -static void show_file_info() -{ - FLAC__StreamMetadata streaminfo; - struct stat _stat; - - gtk_label_set_text(GTK_LABEL(flac_samplerate), ""); - gtk_label_set_text(GTK_LABEL(flac_channels), ""); - gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), ""); - gtk_label_set_text(GTK_LABEL(flac_blocksize), ""); - gtk_label_set_text(GTK_LABEL(flac_filesize), ""); - gtk_label_set_text(GTK_LABEL(flac_samples), ""); - gtk_label_set_text(GTK_LABEL(flac_bitrate), ""); - - if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) { - return; - } - - label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate); - label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels); - label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample); - if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize) - label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize); - else - label_set_text(flac_blocksize, _("Blocksize: variable\n min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize); - - if (streaminfo.data.stream_info.total_samples) - label_set_text(flac_samples, _("Samples: %llu\nLength: %d:%.2d"), - streaminfo.data.stream_info.total_samples, - (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60), - (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60)); - - if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) { -#if _FILE_OFFSET_BITS == 64 - label_set_text(flac_filesize, _("Filesize: %lld B"), _stat.st_size); -#else - label_set_text(flac_filesize, _("Filesize: %ld B"), _stat.st_size); -#endif - if (streaminfo.data.stream_info.total_samples) - label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"), - 8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate), - 100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples)); - } -} - -static void show_replaygain() -{ - /* known limitation: If only one of gain and peak is set, neither will be shown. This is true for - * both track and album replaygain tags. Written so it will be easy to fix, with some trouble. */ - - gtk_label_set_text(GTK_LABEL(replaygain_reference), ""); - gtk_label_set_text(GTK_LABEL(replaygain_track_gain), ""); - gtk_label_set_text(GTK_LABEL(replaygain_album_gain), ""); - gtk_label_set_text(GTK_LABEL(replaygain_track_peak), ""); - gtk_label_set_text(GTK_LABEL(replaygain_album_peak), ""); - - double reference, track_gain, track_peak, album_gain, album_peak; - FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set; - - FLAC_plugin__replaygain_get_from_file( - current_filename, - &reference, &reference_set, - &track_gain, &track_gain_set, - &album_gain, &album_gain_set, - &track_peak, &track_peak_set, - &album_peak, &album_peak_set - ); - - if(reference_set) - label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference); - if(track_gain_set) - label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain); - if(album_gain_set) - label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain); - if(track_peak_set) - label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak); - if(album_peak_set) - label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak); -} - -void FLAC_XMMS__file_info_box(char *filename) -{ - unsigned i; - gchar *title; - gchar *filename_utf8; - - if (!window) - { - GtkWidget *vbox, *hbox, *left_vbox, *table; - GtkWidget *flac_frame, *flac_box; - GtkWidget *label, *filename_hbox; - GtkWidget *bbox, *save, *remove, *cancel; - - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); - gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); - gtk_container_set_border_width(GTK_CONTAINER(window), 10); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(window), vbox); - - filename_hbox = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0); - - label = gtk_label_new(_("Filename:")); - gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); - filename_entry = gtk_entry_new(); - gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); - gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0); - - hbox = gtk_hbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); - - left_vbox = gtk_vbox_new(FALSE, 10); - gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0); - - tag_frame = gtk_frame_new(_("Tag:")); - gtk_box_pack_start(GTK_BOX(left_vbox), tag_frame, FALSE, FALSE, 0); - - table = gtk_table_new(5, 5, FALSE); - gtk_container_set_border_width(GTK_CONTAINER(table), 5); - gtk_container_add(GTK_CONTAINER(tag_frame), table); - - label = gtk_label_new(_("Title:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 5); - - title_entry = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Artist:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 5); - - artist_entry = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Album:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 5); - - album_entry = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Comment:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5); - - comment_entry = gtk_entry_new(); - gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Date:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 5); - - date_entry = gtk_entry_new(); - gtk_widget_set_usize(date_entry, 40, -1); - gtk_table_attach(GTK_TABLE(table), date_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Track number:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 5); - - tracknum_entry = gtk_entry_new(); - gtk_widget_set_usize(tracknum_entry, 40, -1); - gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - label = gtk_label_new(_("Genre:")); - gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); - gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 5); - - genre_combo = gtk_combo_new(); - gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), TRUE); - - if (!genre_list) - { - for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++) - genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]); - genre_list = g_list_prepend(genre_list, ""); - genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp); - } - gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list); - - gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); - - bbox = gtk_hbutton_box_new(); - gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); - gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); - gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0); - - save = gtk_button_new_with_label(_("Save")); - gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_tag), NULL); - GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0); - gtk_widget_grab_default(save); - - remove= gtk_button_new_with_label(_("Remove Tag")); - gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL); - GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), remove, TRUE, TRUE, 0); - - cancel = gtk_button_new_with_label(_("Cancel")); - gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window)); - GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); - - flac_frame = gtk_frame_new(_("FLAC Info:")); - gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0); - - flac_box = gtk_vbox_new(FALSE, 5); - gtk_container_add(GTK_CONTAINER(flac_frame), flac_box); - gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10); - gtk_box_set_spacing(GTK_BOX(flac_box), 0); - - flac_samplerate = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0); - - flac_channels = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0); - - flac_bits_per_sample = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0); - - flac_blocksize = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0); - - flac_filesize = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0); - - flac_samples = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0); - - flac_bitrate = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0); - gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0); - - replaygain_reference = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0); - gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0); - - replaygain_track_gain = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0); - gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0); - - replaygain_album_gain = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0); - gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0); - - replaygain_track_peak = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0); - gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0); - - replaygain_album_peak = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0); - gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT); - gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0); - - gtk_widget_show_all(window); - } - - if(current_filename) - g_free(current_filename); - if(!(current_filename = g_strdup(filename))) - return; - - filename_utf8 = filename_to_utf8(current_filename); - title = g_strdup_printf(_("File Info - %s"), g_basename(filename_utf8)); - gtk_window_set_title(GTK_WINDOW(window), title); - g_free(title); - - gtk_entry_set_text(GTK_ENTRY(filename_entry), filename_utf8); - gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1); - - g_free(filename_utf8); - - if(tags_) - FLAC_plugin__tags_destroy(&tags_); - - FLAC_plugin__tags_get(current_filename, &tags_); - - show_tag(); - show_file_info(); - show_replaygain(); - - gtk_widget_set_sensitive(tag_frame, TRUE); -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/grabbag.h --- a/src/flac/grabbag.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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. - */ - -#ifndef SHARE__GRABBAG_H -#define SHARE__GRABBAG_H - -#include -#include "plugin_common/all.h" - - -/* These can't be included by themselves, only from within grabbag.h */ -#include "grabbag/cuesheet.h" -#include "grabbag/file.h" -#include "grabbag/replaygain.h" -#include "grabbag/seektable.h" - - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/grabbag/cuesheet.h --- a/src/flac/grabbag/cuesheet.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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. - */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABBAG__CUESHEET_H -#define GRABBAG__CUESHEET_H - -#include -#include "FLAC/metadata.h" - -#ifdef __cplusplus -extern "C" { -#endif - -unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames); -void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames); - -FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); - -void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference); - -#ifdef __cplusplus -} -#endif - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/grabbag/file.h --- a/src/flac/grabbag/file.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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. - */ - -/* Convenience routines for manipulating files */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABAG__FILE_H -#define GRABAG__FILE_H - -#include /* for off_t */ -#include /* for FILE */ -#include "FLAC/ordinals.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void grabbag__file_copy_metadata(const char *srcpath, const char *destpath); -off_t grabbag__file_get_filesize(const char *srcpath); -const char *grabbag__file_get_basename(const char *srcpath); - -/* read_only == false means "make file writable by user" - * read_only == true means "make file read-only for everyone" - */ -FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only); - -/* attempts to make writable before unlinking */ -FLAC__bool grabbag__file_remove_file(const char *filename); - -/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */ -FILE *grabbag__file_get_binary_stdin(); -FILE *grabbag__file_get_binary_stdout(); - -#ifdef __cplusplus -} -#endif - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/grabbag/replaygain.h --- a/src/flac/grabbag/replaygain.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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 - * 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. - */ - -/* - * This wraps the replaygain_analysis lib, which is LGPL. This wrapper - * allows analysis of different input resolutions by automatically - * scaling the input signal - */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABBAG__REPLAYGAIN_H -#define GRABBAG__REPLAYGAIN_H - -#include "FLAC/metadata.h" - -#ifdef __cplusplus -extern "C" { -#endif - -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); - -/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */ -FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples); - -void grabbag__replaygain_get_album(float *gain, float *peak); -void grabbag__replaygain_get_title(float *gain, float *peak); - -/* 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, 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 -} -#endif - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/grabbag/seektable.h --- a/src/flac/grabbag/seektable.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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. - */ - -/* Convenience routines for working with seek tables */ - -/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ - -#ifndef GRABAG__SEEKTABLE_H -#define GRABAG__SEEKTABLE_H - -#include "FLAC/format.h" - -#ifdef __cplusplus -extern "C" { -#endif - -FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points); - -#ifdef __cplusplus -} -#endif - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/http.c --- a/src/flac/http.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,897 +0,0 @@ -/* XMMS - Cross-platform multimedia player - * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies - * - * 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. - */ -/* modified for FLAC support by Steven Richman (2003) */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "configure.h" -#include "plugin_common/locale_hack.h" -#include "FLAC/format.h" -#include "plugin.h" - -#define min(x,y) ((x)<(y)?(x):(y)) -#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z)) -#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w)) - -static gchar *icy_name = NULL; -static gint icy_metaint = 0; - -extern InputPlugin flac_ip; - -#undef DEBUG_UDP - -/* Static udp channel functions */ -static int udp_establish_listener (gint *sock); -static int udp_check_for_data(gint sock); - -static char *flac_http_get_title(char *url); - -static gboolean prebuffering, going, eof = FALSE; -static gint sock, rd_index, wr_index, buffer_length, prebuffer_length; -static guint64 buffer_read = 0; -static gchar *buffer; -static guint64 offset; -static GThread *thread; -static GtkWidget *error_dialog = NULL; - -static FILE *output_file = NULL; - -#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) - -/* Encode the string S of length LENGTH to base64 format and place it - to STORE. STORE will be 0-terminated, and must point to a writable - buffer of at least 1+BASE64_LENGTH(length) bytes. */ -static void base64_encode (const gchar *s, gchar *store, gint length) -{ - /* Conversion table. */ - static gchar tbl[64] = { - 'A','B','C','D','E','F','G','H', - 'I','J','K','L','M','N','O','P', - 'Q','R','S','T','U','V','W','X', - 'Y','Z','a','b','c','d','e','f', - 'g','h','i','j','k','l','m','n', - 'o','p','q','r','s','t','u','v', - 'w','x','y','z','0','1','2','3', - '4','5','6','7','8','9','+','/' - }; - gint i; - guchar *p = (guchar *)store; - - /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ - for (i = 0; i < length; i += 3) - { - *p++ = tbl[s[0] >> 2]; - *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; - *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; - *p++ = tbl[s[2] & 0x3f]; - s += 3; - } - /* Pad the result if necessary... */ - if (i == length + 1) - *(p - 1) = '='; - else if (i == length + 2) - *(p - 1) = *(p - 2) = '='; - /* ...and zero-terminate it. */ - *p = '\0'; -} - -/* Create the authentication header contents for the `Basic' scheme. - This is done by encoding the string `USER:PASS' in base64 and - prepending `HEADER: Basic ' to it. */ -static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header) -{ - gchar *t1, *t2, *res; - gint len1 = strlen (user) + 1 + strlen (passwd); - gint len2 = BASE64_LENGTH (len1); - - t1 = g_strdup_printf("%s:%s", user, passwd); - t2 = g_malloc0(len2 + 1); - base64_encode (t1, t2, len1); - res = g_strdup_printf("%s: Basic %s\r\n", header, t2); - g_free(t2); - g_free(t1); - - return res; -} - -static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename) -{ - gchar *h, *p, *pt, *f, *temp, *ptr; - - temp = g_strdup(url); - ptr = temp; - - if (!strncasecmp("http://", ptr, 7)) - ptr += 7; - h = strchr(ptr, '@'); - f = strchr(ptr, '/'); - if (h != NULL && (!f || h < f)) - { - *h = '\0'; - p = strchr(ptr, ':'); - if (p != NULL && p < h) - { - *p = '\0'; - p++; - *pass = g_strdup(p); - } - else - *pass = NULL; - *user = g_strdup(ptr); - h++; - ptr = h; - } - else - { - *user = NULL; - *pass = NULL; - h = ptr; - } - pt = strchr(ptr, ':'); - if (pt != NULL && (f == NULL || pt < f)) - { - *pt = '\0'; - *port = atoi(pt + 1); - } - else - { - if (f) - *f = '\0'; - *port = 80; - } - *host = g_strdup(h); - - if (f) - *filename = g_strdup(f + 1); - else - *filename = NULL; - g_free(temp); -} - -void flac_http_close(void) -{ - going = FALSE; - - g_thread_join(thread); - g_free(icy_name); - icy_name = NULL; -} - - -static gint http_used(void) -{ - if (wr_index >= rd_index) - return wr_index - rd_index; - return buffer_length - (rd_index - wr_index); -} - -static gint http_free(void) -{ - if (rd_index > wr_index) - return (rd_index - wr_index) - 1; - return (buffer_length - (wr_index - rd_index)) - 1; -} - -static void http_wait_for_data(gint bytes) -{ - while ((prebuffering || http_used() < bytes) && !eof && going) - xmms_usleep(10000); -} - -static void show_error_message(gchar *error) -{ - if(!error_dialog) - { - GDK_THREADS_ENTER(); - error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE, - NULL, NULL); - g_signal_connect(G_OBJECT(error_dialog), - "destroy", - G_CALLBACK(gtk_widget_destroyed), - &error_dialog); - GDK_THREADS_LEAVE(); - } -} - -int flac_http_read(gpointer data, gint length) -{ - gint len, cnt, off = 0, meta_len, meta_off = 0, i; - gchar *meta_data, **tags, *temp, *title; - if (length > buffer_length) { - length = buffer_length; - } - - http_wait_for_data(length); - - if (!going) - return 0; - len = min(http_used(), length); - - while (len && http_used()) - { - if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0)) - { - meta_len = *((guchar *) buffer + rd_index) * 16; - rd_index = (rd_index + 1) % buffer_length; - if (meta_len > 0) - { - http_wait_for_data(meta_len); - meta_data = g_malloc0(meta_len); - if (http_used() >= meta_len) - { - while (meta_len) - { - cnt = min(meta_len, buffer_length - rd_index); - memcpy(meta_data + meta_off, buffer + rd_index, cnt); - rd_index = (rd_index + cnt) % buffer_length; - meta_len -= cnt; - meta_off += cnt; - } - tags = g_strsplit(meta_data, "';", 0); - - for (i = 0; tags[i]; i++) - { - if (!strncasecmp(tags[i], "StreamTitle=", 12)) - { - temp = g_strdup(tags[i] + 13); - title = g_strdup_printf("%s (%s)", temp, icy_name); - set_track_info(title, -1); - g_free(title); - g_free(temp); - } - - } - g_strfreev(tags); - - } - g_free(meta_data); - } - if (!http_used()) - http_wait_for_data(length - off); - cnt = min3(len, buffer_length - rd_index, http_used()); - } - else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming)) - cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint)); - else - cnt = min3(len, buffer_length - rd_index, http_used()); - if (output_file) - fwrite(buffer + rd_index, 1, cnt, output_file); - - memcpy((gchar *)data + off, buffer + rd_index, cnt); - rd_index = (rd_index + cnt) % buffer_length; - buffer_read += cnt; - len -= cnt; - off += cnt; - } - if (!off) { - fprintf(stderr, "returning zero\n"); - } - return off; -} - -static gboolean http_check_for_data(void) -{ - - fd_set set; - struct timeval tv; - gint ret; - - tv.tv_sec = 0; - tv.tv_usec = 20000; - FD_ZERO(&set); - FD_SET(sock, &set); - ret = select(sock + 1, &set, NULL, NULL, &tv); - if (ret > 0) - return TRUE; - return FALSE; -} - -gint flac_http_read_line(gchar * buf, gint size) -{ - gint i = 0; - - while (going && i < size - 1) - { - if (http_check_for_data()) - { - if (read(sock, buf + i, 1) <= 0) - return -1; - if (buf[i] == '\n') - break; - if (buf[i] != '\r') - i++; - } - } - if (!going) - return -1; - buf[i] = '\0'; - return i; -} - -/* returns the file descriptor of the socket, or -1 on error */ -static int http_connect (gchar *url_, gboolean head, guint64 offset) -{ - gchar line[1024], *user, *pass, *host, *filename, - *status, *url, *temp, *file; - gchar *chost; - gint cnt, error, port, cport; - guint err_len; - gboolean redirect; - int udp_sock = 0; - fd_set set; - struct hostent *hp; - struct sockaddr_in address; - struct timeval tv; - - url = g_strdup (url_); - - do - { - redirect=FALSE; - - g_strstrip(url); - - parse_url(url, &user, &pass, &host, &port, &filename); - - if ((!filename || !*filename) && url[strlen(url) - 1] != '/') - temp = g_strconcat(url, "/", NULL); - else - temp = g_strdup(url); - g_free(url); - url = temp; - - chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host; - cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port; - - sock = socket(AF_INET, SOCK_STREAM, 0); - fcntl(sock, F_SETFL, O_NONBLOCK); - address.sin_family = AF_INET; - - status = g_strdup_printf(_("LOOKING UP %s"), chost); - flac_ip.set_info_text(status); - g_free(status); - - if (!(hp = gethostbyname(chost))) - { - status = g_strdup_printf(_("Couldn't look up host %s"), chost); - show_error_message(status); - g_free(status); - - flac_ip.set_info_text(NULL); - eof = TRUE; - } - - if (!eof) - { - memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr)); - address.sin_port = (gint) g_htons(cport); - - status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport); - flac_ip.set_info_text(status); - g_free(status); - if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1) - { - if (errno != EINPROGRESS) - { - status = g_strdup_printf(_("Couldn't connect to host %s"), chost); - show_error_message(status); - g_free(status); - - flac_ip.set_info_text(NULL); - eof = TRUE; - } - } - while (going) - { - tv.tv_sec = 0; - tv.tv_usec = 10000; - FD_ZERO(&set); - FD_SET(sock, &set); - if (select(sock + 1, NULL, &set, NULL, &tv) > 0) - { - err_len = sizeof (error); - getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len); - if (error) - { - status = g_strdup_printf(_("Couldn't connect to host %s"), - chost); - show_error_message(status); - g_free(status); - - flac_ip.set_info_text(NULL); - eof = TRUE; - - } - break; - } - } - if (!eof) - { - gchar *auth = NULL, *proxy_auth = NULL; - gchar udpspace[30]; - int udp_port; - - if (flac_cfg.stream.use_udp_channel) - { - udp_port = udp_establish_listener (&udp_sock); - if (udp_port > 0) - sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port); - else - udp_sock = 0; - } - - if(user && pass) - auth = basic_authentication_encode(user, pass, "Authorization"); - - if (flac_cfg.stream.use_proxy) - { - file = g_strdup(url); - if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass) - { - proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user, - flac_cfg.stream.proxy_pass, - "Proxy-Authorization"); - } - } - else - file = g_strconcat("/", filename, NULL); - - temp = g_strdup_printf("GET %s HTTP/1.0\r\n" - "Host: %s\r\n" - "User-Agent: %s/%s\r\n" - "%s%s%s%s", - file, host, "Reference FLAC Player", FLAC__VERSION_STRING, - proxy_auth ? proxy_auth : "", auth ? auth : "", - flac_cfg.stream.cast_title_streaming ? "Icy-MetaData:1\r\n" : "", - flac_cfg.stream.use_udp_channel ? udpspace : ""); - if (offset && !head) { - gchar *temp_dead = temp; - temp = g_strconcat ("%sRange: %ll-\r\n", temp, offset, NULL); - fprintf (stderr, "%s", temp); - g_free (temp_dead); - } - - g_free(file); - if(proxy_auth) - g_free(proxy_auth); - if(auth) - g_free(auth); - write(sock, temp, strlen(temp)); - write(sock, "\r\n", 2); - g_free(temp); - flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY")); - while (going && !eof) - { - if (http_check_for_data()) - { - if (flac_http_read_line(line, 1024)) - { - status = strchr(line, ' '); - if (status) - { - if (status[1] == '2') - break; - else if(status[1] == '3' && status[2] == '0' && status[3] == '2') - { - while(going) - { - if(http_check_for_data()) - { - if((cnt = flac_http_read_line(line, 1024)) != -1) - { - if(!cnt) - break; - if(!strncmp(line, "Location:", 9)) - { - g_free(url); - url = g_strdup(line+10); - } - } - else - { - eof=TRUE; - flac_ip.set_info_text(NULL); - break; - } - } - } - redirect=TRUE; - break; - } - else - { - status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status); - show_error_message(status); - g_free(status); - break; - } - } - } - else - { - eof = TRUE; - flac_ip.set_info_text(NULL); - } - } - } - - while (going && !redirect) - { - if (http_check_for_data()) - { - if ((cnt = flac_http_read_line(line, 1024)) != -1) - { - if (!cnt) - break; - if (!strncmp(line, "icy-name:", 9)) - icy_name = g_strdup(line + 9); - else if (!strncmp(line, "x-audiocast-name:", 17)) - icy_name = g_strdup(line + 17); - if (!strncmp(line, "icy-metaint:", 12)) - icy_metaint = atoi(line + 12); - if (!strncmp(line, "x-audiocast-udpport:", 20)) { -#ifdef DEBUG_UDP - fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20)); -#endif - /*udp_serverport = atoi (line + 20);*/ - } - - } - else - { - eof = TRUE; - flac_ip.set_info_text(NULL); - break; - } - } - } - } - } - - if(redirect) - { - if (output_file) - { - fclose(output_file); - output_file = NULL; - } - close(sock); - } - - g_free(user); - g_free(pass); - g_free(host); - g_free(filename); - } while(redirect); - - g_free(url); - return eof ? -1 : sock; -} - -static void *http_buffer_loop(void *arg) -{ - gchar *status, *url, *temp, *file; - gint cnt, written; - int udp_sock = 0; - - url = (gchar *) arg; - sock = http_connect (url, false, offset); - - if (sock >= 0 && flac_cfg.stream.save_http_stream) { - gchar *output_name; - file = flac_http_get_title(url); - output_name = file; - if (!strncasecmp(output_name, "http://", 7)) - output_name += 7; - temp = strrchr(output_name, '.'); - if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac"))) - *temp = '\0'; - - while ((temp = strchr(output_name, '/'))) - *temp = '_'; - output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name); - - g_free(file); - - output_file = fopen(output_name, "wb"); - g_free(output_name); - } - - while (going) - { - - if (!http_used() && !flac_ip.output->buffer_playing()) - { - prebuffering = TRUE; - flac_ip.set_status_buffering(TRUE); - } - if (http_free() > 0 && !eof) - { - if (http_check_for_data()) - { - cnt = min(http_free(), buffer_length - wr_index); - if (cnt > 1024) - cnt = 1024; - written = read(sock, buffer + wr_index, cnt); - if (written <= 0) - { - eof = TRUE; - if (prebuffering) - { - prebuffering = FALSE; - flac_ip.set_status_buffering(FALSE); - - flac_ip.set_info_text(NULL); - } - - } - else - wr_index = (wr_index + written) % buffer_length; - } - - if (prebuffering) - { - if (http_used() > prebuffer_length) - { - prebuffering = FALSE; - flac_ip.set_status_buffering(FALSE); - flac_ip.set_info_text(NULL); - } - else - { - status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024); - flac_ip.set_info_text(status); - g_free(status); - } - - } - } - else - xmms_usleep(10000); - - if (flac_cfg.stream.use_udp_channel && udp_sock != 0) - if (udp_check_for_data(udp_sock) < 0) - { - close(udp_sock); - udp_sock = 0; - } - } - if (output_file) - { - fclose(output_file); - output_file = NULL; - } - if (sock >= 0) { - close(sock); - } - if (udp_sock != 0) - close(udp_sock); - - g_free(buffer); - g_free(url); - - g_thread_exit(NULL); - return NULL; /* avoid compiler warning */ -} - -int flac_http_open(gchar * _url, guint64 _offset) -{ - gchar *url; - - url = g_strdup(_url); - - rd_index = 0; - wr_index = 0; - buffer_length = flac_cfg.stream.http_buffer_size * 1024; - prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100; - buffer_read = 0; - icy_metaint = 0; - prebuffering = TRUE; - flac_ip.set_status_buffering(TRUE); - going = TRUE; - eof = FALSE; - buffer = g_malloc(buffer_length); - offset = _offset; - - thread = g_thread_create((GThreadFunc)http_buffer_loop, url, TRUE, NULL); - - return 0; -} - -char *flac_http_get_title(char *url) -{ - if (icy_name) - return g_strdup(icy_name); - if (g_basename(url) && strlen(g_basename(url)) > 0) - return g_strdup(g_basename(url)); - return g_strdup(url); -} - -/* Start UDP Channel specific stuff */ - -/* Find a good local udp port and bind udp_sock to it, return the port */ -static int udp_establish_listener(int *sock) -{ - struct sockaddr_in sin; - socklen_t sinlen = sizeof (struct sockaddr_in); - -#ifdef DEBUG_UDP - fprintf (stderr,"Establishing udp listener\n"); -#endif - - if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - g_log(NULL, G_LOG_LEVEL_CRITICAL, - "udp_establish_listener(): unable to create socket"); - return -1; - } - - memset(&sin, 0, sinlen); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = g_htonl(INADDR_ANY); - - if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0) - { - g_log(NULL, G_LOG_LEVEL_CRITICAL, - "udp_establish_listener(): Failed to bind socket to localhost: %s", strerror(errno)); - close(*sock); - return -1; - } - if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0) - { - g_log(NULL, G_LOG_LEVEL_CRITICAL, - "udp_establish_listener(): Failed to set flags: %s", strerror(errno)); - close(*sock); - return -1; - } - - memset(&sin, 0, sinlen); - if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0) - { - g_log(NULL, G_LOG_LEVEL_CRITICAL, - "udp_establish_listener(): Failed to retrieve socket info: %s", strerror(errno)); - close(*sock); - return -1; - } - -#ifdef DEBUG_UDP - fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); -#endif - - return g_ntohs(sin.sin_port); -} - -static int udp_check_for_data(int sock) -{ - char buf[1025], **lines; - char *valptr; - gchar *title; - gint len, i; - struct sockaddr_in from; - socklen_t fromlen; - - fromlen = sizeof(struct sockaddr_in); - - if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0) - { - if (errno != EAGAIN) - { - g_log(NULL, G_LOG_LEVEL_CRITICAL, - "udp_read_data(): Error reading from socket: %s", strerror(errno)); - return -1; - } - return 0; - } - buf[len] = '\0'; -#ifdef DEBUG_UDP - fprintf (stderr,"Received: [%s]\n", buf); -#endif - lines = g_strsplit(buf, "\n", 0); - if (!lines) - return 0; - - for (i = 0; lines[i]; i++) - { - while ((lines[i][strlen(lines[i]) - 1] == '\n') || - (lines[i][strlen(lines[i]) - 1] == '\r')) - lines[i][strlen(lines[i]) - 1] = '\0'; - - valptr = strchr(lines[i], ':'); - - if (!valptr) - continue; - else - valptr++; - - g_strstrip(valptr); - if (!strlen(valptr)) - continue; - - if (strstr(lines[i], "x-audiocast-streamtitle") != NULL) - { - title = g_strdup_printf ("%s (%s)", valptr, icy_name); - if (going) - set_track_info(title, -1); - g_free (title); - } - -#if 0 - else if (strstr(lines[i], "x-audiocast-streamlength") != NULL) - { - if (atoi(valptr) != -1) - set_track_info(NULL, atoi(valptr)); - } -#endif - - else if (strstr(lines[i], "x-audiocast-streammsg") != NULL) - { - /* set_track_info(title, -1); */ -/* xmms_show_message(_("Message"), valptr, _("Ok"), */ -/* FALSE, NULL, NULL); */ - g_message("Stream_message: %s", valptr); - } - -#if 0 - /* Use this to direct your webbrowser.. yeah right.. */ - else if (strstr(lines[i], "x-audiocast-streamurl") != NULL) - { - if (lasturl && g_strcmp (valptr, lasturl)) - { - c_message (stderr, "Song URL: %s\n", valptr); - g_free (lasturl); - lasturl = g_strdup (valptr); - } - } -#endif - else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL) - { - gchar obuf[60]; - sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr)); - if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0) - { - g_log(NULL, G_LOG_LEVEL_WARNING, - "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno)); - } -#ifdef DEBUG_UDP - else - fprintf(stderr,"Sent ack: %s", obuf); - fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port)); -#endif - } - } - g_strfreev(lines); - return 0; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/http.h --- a/src/flac/http.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * - * 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. - */ - -#ifndef __HTTP_H__ -#define __HTTP_H__ - -extern int flac_http_open(gchar * url, guint64 offset); -extern void flac_http_close(void); -extern int flac_http_read(gpointer data, gint length); - - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin.c --- a/src/flac/plugin.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,718 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2000,2001,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 - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "audacious/plugin.h" -#include "audacious/output.h" -#include "audacious/util.h" -#include "audacious/configdb.h" -#include "audacious/titlestring.h" -#include "audacious/vfs.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LANGINFO_CODESET -#include -#endif - -#include "FLAC/all.h" -#include "plugin_common/all.h" -#include "grabbag.h" -#include "replaygain_synthesis.h" -#include "configure.h" -#include "charset.h" -#include "http.h" -#include "tag.h" - -#ifdef min -#undef min -#endif -#define min(x,y) ((x)<(y)?(x):(y)) - -extern void FLAC_XMMS__file_info_box(char *filename); - -typedef struct { - FLAC__bool abort_flag; - FLAC__bool is_playing; - FLAC__bool is_http_source; - FLAC__bool eof; - FLAC__bool play_thread_open; /* if true, is_playing must also be true */ - FLAC__uint64 total_samples; - unsigned bits_per_sample; - unsigned channels; - unsigned sample_rate; - int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */ - gchar *title; - AFormat sample_format; - unsigned sample_format_bytes_per_sample; - int seek_to_in_sec; - FLAC__bool has_replaygain; - double replay_scale; - DitherContext dither_context; -} stream_data_struct; - -static void FLAC_XMMS__init(); -static int FLAC_XMMS__is_our_file(char *filename); -static void FLAC_XMMS__play_file(char *filename); -static void FLAC_XMMS__stop(); -static void FLAC_XMMS__pause(short p); -static void FLAC_XMMS__seek(int time); -static int FLAC_XMMS__get_time(); -static void FLAC_XMMS__cleanup(); -static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length); - -static void *play_loop_(void *arg); - -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); - -static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); -static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); -static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - -InputPlugin flac_ip = -{ - NULL, - NULL, - NULL, - FLAC_XMMS__init, - FLAC_XMMS__aboutbox, - FLAC_XMMS__configure, - FLAC_XMMS__is_our_file, - NULL, - FLAC_XMMS__play_file, - FLAC_XMMS__stop, - FLAC_XMMS__pause, - FLAC_XMMS__seek, - NULL, - FLAC_XMMS__get_time, - NULL, - NULL, - FLAC_XMMS__cleanup, - NULL, - NULL, - NULL, - NULL, - FLAC_XMMS__get_song_info, - FLAC_XMMS__file_info_box, - NULL, - flac_get_tuple -}; - -#define SAMPLES_PER_WRITE 512 -#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8)) -static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE]; -static unsigned sample_buffer_first_, sample_buffer_last_; - -static FLAC__StreamDecoder *decoder_ = 0, *decoder2 = 0; -static stream_data_struct stream_data_; -static GThread *decode_thread_; -static FLAC__bool audio_error_ = false; -static FLAC__bool is_big_endian_host_; - -#define BITRATE_HIST_SEGMENT_MSEC 500 -/* 500ms * 50 = 25s should be enough */ -#define BITRATE_HIST_SIZE 50 -static unsigned bitrate_history_[BITRATE_HIST_SIZE]; - -#ifdef SUPPORT_ATTRIBUTE_VISIBILITY -InputPlugin *get_iplugin_info() __attribute__((visibility("default"))); -#endif - -InputPlugin *get_iplugin_info() -{ - flac_ip.description = g_strdup_printf(_("FLAC Audio Plugin")); - return &flac_ip; -} - -void set_track_info(const char* title, int length_in_msec) -{ - if (stream_data_.is_playing) { - flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels); - } -} - -static gchar* homedir() -{ - gchar *result; - char *env_home = getenv("HOME"); - if (env_home) { - result = g_strdup (env_home); - } else { - uid_t uid = getuid(); - struct passwd *pwent; - do { - pwent = getpwent(); - } while (pwent && pwent->pw_uid != uid); - result = pwent ? g_strdup (pwent->pw_dir) : NULL; - endpwent(); - } - return result; -} - -static FLAC__bool is_http_source(const char *source) -{ - return 0 == strncasecmp(source, "http://", 7); -} - -void FLAC_XMMS__init() -{ - ConfigDb *db; - FLAC__uint32 test = 1; - gchar *tmp; - - is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; - - flac_cfg.title.tag_override = FALSE; - if (flac_cfg.title.tag_format) - g_free(flac_cfg.title.tag_format); - flac_cfg.title.convert_char_set = FALSE; - - db = bmp_cfg_db_open(); - - /* title */ - - bmp_cfg_db_get_bool(db, "flac", "title.tag_override", &flac_cfg.title.tag_override); - - if(!bmp_cfg_db_get_string(db, "flac", "title.tag_format", &flac_cfg.title.tag_format)) - flac_cfg.title.tag_format = g_strdup("%p - %t"); - - bmp_cfg_db_get_bool(db, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set); - - if(!bmp_cfg_db_get_string(db, "flac", "title.user_char_set", &flac_cfg.title.user_char_set)) - flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current(); - - /* replaygain */ - - bmp_cfg_db_get_bool(db, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable); - - bmp_cfg_db_get_bool(db, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode); - - if(!bmp_cfg_db_get_int(db, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp)) - flac_cfg.output.replaygain.preamp = 0; - - bmp_cfg_db_get_bool(db, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit); - - bmp_cfg_db_get_bool(db, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16); - bmp_cfg_db_get_bool(db, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither); - - if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping)) - flac_cfg.output.resolution.replaygain.noise_shaping = 1; - - if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out)) - flac_cfg.output.resolution.replaygain.bps_out = 16; - - /* stream */ - - bmp_cfg_db_get_int(db, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size); - bmp_cfg_db_get_int(db, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer); - bmp_cfg_db_get_bool(db, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream); - if (!bmp_cfg_db_get_string(db, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) || - ! *flac_cfg.stream.save_http_path) { - /* TODO: Is this a memory leak ?? */ - /* - if (flac_cfg.stream.save_http_path) - g_free (flac_cfg.stream.save_http_path); - */ - flac_cfg.stream.save_http_path = homedir(); - } - bmp_cfg_db_get_bool(db, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming); - bmp_cfg_db_get_bool(db, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel); - - bmp_cfg_db_get_bool(db, NULL, "use_proxy", &flac_cfg.stream.use_proxy); - bmp_cfg_db_get_string(db, NULL, "proxy_host", &flac_cfg.stream.proxy_host); - bmp_cfg_db_get_string(db, NULL, "proxy_port", &tmp); - - bmp_cfg_db_get_bool(db, NULL, "proxy_use_auth", &flac_cfg.stream.proxy_use_auth); - bmp_cfg_db_get_string(db, NULL, "proxy_user", &flac_cfg.stream.proxy_user); - bmp_cfg_db_get_string(db, NULL, "proxy_pass", &flac_cfg.stream.proxy_pass); - - decoder_ = FLAC__stream_decoder_new(); - bmp_cfg_db_close(db); -} - -int FLAC_XMMS__is_our_file(char *filename) -{ - FILE *f; - FLAC__StreamMetadata streaminfo; - - if(!is_http_source(filename)) { - if(0 == (f = fopen(filename, "r"))) - return 0; - fclose(f); - if(FLAC__metadata_get_streaminfo(filename, &streaminfo)) - return 1; - return 0; - } - - if(!safe_decoder_init_(filename, decoder2)) - return 0; - - safe_decoder_finish_(decoder2); - return 1; -} - -void FLAC_XMMS__play_file(char *filename) -{ - FILE *f; - - sample_buffer_first_ = sample_buffer_last_ = 0; - audio_error_ = false; - stream_data_.abort_flag = false; - stream_data_.is_playing = false; - stream_data_.is_http_source = is_http_source(filename); - stream_data_.eof = false; - stream_data_.play_thread_open = false; - stream_data_.has_replaygain = false; - - if(!is_http_source(filename)) { - if(0 == (f = fopen(filename, "r"))) - return; - fclose(f); - } - - if(decoder_ == 0) - return; - - if(!safe_decoder_init_(filename, decoder_)) - return; - - if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) { - if(flac_cfg.output.resolution.replaygain.bps_out == 8) { - stream_data_.sample_format = FMT_U8; - stream_data_.sample_format_bytes_per_sample = 1; - } - else if(flac_cfg.output.resolution.replaygain.bps_out == 16) { - stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; - stream_data_.sample_format_bytes_per_sample = 2; - } - else { - /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ - fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out); - safe_decoder_finish_(decoder_); - return; - } - } - else { - if(stream_data_.bits_per_sample == 8) { - stream_data_.sample_format = FMT_U8; - stream_data_.sample_format_bytes_per_sample = 1; - } - else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) { - stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; - stream_data_.sample_format_bytes_per_sample = 2; - } - else { - /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ - fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", stream_data_.bits_per_sample); - safe_decoder_finish_(decoder_); - return; - } - } - FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping); - stream_data_.is_playing = true; - - if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) { - audio_error_ = true; - safe_decoder_finish_(decoder_); - return; - } - - stream_data_.title = flac_format_song_title(filename); - flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels); - - stream_data_.seek_to_in_sec = -1; - stream_data_.play_thread_open = true; - decode_thread_ = g_thread_create((GThreadFunc)play_loop_, NULL, TRUE, NULL); -} - -void FLAC_XMMS__stop() -{ - if(stream_data_.is_playing) { - stream_data_.is_playing = false; - if(stream_data_.play_thread_open) { - stream_data_.play_thread_open = false; - g_thread_join(decode_thread_); - } - flac_ip.output->close_audio(); - safe_decoder_finish_(decoder_); - } -} - -void FLAC_XMMS__pause(short p) -{ - flac_ip.output->pause(p); -} - -void FLAC_XMMS__seek(int time) -{ - if(!stream_data_.is_http_source) { - stream_data_.seek_to_in_sec = time; - stream_data_.eof = false; - - while(stream_data_.seek_to_in_sec != -1) - xmms_usleep(10000); - } -} - -int FLAC_XMMS__get_time() -{ - if(audio_error_) - return -2; - if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing())) - return -1; - else - return flac_ip.output->output_time(); -} - -void FLAC_XMMS__cleanup() -{ - g_free(flac_ip.description); - flac_ip.description = NULL; - - if (flac_cfg.title.tag_format) { - free(flac_cfg.title.tag_format); - flac_cfg.title.tag_format = NULL; - } - - if (flac_cfg.title.user_char_set) { - free(flac_cfg.title.user_char_set); - flac_cfg.title.user_char_set = NULL; - } - - if (flac_cfg.stream.proxy_host) { - free(flac_cfg.stream.proxy_host); - flac_cfg.stream.proxy_host = NULL; - } - - if (flac_cfg.stream.proxy_user) { - free(flac_cfg.stream.proxy_user); - flac_cfg.stream.proxy_user = NULL; - - } - - if (flac_cfg.stream.proxy_pass) { - free(flac_cfg.stream.proxy_pass); - flac_cfg.stream.proxy_pass = NULL; - } - - safe_decoder_delete_(decoder_); - decoder_ = 0; -} - -void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) -{ - FLAC__StreamMetadata streaminfo; - - if(0 == filename) - filename = ""; - - if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) { - /* @@@ how to report the error? */ - if(title) { - if (!is_http_source(filename)) { - static const char *errtitle = "Invalid FLAC File: "; - *title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1); - sprintf(*title, "%s\"%s\"", errtitle, filename); - } else { - *title = NULL; - } - } - if(length_in_msec) - *length_in_msec = -1; - return; - } - - if(title) { - *title = flac_format_song_title(filename); - } - if(length_in_msec) { - FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5); - if (l > INT_MAX) - l = INT_MAX; - *length_in_msec = (int)l; - } -} - -/*********************************************************************** - * local routines - **********************************************************************/ - -void *play_loop_(void *arg) -{ - unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; - FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; - - (void)arg; - - while(stream_data_.is_playing) { - if(!stream_data_.eof) { - while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { - unsigned s; - - s = sample_buffer_last_ - sample_buffer_first_; - if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) { - stream_data_.eof = true; - break; - } - else if(!FLAC__stream_decoder_process_single(decoder_)) { - /*@@@ this should probably be a dialog */ - fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); - stream_data_.eof = true; - break; - } - blocksize = sample_buffer_last_ - sample_buffer_first_ - s; - decode_position_frame_last = decode_position_frame; - if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) - decode_position_frame = 0; - } - if(sample_buffer_last_ - sample_buffer_first_ > 0) { - const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); - int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; - FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; - unsigned written_time, bh_index_w; - FLAC__uint64 decode_position; - - sample_buffer_first_ += n; - while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) - xmms_usleep(10000); - if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) - produce_audio(flac_ip.output->written_time(), stream_data_.sample_format, - stream_data_.channels, bytes, sample_buffer_start, NULL); - - /* compute current bitrate */ - - written_time = flac_ip.output->written_time(); - bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; - if(bh_index_w != bh_index_last_w) { - bh_index_last_w = bh_index_w; - decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; - bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = - decode_position > decode_position_last && written_time > written_time_last ? - 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : - stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample; - decode_position_last = decode_position; - written_time_last = written_time; - } - } - else { - stream_data_.eof = true; - xmms_usleep(10000); - } - } - else - xmms_usleep(10000); - if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) { - const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec; - FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples); - if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples) - target_sample = stream_data_.total_samples - 1; - if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) { - flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000); - bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; - if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) - decode_position_frame = 0; - stream_data_.eof = false; - sample_buffer_first_ = sample_buffer_last_ = 0; - } - else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) { - /*@@@ this should probably be a dialog */ - fprintf(stderr, "libxmms-flac: SEEK ERROR\n"); - FLAC__stream_decoder_flush(decoder_); - stream_data_.eof = false; - sample_buffer_first_ = sample_buffer_last_ = 0; - } - stream_data_.seek_to_in_sec = -1; - } - else { - /* display the right bitrate from history */ - unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; - if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { - bh_index_last_o = bh_index_o; - flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels); - } - } - } - - safe_decoder_finish_(decoder_); - - /* are these two calls necessary? */ - flac_ip.output->buffer_free(); - flac_ip.output->buffer_free(); - - g_free(stream_data_.title); - - g_thread_exit(NULL); - return 0; /* to silence the compiler warning about not returning a value */ -} - -FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder) -{ - if(decoder == 0) - return false; - - safe_decoder_finish_(decoder); - - 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__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); - if(stream_data_.is_http_source) { - flac_http_open(filename, 0); - if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return false; - } - else { - if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK) - return false; - } - - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) - return false; - - return true; -} - -void safe_decoder_finish_(FLAC__StreamDecoder *decoder) -{ - if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) - FLAC__stream_decoder_finish(decoder); - if(stream_data_.is_http_source) - flac_http_close(); -} - -void safe_decoder_delete_(FLAC__StreamDecoder *decoder) -{ - if(decoder) { - safe_decoder_finish_(decoder); - FLAC__stream_decoder_delete(decoder); - } -} - -FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - (void)decoder; - (void)client_data; - *bytes = flac_http_read(buffer, *bytes); - return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; -} - -FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) -{ - stream_data_struct *stream_data = (stream_data_struct *)client_data; - const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize; - const unsigned bits_per_sample = stream_data->bits_per_sample; - FLAC__byte *sample_buffer_start; - - (void)decoder; - - if(stream_data->abort_flag) - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - - if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) { - memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample); - sample_buffer_last_ -= sample_buffer_first_; - sample_buffer_first_ = 0; - } - sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample; - if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) { - FLAC__replaygain_synthesis__apply_gain( - sample_buffer_start, - !is_big_endian_host_, - stream_data->sample_format_bytes_per_sample == 1, /* unsigned_data_out */ - buffer, - wide_samples, - channels, - bits_per_sample, - stream_data->sample_format_bytes_per_sample * 8, - stream_data->replay_scale, - flac_cfg.output.replaygain.hard_limit, - flac_cfg.output.resolution.replaygain.dither, - &stream_data->dither_context - ); - } - else if(is_big_endian_host_) { - FLAC__plugin_common__pack_pcm_signed_big_endian( - sample_buffer_start, - buffer, - wide_samples, - channels, - bits_per_sample, - stream_data->sample_format_bytes_per_sample * 8 - ); - } - else { - FLAC__plugin_common__pack_pcm_signed_little_endian( - sample_buffer_start, - buffer, - wide_samples, - channels, - bits_per_sample, - stream_data->sample_format_bytes_per_sample * 8 - ); - } - - sample_buffer_last_ += wide_samples; - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - stream_data_struct *stream_data = (stream_data_struct *)client_data; - (void)decoder; - if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { - stream_data->total_samples = metadata->data.stream_info.total_samples; - stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample; - stream_data->channels = metadata->data.stream_info.channels; - stream_data->sample_rate = metadata->data.stream_info.sample_rate; - { - FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5); - if (l > INT_MAX) - l = INT_MAX; - stream_data->length_in_msec = (int)l; - } - } - else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { - double reference, gain, peak; - if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) { - stream_data->has_replaygain = true; - stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit); - } - } -} - -void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - stream_data_struct *stream_data = (stream_data_struct *)client_data; - (void)decoder; - if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) - stream_data->abort_flag = true; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin.h --- a/src/flac/plugin.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 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. - */ - -#ifndef FLAC__PLUGIN_XMMS__PLUGIN_H -#define FLAC__PLUGIN_XMMS__PLUGIN_H - -void set_track_info(const char* title, int length_in_msec); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/Makefile --- a/src/flac/plugin_common/Makefile Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,28 +0,0 @@ -include ../../../mk/rules.mk -include ../../../mk/init.mk - -CFLAGS += $(PICFLAGS) -I.. -I../../.. - -OBJECTIVE_LIBS_NOINST = libplugin_common.a - -noinst_HEADERS = \ - all.h \ - charset.h \ - defs.h \ - dither.h \ - locale_hack.h \ - tags.h \ - replaygain.h - -SOURCES = \ - charset.c \ - dither.c \ - tags.c \ - replaygain.c - -OBJECTS = ${SOURCES:.c=.o} - -libplugin_common.a: $(OBJECTS) - $(AR) cq $@ $(OBJECTS) - -include ../../../mk/objective.mk diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/all.h --- a/src/flac/plugin_common/all.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +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. - */ - -#ifndef FLAC__PLUGIN_COMMON__ALL_H -#define FLAC__PLUGIN_COMMON__ALL_H - -#include "charset.h" -#include "dither.h" -#include "locale_hack.h" -#include "tags.h" - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/charset.c --- a/src/flac/plugin_common/charset.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -/* plugin_common - Routines common to several plugins - * Copyright (C) 2002,2003,2004,2005 Josh Coalson - * - * Only slightly modified charset.c from: - * EasyTAG - Tag editor for MP3 and OGG files - * Copyright (C) 1999-2001 Håvard Kvålen - * - * 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. - */ - -#include -#include -#include -#include - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_ICONV -#include -#endif - -#ifdef HAVE_LANGINFO_CODESET -#include -#endif - -#include "charset.h" - - -/************* - * Functions * - *************/ - -char* FLAC_plugin__charset_get_current (void) -{ - char *charset = getenv("CHARSET"); - -#ifdef HAVE_LANGINFO_CODESET - if (!charset) - charset = nl_langinfo(CODESET); -#endif - - if (charset) - return strdup(charset); - - return strdup("ISO-8859-1"); -} - - -#ifdef HAVE_ICONV -char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) -{ - size_t outleft, outsize, length; - iconv_t cd; - char *out, *outptr; - const char *input = string; - - if (!string) - return NULL; - - length = strlen(string); - - if ((cd = iconv_open(to, from)) == (iconv_t)-1) - { -#ifdef DEBUG - fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to); -#endif - return strdup(string); - } - - /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ - /* + 1 for nul in case len == 1 */ - outsize = ((length + 3) & ~3) + 1; - out = (char*)malloc(outsize); - outleft = outsize - 1; - outptr = out; - -retry: -#if defined __OpenBSD__ || defined __NetBSD__ - if (iconv(cd, &input, &length, &outptr, &outleft) == (size_t)-1) -#else - if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)-1) -#endif - { - int used; - switch (errno) - { - case E2BIG: - used = outptr - out; - outsize = (outsize - 1) * 2 + 1; - out = realloc(out, outsize); - outptr = out + used; - outleft = outsize - 1 - used; - goto retry; - case EINVAL: - break; - case EILSEQ: - /* Invalid sequence, try to get the rest of the string */ - input++; - length = strlen(input); - goto retry; - default: -#ifdef DEBUG - fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno)); -#endif - break; - } - } - *outptr = '\0'; - - iconv_close(cd); - return out; -} -#else -char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) -{ - (void)from, (void)to; - if (!string) - return NULL; - return strdup(string); -} -#endif - -#ifdef HAVE_ICONV -int FLAC_plugin__charset_test_conversion (char *from, char *to) -{ - iconv_t cd; - - if ((cd=iconv_open(to,from)) == (iconv_t)-1) - { - /* Conversion not supported */ - return 0; - } - iconv_close(cd); - return 1; -} -#else -int FLAC_plugin__charset_test_conversion (char *from, char *to) -{ - (void)from, (void)to; - return 1; -} -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/charset.h --- a/src/flac/plugin_common/charset.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* plugin_common - Routines common to several plugins - * Copyright (C) 2002,2003,2004,2005 Josh Coalson - * - * Only slightly modified charset.h from: - * charset.h - 2001/12/04 - * EasyTAG - Tag editor for MP3 and OGG files - * Copyright (C) 1999-2001 H蛆ard Kvè™±en - * - * 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. - */ - - -#ifndef FLAC__PLUGIN_COMMON__CHARSET_H -#define FLAC__PLUGIN_COMMON__CHARSET_H - - -/************** - * Prototypes * - **************/ - -char *FLAC_plugin__charset_get_current(); -char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to); - -/* returns 1 for success, 0 for failure or no iconv */ -int FLAC_plugin__charset_test_conversion(char *from, char *to); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/defs.h --- a/src/flac/plugin_common/defs.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,24 +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. - */ - -#ifndef FLAC__PLUGIN_COMMON__DEFS_H -#define FLAC__PLUGIN_COMMON__DEFS_H - -#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2 - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/dither.c --- a/src/flac/plugin_common/dither.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,260 +0,0 @@ -/* plugin_common - Routines common to several plugins - * Copyright (C) 2002,2003,2004,2005 Josh Coalson - * - * dithering routine derived from (other GPLed source): - * mad - MPEG audio decoder - * Copyright (C) 2000-2001 Robert Leslie - * - * 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. - */ - -#include "dither.h" -#include "FLAC/assert.h" - -#ifdef max -#undef max -#endif -#define max(a,b) ((a)>(b)?(a):(b)) - - -#if defined _MSC_VER -#define FLAC__INLINE __inline -#else -#define FLAC__INLINE -#endif - -/* 32-bit pseudo-random number generator - * - * @@@ According to Miroslav, this one is poor quality, the one from the - * @@@ original replaygain code is much better - */ -static FLAC__INLINE FLAC__uint32 prng(FLAC__uint32 state) -{ - return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; -} - -/* dither routine derived from MAD winamp plugin */ - -typedef struct { - FLAC__int32 error[3]; - FLAC__int32 random; -} dither_state; - -static FLAC__INLINE FLAC__int32 linear_dither(unsigned source_bps, unsigned target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX) -{ - unsigned scalebits; - FLAC__int32 output, mask, random; - - FLAC__ASSERT(source_bps < 32); - FLAC__ASSERT(target_bps <= 24); - FLAC__ASSERT(target_bps <= source_bps); - - /* noise shape */ - sample += dither->error[0] - dither->error[1] + dither->error[2]; - - dither->error[2] = dither->error[1]; - dither->error[1] = dither->error[0] / 2; - - /* bias */ - output = sample + (1L << (source_bps - target_bps - 1)); - - scalebits = source_bps - target_bps; - mask = (1L << scalebits) - 1; - - /* dither */ - random = (FLAC__int32)prng(dither->random); - output += (random & mask) - (dither->random & mask); - - dither->random = random; - - /* clip */ - if(output > MAX) { - output = MAX; - - if(sample > MAX) - sample = MAX; - } - else if(output < MIN) { - output = MIN; - - if(sample < MIN) - sample = MIN; - } - - /* quantize */ - output &= ~mask; - - /* error feedback */ - dither->error[0] = sample - output; - - /* scale */ - return output >> scalebits; -} - -size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps) -{ - static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS]; - FLAC__byte * const start = data; - FLAC__int32 sample; - const FLAC__int32 *input_; - unsigned samples, channel; - const unsigned bytes_per_sample = target_bps / 8; - const unsigned incr = bytes_per_sample * channels; - - FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS); - FLAC__ASSERT(source_bps < 32); - FLAC__ASSERT(target_bps <= 24); - FLAC__ASSERT(target_bps <= source_bps); - FLAC__ASSERT((source_bps & 7) == 0); - FLAC__ASSERT((target_bps & 7) == 0); - - if(source_bps != target_bps) { - const FLAC__int32 MIN = -(1L << (source_bps - 1)); - const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */ - - for(channel = 0; channel < channels; channel++) { - - samples = wide_samples; - data = start + bytes_per_sample * channel; - input_ = input[channel]; - - while(samples--) { - sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX); - - switch(target_bps) { - case 8: - data[0] = sample ^ 0x80; - break; - case 16: - data[0] = (FLAC__byte)(sample >> 8); - data[1] = (FLAC__byte)sample; - break; - case 24: - data[0] = (FLAC__byte)(sample >> 16); - data[1] = (FLAC__byte)(sample >> 8); - data[2] = (FLAC__byte)sample; - break; - } - - data += incr; - } - } - } - else { - for(channel = 0; channel < channels; channel++) { - samples = wide_samples; - data = start + bytes_per_sample * channel; - input_ = input[channel]; - - while(samples--) { - sample = *input_++; - - switch(target_bps) { - case 8: - data[0] = sample ^ 0x80; - break; - case 16: - data[0] = (FLAC__byte)(sample >> 8); - data[1] = (FLAC__byte)sample; - break; - case 24: - data[0] = (FLAC__byte)(sample >> 16); - data[1] = (FLAC__byte)(sample >> 8); - data[2] = (FLAC__byte)sample; - break; - } - - data += incr; - } - } - } - - return wide_samples * channels * (target_bps/8); -} - -size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps) -{ - static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS]; - FLAC__byte * const start = data; - FLAC__int32 sample; - const FLAC__int32 *input_; - unsigned samples, channel; - const unsigned bytes_per_sample = target_bps / 8; - const unsigned incr = bytes_per_sample * channels; - - FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS); - FLAC__ASSERT(source_bps < 32); - FLAC__ASSERT(target_bps <= 24); - FLAC__ASSERT(target_bps <= source_bps); - FLAC__ASSERT((source_bps & 7) == 0); - FLAC__ASSERT((target_bps & 7) == 0); - - if(source_bps != target_bps) { - const FLAC__int32 MIN = -(1L << (source_bps - 1)); - const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */ - - for(channel = 0; channel < channels; channel++) { - - samples = wide_samples; - data = start + bytes_per_sample * channel; - input_ = input[channel]; - - while(samples--) { - sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX); - - switch(target_bps) { - case 8: - data[0] = sample ^ 0x80; - break; - case 24: - data[2] = (FLAC__byte)(sample >> 16); - /* fall through */ - case 16: - data[1] = (FLAC__byte)(sample >> 8); - data[0] = (FLAC__byte)sample; - } - - data += incr; - } - } - } - else { - for(channel = 0; channel < channels; channel++) { - samples = wide_samples; - data = start + bytes_per_sample * channel; - input_ = input[channel]; - - while(samples--) { - sample = *input_++; - - switch(target_bps) { - case 8: - data[0] = sample ^ 0x80; - break; - case 24: - data[2] = (FLAC__byte)(sample >> 16); - /* fall through */ - case 16: - data[1] = (FLAC__byte)(sample >> 8); - data[0] = (FLAC__byte)sample; - } - - data += incr; - } - } - } - - return wide_samples * channels * (target_bps/8); -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/dither.h --- a/src/flac/plugin_common/dither.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,29 +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. - */ - -#ifndef FLAC__PLUGIN_COMMON__DITHER_H -#define FLAC__PLUGIN_COMMON__DITHER_H - -#include /* for size_t */ -#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */ -#include "FLAC/ordinals.h" - -size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps); -size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/locale_hack.h --- a/src/flac/plugin_common/locale_hack.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* plugin_common - Routines common to several plugins - * Copyright (C) 2002,2003,2004,2005 Josh Coalson - * - * Based on: - * locale.h - 2000/05/05 13:10 Jerome Couderc - * EasyTAG - Tag editor for MP3 and OGG files - * Copyright (C) 1999-2001 H蛆ard Kvè™±en - * - * 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. - */ -/* - * Gettext support for EasyTAG - */ - - -#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H -#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H - -#include - -/* - * Standard gettext macros. - */ -#ifdef ENABLE_NLS -# include -# define _(String) gettext (String) -# ifdef gettext_noop -# define N_(String) gettext_noop (String) -# else -# define N_(String) (String) -# endif -#else -# define textdomain(String) (String) -# define gettext(String) (String) -# define dgettext(Domain,Message) (Message) -# define dcgettext(Domain,Message,Type) (Message) -# define bindtextdomain(Domain,Directory) (Domain) -# define _(String) (String) -# define N_(String) (String) -#endif - - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/replaygain.c --- a/src/flac/plugin_common/replaygain.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* 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 -#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; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/replaygain.h --- a/src/flac/plugin_common/replaygain.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* 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 diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/tags.c --- a/src/flac/plugin_common/tags.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +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. - */ - -#include -#include -#include - -#include "tags.h" -#include "FLAC/assert.h" -#include "FLAC/metadata.h" - - -static __inline unsigned local__wide_strlen(const FLAC__uint16 *s) -{ - unsigned n = 0; - while(*s++) - n++; - return n; -} - -static __inline unsigned local__utf8len(const FLAC__byte *utf8) -{ - FLAC__ASSERT(0 != utf8); - if ((utf8[0] & 0x80) == 0) - return 1; - else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) - return 2; - else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) - return 3; - else - return 0; -} - -static __inline unsigned local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2) -{ - const unsigned len = local__utf8len(utf8); - - FLAC__ASSERT(0 != ucs2); - - if (len == 1) - *ucs2 = *utf8; - else if (len == 2) - *ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F); - else if (len == 3) - *ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F); - - return len; -} - -static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, unsigned length) -{ - FLAC__uint16 *out; - unsigned chars = 0; - - FLAC__ASSERT(0 != src); - - /* calculate length */ - { - const char *s, *end; - for (s=src, end=src+length; s> 6); - utf8[1] = 0x80 | (ucs2 & 0x3f); - return 2; - } - else { - utf8[0] = 0xe0 | (ucs2 >> 12); - utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f); - utf8[2] = 0x80 | (ucs2 & 0x3f); - return 3; - } -} - -static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, unsigned length) -{ - char *out; - unsigned len = 0; - - FLAC__ASSERT(0 != src); - - /* calculate length */ - { - unsigned i; - for (i = 0; i < length; i++) - len += local__ucs2len(src[i]); - } - - /* allocate */ - out = (char*)malloc(len * sizeof(char)); - if (0 == out) - return 0; - - /* convert */ - { - unsigned char *u = (unsigned char*) out; - for ( ; *src; src++) - u += local__ucs2_to_utf8(*src, u); - local__ucs2_to_utf8(*src, u); - } - - return out; -} - - -FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags) -{ - if(!FLAC__metadata_get_tags(filename, tags)) - if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT))) - return false; - return true; -} - -FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags) -{ - FLAC__Metadata_Chain *chain; - FLAC__Metadata_Iterator *iterator; - FLAC__StreamMetadata *block; - FLAC__bool got_vorbis_comments = false; - FLAC__bool ok; - - if(0 == (chain = FLAC__metadata_chain_new())) - return false; - - if(!FLAC__metadata_chain_read(chain, filename)) { - FLAC__metadata_chain_delete(chain); - return false; - } - - if(0 == (iterator = FLAC__metadata_iterator_new())) { - FLAC__metadata_chain_delete(chain); - return false; - } - - FLAC__metadata_iterator_init(iterator, chain); - - do { - if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) - got_vorbis_comments = true; - } while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator)); - - if(0 == (block = FLAC__metadata_object_clone(tags))) { - FLAC__metadata_chain_delete(chain); - FLAC__metadata_iterator_delete(iterator); - return false; - } - - if(got_vorbis_comments) - ok = FLAC__metadata_iterator_set_block(iterator, block); - else - ok = FLAC__metadata_iterator_insert_block_after(iterator, block); - - FLAC__metadata_iterator_delete(iterator); - - if(ok) { - FLAC__metadata_chain_sort_padding(chain); - ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true); - } - - FLAC__metadata_chain_delete(chain); - - return ok; -} - -void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags) -{ - FLAC__metadata_object_delete(*tags); - *tags = 0; -} - -const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name) -{ - const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name); - return (i < 0? 0 : strchr((const char*)tags->data.vorbis_comment.comments[i].entry, '=')+1); -} - -FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name) -{ - const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name); - if(0 == utf8) - return 0; - return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */ -} - -int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name) -{ - return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name); -} - -int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags) -{ - int n = (int)tags->data.vorbis_comment.num_comments; - if(n > 0) { - if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0)) - n = -1; - } - return n; -} - -FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator) -{ - int i; - - FLAC__ASSERT(0 != tags); - FLAC__ASSERT(0 != name); - FLAC__ASSERT(0 != value); - - if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) { - FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i; - const size_t value_len = strlen(value); - const size_t separator_len = strlen(separator); - FLAC__byte *new_entry; - if(0 == (new_entry = (FLAC__byte*)realloc(entry->entry, entry->length + value_len + separator_len + 1))) - return false; - memcpy(new_entry+entry->length, separator, separator_len); - entry->length += separator_len; - memcpy(new_entry+entry->length, value, value_len); - entry->length += value_len; - new_entry[entry->length] = '\0'; - entry->entry = new_entry; - } - else { - FLAC__StreamMetadata_VorbisComment_Entry entry; - if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value)) - return false; - FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false); - } - return true; -} - -FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all) -{ - FLAC__StreamMetadata_VorbisComment_Entry entry; - - FLAC__ASSERT(0 != tags); - FLAC__ASSERT(0 != name); - FLAC__ASSERT(0 != value); - - { - char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */ - if(0 == utf8) - return false; - if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) { - free(utf8); - return false; - } - free(utf8); - } - if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false)) - return false; - return true; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/plugin_common/tags.h --- a/src/flac/plugin_common/tags.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +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. - */ - -#ifndef FLAC__PLUGIN_COMMON__TAGS_H -#define FLAC__PLUGIN_COMMON__TAGS_H - -#include "FLAC/format.h" - -FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags); -FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags); - -/* - * Deletes the tags object and sets '*tags' to NULL. - */ -void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags); - -/* - * Gets the value (in UTF-8) of the first tag with the given name (NULL if no - * such tag exists). - */ -const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name); - -/* - * Gets the value (in UCS-2) of the first tag with the given name (NULL if no - * such tag exists). - * - * NOTE: the returned string is malloc()ed and must be free()d by the caller. - */ -FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name); - -/* - * Removes all tags with the given 'name'. Returns the number of tags removed, - * or -1 on memory allocation error. - */ -int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name); - -/* - * Removes all tags. Returns the number of tags removed, or -1 on memory - * allocation error. - */ -int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags); - -/* - * Adds a "name=value" tag to the tags. 'value' must be in UTF-8. If - * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the - * first such tag's value is appended with separator, then value. - */ -FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator); - -/* - * Adds a "name=value" tag to the tags. 'value' must be in UCS-2. If 'tags' - * already contains a tag or tags for 'name', then they will be replaced - * according to 'replace_all': if 'replace_all' is false, only the first such - * tag will be replaced; if true, all matching tags will be replaced by the one - * new tag. - */ -FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/replaygain.c --- a/src/flac/replaygain.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,665 +0,0 @@ -/* grabbag - Convenience lib for various routines common to several tools - * 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 - * 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. - */ - -#if HAVE_CONFIG_H -# include -#endif - -#include "grabbag.h" -#include "replaygain_analysis.h" -#include "FLAC/assert.h" -#include "FLAC/metadata.h" -#include "FLAC/stream_decoder.h" -#include -#include -#include -#include -#include -#if defined _MSC_VER || defined __MINGW32__ -#include /* for chmod() */ -#endif -#include /* for stat(), maybe chmod() */ - -#ifdef local_min -#undef local_min -#endif -#define local_min(a,b) ((a)<(b)?(a):(b)) - -#ifdef local_max -#undef local_max -#endif -#define local_max(a,b) ((a)>(b)?(a):(b)) - -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 double album_peak_, title_peak_; - -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) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != stats); - return (0 == stat(filename, stats)); -} - -static void set_file_stats_(const char *filename, struct stat *stats) -{ - FLAC__ASSERT(0 != filename); - FLAC__ASSERT(0 != stats); - - (void)chmod(filename, stats->st_mode); -} - -static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value) -{ - char buffer[256]; - char *saved_locale; - FLAC__StreamMetadata_VorbisComment_Entry entry; - - FLAC__ASSERT(0 != block); - FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - FLAC__ASSERT(0 != format); - FLAC__ASSERT(0 != name); - - buffer[sizeof(buffer)-1] = '\0'; - /* - * We need to save the old locale and switch to "C" because the locale - * influences the formatting of %f and we want it a certain way. - */ - saved_locale = setlocale(LC_ALL, 0); - setlocale(LC_ALL, "C"); -#if defined _MSC_VER || defined __MINGW32__ - _snprintf(buffer, sizeof(buffer)-1, format, name, value); -#else - snprintf(buffer, sizeof(buffer)-1, format, name, value); -#endif - setlocale(LC_ALL, saved_locale); - - entry.entry = (FLAC__byte *)buffer; - entry.length = strlen(buffer); - - return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true); -} - -FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency) -{ - static const unsigned valid_sample_rates[] = { - 8000, - 11025, - 12000, - 16000, - 22050, - 24000, - 32000, - 44100, - 48000 - }; - static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]); - - unsigned i; - - for(i = 0; i < n_valid_sample_rates; i++) - if(sample_frequency == valid_sample_rates[i]) - return true; - return false; -} - -FLAC__bool grabbag__replaygain_init(unsigned sample_frequency) -{ - title_peak_ = album_peak_ = 0.0; - return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK; -} - -FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples) -{ - /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */ - static Float_t lbuffer[2048], rbuffer[2048]; - static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]); - FLAC__int32 block_peak = 0, s; - unsigned i, j; - - FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE); - FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4); - /* - * We use abs() on a FLAC__int32 which is undefined for the most negative value. - * If the reference codec ever handles 32bps we will have to write a special - * case here. - */ - FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32); - - if(bps == 16) { - if(is_stereo) { - j = 0; - while(samples > 0) { - const unsigned n = local_min(samples, nbuffer); - for(i = 0; i < n; i++, j++) { - s = input[0][j]; - lbuffer[i] = (Float_t)s; - s = abs(s); - block_peak = local_max(block_peak, s); - - s = input[1][j]; - rbuffer[i] = (Float_t)s; - s = abs(s); - block_peak = local_max(block_peak, s); - } - samples -= n; - if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) - return false; - } - } - else { - j = 0; - while(samples > 0) { - const unsigned n = local_min(samples, nbuffer); - for(i = 0; i < n; i++, j++) { - s = input[0][j]; - lbuffer[i] = (Float_t)s; - s = abs(s); - block_peak = local_max(block_peak, s); - } - samples -= n; - if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) - return false; - } - } - } - else { /* bps must be < 32 according to above assertion */ - const double scale = ( - (bps > 16)? - (double)1. / (double)(1u << (bps - 16)) : - (double)(1u << (16 - bps)) - ); - - if(is_stereo) { - j = 0; - while(samples > 0) { - const unsigned n = local_min(samples, nbuffer); - for(i = 0; i < n; i++, j++) { - s = input[0][j]; - lbuffer[i] = (Float_t)(scale * (double)s); - s = abs(s); - block_peak = local_max(block_peak, s); - - s = input[1][j]; - rbuffer[i] = (Float_t)(scale * (double)s); - s = abs(s); - block_peak = local_max(block_peak, s); - } - samples -= n; - if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) - return false; - } - } - else { - j = 0; - while(samples > 0) { - const unsigned n = local_min(samples, nbuffer); - for(i = 0; i < n; i++, j++) { - s = input[0][j]; - lbuffer[i] = (Float_t)(scale * (double)s); - s = abs(s); - block_peak = local_max(block_peak, s); - } - samples -= n; - if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) - return false; - } - } - } - - { - const double peak_scale = (double)(1u << (bps - 1)); - double peak = (double)block_peak / peak_scale; - if(peak > title_peak_) - title_peak_ = peak; - if(peak > album_peak_) - album_peak_ = peak; - } - - return true; -} - -void grabbag__replaygain_get_album(float *gain, float *peak) -{ - *gain = (float)GetAlbumGain(); - *peak = (float)album_peak_; - album_peak_ = 0.0; -} - -void grabbag__replaygain_get_title(float *gain, float *peak) -{ - *gain = (float)GetTitleGain(); - *peak = (float)title_peak_; - title_peak_ = 0.0; -} - - -typedef struct { - unsigned channels; - unsigned bits_per_sample; - unsigned sample_rate; - FLAC__bool error; -} DecoderInstance; - -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; - const unsigned channels = frame->header.channels; - const unsigned sample_rate = frame->header.sample_rate; - const unsigned samples = frame->header.blocksize; - - (void)decoder; - - if( - !instance->error && - (channels == 2 || channels == 1) && - bits_per_sample == instance->bits_per_sample && - channels == instance->channels && - sample_rate == instance->sample_rate - ) { - instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples); - } - else { - instance->error = true; - } - - if(!instance->error) - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - else - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; -} - -static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - DecoderInstance *instance = (DecoderInstance*)client_data; - - (void)decoder; - - if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { - instance->bits_per_sample = metadata->data.stream_info.bits_per_sample; - instance->channels = metadata->data.stream_info.channels; - instance->sample_rate = metadata->data.stream_info.sample_rate; - - if(instance->channels != 1 && instance->channels != 2) { - instance->error = true; - return; - } - - if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) { - instance->error = true; - return; - } - } -} - -static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) -{ - DecoderInstance *instance = (DecoderInstance*)client_data; - - (void)decoder, (void)status; - - instance->error = true; -} - -const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak) -{ - DecoderInstance instance; - FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); - - if(0 == decoder) - return "memory allocation error"; - - instance.error = false; - - /* It does these three by default but lets be explicit: */ - 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); - - 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__stream_decoder_process_until_end_of_stream(decoder) || instance.error) { - FLAC__stream_decoder_delete(decoder); - return "decoding file"; - } - - FLAC__stream_decoder_delete(decoder); - - grabbag__replaygain_get_title(title_gain, title_peak); - - return 0; -} - -const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak) -{ - 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; - - if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) - return error; - - 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 *)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, 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"; - - return 0; -} - -const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_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 *)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, 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"; - - return 0; -} - -static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block) -{ - FLAC__Metadata_Iterator *iterator; - const char *error; - FLAC__bool found_vc_block = false; - - if(0 == (*chain = FLAC__metadata_chain_new())) - return "memory allocation error"; - - if(!FLAC__metadata_chain_read(*chain, filename)) { - error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; - FLAC__metadata_chain_delete(*chain); - return error; - } - - if(0 == (iterator = FLAC__metadata_iterator_new())) { - FLAC__metadata_chain_delete(*chain); - return "memory allocation error"; - } - - FLAC__metadata_iterator_init(iterator, *chain); - - do { - *block = FLAC__metadata_iterator_get_block(iterator); - if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) - found_vc_block = true; - } while(!found_vc_block && FLAC__metadata_iterator_next(iterator)); - - if(!found_vc_block) { - /* create a new block */ - *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); - if(0 == *block) { - FLAC__metadata_chain_delete(*chain); - FLAC__metadata_iterator_delete(iterator); - return "memory allocation error"; - } - while(FLAC__metadata_iterator_next(iterator)) - ; - if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) { - error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; - FLAC__metadata_chain_delete(*chain); - FLAC__metadata_iterator_delete(iterator); - return error; - } - /* iterator is left pointing to new block */ - FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block); - } - - FLAC__metadata_iterator_delete(iterator); - - FLAC__ASSERT(0 != *block); - FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); - - return 0; -} - -static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime) -{ - struct stat stats; - const FLAC__bool have_stats = get_file_stats_(filename, &stats); - - (void)grabbag__file_change_stats(filename, /*read_only=*/false); - - FLAC__metadata_chain_sort_padding(chain); - if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) { - FLAC__metadata_chain_delete(chain); - return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)]; - } - - FLAC__metadata_chain_delete(chain); - - if(have_stats) - set_file_stats_(filename, &stats); - - return 0; -} - -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) -{ - 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(block, album_gain, album_peak, title_gain, title_peak))) { - 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_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; - 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_album(block, album_gain, album_peak))) { - 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_title(const char *filename, float title_gain, float title_peak, 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_title(block, title_gain, title_peak))) { - FLAC__metadata_chain_delete(chain); - return error; - } - - if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) - return error; - - return 0; -} - -static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val) -{ - char s[32], *end; - const char *p, *q; - double v; - - FLAC__ASSERT(0 != entry); - FLAC__ASSERT(0 != val); - - p = (const char *)entry->entry; - q = strchr(p, '='); - if(0 == q) - return false; - q++; - memset(s, 0, sizeof(s)-1); - strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p))); - - v = strtod(s, &end); - if(end == s) - return false; - - *val = v; - return true; -} - -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 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); - - /* 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 !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 !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak); - - return true; -} - -double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping) -{ - double scale; - FLAC__ASSERT(peak >= 0.0); - gain += preamp; - scale = (float) pow(10.0, gain * 0.05); - if(prevent_clipping && peak > 0.0) { - const double max_scale = (float)(1.0 / peak); - if(scale > max_scale) - scale = max_scale; - } - return scale; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/replaygain_analysis.c --- a/src/flac/replaygain_analysis.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,419 +0,0 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001 David Robinson and Glen Sawyer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * original coding by Glen Sawyer (glensawyer@hotmail.com) - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * - * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) - * -- credit him for all the _good_ programming ;) - * - * minor cosmetic tweaks to integrate with FLAC by Josh Coalson - * - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -/* - * Here's the deal. Call - * - * InitGainAnalysis ( long samplefreq ); - * - * to initialize everything. Call - * - * AnalyzeSamples ( const Float_t* left_samples, - * const Float_t* right_samples, - * size_t num_samples, - * int num_channels ); - * - * as many times as you want, with as many or as few samples as you want. - * If mono, pass the sample buffer in through left_samples, leave - * right_samples NULL, and make sure num_channels = 1. - * - * GetTitleGain() - * - * will return the recommended dB level change for all samples analyzed - * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). - * - * GetAlbumGain() - * - * will return the recommended dB level change for all samples analyzed - * since InitGainAnalysis() was called and finalized with GetTitleGain(). - * - * Pseudo-code to process an album: - * - * Float_t l_samples [4096]; - * Float_t r_samples [4096]; - * size_t num_samples; - * unsigned int num_songs; - * unsigned int i; - * - * InitGainAnalysis ( 44100 ); - * for ( i = 1; i <= num_songs; i++ ) { - * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) - * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); - * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); - * } - * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); - */ - -/* - * So here's the main source of potential code confusion: - * - * The filters applied to the incoming samples are IIR filters, - * meaning they rely on up to number of previous samples - * AND up to number of previous filtered samples. - * - * I set up the AnalyzeSamples routine to minimize memory usage and interface - * complexity. The speed isn't compromised too much (I don't think), but the - * internal complexity is higher than it should be for such a relatively - * simple routine. - * - * Optimization/clarity suggestions are welcome. - */ - -#if HAVE_CONFIG_H -# include -#endif - -#include -#include -#include -#include - -#include "replaygain_analysis.h" - -Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */ - -typedef unsigned short Uint16_t; -typedef signed short Int16_t; -typedef unsigned int Uint32_t; -typedef signed int Int32_t; - -#define YULE_ORDER 10 -#define BUTTER_ORDER 2 -#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ -#define MAX_SAMP_FREQ 48000. /* maximum allowed sample frequency [Hz] */ -#define RMS_WINDOW_TIME 0.050 /* Time slice size [s] */ -#define STEPS_per_dB 100. /* Table entries per dB */ -#define MAX_dB 120. /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ - -#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) -/* [JEC] the following was originally #defined as: - * (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME) - * but that seemed to fail to take into account the ceil() part of the - * sampleWindow calculation in ResetSampleFrequency(), and was causing - * buffer overflows for 48kHz analysis, hence the +1. - */ -#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.) /* max. Samples per Time slice */ -#define PINK_REF 64.82 /* 298640883795 */ /* calibration value */ - -static Float_t linprebuf [MAX_ORDER * 2]; -static Float_t* linpre; /* left input samples, with pre-buffer */ -static Float_t lstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; -static Float_t* lstep; /* left "first step" (i.e. post first filter) samples */ -static Float_t loutbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; -static Float_t* lout; /* left "out" (i.e. post second filter) samples */ -static Float_t rinprebuf [MAX_ORDER * 2]; -static Float_t* rinpre; /* right input samples ... */ -static Float_t rstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; -static Float_t* rstep; -static Float_t routbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; -static Float_t* rout; -static unsigned int sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ -static unsigned long totsamp; -static double lsum; -static double rsum; -static int freqindex; -static Uint32_t A [(size_t)(STEPS_per_dB * MAX_dB)]; -static Uint32_t B [(size_t)(STEPS_per_dB * MAX_dB)]; - -/* for each filter: - [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */ - -#ifdef WIN32 -#pragma warning ( disable : 4305 ) -#endif - -static const Float_t AYule [9] [11] = { - { 1., -3.84664617118067, 7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294, 9.48293806319790, -5.87257861775999, 2.75465861874613, -0.86984376593551, 0.13919314567432 }, - { 1., -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280, -8.81498681370155, 6.85401540936998, -4.39470996079559, 2.19611684890774, -0.75104302451432, 0.13149317958808 }, - { 1., -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713, -1.67148153367602, 1.00595954808547, -0.45953458054983, 0.16378164858596, -0.05032077717131, 0.02347897407020 }, - { 1., -1.61273165137247, 1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906, 0.39120800788284, -0.22138138954925, 0.04500235387352, 0.02005851806501, 0.00302439095741 }, - { 1., -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438, 0.47854794562326, -0.12453458140019, -0.04067510197014, 0.08333755284107, -0.04237348025746, 0.02977207319925 }, - { 1., -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124, -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683, 0.05784820375801, 0.03222754072173 }, - { 1., -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858, 0.45054734505008, -0.33032403314006, 0.06739368333110, -0.04784254229033, 0.01639907836189, 0.01807364323573 }, - { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477, 0.14728154134330, 0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053, 0.02442357316099, 0.01818801111503 }, - { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242, 0.26408300200955, 0.15113130533216, -0.17556493366449, -0.18823009262115, 0.05477720428674, 0.04704409688120 } -}; - -static const Float_t BYule [9] [11] = { - { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619, 0.02161526843274, -0.02074045215285, 0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916 }, - { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936, 0.02245293253339, -0.02596338512915, 0.01624864962975, -0.00240879051584, 0.00674613682247, -0.00187763777362 }, - { 0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798, -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049, -0.01390589421898, 0.00651420667831, -0.00881362733839 }, - { 0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913, 0.06276101321749, -0.00000828086748, 0.00205861885564, -0.02950134983287 }, - { 0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440, 0.05724228140351, 0.00832043980773, -0.01635381384540, -0.01760176568150 }, - { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551, 0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251, -0.01863887810927, -0.03193428438915, 0.00541907748707 }, - { 0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672, -0.18901604199609, 0.30931782841830, -0.27562961986224, 0.00647310677246, 0.08647503780351, -0.03788984554840, -0.00588215443421 }, - { 0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522, 0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333, 0.06920467763959, -0.03721611395801, -0.00749618797172 }, - { 0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415, -0.10214864179676, 0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000, 0.04788665548180, -0.02217936801134 } -}; - -static const Float_t AButter [9] [3] = { - { 1., -1.97223372919527, 0.97261396931306 }, - { 1., -1.96977855582618, 0.97022847566350 }, - { 1., -1.95835380975398, 0.95920349965459 }, - { 1., -1.95002759149878, 0.95124613669835 }, - { 1., -1.94561023566527, 0.94705070426118 }, - { 1., -1.92783286977036, 0.93034775234268 }, - { 1., -1.91858953033784, 0.92177618768381 }, - { 1., -1.91542108074780, 0.91885558323625 }, - { 1., -1.88903307939452, 0.89487434461664 } -}; - -static const Float_t BButter [9] [3] = { - { 0.98621192462708, -1.97242384925416, 0.98621192462708 }, - { 0.98500175787242, -1.97000351574484, 0.98500175787242 }, - { 0.97938932735214, -1.95877865470428, 0.97938932735214 }, - { 0.97531843204928, -1.95063686409857, 0.97531843204928 }, - { 0.97316523498161, -1.94633046996323, 0.97316523498161 }, - { 0.96454515552826, -1.92909031105652, 0.96454515552826 }, - { 0.96009142950541, -1.92018285901082, 0.96009142950541 }, - { 0.95856916599601, -1.91713833199203, 0.95856916599601 }, - { 0.94597685600279, -1.89195371200558, 0.94597685600279 } -}; - -#ifdef WIN32 -#pragma warning ( default : 4305 ) -#endif - -/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */ - -static void -filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order ) -{ - double y; - size_t i; - size_t k; - - for ( i = 0; i < nSamples; i++ ) { - y = input[i] * b[0]; - for ( k = 1; k <= order; k++ ) - y += input[i-k] * b[k] - output[i-k] * a[k]; - output[i] = (Float_t)y; - } -} - -/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */ - -int -ResetSampleFrequency ( long samplefreq ) { - int i; - - /* zero out initial values */ - for ( i = 0; i < MAX_ORDER; i++ ) - linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.; - - switch ( (int)(samplefreq) ) { - case 48000: freqindex = 0; break; - case 44100: freqindex = 1; break; - case 32000: freqindex = 2; break; - case 24000: freqindex = 3; break; - case 22050: freqindex = 4; break; - case 16000: freqindex = 5; break; - case 12000: freqindex = 6; break; - case 11025: freqindex = 7; break; - case 8000: freqindex = 8; break; - default: return INIT_GAIN_ANALYSIS_ERROR; - } - - sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME); - - lsum = 0.; - rsum = 0.; - totsamp = 0; - - memset ( A, 0, sizeof(A) ); - - return INIT_GAIN_ANALYSIS_OK; -} - -int -InitGainAnalysis ( long samplefreq ) -{ - if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) { - return INIT_GAIN_ANALYSIS_ERROR; - } - - linpre = linprebuf + MAX_ORDER; - rinpre = rinprebuf + MAX_ORDER; - lstep = lstepbuf + MAX_ORDER; - rstep = rstepbuf + MAX_ORDER; - lout = loutbuf + MAX_ORDER; - rout = routbuf + MAX_ORDER; - - memset ( B, 0, sizeof(B) ); - - return INIT_GAIN_ANALYSIS_OK; -} - -/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */ - -int -AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ) -{ - const Float_t* curleft; - const Float_t* curright; - long batchsamples; - long cursamples; - long cursamplepos; - int i; - - if ( num_samples == 0 ) - return GAIN_ANALYSIS_OK; - - cursamplepos = 0; - batchsamples = num_samples; - - switch ( num_channels) { - case 1: right_samples = left_samples; - case 2: break; - default: return GAIN_ANALYSIS_ERROR; - } - - if ( num_samples < MAX_ORDER ) { - memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) ); - } - else { - memcpy ( linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t) ); - } - - while ( batchsamples > 0 ) { - cursamples = batchsamples > (long)(sampleWindow-totsamp) ? (long)(sampleWindow - totsamp) : batchsamples; - if ( cursamplepos < MAX_ORDER ) { - curleft = linpre+cursamplepos; - curright = rinpre+cursamplepos; - if (cursamples > MAX_ORDER - cursamplepos ) - cursamples = MAX_ORDER - cursamplepos; - } - else { - curleft = left_samples + cursamplepos; - curright = right_samples + cursamplepos; - } - - filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER ); - filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER ); - - filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER ); - filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER ); - - for ( i = 0; i < cursamples; i++ ) { /* Get the squared values */ - lsum += lout [totsamp+i] * lout [totsamp+i]; - rsum += rout [totsamp+i] * rout [totsamp+i]; - } - - batchsamples -= cursamples; - cursamplepos += cursamples; - totsamp += cursamples; - if ( totsamp == sampleWindow ) { /* Get the Root Mean Square (RMS) for this set of samples */ - double val = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 ); - int ival = (int) val; - if ( ival < 0 ) ival = 0; - if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1; - A [ival]++; - lsum = rsum = 0.; - memmove ( loutbuf , loutbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); - totsamp = 0; - } - if ( totsamp > sampleWindow ) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */ - return GAIN_ANALYSIS_ERROR; - } - if ( num_samples < MAX_ORDER ) { - memmove ( linprebuf, linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); - memmove ( rinprebuf, rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); - memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(Float_t) ); - memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(Float_t) ); - } - else { - memcpy ( linprebuf, left_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); - memcpy ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); - } - - return GAIN_ANALYSIS_OK; -} - - -static Float_t -analyzeResult ( Uint32_t* Array, size_t len ) -{ - Uint32_t elems; - Int32_t upper; - size_t i; - - elems = 0; - for ( i = 0; i < len; i++ ) - elems += Array[i]; - if ( elems == 0 ) - return GAIN_NOT_ENOUGH_SAMPLES; - - upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE)); - for ( i = len; i-- > 0; ) { - if ( (upper -= Array[i]) <= 0 ) - break; - } - - return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB); -} - - -Float_t -GetTitleGain ( void ) -{ - Float_t retval; - unsigned int i; - - retval = analyzeResult ( A, sizeof(A)/sizeof(*A) ); - - for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) { - B[i] += A[i]; - A[i] = 0; - } - - for ( i = 0; i < MAX_ORDER; i++ ) - linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f; - - totsamp = 0; - lsum = rsum = 0.; - return retval; -} - - -Float_t -GetAlbumGain ( void ) -{ - return analyzeResult ( B, sizeof(B)/sizeof(*B) ); -} - -/* end of replaygain_analysis.c */ diff -r aff1cf3e86dd -r 117bc56d906b src/flac/replaygain_analysis.h --- a/src/flac/replaygain_analysis.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,58 +0,0 @@ -/* - * ReplayGainAnalysis - analyzes input samples and give the recommended dB change - * Copyright (C) 2001 David Robinson and Glen Sawyer - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * concept and filter values by David Robinson (David@Robinson.org) - * -- blame him if you think the idea is flawed - * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA - * -- blame him if you think this runs too slowly, or the coding is otherwise flawed - * minor cosmetic tweaks to integrate with FLAC by Josh Coalson - * - * For an explanation of the concepts and the basic algorithms involved, go to: - * http://www.replaygain.org/ - */ - -#ifndef GAIN_ANALYSIS_H -#define GAIN_ANALYSIS_H - -#include - -#define GAIN_NOT_ENOUGH_SAMPLES -24601 -#define GAIN_ANALYSIS_ERROR 0 -#define GAIN_ANALYSIS_OK 1 - -#define INIT_GAIN_ANALYSIS_ERROR 0 -#define INIT_GAIN_ANALYSIS_OK 1 - -#ifdef __cplusplus -extern "C" { -#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 ); -int ResetSampleFrequency ( long samplefreq ); -Float_t GetTitleGain ( void ); -Float_t GetAlbumGain ( void ); - -#ifdef __cplusplus -} -#endif - -#endif /* GAIN_ANALYSIS_H */ diff -r aff1cf3e86dd -r 117bc56d906b src/flac/replaygain_synthesis.c --- a/src/flac/replaygain_synthesis.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* replaygain_synthesis - Routines for applying ReplayGain to a signal - * 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. - */ -/* - * This is an aggregation of pieces of code from John Edwards' WaveGain - * program. Mostly cosmetic changes were made; otherwise, the dithering - * code is almost untouched and the gain processing was converted from - * processing a whole file to processing chunks of samples. - * - * The original copyright notices for WaveGain's dither.c and wavegain.c - * appear below: - */ -/* - * (c) 2002 John Edwards - * mostly lifted from work by Frank Klemm - * random functions for dithering. - */ -/* - * Copyright (C) 2002 John Edwards - * Additional code by Magnus Holmgren and Gian-Carlo Pascutto - */ - -#include /* for memset() */ -#include -#include "fast_float_math_hack.h" -#include "replaygain_synthesis.h" -#include "FLAC/assert.h" - -#if defined _MSC_VER -#define FLAC__INLINE __inline -#else -#define FLAC__INLINE -#endif - -/* adjust for compilers that can't understand using LL suffix for int64_t literals */ -#ifdef _MSC_VER -#define FLAC__I64L(x) x -#else -#define FLAC__I64L(x) x##LL -#endif - - -/* - * the following is based on parts of dither.c - */ - - -/* - * This is a simple random number generator with good quality for audio purposes. - * It consists of two polycounters with opposite rotation direction and different - * periods. The periods are coprime, so the total period is the product of both. - * - * ------------------------------------------------------------------------------------------------- - * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| - * | ------------------------------------------------------------------------------------------------- - * | | | | | | | - * | +--+--+--+-XOR-+--------+ - * | | - * +--------------------------------------------------------------------------------------+ - * - * ------------------------------------------------------------------------------------------------- - * |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+ - * ------------------------------------------------------------------------------------------------- | - * | | | | | - * +--+----XOR----+--+ | - * | | - * +----------------------------------------------------------------------------------------+ - * - * - * The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481, - * which gives a period of 18.410.713.077.675.721.215. The result is the - * XORed values of both generators. - */ - -static unsigned int random_int_() -{ - static const unsigned char parity_[256] = { - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, - 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 - }; - static unsigned int r1_ = 1; - static unsigned int r2_ = 1; - - unsigned int t1, t2, t3, t4; - - /* Parity calculation is done via table lookup, this is also available - * on CPUs without parity, can be implemented in C and avoid unpredictable - * jumps and slow rotate through the carry flag operations. - */ - t3 = t1 = r1_; t4 = t2 = r2_; - t1 &= 0xF5; t2 >>= 25; - t1 = parity_[t1]; t2 &= 0x63; - t1 <<= 31; t2 = parity_[t2]; - - return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 ); -} - -/* gives a equal distributed random number */ -/* between -2^31*mult and +2^31*mult */ -static double random_equi_(double mult) -{ - return mult * (int) random_int_(); -} - -/* gives a triangular distributed random number */ -/* between -2^32*mult and +2^32*mult */ -static double random_triangular_(double mult) -{ - return mult * ( (double) (int) random_int_() + (double) (int) random_int_() ); -} - - -static const float F44_0 [16 + 32] = { - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, - - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, - - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, - (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0 -}; - - -static const float F44_1 [16 + 32] = { /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */ - (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, - (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, - (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, - (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, - - (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, - (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, - (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, - (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, - - (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, - (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, - (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, - (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, -}; - - -static const float F44_2 [16 + 32] = { /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */ - (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, - (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, - (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, - (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, - - (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, - (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, - (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, - (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, - - (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, - (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, - (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, - (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, -}; - - -static const float F44_3 [16 + 32] = { /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */ - (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, - (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, - (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, - (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, - - (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, - (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, - (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, - (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, - - (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, - (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, - (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, - (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099 -}; - - -static double scalar16_(const float* x, const float* y) -{ - return - x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] + - x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] + - x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] + - x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15]; -} - - -void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype) -{ - static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67, 0, 0 }; - static const float* F [] = { F44_0, F44_1, F44_2, F44_3 }; - - int index; - - if (shapingtype < 0) shapingtype = 0; - if (shapingtype > 3) shapingtype = 3; - d->ShapingType = (NoiseShaping)shapingtype; - index = bits - 11 - shapingtype; - if (index < 0) index = 0; - if (index > 9) index = 9; - - memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) ); - memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) ); - - d->FilterCoeff = F [shapingtype]; - d->Mask = ((FLAC__uint64)-1) << (32 - bits); - d->Add = 0.5 * ((1L << (32 - bits)) - 1); - d->Dither = 0.01f*default_dither[index] / (((FLAC__int64)1) << bits); - d->LastHistoryIndex = 0; -} - -/* - * the following is based on parts of wavegain.c - */ - -static FLAC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k) -{ - union { - double d; - FLAC__int64 i; - } doubletmp; - double Sum2; - FLAC__int64 val; - -#define ROUND64(x) ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) ) - - if(do_dithering) { - if(shapingtype == 0) { - double tmp = random_equi_(d->Dither); - Sum2 = tmp - d->LastRandomNumber [k]; - d->LastRandomNumber [k] = (int)tmp; - Sum2 = Sum += Sum2; - val = ROUND64(Sum2) & d->Mask; - } - else { - Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i); - Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2; - Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i); - val = ROUND64(Sum2) & d->Mask; - d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val); - } - return val; - } - else - return ROUND64(Sum); - -#undef ROUND64 -} - -#if 0 - float peak = 0.f, - new_peak, - factor_clip - double scale, - dB; - - ... - - peak is in the range -32768.0 .. 32767.0 - - /* calculate factors for ReplayGain and ClippingPrevention */ - *track_gain = GetTitleGain() + settings->man_gain; - scale = (float) pow(10., *track_gain * 0.05); - if(settings->clip_prev) { - factor_clip = (float) (32767./( peak + 1)); - if(scale < factor_clip) - factor_clip = 1.f; - else - factor_clip /= scale; - scale *= factor_clip; - } - new_peak = (float) peak * scale; - - dB = 20. * log10(scale); - *track_gain = (float) dB; - - const double scale = pow(10., (double)gain * 0.05); -#endif - - -size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context) -{ - static const FLAC__int32 conv_factors_[33] = { - -1, /* 0 bits-per-sample (not supported) */ - -1, /* 1 bits-per-sample (not supported) */ - -1, /* 2 bits-per-sample (not supported) */ - -1, /* 3 bits-per-sample (not supported) */ - 268435456, /* 4 bits-per-sample */ - 134217728, /* 5 bits-per-sample */ - 67108864, /* 6 bits-per-sample */ - 33554432, /* 7 bits-per-sample */ - 16777216, /* 8 bits-per-sample */ - 8388608, /* 9 bits-per-sample */ - 4194304, /* 10 bits-per-sample */ - 2097152, /* 11 bits-per-sample */ - 1048576, /* 12 bits-per-sample */ - 524288, /* 13 bits-per-sample */ - 262144, /* 14 bits-per-sample */ - 131072, /* 15 bits-per-sample */ - 65536, /* 16 bits-per-sample */ - 32768, /* 17 bits-per-sample */ - 16384, /* 18 bits-per-sample */ - 8192, /* 19 bits-per-sample */ - 4096, /* 20 bits-per-sample */ - 2048, /* 21 bits-per-sample */ - 1024, /* 22 bits-per-sample */ - 512, /* 23 bits-per-sample */ - 256, /* 24 bits-per-sample */ - 128, /* 25 bits-per-sample */ - 64, /* 26 bits-per-sample */ - 32, /* 27 bits-per-sample */ - 16, /* 28 bits-per-sample */ - 8, /* 29 bits-per-sample */ - 4, /* 30 bits-per-sample */ - 2, /* 31 bits-per-sample */ - 1 /* 32 bits-per-sample */ - }; - static const FLAC__int64 hard_clip_factors_[33] = { - 0, /* 0 bits-per-sample (not supported) */ - 0, /* 1 bits-per-sample (not supported) */ - 0, /* 2 bits-per-sample (not supported) */ - 0, /* 3 bits-per-sample (not supported) */ - -8, /* 4 bits-per-sample */ - -16, /* 5 bits-per-sample */ - -32, /* 6 bits-per-sample */ - -64, /* 7 bits-per-sample */ - -128, /* 8 bits-per-sample */ - -256, /* 9 bits-per-sample */ - -512, /* 10 bits-per-sample */ - -1024, /* 11 bits-per-sample */ - -2048, /* 12 bits-per-sample */ - -4096, /* 13 bits-per-sample */ - -8192, /* 14 bits-per-sample */ - -16384, /* 15 bits-per-sample */ - -32768, /* 16 bits-per-sample */ - -65536, /* 17 bits-per-sample */ - -131072, /* 18 bits-per-sample */ - -262144, /* 19 bits-per-sample */ - -524288, /* 20 bits-per-sample */ - -1048576, /* 21 bits-per-sample */ - -2097152, /* 22 bits-per-sample */ - -4194304, /* 23 bits-per-sample */ - -8388608, /* 24 bits-per-sample */ - -16777216, /* 25 bits-per-sample */ - -33554432, /* 26 bits-per-sample */ - -67108864, /* 27 bits-per-sample */ - -134217728, /* 28 bits-per-sample */ - -268435456, /* 29 bits-per-sample */ - -536870912, /* 30 bits-per-sample */ - -1073741824, /* 31 bits-per-sample */ - (FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */ - }; - const FLAC__int32 conv_factor = conv_factors_[target_bps]; - const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps]; - /* - * The integer input coming in has a varying range based on the - * source_bps. We want to normalize it to [-1.0, 1.0) so instead - * of doing two multiplies on each sample, we just multiple - * 'scale' by 1/(2^(source_bps-1)) - */ - const double multi_scale = scale / (double)(1u << (source_bps-1)); - - FLAC__byte * const start = data_out; - unsigned i, channel; - const FLAC__int32 *input_; - double sample; - const unsigned bytes_per_sample = target_bps / 8; - const unsigned last_history_index = dither_context->LastHistoryIndex; - NoiseShaping noise_shaping = dither_context->ShapingType; - FLAC__int64 val64; - FLAC__int32 val32; - FLAC__int32 uval32; - const FLAC__uint32 twiggle = 1u << (target_bps - 1); - - FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS); - FLAC__ASSERT(source_bps >= 4); - FLAC__ASSERT(target_bps >= 4); - FLAC__ASSERT(source_bps <= 32); - FLAC__ASSERT(target_bps < 32); - FLAC__ASSERT((target_bps & 7) == 0); - - for(channel = 0; channel < channels; channel++) { - const unsigned incr = bytes_per_sample * channels; - data_out = start + bytes_per_sample * channel; - input_ = input[channel]; - for(i = 0; i < wide_samples; i++, data_out += incr) { - sample = (double)input_[i] * multi_scale; - - if(hard_limit) { - /* hard 6dB limiting */ - if(sample < -0.5) - sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5; - else if(sample > 0.5) - sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5; - } - sample *= 2147483647.f; - - val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor; - - val32 = (FLAC__int32)val64; - if(val64 >= -hard_clip_factor) - val32 = (FLAC__int32)(-(hard_clip_factor+1)); - else if(val64 < hard_clip_factor) - val32 = (FLAC__int32)hard_clip_factor; - - uval32 = (FLAC__uint32)val32; - if (unsigned_data_out) - uval32 ^= twiggle; - - if (little_endian_data_out) { - switch(target_bps) { - case 24: - data_out[2] = (FLAC__byte)(uval32 >> 16); - /* fall through */ - case 16: - data_out[1] = (FLAC__byte)(uval32 >> 8); - /* fall through */ - case 8: - data_out[0] = (FLAC__byte)uval32; - break; - } - } - else { - switch(target_bps) { - case 24: - data_out[0] = (FLAC__byte)(uval32 >> 16); - data_out[1] = (FLAC__byte)(uval32 >> 8); - data_out[2] = (FLAC__byte)uval32; - break; - case 16: - data_out[0] = (FLAC__byte)(uval32 >> 8); - data_out[1] = (FLAC__byte)uval32; - break; - case 8: - data_out[0] = (FLAC__byte)uval32; - break; - } - } - } - } - dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32; - - return wide_samples * channels * (target_bps/8); -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/replaygain_synthesis.h --- a/src/flac/replaygain_synthesis.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/* replaygain_synthesis - Routines for applying ReplayGain to a signal - * 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. - */ - -#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H -#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H - -#include /* for size_t */ -#include "FLAC/ordinals.h" - -#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2 - -typedef enum { - NOISE_SHAPING_NONE = 0, - NOISE_SHAPING_LOW = 1, - NOISE_SHAPING_MEDIUM = 2, - NOISE_SHAPING_HIGH = 3 -} NoiseShaping; - -typedef struct { - const float* FilterCoeff; - FLAC__uint64 Mask; - double Add; - float Dither; - float ErrorHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; /* 16th order Noise shaping */ - float DitherHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; - int LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS]; - unsigned LastHistoryIndex; - NoiseShaping ShapingType; -} DitherContext; - -void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype); - -/* scale = (float) pow(10., (double)replaygain * 0.05); */ -size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac/tag.c --- a/src/flac/tag.c Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2000,2001,2002,2003,2004,2005 Josh Coalson - * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura - * - * Based on FLAC plugin.c and mpg123 plugin - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "FLAC/metadata.h" -#include "plugin_common/tags.h" -#include "charset.h" -#include "configure.h" - -/* - * Function local__extname (filename) - * - * Return pointer within filename to its extenstion, or NULL if - * filename has no extension. - * - */ -static char *local__extname(const char *filename) -{ - char *ext = strrchr(filename, '.'); - - if (ext != NULL) - ++ext; - - return ext; -} - -static char *local__getstr(char* str) -{ - if (str && strlen(str) > 0) - return g_strdup(str); - return NULL; -} - -static int local__getnum(char* str) -{ - if (str && strlen(str) > 0) - return atoi(str); - return 0; -} - -static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name) -{ - if (0 != tags) { - const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name); - if (0 != utf8) { - if(flac_cfg.title.convert_char_set) - return convert_from_utf8_to_user(utf8); - else - return strdup(utf8); - } - } - - return 0; -} - -/* - * Function flac_format_song_title (tag, filename) - * - * Create song title according to `tag' and/or `filename' and - * return it. The title must be subsequently freed using g_free(). - * - */ -TitleInput *flac_get_tuple(char *filename) -{ - TitleInput *input = NULL; - FLAC__StreamMetadata *tags; - FLAC__StreamMetadata info; - char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description; - gchar *filename_proxy = g_strdup(filename); - - FLAC_plugin__tags_get(filename_proxy, &tags); - - title = local__getfield(tags, "TITLE"); - artist = local__getfield(tags, "ARTIST"); - performer = local__getfield(tags, "PERFORMER"); - album = local__getfield(tags, "ALBUM"); - date = local__getfield(tags, "DATE"); - tracknumber = local__getfield(tags, "TRACKNUMBER"); - genre = local__getfield(tags, "GENRE"); - description = local__getfield(tags, "DESCRIPTION"); - - input = bmp_title_input_new(); - - input->performer = local__getstr(performer); - if(!input->performer) - input->performer = local__getstr(artist); - input->album_name = local__getstr(album); - input->track_name = local__getstr(title); - input->track_number = local__getnum(tracknumber); - input->year = local__getnum(date); - input->genre = local__getstr(genre); - input->comment = local__getstr(description); - - input->file_name = g_path_get_basename(filename_proxy); - input->file_path = g_path_get_dirname(filename_proxy); - input->file_ext = local__extname(filename_proxy); - - FLAC__metadata_get_streaminfo(filename, &info); - - input->length = (unsigned)((double)info.data.stream_info.total_samples / (double)info.data.stream_info.sample_rate * 1000.0 + 0.5); - - return input; -} - -gchar *flac_format_song_title(gchar *filename) -{ - gchar *ret = NULL; - TitleInput *tuple = flac_get_tuple(filename); - - ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), tuple); - - if (!ret) { - /* - * Format according to filename. - */ - ret = g_strdup(g_basename(filename)); - if (local__extname(ret) != NULL) - *(local__extname(ret) - 1) = '\0'; /* removes period */ - } - - bmp_title_input_free(tuple); - - return ret; -} diff -r aff1cf3e86dd -r 117bc56d906b src/flac/tag.h --- a/src/flac/tag.h Mon Oct 23 19:46:25 2006 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/* libxmms-flac - XMMS FLAC input plugin - * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura - * - * 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. - */ - -#ifndef __FLAC__PLUGIN_XMMS__TAG_H__ -#define __FLAC__PLUGIN_XMMS__TAG_H__ - -TitleInput *flac_get_tuple(gchar * filename); -gchar *flac_format_song_title(gchar * filename); - -#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/Makefile Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,39 @@ +include ../../mk/rules.mk +include ../../mk/init.mk + +SUBDIRS = plugin_common + +noinst_HEADERS = \ + charset.h \ + configure.h \ + http.h \ + plugin.h \ + tag.h \ + fast_float_math_hack.h \ + replaygain_analysis.h \ + grabbag.h \ + replaygain_synthesis.h + +OBJECTIVE_LIBS = libflac$(SHARED_SUFFIX) + +LIBDIR = $(plugindir)/$(INPUT_PLUGIN_DIR) + +LIBADD = $(LIBFLAC_LIBS) -L./plugin_common -lplugin_common + +SOURCES = \ + charset.c \ + configure.c \ + fileinfo.c \ + http.c \ + plugin.c \ + tag.c \ + replaygain_synthesis.c \ + replaygain.c \ + replaygain_analysis.c \ + file.c + +OBJECTS = ${SOURCES:.c=.o} + +CFLAGS += $(PICFLAGS) $(GTK_CFLAGS) -I../../intl -I../.. $(LIBFLAC_CFLAGS) + +include ../../mk/objective.mk diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/charset.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/charset.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,194 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura + * + * Almost from charset.c + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 Håvard Kvålen + * + * 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. + */ + +#include +#include +#include +#include + +#include "plugin_common/charset.h" +#include "plugin_common/locale_hack.h" +#include "charset.h" +#include "configure.h" + + +/**************** + * Declarations * + ****************/ + +#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) ) +const CharsetInfo charset_trans_array[] = { + {N_("Arabic (IBM-864)"), "IBM864" }, + {N_("Arabic (ISO-8859-6)"), "ISO-8859-6" }, + {N_("Arabic (Windows-1256)"), "windows-1256" }, + {N_("Baltic (ISO-8859-13)"), "ISO-8859-13" }, + {N_("Baltic (ISO-8859-4)"), "ISO-8859-4" }, + {N_("Baltic (Windows-1257)"), "windows-1257" }, + {N_("Celtic (ISO-8859-14)"), "ISO-8859-14" }, + {N_("Central European (IBM-852)"), "IBM852" }, + {N_("Central European (ISO-8859-2)"), "ISO-8859-2" }, + {N_("Central European (Windows-1250)"), "windows-1250" }, + {N_("Chinese Simplified (GB18030)"), "gb18030" }, + {N_("Chinese Simplified (GB2312)"), "GB2312" }, + {N_("Chinese Traditional (Big5)"), "Big5" }, + {N_("Chinese Traditional (Big5-HKSCS)"), "Big5-HKSCS" }, + {N_("Cyrillic (IBM-855)"), "IBM855" }, + {N_("Cyrillic (ISO-8859-5)"), "ISO-8859-5" }, + {N_("Cyrillic (ISO-IR-111)"), "ISO-IR-111" }, + {N_("Cyrillic (KOI8-R)"), "KOI8-R" }, + {N_("Cyrillic (Windows-1251)"), "windows-1251" }, + {N_("Cyrillic/Russian (CP-866)"), "IBM866" }, + {N_("Cyrillic/Ukrainian (KOI8-U)"), "KOI8-U" }, + {N_("English (US-ASCII)"), "us-ascii" }, + {N_("Greek (ISO-8859-7)"), "ISO-8859-7" }, + {N_("Greek (Windows-1253)"), "windows-1253" }, + {N_("Hebrew (IBM-862)"), "IBM862" }, + {N_("Hebrew (Windows-1255)"), "windows-1255" }, + {N_("Japanese (EUC-JP)"), "EUC-JP" }, + {N_("Japanese (ISO-2022-JP)"), "ISO-2022-JP" }, + {N_("Japanese (Shift_JIS)"), "Shift_JIS" }, + {N_("Korean (EUC-KR)"), "EUC-KR" }, + {N_("Nordic (ISO-8859-10)"), "ISO-8859-10" }, + {N_("South European (ISO-8859-3)"), "ISO-8859-3" }, + {N_("Thai (TIS-620)"), "TIS-620" }, + {N_("Turkish (IBM-857)"), "IBM857" }, + {N_("Turkish (ISO-8859-9)"), "ISO-8859-9" }, + {N_("Turkish (Windows-1254)"), "windows-1254" }, + {N_("Unicode (UTF-7)"), "UTF-7" }, + {N_("Unicode (UTF-8)"), "UTF-8" }, + {N_("Unicode (UTF-16BE)"), "UTF-16BE" }, + {N_("Unicode (UTF-16LE)"), "UTF-16LE" }, + {N_("Unicode (UTF-32BE)"), "UTF-32BE" }, + {N_("Unicode (UTF-32LE)"), "UTF-32LE" }, + {N_("Vietnamese (VISCII)"), "VISCII" }, + {N_("Vietnamese (Windows-1258)"), "windows-1258" }, + {N_("Visual Hebrew (ISO-8859-8)"), "ISO-8859-8" }, + {N_("Western (IBM-850)"), "IBM850" }, + {N_("Western (ISO-8859-1)"), "ISO-8859-1" }, + {N_("Western (ISO-8859-15)"), "ISO-8859-15" }, + {N_("Western (Windows-1252)"), "windows-1252" } + + /* + * From this point, character sets aren't supported by iconv + */ +#if 0 + {N_("Arabic (IBM-864-I)"), "IBM864i" }, + {N_("Arabic (ISO-8859-6-E)"), "ISO-8859-6-E" }, + {N_("Arabic (ISO-8859-6-I)"), "ISO-8859-6-I" }, + {N_("Arabic (MacArabic)"), "x-mac-arabic" }, + {N_("Armenian (ARMSCII-8)"), "armscii-8" }, + {N_("Central European (MacCE)"), "x-mac-ce" }, + {N_("Chinese Simplified (GBK)"), "x-gbk" }, + {N_("Chinese Simplified (HZ)"), "HZ-GB-2312" }, + {N_("Chinese Traditional (EUC-TW)"), "x-euc-tw" }, + {N_("Croatian (MacCroatian)"), "x-mac-croatian" }, + {N_("Cyrillic (MacCyrillic)"), "x-mac-cyrillic" }, + {N_("Cyrillic/Ukrainian (MacUkrainian)"), "x-mac-ukrainian" }, + {N_("Farsi (MacFarsi)"), "x-mac-farsi"}, + {N_("Greek (MacGreek)"), "x-mac-greek" }, + {N_("Gujarati (MacGujarati)"), "x-mac-gujarati" }, + {N_("Gurmukhi (MacGurmukhi)"), "x-mac-gurmukhi" }, + {N_("Hebrew (ISO-8859-8-E)"), "ISO-8859-8-E" }, + {N_("Hebrew (ISO-8859-8-I)"), "ISO-8859-8-I" }, + {N_("Hebrew (MacHebrew)"), "x-mac-hebrew" }, + {N_("Hindi (MacDevanagari)"), "x-mac-devanagari" }, + {N_("Icelandic (MacIcelandic)"), "x-mac-icelandic" }, + {N_("Korean (JOHAB)"), "x-johab" }, + {N_("Korean (UHC)"), "x-windows-949" }, + {N_("Romanian (MacRomanian)"), "x-mac-romanian" }, + {N_("Turkish (MacTurkish)"), "x-mac-turkish" }, + {N_("User Defined"), "x-user-defined" }, + {N_("Vietnamese (TCVN)"), "x-viet-tcvn5712" }, + {N_("Vietnamese (VPS)"), "x-viet-vps" }, + {N_("Western (MacRoman)"), "x-mac-roman" }, + /* charsets whithout posibly translatable names */ + {"T61.8bit", "T61.8bit" }, + {"x-imap4-modified-utf7", "x-imap4-modified-utf7"}, + {"x-u-escaped", "x-u-escaped" }, + {"windows-936", "windows-936" } +#endif +}; + +/************* + * Functions * + *************/ + +/* + * Commons conversion functions + */ +char *convert_from_utf8_to_user(const char *string) +{ + return FLAC_plugin__charset_convert_string(string, "UTF-8", flac_cfg.title.user_char_set); +} + +char *convert_from_user_to_utf8(const char *string) +{ + return FLAC_plugin__charset_convert_string(string, flac_cfg.title.user_char_set, "UTF-8"); +} + +GList *Charset_Create_List (void) +{ + GList *list = NULL; + guint i; + + for (i=0; i + * + * 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. + */ + + +#ifndef __CHARSET_H__ +#define __CHARSET_H__ + + +/*************** + * Declaration * + ***************/ + +typedef struct { + gchar *charset_title; + gchar *charset_name; +} CharsetInfo; + +/* translated charset titles */ +extern const CharsetInfo charset_trans_array[]; + +/************** + * Prototypes * + **************/ + +/* + * The returned strings are malloc()ed an must be free()d by the caller + */ +char *convert_from_utf8_to_user(const char *string); +char *convert_from_user_to_utf8(const char *string); + +GList *Charset_Create_List (void); +GList *Charset_Create_List_UTF8_Only (void); +gchar *Charset_Get_Name_From_Title (const gchar *charset_title); +gchar *Charset_Get_Title_From_Name (const gchar *charset_name); + +#endif /* __CHARSET_H__ */ + diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/configure.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/configure.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,685 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura + * + * Based on mpg123 plugin + * and prefs.c - 2000/05/06 + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 2000-2002 Jerome Couderc + * + * 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. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "plugin_common/locale_hack.h" +#include "replaygain_synthesis.h" /* for NOISE_SHAPING_LOW */ +#include "charset.h" +#include "configure.h" + +/* + * Initialize Global Valueable + */ +flac_config_t flac_cfg = { + /* title */ + { + FALSE, /* tag_override */ + NULL, /* tag_format */ + FALSE, /* convert_char_set */ + NULL /* user_char_set */ + }, + /* stream */ + { + 100 /* KB */, /* http_buffer_size */ + 50, /* http_prebuffer */ + FALSE, /* use_proxy */ + "", /* proxy_host */ + 0, /* proxy_port */ + FALSE, /* proxy_use_auth */ + "", /* proxy_user */ + "", /* proxy_pass */ + FALSE, /* save_http_stream */ + "", /* save_http_path */ + FALSE, /* cast_title_streaming */ + FALSE /* use_udp_channel */ + }, + /* output */ + { + /* replaygain */ + { + FALSE, /* enable */ + TRUE, /* album_mode */ + 0, /* preamp */ + FALSE /* hard_limit */ + }, + /* resolution */ + { + /* normal */ + { + TRUE /* dither_24_to_16 */ + }, + /* replaygain */ + { + TRUE, /* dither */ + NOISE_SHAPING_LOW, /* noise_shaping */ + 16 /* bps_out */ + } + } + } +}; + + +static GtkWidget *flac_configurewin = NULL; +static GtkWidget *vbox, *notebook; + +static GtkWidget *title_tag_override, *title_tag_box, *title_tag_entry, *title_desc; +static GtkWidget *convert_char_set, *fileCharacterSetEntry, *userCharacterSetEntry; +static GtkWidget *replaygain_enable, *replaygain_album_mode; +static GtkWidget *replaygain_preamp_hscale, *replaygain_preamp_label, *replaygain_hard_limit; +static GtkObject *replaygain_preamp; +static GtkWidget *resolution_normal_dither_24_to_16; +static GtkWidget *resolution_replaygain_dither; +static GtkWidget *resolution_replaygain_noise_shaping_frame; +static GtkWidget *resolution_replaygain_noise_shaping_radio_none; +static GtkWidget *resolution_replaygain_noise_shaping_radio_low; +static GtkWidget *resolution_replaygain_noise_shaping_radio_medium; +static GtkWidget *resolution_replaygain_noise_shaping_radio_high; +static GtkWidget *resolution_replaygain_bps_out_frame; +static GtkWidget *resolution_replaygain_bps_out_radio_16bps; +static GtkWidget *resolution_replaygain_bps_out_radio_24bps; + +static GtkObject *streaming_size_adj, *streaming_pre_adj; +static GtkWidget *streaming_save_use, *streaming_save_entry; +#ifdef FLAC_ICECAST +static GtkWidget *streaming_cast_title, *streaming_udp_title; +#endif +static GtkWidget *streaming_save_dirbrowser; +static GtkWidget *streaming_save_hbox; + +static const gchar *gtk_entry_get_text_1 (GtkWidget *widget); +static void flac_configurewin_ok(GtkWidget * widget, gpointer data); +static void configure_destroy(GtkWidget * w, gpointer data); + +static void flac_configurewin_ok(GtkWidget * widget, gpointer data) +{ + ConfigDb *db; + + (void)widget, (void)data; /* unused arguments */ + g_free(flac_cfg.title.tag_format); + flac_cfg.title.tag_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_tag_entry))); + flac_cfg.title.user_char_set = Charset_Get_Name_From_Title(gtk_entry_get_text_1(userCharacterSetEntry)); + + db = bmp_cfg_db_open(); + /* title */ + bmp_cfg_db_set_bool(db, "flac", "title.tag_override", flac_cfg.title.tag_override); + bmp_cfg_db_set_string(db, "flac", "title.tag_format", flac_cfg.title.tag_format); + bmp_cfg_db_set_bool(db, "flac", "title.convert_char_set", flac_cfg.title.convert_char_set); + bmp_cfg_db_set_string(db, "flac", "title.user_char_set", flac_cfg.title.user_char_set); + /* output */ + bmp_cfg_db_set_bool(db, "flac", "output.replaygain.enable", flac_cfg.output.replaygain.enable); + bmp_cfg_db_set_bool(db, "flac", "output.replaygain.album_mode", flac_cfg.output.replaygain.album_mode); + bmp_cfg_db_set_int(db, "flac", "output.replaygain.preamp", flac_cfg.output.replaygain.preamp); + bmp_cfg_db_set_bool(db, "flac", "output.replaygain.hard_limit", flac_cfg.output.replaygain.hard_limit); + bmp_cfg_db_set_bool(db, "flac", "output.resolution.normal.dither_24_to_16", flac_cfg.output.resolution.normal.dither_24_to_16); + bmp_cfg_db_set_bool(db, "flac", "output.resolution.replaygain.dither", flac_cfg.output.resolution.replaygain.dither); + bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.noise_shaping", flac_cfg.output.resolution.replaygain.noise_shaping); + bmp_cfg_db_set_int(db, "flac", "output.resolution.replaygain.bps_out", flac_cfg.output.resolution.replaygain.bps_out); + /* streaming */ + flac_cfg.stream.http_buffer_size = (gint) GTK_ADJUSTMENT(streaming_size_adj)->value; + flac_cfg.stream.http_prebuffer = (gint) GTK_ADJUSTMENT(streaming_pre_adj)->value; + + flac_cfg.stream.save_http_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use)); + + if (flac_cfg.stream.save_http_path != NULL) + g_free(flac_cfg.stream.save_http_path); + + flac_cfg.stream.save_http_path = g_strdup(gtk_entry_get_text(GTK_ENTRY(streaming_save_entry))); + +#ifdef FLAC_ICECAST + flac_cfg.stream.cast_title_streaming = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_cast_title)); + flac_cfg.stream.use_udp_channel = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_udp_title)); +#endif + + bmp_cfg_db_set_int(db, "flac", "stream.http_buffer_size", flac_cfg.stream.http_buffer_size); + bmp_cfg_db_set_int(db, "flac", "stream.http_prebuffer", flac_cfg.stream.http_prebuffer); + bmp_cfg_db_set_bool(db, "flac", "stream.save_http_stream", flac_cfg.stream.save_http_stream); + bmp_cfg_db_set_string(db, "flac", "stream.save_http_path", flac_cfg.stream.save_http_path); +#ifdef FLAC_ICECAST + bmp_cfg_db_set_bool(db, "flac", "stream.cast_title_streaming", flac_cfg.stream.cast_title_streaming); + bmp_cfg_db_set_bool(db, "flac", "stream.use_udp_channel", flac_cfg.stream.use_udp_channel); +#endif + + bmp_cfg_db_close(db); + gtk_widget_destroy(flac_configurewin); +} + +static void configure_destroy(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ +} + +static void title_tag_override_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.title.tag_override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_tag_override)); + + gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override); + gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override); + +} + +static void convert_char_set_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.title.convert_char_set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(convert_char_set)); + + gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE); + gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set); +} + +static void replaygain_enable_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.replaygain.enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_enable)); + + gtk_widget_set_sensitive(replaygain_album_mode, flac_cfg.output.replaygain.enable); + gtk_widget_set_sensitive(replaygain_preamp_hscale, flac_cfg.output.replaygain.enable); + gtk_widget_set_sensitive(replaygain_hard_limit, flac_cfg.output.replaygain.enable); +} + +static void replaygain_album_mode_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.replaygain.album_mode = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_album_mode)); +} + +static void replaygain_hard_limit_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.replaygain.hard_limit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit)); +} + +static void replaygain_preamp_cb(GtkWidget *widget, gpointer data) +{ + GString *gstring = g_string_new(""); + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.replaygain.preamp = (int) floor(GTK_ADJUSTMENT(replaygain_preamp)->value + 0.5); + + g_string_sprintf(gstring, "%i dB", flac_cfg.output.replaygain.preamp); + gtk_label_set_text(GTK_LABEL(replaygain_preamp_label), _(gstring->str)); +} + +static void resolution_normal_dither_24_to_16_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.resolution.normal.dither_24_to_16 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16)); +} + +static void resolution_replaygain_dither_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.resolution.replaygain.dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither)); + + gtk_widget_set_sensitive(resolution_replaygain_noise_shaping_frame, flac_cfg.output.resolution.replaygain.dither); +} + +static void resolution_replaygain_noise_shaping_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.resolution.replaygain.noise_shaping = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none))? 0 : + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low))? 1 : + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium))? 2 : + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high))? 3 : + 0 + ; +} + +static void resolution_replaygain_bps_out_cb(GtkWidget *widget, gpointer data) +{ + (void)widget, (void)data; /* unused arguments */ + flac_cfg.output.resolution.replaygain.bps_out = + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps))? 16 : + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps))? 24 : + 16 + ; +} + +static void streaming_save_dirbrowser_cb(gchar * dir) +{ + gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), dir); +} + +static void streaming_save_browse_cb(GtkWidget * w, gpointer data) +{ + (void) w; + (void) data; + if (!streaming_save_dirbrowser) + { + streaming_save_dirbrowser = xmms_create_dir_browser(_("Select the directory where you want to store the MPEG streams:"), + flac_cfg.stream.save_http_path, GTK_SELECTION_SINGLE, streaming_save_dirbrowser_cb); + gtk_signal_connect(GTK_OBJECT(streaming_save_dirbrowser), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &streaming_save_dirbrowser); + gtk_window_set_transient_for(GTK_WINDOW(streaming_save_dirbrowser), GTK_WINDOW(flac_configurewin)); + gtk_widget_show(streaming_save_dirbrowser); + } +} + +static void streaming_save_use_cb(GtkWidget * w, gpointer data) +{ + gboolean save_stream; + (void) w; + (void) data; + + save_stream = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(streaming_save_use)); + + gtk_widget_set_sensitive(streaming_save_hbox, save_stream); +} + + +void FLAC_XMMS__configure(void) +{ + GtkWidget *title_frame, *title_tag_vbox, *title_tag_label; + GtkWidget *replaygain_frame, *resolution_frame, *output_vbox, *resolution_normal_frame, *resolution_replaygain_frame; + GtkWidget *replaygain_vbox, *resolution_hbox, *resolution_normal_vbox, *resolution_replaygain_vbox; + GtkWidget *resolution_replaygain_noise_shaping_vbox; + GtkWidget *resolution_replaygain_bps_out_vbox; + GtkWidget *label, *hbox; + GtkWidget *bbox, *ok, *cancel; + GList *list; + + GtkWidget *streaming_vbox; + GtkWidget *streaming_buf_frame, *streaming_buf_hbox; + GtkWidget *streaming_size_box, *streaming_size_label, *streaming_size_spin; + GtkWidget *streaming_pre_box, *streaming_pre_label, *streaming_pre_spin; + GtkWidget *streaming_save_frame, *streaming_save_vbox; + GtkWidget *streaming_save_label, *streaming_save_browse; +#ifdef FLAC_ICECAST + GtkWidget *streaming_cast_frame, *streaming_cast_vbox; +#endif + + if (flac_configurewin != NULL) { + gdk_window_raise(flac_configurewin->window); + return; + } + flac_configurewin = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &flac_configurewin); + gtk_signal_connect(GTK_OBJECT(flac_configurewin), "destroy", GTK_SIGNAL_FUNC(configure_destroy), &flac_configurewin); + gtk_window_set_title(GTK_WINDOW(flac_configurewin), _("Flac Configuration")); + gtk_window_set_policy(GTK_WINDOW(flac_configurewin), FALSE, FALSE, FALSE); + gtk_container_border_width(GTK_CONTAINER(flac_configurewin), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(flac_configurewin), vbox); + + notebook = gtk_notebook_new(); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + + /* Title config.. */ + + title_frame = gtk_frame_new(_("Tag Handling")); + gtk_container_border_width(GTK_CONTAINER(title_frame), 5); + + title_tag_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(title_tag_vbox), 5); + gtk_container_add(GTK_CONTAINER(title_frame), title_tag_vbox); + + /* Convert Char Set */ + + convert_char_set = gtk_check_button_new_with_label(_("Convert Character Set")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(convert_char_set), flac_cfg.title.convert_char_set); + gtk_signal_connect(GTK_OBJECT(convert_char_set), "clicked", (GCallback)convert_char_set_cb, NULL); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), convert_char_set, FALSE, FALSE, 0); + /* Combo boxes... */ + hbox = gtk_hbox_new(FALSE,4); + gtk_container_add(GTK_CONTAINER(title_tag_vbox),hbox); + label = gtk_label_new(_("Convert character set from :")); + gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); + fileCharacterSetEntry = gtk_combo_new(); + gtk_box_pack_start(GTK_BOX(hbox),fileCharacterSetEntry,TRUE,TRUE,0); + + label = gtk_label_new (_("to :")); + gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); + userCharacterSetEntry = gtk_combo_new(); + gtk_box_pack_start(GTK_BOX(hbox),userCharacterSetEntry,TRUE,TRUE,0); + + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(fileCharacterSetEntry)->entry),FALSE); + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),FALSE); + gtk_combo_set_value_in_list(GTK_COMBO(fileCharacterSetEntry),TRUE,FALSE); + gtk_combo_set_value_in_list(GTK_COMBO(userCharacterSetEntry),TRUE,FALSE); + + list = Charset_Create_List(); + gtk_combo_set_popdown_strings(GTK_COMBO(fileCharacterSetEntry),Charset_Create_List_UTF8_Only()); + gtk_combo_set_popdown_strings(GTK_COMBO(userCharacterSetEntry),list); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(userCharacterSetEntry)->entry),Charset_Get_Title_From_Name(flac_cfg.title.user_char_set)); + gtk_widget_set_sensitive(fileCharacterSetEntry, FALSE); + gtk_widget_set_sensitive(userCharacterSetEntry, flac_cfg.title.convert_char_set); + + /* Override Tagging Format */ + + title_tag_override = gtk_check_button_new_with_label(_("Override generic titles")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_tag_override), flac_cfg.title.tag_override); + gtk_signal_connect(GTK_OBJECT(title_tag_override), "clicked", (GCallback)title_tag_override_cb, NULL); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_override, FALSE, FALSE, 0); + + title_tag_box = gtk_hbox_new(FALSE, 5); + gtk_widget_set_sensitive(title_tag_box, flac_cfg.title.tag_override); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_tag_box, FALSE, FALSE, 0); + + title_tag_label = gtk_label_new(_("Title format:")); + gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_label, FALSE, FALSE, 0); + + title_tag_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(title_tag_entry), flac_cfg.title.tag_format); + gtk_box_pack_start(GTK_BOX(title_tag_box), title_tag_entry, TRUE, TRUE, 0); + + title_desc = xmms_titlestring_descriptions("pafFetnygc", 2); + gtk_widget_set_sensitive(title_desc, flac_cfg.title.tag_override); + gtk_box_pack_start(GTK_BOX(title_tag_vbox), title_desc, FALSE, FALSE, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title"))); + + /* Output config.. */ + + output_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(output_vbox), 5); + + /* replaygain */ + + replaygain_frame = gtk_frame_new(_("ReplayGain")); + gtk_container_border_width(GTK_CONTAINER(replaygain_frame), 5); + gtk_box_pack_start(GTK_BOX(output_vbox), replaygain_frame, TRUE, TRUE, 0); + + replaygain_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(replaygain_vbox), 5); + gtk_container_add(GTK_CONTAINER(replaygain_frame), replaygain_vbox); + + replaygain_enable = gtk_check_button_new_with_label(_("Enable ReplayGain processing")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_enable), flac_cfg.output.replaygain.enable); + gtk_signal_connect(GTK_OBJECT(replaygain_enable), "clicked", (GCallback)replaygain_enable_cb, NULL); + gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_enable, FALSE, FALSE, 0); + + replaygain_album_mode = gtk_check_button_new_with_label(_("Album mode")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_album_mode), flac_cfg.output.replaygain.album_mode); + gtk_signal_connect(GTK_OBJECT(replaygain_album_mode), "clicked", (GCallback)replaygain_album_mode_cb, NULL); + gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_album_mode, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(FALSE,3); + gtk_container_add(GTK_CONTAINER(replaygain_vbox),hbox); + label = gtk_label_new(_("Preamp:")); + gtk_box_pack_start(GTK_BOX(hbox),label,FALSE,FALSE,0); + replaygain_preamp = gtk_adjustment_new(flac_cfg.output.replaygain.preamp, -24.0, +24.0, 1.0, 6.0, 0.0); + gtk_signal_connect(GTK_OBJECT(replaygain_preamp), "value-changed", (GCallback)replaygain_preamp_cb, NULL); + replaygain_preamp_hscale = gtk_hscale_new(GTK_ADJUSTMENT(replaygain_preamp)); + gtk_scale_set_draw_value(GTK_SCALE(replaygain_preamp_hscale), FALSE); + gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_hscale,TRUE,TRUE,0); + replaygain_preamp_label = gtk_label_new(_("0 dB")); + gtk_box_pack_start(GTK_BOX(hbox),replaygain_preamp_label,FALSE,FALSE,0); + gtk_adjustment_value_changed(GTK_ADJUSTMENT(replaygain_preamp)); + + replaygain_hard_limit = gtk_check_button_new_with_label(_("6dB hard limiting")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(replaygain_hard_limit), flac_cfg.output.replaygain.hard_limit); + gtk_signal_connect(GTK_OBJECT(replaygain_hard_limit), "clicked", (GCallback)replaygain_hard_limit_cb, NULL); + gtk_box_pack_start(GTK_BOX(replaygain_vbox), replaygain_hard_limit, FALSE, FALSE, 0); + + replaygain_enable_cb(replaygain_enable, NULL); + + /* resolution */ + + resolution_frame = gtk_frame_new(_("Resolution")); + gtk_container_border_width(GTK_CONTAINER(resolution_frame), 5); + gtk_box_pack_start(GTK_BOX(output_vbox), resolution_frame, TRUE, TRUE, 0); + + resolution_hbox = gtk_hbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(resolution_hbox), 5); + gtk_container_add(GTK_CONTAINER(resolution_frame), resolution_hbox); + + resolution_normal_frame = gtk_frame_new(_("Without ReplayGain")); + gtk_container_border_width(GTK_CONTAINER(resolution_normal_frame), 5); + gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_normal_frame, TRUE, TRUE, 0); + + resolution_normal_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(resolution_normal_vbox), 5); + gtk_container_add(GTK_CONTAINER(resolution_normal_frame), resolution_normal_vbox); + + resolution_normal_dither_24_to_16 = gtk_check_button_new_with_label(_("Dither 24bps to 16bps")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_normal_dither_24_to_16), flac_cfg.output.resolution.normal.dither_24_to_16); + gtk_signal_connect(GTK_OBJECT(resolution_normal_dither_24_to_16), "clicked", (GCallback)resolution_normal_dither_24_to_16_cb, NULL); + gtk_box_pack_start(GTK_BOX(resolution_normal_vbox), resolution_normal_dither_24_to_16, FALSE, FALSE, 0); + + resolution_replaygain_frame = gtk_frame_new(_("With ReplayGain")); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_frame), 5); + gtk_box_pack_start(GTK_BOX(resolution_hbox), resolution_replaygain_frame, TRUE, TRUE, 0); + + resolution_replaygain_vbox = gtk_vbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_vbox), 5); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_frame), resolution_replaygain_vbox); + + resolution_replaygain_dither = gtk_check_button_new_with_label(_("Enable dithering")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_dither), flac_cfg.output.resolution.replaygain.dither); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_dither), "clicked", (GCallback)resolution_replaygain_dither_cb, NULL); + gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), resolution_replaygain_dither, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(FALSE, 10); + gtk_container_border_width(GTK_CONTAINER(hbox), 5); + gtk_box_pack_start(GTK_BOX(resolution_replaygain_vbox), hbox, TRUE, TRUE, 0); + + resolution_replaygain_noise_shaping_frame = gtk_frame_new(_("Noise shaping")); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), 5); + gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_noise_shaping_frame, TRUE, TRUE, 0); + + resolution_replaygain_noise_shaping_vbox = gtk_vbutton_box_new(); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), 5); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_frame), resolution_replaygain_noise_shaping_vbox); + + resolution_replaygain_noise_shaping_radio_none = gtk_radio_button_new_with_label(NULL, _("none")); + if(flac_cfg.output.resolution.replaygain.noise_shaping == 0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_none), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_none), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_none); + + resolution_replaygain_noise_shaping_radio_low = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("low")); + if(flac_cfg.output.resolution.replaygain.noise_shaping == 1) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_low), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_low), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_low); + + resolution_replaygain_noise_shaping_radio_medium = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("medium")); + if(flac_cfg.output.resolution.replaygain.noise_shaping == 2) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_medium), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_medium), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_medium); + + resolution_replaygain_noise_shaping_radio_high = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_noise_shaping_radio_none), _("high")); + if(flac_cfg.output.resolution.replaygain.noise_shaping == 3) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_noise_shaping_radio_high), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_noise_shaping_radio_high), "clicked", (GCallback)resolution_replaygain_noise_shaping_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_noise_shaping_vbox), resolution_replaygain_noise_shaping_radio_high); + + resolution_replaygain_bps_out_frame = gtk_frame_new(_("Dither to")); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_frame), 5); + gtk_box_pack_start(GTK_BOX(hbox), resolution_replaygain_bps_out_frame, FALSE, FALSE, 0); + + resolution_replaygain_bps_out_vbox = gtk_vbutton_box_new(); + gtk_container_border_width(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), 0); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_frame), resolution_replaygain_bps_out_vbox); + + resolution_replaygain_bps_out_radio_16bps = gtk_radio_button_new_with_label(NULL, _("16 bps")); + if(flac_cfg.output.resolution.replaygain.bps_out == 16) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_16bps), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_16bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_16bps); + + resolution_replaygain_bps_out_radio_24bps = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(resolution_replaygain_bps_out_radio_16bps), _("24 bps")); + if(flac_cfg.output.resolution.replaygain.bps_out == 24) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(resolution_replaygain_bps_out_radio_24bps), TRUE); + gtk_signal_connect(GTK_OBJECT(resolution_replaygain_bps_out_radio_24bps), "clicked", (GCallback)resolution_replaygain_bps_out_cb, NULL); + gtk_container_add(GTK_CONTAINER(resolution_replaygain_bps_out_vbox), resolution_replaygain_bps_out_radio_24bps); + + resolution_replaygain_dither_cb(resolution_replaygain_dither, NULL); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), output_vbox, gtk_label_new(_("Output"))); + + /* Streaming */ + + streaming_vbox = gtk_vbox_new(FALSE, 0); + + streaming_buf_frame = gtk_frame_new(_("Buffering:")); + gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_frame), 5); + gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_buf_frame, FALSE, FALSE, 0); + + streaming_buf_hbox = gtk_hbox_new(TRUE, 5); + gtk_container_set_border_width(GTK_CONTAINER(streaming_buf_hbox), 5); + gtk_container_add(GTK_CONTAINER(streaming_buf_frame), streaming_buf_hbox); + + streaming_size_box = gtk_hbox_new(FALSE, 5); + /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_size_box,0,1,0,1); */ + gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_size_box, TRUE, TRUE, 0); + streaming_size_label = gtk_label_new(_("Buffer size (kb):")); + gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_label, FALSE, FALSE, 0); + streaming_size_adj = gtk_adjustment_new(flac_cfg.stream.http_buffer_size, 4, 4096, 4, 4, 4); + streaming_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_size_adj), 8, 0); + gtk_widget_set_usize(streaming_size_spin, 60, -1); + gtk_box_pack_start(GTK_BOX(streaming_size_box), streaming_size_spin, FALSE, FALSE, 0); + + streaming_pre_box = gtk_hbox_new(FALSE, 5); + /*gtk_table_attach_defaults(GTK_TABLE(streaming_buf_table),streaming_pre_box,1,2,0,1); */ + gtk_box_pack_start(GTK_BOX(streaming_buf_hbox), streaming_pre_box, TRUE, TRUE, 0); + streaming_pre_label = gtk_label_new(_("Pre-buffer (percent):")); + gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_label, FALSE, FALSE, 0); + streaming_pre_adj = gtk_adjustment_new(flac_cfg.stream.http_prebuffer, 0, 90, 1, 1, 1); + streaming_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(streaming_pre_adj), 1, 0); + gtk_widget_set_usize(streaming_pre_spin, 60, -1); + gtk_box_pack_start(GTK_BOX(streaming_pre_box), streaming_pre_spin, FALSE, FALSE, 0); + + /* + * Save to disk config. + */ + streaming_save_frame = gtk_frame_new(_("Save stream to disk:")); + gtk_container_set_border_width(GTK_CONTAINER(streaming_save_frame), 5); + gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_save_frame, FALSE, FALSE, 0); + + streaming_save_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(streaming_save_vbox), 5); + gtk_container_add(GTK_CONTAINER(streaming_save_frame), streaming_save_vbox); + + streaming_save_use = gtk_check_button_new_with_label(_("Save stream to disk")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_save_use), flac_cfg.stream.save_http_stream); + gtk_signal_connect(GTK_OBJECT(streaming_save_use), "clicked", GTK_SIGNAL_FUNC(streaming_save_use_cb), NULL); + gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_use, FALSE, FALSE, 0); + + streaming_save_hbox = gtk_hbox_new(FALSE, 5); + gtk_widget_set_sensitive(streaming_save_hbox, flac_cfg.stream.save_http_stream); + gtk_box_pack_start(GTK_BOX(streaming_save_vbox), streaming_save_hbox, FALSE, FALSE, 0); + + streaming_save_label = gtk_label_new(_("Path:")); + gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_label, FALSE, FALSE, 0); + + streaming_save_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(streaming_save_entry), flac_cfg.stream.save_http_path); + gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_entry, TRUE, TRUE, 0); + + streaming_save_browse = gtk_button_new_with_label(_("Browse")); + gtk_signal_connect(GTK_OBJECT(streaming_save_browse), "clicked", GTK_SIGNAL_FUNC(streaming_save_browse_cb), NULL); + gtk_box_pack_start(GTK_BOX(streaming_save_hbox), streaming_save_browse, FALSE, FALSE, 0); + +#ifdef FLAC_ICECAST + streaming_cast_frame = gtk_frame_new(_("SHOUT/Icecast:")); + gtk_container_set_border_width(GTK_CONTAINER(streaming_cast_frame), 5); + gtk_box_pack_start(GTK_BOX(streaming_vbox), streaming_cast_frame, FALSE, FALSE, 0); + + streaming_cast_vbox = gtk_vbox_new(5, FALSE); + gtk_container_add(GTK_CONTAINER(streaming_cast_frame), streaming_cast_vbox); + + streaming_cast_title = gtk_check_button_new_with_label(_("Enable SHOUT/Icecast title streaming")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_cast_title), flac_cfg.stream.cast_title_streaming); + gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_cast_title, FALSE, FALSE, 0); + + streaming_udp_title = gtk_check_button_new_with_label(_("Enable Icecast Metadata UDP Channel")); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(streaming_udp_title), flac_cfg.stream.use_udp_channel); + gtk_box_pack_start(GTK_BOX(streaming_cast_vbox), streaming_udp_title, FALSE, FALSE, 0); +#endif + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), streaming_vbox, gtk_label_new(_("Streaming"))); + + /* Buttons */ + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + ok = gtk_button_new_with_label(_("Ok")); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(flac_configurewin_ok), NULL); + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); + gtk_widget_grab_default(ok); + + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(flac_configurewin)); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + + gtk_widget_show_all(flac_configurewin); +} + +void FLAC_XMMS__aboutbox() +{ + static GtkWidget *about_window; + + if (about_window) + gdk_window_raise(about_window->window); + else + { + about_window = xmms_show_message( + _("About Flac Plugin"), + _("Flac Plugin by Josh Coalson\n" + "contributions by\n" + "......\n" + "......\n" + "and\n" + "Daisuke Shimamura\n" + "Visit http://flac.sourceforge.net/"), + _("Ok"), FALSE, NULL, NULL); + gtk_signal_connect(GTK_OBJECT(about_window), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &about_window); + } +} + +/* + * Get text of an Entry or a ComboBox + */ +static const gchar *gtk_entry_get_text_1 (GtkWidget *widget) +{ + if (GTK_IS_COMBO(widget)) + { + return gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(widget)->entry)); + }else if (GTK_IS_ENTRY(widget)) + { + return gtk_entry_get_text(GTK_ENTRY(widget)); + }else + { + return NULL; + } +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/configure.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/configure.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,77 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura + * + * Based on mpg123 plugin + * + * 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. + */ + +#ifndef __CONFIGURE_H__ +#define __CONFIGURE_H__ + +#include + +typedef struct { + struct { + gboolean tag_override; + gchar *tag_format; + gboolean convert_char_set; + gchar *user_char_set; + } title; + + struct { + gint http_buffer_size; + gint http_prebuffer; + gboolean use_proxy; + gchar *proxy_host; + gint proxy_port; + gboolean proxy_use_auth; + gchar *proxy_user; + gchar *proxy_pass; + gboolean save_http_stream; + gchar *save_http_path; + gboolean cast_title_streaming; + gboolean use_udp_channel; + } stream; + + struct { + struct { + gboolean enable; + gboolean album_mode; + gint preamp; + gboolean hard_limit; + } replaygain; + struct { + struct { + gboolean dither_24_to_16; + } normal; + struct { + gboolean dither; + gint noise_shaping; /* value must be one of NoiseShaping enum, c.f. plugin_common/replaygain_synthesis.h */ + gint bps_out; + } replaygain; + } resolution; + } output; +} flac_config_t; + +extern flac_config_t flac_cfg; + +extern void FLAC_XMMS__configure(void); +extern void FLAC_XMMS__aboutbox(); + +#endif + + + diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/fast_float_math_hack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/fast_float_math_hack.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,39 @@ +# ifdef __ICL /* only Intel C compiler has fmath ??? */ + + #include + +/* Nearest integer, absolute value, etc. */ + + #define ceil ceilf + #define fabs fabsf + #define floor floorf + #define fmod fmodf + #define rint rintf + #define hypot hypotf + +/* Power functions */ + + #define pow powf + #define sqrt sqrtf + +/* Exponential and logarithmic functions */ + + #define exp expf + #define log logf + #define log10 log10f + +/* Trigonometric functions */ + + #define acos acosf + #define asin asinf + #define atan atanf + #define cos cosf + #define sin sinf + #define tan tanf + +/* Hyperbolic functions */ + #define cosh coshf + #define sinh sinhf + #define tanh tanhf + +# endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/file.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/file.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,142 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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. + */ + +#if defined _MSC_VER || defined __MINGW32__ +#include /* for utime() */ +#include /* for chmod(), _setmode(), unlink() */ +#include /* for _O_BINARY */ +#else +#include /* some flavors of BSD (like OS X) require this to get time_t */ +#include /* for utime() */ +#endif +#ifdef __CYGWIN__ +#include /* for setmode(), O_BINARY */ +#include /* for _O_BINARY */ +#endif +#include /* for stat(), maybe chmod() */ +#if defined _WIN32 && !defined __CYGWIN__ +#else +#include /* for unlink() */ +#endif +#include +#include +#include /* for strrchr() */ +#include "grabbag.h" + + +void grabbag__file_copy_metadata(const char *srcpath, const char *destpath) +{ + struct stat srcstat; + struct utimbuf srctime; + + if(0 == stat(srcpath, &srcstat)) { + srctime.actime = srcstat.st_atime; + srctime.modtime = srcstat.st_mtime; + (void)chmod(destpath, srcstat.st_mode); + (void)utime(destpath, &srctime); + } +} + +off_t grabbag__file_get_filesize(const char *srcpath) +{ + struct stat srcstat; + + if(0 == stat(srcpath, &srcstat)) + return srcstat.st_size; + else + return -1; +} + +const char *grabbag__file_get_basename(const char *srcpath) +{ + const char *p; + + p = strrchr(srcpath, '/'); + if(0 == p) { + p = strrchr(srcpath, '\\'); + if(0 == p) + return srcpath; + } + return ++p; +} + +FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only) +{ + struct stat stats; + + if(0 == stat(filename, &stats)) { +#if !defined _MSC_VER && !defined __MINGW32__ + if(read_only) { + stats.st_mode &= ~S_IWUSR; + stats.st_mode &= ~S_IWGRP; + stats.st_mode &= ~S_IWOTH; + } + else { + stats.st_mode |= S_IWUSR; + } +#else + if(read_only) + stats.st_mode &= ~S_IWRITE; + else + stats.st_mode |= S_IWRITE; +#endif + if(0 != chmod(filename, stats.st_mode)) + return false; + } + else + return false; + + return true; +} + +FLAC__bool grabbag__file_remove_file(const char *filename) +{ + return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename); +} + +FILE *grabbag__file_get_binary_stdin() +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdin), _O_BINARY); +#elif defined __CYGWIN__ + /* almost certainly not needed for any modern Cygwin, but let's be safe... */ + setmode(_fileno(stdin), _O_BINARY); +#endif + + return stdin; +} + +FILE *grabbag__file_get_binary_stdout() +{ + /* if something breaks here it is probably due to the presence or + * absence of an underscore before the identifiers 'setmode', + * 'fileno', and/or 'O_BINARY'; check your system header files. + */ +#if defined _MSC_VER || defined __MINGW32__ + _setmode(_fileno(stdout), _O_BINARY); +#elif defined __CYGWIN__ + /* almost certainly not needed for any modern Cygwin, but let's be safe... */ + setmode(_fileno(stdout), _O_BINARY); +#endif + + return stdout; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/fileinfo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/fileinfo.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,500 @@ +/* XMMS - Cross-platform multimedia player + * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies + * Copyright (C) 1999,2000 Håvard Kvålen + * Copyright (C) 2002,2003,2004,2005,2006 Daisuke Shimamura + * + * 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. + */ + +#include +#include /* for strlen() */ +#include +#include +#include +#include +#include + +#include "audacious/util.h" +#include "FLAC/metadata.h" +#include "charset.h" +#include "configure.h" +#include "plugin_common/locale_hack.h" +#include "plugin_common/replaygain.h" +#include "plugin_common/tags.h" + +static GtkWidget *window = NULL; +static GList *genre_list = NULL; +static GtkWidget *filename_entry, *tag_frame; +static GtkWidget *title_entry, *artist_entry, *album_entry, *date_entry, *tracknum_entry, *comment_entry; +static GtkWidget *replaygain_reference, *replaygain_track_gain, *replaygain_album_gain, *replaygain_track_peak, *replaygain_album_peak; +static GtkWidget *genre_combo; +static GtkWidget *flac_samplerate, *flac_channels, *flac_bits_per_sample, *flac_blocksize, *flac_filesize, *flac_samples, *flac_bitrate; + +static gchar *current_filename = NULL; +static FLAC__StreamMetadata *tags_ = NULL; + +static const gchar *vorbis_genres[] = +{ + N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"), + N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"), + N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"), + N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"), + N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"), + N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"), + N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"), + N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"), + N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"), + N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("Alt"), + N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"), + N_("Meditative"), N_("Instrumental Pop"), + N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"), + N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"), + N_("Pop-Folk"), N_("Eurodance"), N_("Dream"), + N_("Southern Rock"), N_("Comedy"), N_("Cult"), + N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"), + N_("Pop/Funk"), N_("Jungle"), N_("Native American"), + N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"), + N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"), + N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"), + N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"), + N_("Folk/Rock"), N_("National Folk"), N_("Swing"), + N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"), + N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"), + N_("Gothic Rock"), N_("Progressive Rock"), + N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"), + N_("Big Band"), N_("Chorus"), N_("Easy Listening"), + N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"), + N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"), + N_("Booty Bass"), N_("Primus"), N_("Porn Groove"), + N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"), + N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"), + N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"), + N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"), + N_("Euro-House"), N_("Dance Hall"), N_("Goa"), + N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"), + N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"), + N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"), + N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"), + N_("Contemporary Christian"), N_("Christian Rock"), + N_("Merengue"), N_("Salsa"), N_("Thrash Metal"), + N_("Anime"), N_("JPop"), N_("Synthpop") +}; + +static void label_set_text(GtkWidget * label, char *str, ...) +{ + va_list args; + gchar *tempstr; + + va_start(args, str); + tempstr = g_strdup_vprintf(str, args); + va_end(args); + + gtk_label_set_text(GTK_LABEL(label), tempstr); + g_free(tempstr); +} + +static void set_entry_tag(GtkEntry * entry, const char * utf8) +{ + if(utf8) { + if(flac_cfg.title.convert_char_set) { + char *text = convert_from_utf8_to_user(utf8); + gtk_entry_set_text(entry, text); + free(text); + } + else + gtk_entry_set_text(entry, utf8); + } + else + gtk_entry_set_text(entry, ""); +} + +static void get_entry_tag(GtkEntry * entry, const char *name) +{ + gchar *text; + char *utf8; + + text = g_strdup(gtk_entry_get_text(entry)); + if (!text || strlen(text) == 0) + { + g_free(text); + return; + } + if(flac_cfg.title.convert_char_set) + utf8 = convert_from_user_to_utf8(text); + else + utf8 = text; + + FLAC_plugin__tags_add_tag_utf8(tags_, name, utf8, /*separator=*/0); + + if(flac_cfg.title.convert_char_set) + free(utf8); + g_free(text); +} + +static void show_tag() +{ + set_entry_tag(GTK_ENTRY(title_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "TITLE")); + set_entry_tag(GTK_ENTRY(artist_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "ARTIST")); + set_entry_tag(GTK_ENTRY(album_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "ALBUM")); + set_entry_tag(GTK_ENTRY(date_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "DATE")); + set_entry_tag(GTK_ENTRY(tracknum_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "TRACKNUMBER")); + set_entry_tag(GTK_ENTRY(comment_entry) , FLAC_plugin__tags_get_tag_utf8(tags_, "DESCRIPTION")); + set_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), FLAC_plugin__tags_get_tag_utf8(tags_, "GENRE")); +} + +static void save_tag(GtkWidget * w, gpointer data) +{ + (void)w; + (void)data; + + FLAC_plugin__tags_delete_tag(tags_, "TITLE"); + FLAC_plugin__tags_delete_tag(tags_, "ARTIST"); + FLAC_plugin__tags_delete_tag(tags_, "ALBUM"); + FLAC_plugin__tags_delete_tag(tags_, "DATE"); + FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER"); + FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION"); + FLAC_plugin__tags_delete_tag(tags_, "GENRE"); + + get_entry_tag(GTK_ENTRY(title_entry) , "TITLE"); + get_entry_tag(GTK_ENTRY(artist_entry) , "ARTIST"); + get_entry_tag(GTK_ENTRY(album_entry) , "ALBUM"); + get_entry_tag(GTK_ENTRY(date_entry) , "DATE"); + get_entry_tag(GTK_ENTRY(tracknum_entry) , "TRACKNUMBER"); + get_entry_tag(GTK_ENTRY(comment_entry) , "DESCRIPTION"); + get_entry_tag(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), "GENRE"); + + FLAC_plugin__tags_set(current_filename, tags_); + gtk_widget_destroy(window); +} + +static void remove_tag(GtkWidget * w, gpointer data) +{ + (void)w; + (void)data; + + FLAC_plugin__tags_delete_tag(tags_, "TITLE"); + FLAC_plugin__tags_delete_tag(tags_, "ARTIST"); + FLAC_plugin__tags_delete_tag(tags_, "ALBUM"); + FLAC_plugin__tags_delete_tag(tags_, "DATE"); + FLAC_plugin__tags_delete_tag(tags_, "TRACKNUMBER"); + FLAC_plugin__tags_delete_tag(tags_, "DESCRIPTION"); + FLAC_plugin__tags_delete_tag(tags_, "GENRE"); + + FLAC_plugin__tags_set(current_filename, tags_); + gtk_widget_destroy(window); +} + +static void show_file_info() +{ + FLAC__StreamMetadata streaminfo; + struct stat _stat; + + gtk_label_set_text(GTK_LABEL(flac_samplerate), ""); + gtk_label_set_text(GTK_LABEL(flac_channels), ""); + gtk_label_set_text(GTK_LABEL(flac_bits_per_sample), ""); + gtk_label_set_text(GTK_LABEL(flac_blocksize), ""); + gtk_label_set_text(GTK_LABEL(flac_filesize), ""); + gtk_label_set_text(GTK_LABEL(flac_samples), ""); + gtk_label_set_text(GTK_LABEL(flac_bitrate), ""); + + if(!FLAC__metadata_get_streaminfo(current_filename, &streaminfo)) { + return; + } + + label_set_text(flac_samplerate, _("Samplerate: %d Hz"), streaminfo.data.stream_info.sample_rate); + label_set_text(flac_channels, _("Channels: %d"), streaminfo.data.stream_info.channels); + label_set_text(flac_bits_per_sample, _("Bits/Sample: %d"), streaminfo.data.stream_info.bits_per_sample); + if(streaminfo.data.stream_info.min_blocksize == streaminfo.data.stream_info.max_blocksize) + label_set_text(flac_blocksize, _("Blocksize: %d"), streaminfo.data.stream_info.min_blocksize); + else + label_set_text(flac_blocksize, _("Blocksize: variable\n min/max: %d/%d"), streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize); + + if (streaminfo.data.stream_info.total_samples) + label_set_text(flac_samples, _("Samples: %llu\nLength: %d:%.2d"), + streaminfo.data.stream_info.total_samples, + (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate / 60), + (int)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate % 60)); + + if(!stat(current_filename, &_stat) && S_ISREG(_stat.st_mode)) { +#if _FILE_OFFSET_BITS == 64 + label_set_text(flac_filesize, _("Filesize: %lld B"), _stat.st_size); +#else + label_set_text(flac_filesize, _("Filesize: %ld B"), _stat.st_size); +#endif + if (streaminfo.data.stream_info.total_samples) + label_set_text(flac_bitrate, _("Avg. bitrate: %.1f kb/s\nCompression ratio: %.1f%%"), + 8.0 * (float)(_stat.st_size) / (1000.0 * (float)streaminfo.data.stream_info.total_samples / (float)streaminfo.data.stream_info.sample_rate), + 100.0 * (float)_stat.st_size / (float)(streaminfo.data.stream_info.bits_per_sample / 8 * streaminfo.data.stream_info.channels * streaminfo.data.stream_info.total_samples)); + } +} + +static void show_replaygain() +{ + /* known limitation: If only one of gain and peak is set, neither will be shown. This is true for + * both track and album replaygain tags. Written so it will be easy to fix, with some trouble. */ + + gtk_label_set_text(GTK_LABEL(replaygain_reference), ""); + gtk_label_set_text(GTK_LABEL(replaygain_track_gain), ""); + gtk_label_set_text(GTK_LABEL(replaygain_album_gain), ""); + gtk_label_set_text(GTK_LABEL(replaygain_track_peak), ""); + gtk_label_set_text(GTK_LABEL(replaygain_album_peak), ""); + + double reference, track_gain, track_peak, album_gain, album_peak; + FLAC__bool reference_set, track_gain_set, track_peak_set, album_gain_set, album_peak_set; + + FLAC_plugin__replaygain_get_from_file( + current_filename, + &reference, &reference_set, + &track_gain, &track_gain_set, + &album_gain, &album_gain_set, + &track_peak, &track_peak_set, + &album_peak, &album_peak_set + ); + + if(reference_set) + label_set_text(replaygain_reference, _("ReplayGain Reference Loudness: %2.1f dB"), reference); + if(track_gain_set) + label_set_text(replaygain_track_gain, _("ReplayGain Track Gain: %+2.2f dB"), track_gain); + if(album_gain_set) + label_set_text(replaygain_album_gain, _("ReplayGain Album Gain: %+2.2f dB"), album_gain); + if(track_peak_set) + label_set_text(replaygain_track_peak, _("ReplayGain Track Peak: %1.8f"), track_peak); + if(album_peak_set) + label_set_text(replaygain_album_peak, _("ReplayGain Album Peak: %1.8f"), album_peak); +} + +void FLAC_XMMS__file_info_box(char *filename) +{ + unsigned i; + gchar *title; + gchar *filename_utf8; + + if (!window) + { + GtkWidget *vbox, *hbox, *left_vbox, *table; + GtkWidget *flac_frame, *flac_box; + GtkWidget *label, *filename_hbox; + GtkWidget *bbox, *save, *remove, *cancel; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_policy(GTK_WINDOW(window), FALSE, FALSE, FALSE); + gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &window); + gtk_container_set_border_width(GTK_CONTAINER(window), 10); + + vbox = gtk_vbox_new(FALSE, 10); + gtk_container_add(GTK_CONTAINER(window), vbox); + + filename_hbox = gtk_hbox_new(FALSE, 5); + gtk_box_pack_start(GTK_BOX(vbox), filename_hbox, FALSE, TRUE, 0); + + label = gtk_label_new(_("Filename:")); + gtk_box_pack_start(GTK_BOX(filename_hbox), label, FALSE, TRUE, 0); + filename_entry = gtk_entry_new(); + gtk_editable_set_editable(GTK_EDITABLE(filename_entry), FALSE); + gtk_box_pack_start(GTK_BOX(filename_hbox), filename_entry, TRUE, TRUE, 0); + + hbox = gtk_hbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + + left_vbox = gtk_vbox_new(FALSE, 10); + gtk_box_pack_start(GTK_BOX(hbox), left_vbox, FALSE, FALSE, 0); + + tag_frame = gtk_frame_new(_("Tag:")); + gtk_box_pack_start(GTK_BOX(left_vbox), tag_frame, FALSE, FALSE, 0); + + table = gtk_table_new(5, 5, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 5); + gtk_container_add(GTK_CONTAINER(tag_frame), table); + + label = gtk_label_new(_("Title:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL, 5, 5); + + title_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), title_entry, 1, 4, 0, 1, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Artist:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL, 5, 5); + + artist_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), artist_entry, 1, 4, 1, 2, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Album:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL, 5, 5); + + album_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), album_entry, 1, 4, 2, 3, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Comment:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 3, 4, GTK_FILL, GTK_FILL, 5, 5); + + comment_entry = gtk_entry_new(); + gtk_table_attach(GTK_TABLE(table), comment_entry, 1, 4, 3, 4, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Date:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 4, 5, GTK_FILL, GTK_FILL, 5, 5); + + date_entry = gtk_entry_new(); + gtk_widget_set_usize(date_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), date_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Track number:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 2, 3, 4, 5, GTK_FILL, GTK_FILL, 5, 5); + + tracknum_entry = gtk_entry_new(); + gtk_widget_set_usize(tracknum_entry, 40, -1); + gtk_table_attach(GTK_TABLE(table), tracknum_entry, 3, 4, 4, 5, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + label = gtk_label_new(_("Genre:")); + gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5); + gtk_table_attach(GTK_TABLE(table), label, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 5, 5); + + genre_combo = gtk_combo_new(); + gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(genre_combo)->entry), TRUE); + + if (!genre_list) + { + for (i = 0; i < sizeof(vorbis_genres) / sizeof(*vorbis_genres) ; i++) + genre_list = g_list_prepend(genre_list, (char *)vorbis_genres[i]); + genre_list = g_list_prepend(genre_list, ""); + genre_list = g_list_sort(genre_list, (GCompareFunc)g_strcasecmp); + } + gtk_combo_set_popdown_strings(GTK_COMBO(genre_combo), genre_list); + + gtk_table_attach(GTK_TABLE(table), genre_combo, 1, 4, 5, 6, GTK_FILL | GTK_EXPAND | GTK_SHRINK, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 5); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(left_vbox), bbox, FALSE, FALSE, 0); + + save = gtk_button_new_with_label(_("Save")); + gtk_signal_connect(GTK_OBJECT(save), "clicked", GTK_SIGNAL_FUNC(save_tag), NULL); + GTK_WIDGET_SET_FLAGS(save, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), save, TRUE, TRUE, 0); + gtk_widget_grab_default(save); + + remove= gtk_button_new_with_label(_("Remove Tag")); + gtk_signal_connect(GTK_OBJECT(remove), "clicked", GTK_SIGNAL_FUNC(remove_tag), NULL); + GTK_WIDGET_SET_FLAGS(remove, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), remove, TRUE, TRUE, 0); + + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(window)); + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); + + flac_frame = gtk_frame_new(_("FLAC Info:")); + gtk_box_pack_start(GTK_BOX(hbox), flac_frame, FALSE, FALSE, 0); + + flac_box = gtk_vbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(flac_frame), flac_box); + gtk_container_set_border_width(GTK_CONTAINER(flac_box), 10); + gtk_box_set_spacing(GTK_BOX(flac_box), 0); + + flac_samplerate = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_samplerate), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_samplerate), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_samplerate, FALSE, FALSE, 0); + + flac_channels = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_channels), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_channels), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_channels, FALSE, FALSE, 0); + + flac_bits_per_sample = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_bits_per_sample), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_bits_per_sample), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_bits_per_sample, FALSE, FALSE, 0); + + flac_blocksize = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_blocksize), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_blocksize), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_blocksize, FALSE, FALSE, 0); + + flac_filesize = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_filesize), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_filesize), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_filesize, FALSE, FALSE, 0); + + flac_samples = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_samples), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_samples), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_samples, FALSE, FALSE, 0); + + flac_bitrate = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(flac_bitrate), 0, 0); + gtk_label_set_justify(GTK_LABEL(flac_bitrate), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), flac_bitrate, FALSE, FALSE, 0); + + replaygain_reference = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(replaygain_reference), 0, 0); + gtk_label_set_justify(GTK_LABEL(replaygain_reference), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), replaygain_reference, FALSE, FALSE, 0); + + replaygain_track_gain = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(replaygain_track_gain), 0, 0); + gtk_label_set_justify(GTK_LABEL(replaygain_track_gain), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_gain, FALSE, FALSE, 0); + + replaygain_album_gain = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(replaygain_album_gain), 0, 0); + gtk_label_set_justify(GTK_LABEL(replaygain_album_gain), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_gain, FALSE, FALSE, 0); + + replaygain_track_peak = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(replaygain_track_peak), 0, 0); + gtk_label_set_justify(GTK_LABEL(replaygain_track_peak), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), replaygain_track_peak, FALSE, FALSE, 0); + + replaygain_album_peak = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(replaygain_album_peak), 0, 0); + gtk_label_set_justify(GTK_LABEL(replaygain_album_peak), GTK_JUSTIFY_LEFT); + gtk_box_pack_start(GTK_BOX(flac_box), replaygain_album_peak, FALSE, FALSE, 0); + + gtk_widget_show_all(window); + } + + if(current_filename) + g_free(current_filename); + if(!(current_filename = g_strdup(filename))) + return; + + filename_utf8 = filename_to_utf8(current_filename); + title = g_strdup_printf(_("File Info - %s"), g_basename(filename_utf8)); + gtk_window_set_title(GTK_WINDOW(window), title); + g_free(title); + + gtk_entry_set_text(GTK_ENTRY(filename_entry), filename_utf8); + gtk_editable_set_position(GTK_EDITABLE(filename_entry), -1); + + g_free(filename_utf8); + + if(tags_) + FLAC_plugin__tags_destroy(&tags_); + + FLAC_plugin__tags_get(current_filename, &tags_); + + show_tag(); + show_file_info(); + show_replaygain(); + + gtk_widget_set_sensitive(tag_frame, TRUE); +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/grabbag.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/grabbag.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,33 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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. + */ + +#ifndef SHARE__GRABBAG_H +#define SHARE__GRABBAG_H + +#include +#include "plugin_common/all.h" + + +/* These can't be included by themselves, only from within grabbag.h */ +#include "grabbag/cuesheet.h" +#include "grabbag/file.h" +#include "grabbag/replaygain.h" +#include "grabbag/seektable.h" + + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/grabbag/cuesheet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/grabbag/cuesheet.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,42 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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. + */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABBAG__CUESHEET_H +#define GRABBAG__CUESHEET_H + +#include +#include "FLAC/metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames); +void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames); + +FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset); + +void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference); + +#ifdef __cplusplus +} +#endif + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/grabbag/file.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/grabbag/file.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,54 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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. + */ + +/* Convenience routines for manipulating files */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABAG__FILE_H +#define GRABAG__FILE_H + +#include /* for off_t */ +#include /* for FILE */ +#include "FLAC/ordinals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void grabbag__file_copy_metadata(const char *srcpath, const char *destpath); +off_t grabbag__file_get_filesize(const char *srcpath); +const char *grabbag__file_get_basename(const char *srcpath); + +/* read_only == false means "make file writable by user" + * read_only == true means "make file read-only for everyone" + */ +FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only); + +/* attempts to make writable before unlinking */ +FLAC__bool grabbag__file_remove_file(const char *filename); + +/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */ +FILE *grabbag__file_get_binary_stdin(); +FILE *grabbag__file_get_binary_stdout(); + +#ifdef __cplusplus +} +#endif + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/grabbag/replaygain.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/grabbag/replaygain.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,72 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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 + * 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. + */ + +/* + * This wraps the replaygain_analysis lib, which is LGPL. This wrapper + * allows analysis of different input resolutions by automatically + * scaling the input signal + */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABBAG__REPLAYGAIN_H +#define GRABBAG__REPLAYGAIN_H + +#include "FLAC/metadata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +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); + +/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */ +FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples); + +void grabbag__replaygain_get_album(float *gain, float *peak); +void grabbag__replaygain_get_title(float *gain, float *peak); + +/* 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, 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 +} +#endif + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/grabbag/seektable.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/grabbag/seektable.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,38 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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. + */ + +/* Convenience routines for working with seek tables */ + +/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */ + +#ifndef GRABAG__SEEKTABLE_H +#define GRABAG__SEEKTABLE_H + +#include "FLAC/format.h" + +#ifdef __cplusplus +extern "C" { +#endif + +FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points); + +#ifdef __cplusplus +} +#endif + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/http.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/http.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,897 @@ +/* XMMS - Cross-platform multimedia player + * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies + * + * 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. + */ +/* modified for FLAC support by Steven Richman (2003) */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "configure.h" +#include "plugin_common/locale_hack.h" +#include "FLAC/format.h" +#include "plugin.h" + +#define min(x,y) ((x)<(y)?(x):(y)) +#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z)) +#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w)) + +static gchar *icy_name = NULL; +static gint icy_metaint = 0; + +extern InputPlugin flac_ip; + +#undef DEBUG_UDP + +/* Static udp channel functions */ +static int udp_establish_listener (gint *sock); +static int udp_check_for_data(gint sock); + +static char *flac_http_get_title(char *url); + +static gboolean prebuffering, going, eof = FALSE; +static gint sock, rd_index, wr_index, buffer_length, prebuffer_length; +static guint64 buffer_read = 0; +static gchar *buffer; +static guint64 offset; +static GThread *thread; +static GtkWidget *error_dialog = NULL; + +static FILE *output_file = NULL; + +#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3)) + +/* Encode the string S of length LENGTH to base64 format and place it + to STORE. STORE will be 0-terminated, and must point to a writable + buffer of at least 1+BASE64_LENGTH(length) bytes. */ +static void base64_encode (const gchar *s, gchar *store, gint length) +{ + /* Conversion table. */ + static gchar tbl[64] = { + 'A','B','C','D','E','F','G','H', + 'I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X', + 'Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3', + '4','5','6','7','8','9','+','/' + }; + gint i; + guchar *p = (guchar *)store; + + /* Transform the 3x8 bits to 4x6 bits, as required by base64. */ + for (i = 0; i < length; i += 3) + { + *p++ = tbl[s[0] >> 2]; + *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)]; + *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)]; + *p++ = tbl[s[2] & 0x3f]; + s += 3; + } + /* Pad the result if necessary... */ + if (i == length + 1) + *(p - 1) = '='; + else if (i == length + 2) + *(p - 1) = *(p - 2) = '='; + /* ...and zero-terminate it. */ + *p = '\0'; +} + +/* Create the authentication header contents for the `Basic' scheme. + This is done by encoding the string `USER:PASS' in base64 and + prepending `HEADER: Basic ' to it. */ +static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header) +{ + gchar *t1, *t2, *res; + gint len1 = strlen (user) + 1 + strlen (passwd); + gint len2 = BASE64_LENGTH (len1); + + t1 = g_strdup_printf("%s:%s", user, passwd); + t2 = g_malloc0(len2 + 1); + base64_encode (t1, t2, len1); + res = g_strdup_printf("%s: Basic %s\r\n", header, t2); + g_free(t2); + g_free(t1); + + return res; +} + +static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename) +{ + gchar *h, *p, *pt, *f, *temp, *ptr; + + temp = g_strdup(url); + ptr = temp; + + if (!strncasecmp("http://", ptr, 7)) + ptr += 7; + h = strchr(ptr, '@'); + f = strchr(ptr, '/'); + if (h != NULL && (!f || h < f)) + { + *h = '\0'; + p = strchr(ptr, ':'); + if (p != NULL && p < h) + { + *p = '\0'; + p++; + *pass = g_strdup(p); + } + else + *pass = NULL; + *user = g_strdup(ptr); + h++; + ptr = h; + } + else + { + *user = NULL; + *pass = NULL; + h = ptr; + } + pt = strchr(ptr, ':'); + if (pt != NULL && (f == NULL || pt < f)) + { + *pt = '\0'; + *port = atoi(pt + 1); + } + else + { + if (f) + *f = '\0'; + *port = 80; + } + *host = g_strdup(h); + + if (f) + *filename = g_strdup(f + 1); + else + *filename = NULL; + g_free(temp); +} + +void flac_http_close(void) +{ + going = FALSE; + + g_thread_join(thread); + g_free(icy_name); + icy_name = NULL; +} + + +static gint http_used(void) +{ + if (wr_index >= rd_index) + return wr_index - rd_index; + return buffer_length - (rd_index - wr_index); +} + +static gint http_free(void) +{ + if (rd_index > wr_index) + return (rd_index - wr_index) - 1; + return (buffer_length - (wr_index - rd_index)) - 1; +} + +static void http_wait_for_data(gint bytes) +{ + while ((prebuffering || http_used() < bytes) && !eof && going) + xmms_usleep(10000); +} + +static void show_error_message(gchar *error) +{ + if(!error_dialog) + { + GDK_THREADS_ENTER(); + error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE, + NULL, NULL); + g_signal_connect(G_OBJECT(error_dialog), + "destroy", + G_CALLBACK(gtk_widget_destroyed), + &error_dialog); + GDK_THREADS_LEAVE(); + } +} + +int flac_http_read(gpointer data, gint length) +{ + gint len, cnt, off = 0, meta_len, meta_off = 0, i; + gchar *meta_data, **tags, *temp, *title; + if (length > buffer_length) { + length = buffer_length; + } + + http_wait_for_data(length); + + if (!going) + return 0; + len = min(http_used(), length); + + while (len && http_used()) + { + if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0)) + { + meta_len = *((guchar *) buffer + rd_index) * 16; + rd_index = (rd_index + 1) % buffer_length; + if (meta_len > 0) + { + http_wait_for_data(meta_len); + meta_data = g_malloc0(meta_len); + if (http_used() >= meta_len) + { + while (meta_len) + { + cnt = min(meta_len, buffer_length - rd_index); + memcpy(meta_data + meta_off, buffer + rd_index, cnt); + rd_index = (rd_index + cnt) % buffer_length; + meta_len -= cnt; + meta_off += cnt; + } + tags = g_strsplit(meta_data, "';", 0); + + for (i = 0; tags[i]; i++) + { + if (!strncasecmp(tags[i], "StreamTitle=", 12)) + { + temp = g_strdup(tags[i] + 13); + title = g_strdup_printf("%s (%s)", temp, icy_name); + set_track_info(title, -1); + g_free(title); + g_free(temp); + } + + } + g_strfreev(tags); + + } + g_free(meta_data); + } + if (!http_used()) + http_wait_for_data(length - off); + cnt = min3(len, buffer_length - rd_index, http_used()); + } + else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming)) + cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint)); + else + cnt = min3(len, buffer_length - rd_index, http_used()); + if (output_file) + fwrite(buffer + rd_index, 1, cnt, output_file); + + memcpy((gchar *)data + off, buffer + rd_index, cnt); + rd_index = (rd_index + cnt) % buffer_length; + buffer_read += cnt; + len -= cnt; + off += cnt; + } + if (!off) { + fprintf(stderr, "returning zero\n"); + } + return off; +} + +static gboolean http_check_for_data(void) +{ + + fd_set set; + struct timeval tv; + gint ret; + + tv.tv_sec = 0; + tv.tv_usec = 20000; + FD_ZERO(&set); + FD_SET(sock, &set); + ret = select(sock + 1, &set, NULL, NULL, &tv); + if (ret > 0) + return TRUE; + return FALSE; +} + +gint flac_http_read_line(gchar * buf, gint size) +{ + gint i = 0; + + while (going && i < size - 1) + { + if (http_check_for_data()) + { + if (read(sock, buf + i, 1) <= 0) + return -1; + if (buf[i] == '\n') + break; + if (buf[i] != '\r') + i++; + } + } + if (!going) + return -1; + buf[i] = '\0'; + return i; +} + +/* returns the file descriptor of the socket, or -1 on error */ +static int http_connect (gchar *url_, gboolean head, guint64 offset) +{ + gchar line[1024], *user, *pass, *host, *filename, + *status, *url, *temp, *file; + gchar *chost; + gint cnt, error, port, cport; + guint err_len; + gboolean redirect; + int udp_sock = 0; + fd_set set; + struct hostent *hp; + struct sockaddr_in address; + struct timeval tv; + + url = g_strdup (url_); + + do + { + redirect=FALSE; + + g_strstrip(url); + + parse_url(url, &user, &pass, &host, &port, &filename); + + if ((!filename || !*filename) && url[strlen(url) - 1] != '/') + temp = g_strconcat(url, "/", NULL); + else + temp = g_strdup(url); + g_free(url); + url = temp; + + chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host; + cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port; + + sock = socket(AF_INET, SOCK_STREAM, 0); + fcntl(sock, F_SETFL, O_NONBLOCK); + address.sin_family = AF_INET; + + status = g_strdup_printf(_("LOOKING UP %s"), chost); + flac_ip.set_info_text(status); + g_free(status); + + if (!(hp = gethostbyname(chost))) + { + status = g_strdup_printf(_("Couldn't look up host %s"), chost); + show_error_message(status); + g_free(status); + + flac_ip.set_info_text(NULL); + eof = TRUE; + } + + if (!eof) + { + memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr)); + address.sin_port = (gint) g_htons(cport); + + status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport); + flac_ip.set_info_text(status); + g_free(status); + if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1) + { + if (errno != EINPROGRESS) + { + status = g_strdup_printf(_("Couldn't connect to host %s"), chost); + show_error_message(status); + g_free(status); + + flac_ip.set_info_text(NULL); + eof = TRUE; + } + } + while (going) + { + tv.tv_sec = 0; + tv.tv_usec = 10000; + FD_ZERO(&set); + FD_SET(sock, &set); + if (select(sock + 1, NULL, &set, NULL, &tv) > 0) + { + err_len = sizeof (error); + getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len); + if (error) + { + status = g_strdup_printf(_("Couldn't connect to host %s"), + chost); + show_error_message(status); + g_free(status); + + flac_ip.set_info_text(NULL); + eof = TRUE; + + } + break; + } + } + if (!eof) + { + gchar *auth = NULL, *proxy_auth = NULL; + gchar udpspace[30]; + int udp_port; + + if (flac_cfg.stream.use_udp_channel) + { + udp_port = udp_establish_listener (&udp_sock); + if (udp_port > 0) + sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port); + else + udp_sock = 0; + } + + if(user && pass) + auth = basic_authentication_encode(user, pass, "Authorization"); + + if (flac_cfg.stream.use_proxy) + { + file = g_strdup(url); + if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass) + { + proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user, + flac_cfg.stream.proxy_pass, + "Proxy-Authorization"); + } + } + else + file = g_strconcat("/", filename, NULL); + + temp = g_strdup_printf("GET %s HTTP/1.0\r\n" + "Host: %s\r\n" + "User-Agent: %s/%s\r\n" + "%s%s%s%s", + file, host, "Reference FLAC Player", FLAC__VERSION_STRING, + proxy_auth ? proxy_auth : "", auth ? auth : "", + flac_cfg.stream.cast_title_streaming ? "Icy-MetaData:1\r\n" : "", + flac_cfg.stream.use_udp_channel ? udpspace : ""); + if (offset && !head) { + gchar *temp_dead = temp; + temp = g_strconcat ("%sRange: %ll-\r\n", temp, offset, NULL); + fprintf (stderr, "%s", temp); + g_free (temp_dead); + } + + g_free(file); + if(proxy_auth) + g_free(proxy_auth); + if(auth) + g_free(auth); + write(sock, temp, strlen(temp)); + write(sock, "\r\n", 2); + g_free(temp); + flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY")); + while (going && !eof) + { + if (http_check_for_data()) + { + if (flac_http_read_line(line, 1024)) + { + status = strchr(line, ' '); + if (status) + { + if (status[1] == '2') + break; + else if(status[1] == '3' && status[2] == '0' && status[3] == '2') + { + while(going) + { + if(http_check_for_data()) + { + if((cnt = flac_http_read_line(line, 1024)) != -1) + { + if(!cnt) + break; + if(!strncmp(line, "Location:", 9)) + { + g_free(url); + url = g_strdup(line+10); + } + } + else + { + eof=TRUE; + flac_ip.set_info_text(NULL); + break; + } + } + } + redirect=TRUE; + break; + } + else + { + status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status); + show_error_message(status); + g_free(status); + break; + } + } + } + else + { + eof = TRUE; + flac_ip.set_info_text(NULL); + } + } + } + + while (going && !redirect) + { + if (http_check_for_data()) + { + if ((cnt = flac_http_read_line(line, 1024)) != -1) + { + if (!cnt) + break; + if (!strncmp(line, "icy-name:", 9)) + icy_name = g_strdup(line + 9); + else if (!strncmp(line, "x-audiocast-name:", 17)) + icy_name = g_strdup(line + 17); + if (!strncmp(line, "icy-metaint:", 12)) + icy_metaint = atoi(line + 12); + if (!strncmp(line, "x-audiocast-udpport:", 20)) { +#ifdef DEBUG_UDP + fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20)); +#endif + /*udp_serverport = atoi (line + 20);*/ + } + + } + else + { + eof = TRUE; + flac_ip.set_info_text(NULL); + break; + } + } + } + } + } + + if(redirect) + { + if (output_file) + { + fclose(output_file); + output_file = NULL; + } + close(sock); + } + + g_free(user); + g_free(pass); + g_free(host); + g_free(filename); + } while(redirect); + + g_free(url); + return eof ? -1 : sock; +} + +static void *http_buffer_loop(void *arg) +{ + gchar *status, *url, *temp, *file; + gint cnt, written; + int udp_sock = 0; + + url = (gchar *) arg; + sock = http_connect (url, false, offset); + + if (sock >= 0 && flac_cfg.stream.save_http_stream) { + gchar *output_name; + file = flac_http_get_title(url); + output_name = file; + if (!strncasecmp(output_name, "http://", 7)) + output_name += 7; + temp = strrchr(output_name, '.'); + if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac"))) + *temp = '\0'; + + while ((temp = strchr(output_name, '/'))) + *temp = '_'; + output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name); + + g_free(file); + + output_file = fopen(output_name, "wb"); + g_free(output_name); + } + + while (going) + { + + if (!http_used() && !flac_ip.output->buffer_playing()) + { + prebuffering = TRUE; + flac_ip.set_status_buffering(TRUE); + } + if (http_free() > 0 && !eof) + { + if (http_check_for_data()) + { + cnt = min(http_free(), buffer_length - wr_index); + if (cnt > 1024) + cnt = 1024; + written = read(sock, buffer + wr_index, cnt); + if (written <= 0) + { + eof = TRUE; + if (prebuffering) + { + prebuffering = FALSE; + flac_ip.set_status_buffering(FALSE); + + flac_ip.set_info_text(NULL); + } + + } + else + wr_index = (wr_index + written) % buffer_length; + } + + if (prebuffering) + { + if (http_used() > prebuffer_length) + { + prebuffering = FALSE; + flac_ip.set_status_buffering(FALSE); + flac_ip.set_info_text(NULL); + } + else + { + status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024); + flac_ip.set_info_text(status); + g_free(status); + } + + } + } + else + xmms_usleep(10000); + + if (flac_cfg.stream.use_udp_channel && udp_sock != 0) + if (udp_check_for_data(udp_sock) < 0) + { + close(udp_sock); + udp_sock = 0; + } + } + if (output_file) + { + fclose(output_file); + output_file = NULL; + } + if (sock >= 0) { + close(sock); + } + if (udp_sock != 0) + close(udp_sock); + + g_free(buffer); + g_free(url); + + g_thread_exit(NULL); + return NULL; /* avoid compiler warning */ +} + +int flac_http_open(gchar * _url, guint64 _offset) +{ + gchar *url; + + url = g_strdup(_url); + + rd_index = 0; + wr_index = 0; + buffer_length = flac_cfg.stream.http_buffer_size * 1024; + prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100; + buffer_read = 0; + icy_metaint = 0; + prebuffering = TRUE; + flac_ip.set_status_buffering(TRUE); + going = TRUE; + eof = FALSE; + buffer = g_malloc(buffer_length); + offset = _offset; + + thread = g_thread_create((GThreadFunc)http_buffer_loop, url, TRUE, NULL); + + return 0; +} + +char *flac_http_get_title(char *url) +{ + if (icy_name) + return g_strdup(icy_name); + if (g_basename(url) && strlen(g_basename(url)) > 0) + return g_strdup(g_basename(url)); + return g_strdup(url); +} + +/* Start UDP Channel specific stuff */ + +/* Find a good local udp port and bind udp_sock to it, return the port */ +static int udp_establish_listener(int *sock) +{ + struct sockaddr_in sin; + socklen_t sinlen = sizeof (struct sockaddr_in); + +#ifdef DEBUG_UDP + fprintf (stderr,"Establishing udp listener\n"); +#endif + + if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + g_log(NULL, G_LOG_LEVEL_CRITICAL, + "udp_establish_listener(): unable to create socket"); + return -1; + } + + memset(&sin, 0, sinlen); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = g_htonl(INADDR_ANY); + + if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0) + { + g_log(NULL, G_LOG_LEVEL_CRITICAL, + "udp_establish_listener(): Failed to bind socket to localhost: %s", strerror(errno)); + close(*sock); + return -1; + } + if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0) + { + g_log(NULL, G_LOG_LEVEL_CRITICAL, + "udp_establish_listener(): Failed to set flags: %s", strerror(errno)); + close(*sock); + return -1; + } + + memset(&sin, 0, sinlen); + if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0) + { + g_log(NULL, G_LOG_LEVEL_CRITICAL, + "udp_establish_listener(): Failed to retrieve socket info: %s", strerror(errno)); + close(*sock); + return -1; + } + +#ifdef DEBUG_UDP + fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port)); +#endif + + return g_ntohs(sin.sin_port); +} + +static int udp_check_for_data(int sock) +{ + char buf[1025], **lines; + char *valptr; + gchar *title; + gint len, i; + struct sockaddr_in from; + socklen_t fromlen; + + fromlen = sizeof(struct sockaddr_in); + + if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0) + { + if (errno != EAGAIN) + { + g_log(NULL, G_LOG_LEVEL_CRITICAL, + "udp_read_data(): Error reading from socket: %s", strerror(errno)); + return -1; + } + return 0; + } + buf[len] = '\0'; +#ifdef DEBUG_UDP + fprintf (stderr,"Received: [%s]\n", buf); +#endif + lines = g_strsplit(buf, "\n", 0); + if (!lines) + return 0; + + for (i = 0; lines[i]; i++) + { + while ((lines[i][strlen(lines[i]) - 1] == '\n') || + (lines[i][strlen(lines[i]) - 1] == '\r')) + lines[i][strlen(lines[i]) - 1] = '\0'; + + valptr = strchr(lines[i], ':'); + + if (!valptr) + continue; + else + valptr++; + + g_strstrip(valptr); + if (!strlen(valptr)) + continue; + + if (strstr(lines[i], "x-audiocast-streamtitle") != NULL) + { + title = g_strdup_printf ("%s (%s)", valptr, icy_name); + if (going) + set_track_info(title, -1); + g_free (title); + } + +#if 0 + else if (strstr(lines[i], "x-audiocast-streamlength") != NULL) + { + if (atoi(valptr) != -1) + set_track_info(NULL, atoi(valptr)); + } +#endif + + else if (strstr(lines[i], "x-audiocast-streammsg") != NULL) + { + /* set_track_info(title, -1); */ +/* xmms_show_message(_("Message"), valptr, _("Ok"), */ +/* FALSE, NULL, NULL); */ + g_message("Stream_message: %s", valptr); + } + +#if 0 + /* Use this to direct your webbrowser.. yeah right.. */ + else if (strstr(lines[i], "x-audiocast-streamurl") != NULL) + { + if (lasturl && g_strcmp (valptr, lasturl)) + { + c_message (stderr, "Song URL: %s\n", valptr); + g_free (lasturl); + lasturl = g_strdup (valptr); + } + } +#endif + else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL) + { + gchar obuf[60]; + sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr)); + if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0) + { + g_log(NULL, G_LOG_LEVEL_WARNING, + "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno)); + } +#ifdef DEBUG_UDP + else + fprintf(stderr,"Sent ack: %s", obuf); + fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port)); +#endif + } + } + g_strfreev(lines); + return 0; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/http.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/http.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,26 @@ +/* libxmms-flac - XMMS FLAC input plugin + * + * 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. + */ + +#ifndef __HTTP_H__ +#define __HTTP_H__ + +extern int flac_http_open(gchar * url, guint64 offset); +extern void flac_http_close(void); +extern int flac_http_read(gpointer data, gint length); + + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,718 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2000,2001,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 + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "audacious/plugin.h" +#include "audacious/output.h" +#include "audacious/util.h" +#include "audacious/configdb.h" +#include "audacious/titlestring.h" +#include "audacious/vfs.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +#include "FLAC/all.h" +#include "plugin_common/all.h" +#include "grabbag.h" +#include "replaygain_synthesis.h" +#include "configure.h" +#include "charset.h" +#include "http.h" +#include "tag.h" + +#ifdef min +#undef min +#endif +#define min(x,y) ((x)<(y)?(x):(y)) + +extern void FLAC_XMMS__file_info_box(char *filename); + +typedef struct { + FLAC__bool abort_flag; + FLAC__bool is_playing; + FLAC__bool is_http_source; + FLAC__bool eof; + FLAC__bool play_thread_open; /* if true, is_playing must also be true */ + FLAC__uint64 total_samples; + unsigned bits_per_sample; + unsigned channels; + unsigned sample_rate; + int length_in_msec; /* int (instead of FLAC__uint64) only because that's what XMMS uses; seeking won't work right if this maxes out */ + gchar *title; + AFormat sample_format; + unsigned sample_format_bytes_per_sample; + int seek_to_in_sec; + FLAC__bool has_replaygain; + double replay_scale; + DitherContext dither_context; +} stream_data_struct; + +static void FLAC_XMMS__init(); +static int FLAC_XMMS__is_our_file(char *filename); +static void FLAC_XMMS__play_file(char *filename); +static void FLAC_XMMS__stop(); +static void FLAC_XMMS__pause(short p); +static void FLAC_XMMS__seek(int time); +static int FLAC_XMMS__get_time(); +static void FLAC_XMMS__cleanup(); +static void FLAC_XMMS__get_song_info(char *filename, char **title, int *length); + +static void *play_loop_(void *arg); + +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); + +static FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); +static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); + +InputPlugin flac_ip = +{ + NULL, + NULL, + NULL, + FLAC_XMMS__init, + FLAC_XMMS__aboutbox, + FLAC_XMMS__configure, + FLAC_XMMS__is_our_file, + NULL, + FLAC_XMMS__play_file, + FLAC_XMMS__stop, + FLAC_XMMS__pause, + FLAC_XMMS__seek, + NULL, + FLAC_XMMS__get_time, + NULL, + NULL, + FLAC_XMMS__cleanup, + NULL, + NULL, + NULL, + NULL, + FLAC_XMMS__get_song_info, + FLAC_XMMS__file_info_box, + NULL, + flac_get_tuple +}; + +#define SAMPLES_PER_WRITE 512 +#define SAMPLE_BUFFER_SIZE ((FLAC__MAX_BLOCK_SIZE + SAMPLES_PER_WRITE) * FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS * (24/8)) +static FLAC__byte sample_buffer_[SAMPLE_BUFFER_SIZE]; +static unsigned sample_buffer_first_, sample_buffer_last_; + +static FLAC__StreamDecoder *decoder_ = 0, *decoder2 = 0; +static stream_data_struct stream_data_; +static GThread *decode_thread_; +static FLAC__bool audio_error_ = false; +static FLAC__bool is_big_endian_host_; + +#define BITRATE_HIST_SEGMENT_MSEC 500 +/* 500ms * 50 = 25s should be enough */ +#define BITRATE_HIST_SIZE 50 +static unsigned bitrate_history_[BITRATE_HIST_SIZE]; + +#ifdef SUPPORT_ATTRIBUTE_VISIBILITY +InputPlugin *get_iplugin_info() __attribute__((visibility("default"))); +#endif + +InputPlugin *get_iplugin_info() +{ + flac_ip.description = g_strdup_printf(_("FLAC Audio Plugin")); + return &flac_ip; +} + +void set_track_info(const char* title, int length_in_msec) +{ + if (stream_data_.is_playing) { + flac_ip.set_info((char*) title, length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels); + } +} + +static gchar* homedir() +{ + gchar *result; + char *env_home = getenv("HOME"); + if (env_home) { + result = g_strdup (env_home); + } else { + uid_t uid = getuid(); + struct passwd *pwent; + do { + pwent = getpwent(); + } while (pwent && pwent->pw_uid != uid); + result = pwent ? g_strdup (pwent->pw_dir) : NULL; + endpwent(); + } + return result; +} + +static FLAC__bool is_http_source(const char *source) +{ + return 0 == strncasecmp(source, "http://", 7); +} + +void FLAC_XMMS__init() +{ + ConfigDb *db; + FLAC__uint32 test = 1; + gchar *tmp; + + is_big_endian_host_ = (*((FLAC__byte*)(&test)))? false : true; + + flac_cfg.title.tag_override = FALSE; + if (flac_cfg.title.tag_format) + g_free(flac_cfg.title.tag_format); + flac_cfg.title.convert_char_set = FALSE; + + db = bmp_cfg_db_open(); + + /* title */ + + bmp_cfg_db_get_bool(db, "flac", "title.tag_override", &flac_cfg.title.tag_override); + + if(!bmp_cfg_db_get_string(db, "flac", "title.tag_format", &flac_cfg.title.tag_format)) + flac_cfg.title.tag_format = g_strdup("%p - %t"); + + bmp_cfg_db_get_bool(db, "flac", "title.convert_char_set", &flac_cfg.title.convert_char_set); + + if(!bmp_cfg_db_get_string(db, "flac", "title.user_char_set", &flac_cfg.title.user_char_set)) + flac_cfg.title.user_char_set = FLAC_plugin__charset_get_current(); + + /* replaygain */ + + bmp_cfg_db_get_bool(db, "flac", "output.replaygain.enable", &flac_cfg.output.replaygain.enable); + + bmp_cfg_db_get_bool(db, "flac", "output.replaygain.album_mode", &flac_cfg.output.replaygain.album_mode); + + if(!bmp_cfg_db_get_int(db, "flac", "output.replaygain.preamp", &flac_cfg.output.replaygain.preamp)) + flac_cfg.output.replaygain.preamp = 0; + + bmp_cfg_db_get_bool(db, "flac", "output.replaygain.hard_limit", &flac_cfg.output.replaygain.hard_limit); + + bmp_cfg_db_get_bool(db, "flac", "output.resolution.normal.dither_24_to_16", &flac_cfg.output.resolution.normal.dither_24_to_16); + bmp_cfg_db_get_bool(db, "flac", "output.resolution.replaygain.dither", &flac_cfg.output.resolution.replaygain.dither); + + if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.noise_shaping", &flac_cfg.output.resolution.replaygain.noise_shaping)) + flac_cfg.output.resolution.replaygain.noise_shaping = 1; + + if(!bmp_cfg_db_get_int(db, "flac", "output.resolution.replaygain.bps_out", &flac_cfg.output.resolution.replaygain.bps_out)) + flac_cfg.output.resolution.replaygain.bps_out = 16; + + /* stream */ + + bmp_cfg_db_get_int(db, "flac", "stream.http_buffer_size", &flac_cfg.stream.http_buffer_size); + bmp_cfg_db_get_int(db, "flac", "stream.http_prebuffer", &flac_cfg.stream.http_prebuffer); + bmp_cfg_db_get_bool(db, "flac", "stream.save_http_stream", &flac_cfg.stream.save_http_stream); + if (!bmp_cfg_db_get_string(db, "flac", "stream.save_http_path", &flac_cfg.stream.save_http_path) || + ! *flac_cfg.stream.save_http_path) { + /* TODO: Is this a memory leak ?? */ + /* + if (flac_cfg.stream.save_http_path) + g_free (flac_cfg.stream.save_http_path); + */ + flac_cfg.stream.save_http_path = homedir(); + } + bmp_cfg_db_get_bool(db, "flac", "stream.cast_title_streaming", &flac_cfg.stream.cast_title_streaming); + bmp_cfg_db_get_bool(db, "flac", "stream.use_udp_channel", &flac_cfg.stream.use_udp_channel); + + bmp_cfg_db_get_bool(db, NULL, "use_proxy", &flac_cfg.stream.use_proxy); + bmp_cfg_db_get_string(db, NULL, "proxy_host", &flac_cfg.stream.proxy_host); + bmp_cfg_db_get_string(db, NULL, "proxy_port", &tmp); + + bmp_cfg_db_get_bool(db, NULL, "proxy_use_auth", &flac_cfg.stream.proxy_use_auth); + bmp_cfg_db_get_string(db, NULL, "proxy_user", &flac_cfg.stream.proxy_user); + bmp_cfg_db_get_string(db, NULL, "proxy_pass", &flac_cfg.stream.proxy_pass); + + decoder_ = FLAC__stream_decoder_new(); + bmp_cfg_db_close(db); +} + +int FLAC_XMMS__is_our_file(char *filename) +{ + FILE *f; + FLAC__StreamMetadata streaminfo; + + if(!is_http_source(filename)) { + if(0 == (f = fopen(filename, "r"))) + return 0; + fclose(f); + if(FLAC__metadata_get_streaminfo(filename, &streaminfo)) + return 1; + return 0; + } + + if(!safe_decoder_init_(filename, decoder2)) + return 0; + + safe_decoder_finish_(decoder2); + return 1; +} + +void FLAC_XMMS__play_file(char *filename) +{ + FILE *f; + + sample_buffer_first_ = sample_buffer_last_ = 0; + audio_error_ = false; + stream_data_.abort_flag = false; + stream_data_.is_playing = false; + stream_data_.is_http_source = is_http_source(filename); + stream_data_.eof = false; + stream_data_.play_thread_open = false; + stream_data_.has_replaygain = false; + + if(!is_http_source(filename)) { + if(0 == (f = fopen(filename, "r"))) + return; + fclose(f); + } + + if(decoder_ == 0) + return; + + if(!safe_decoder_init_(filename, decoder_)) + return; + + if(stream_data_.has_replaygain && flac_cfg.output.replaygain.enable) { + if(flac_cfg.output.resolution.replaygain.bps_out == 8) { + stream_data_.sample_format = FMT_U8; + stream_data_.sample_format_bytes_per_sample = 1; + } + else if(flac_cfg.output.resolution.replaygain.bps_out == 16) { + stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; + stream_data_.sample_format_bytes_per_sample = 2; + } + else { + /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ + fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", flac_cfg.output.resolution.replaygain.bps_out); + safe_decoder_finish_(decoder_); + return; + } + } + else { + if(stream_data_.bits_per_sample == 8) { + stream_data_.sample_format = FMT_U8; + stream_data_.sample_format_bytes_per_sample = 1; + } + else if(stream_data_.bits_per_sample == 16 || (stream_data_.bits_per_sample == 24 && flac_cfg.output.resolution.normal.dither_24_to_16)) { + stream_data_.sample_format = (is_big_endian_host_) ? FMT_S16_BE : FMT_S16_LE; + stream_data_.sample_format_bytes_per_sample = 2; + } + else { + /*@@@ need some error here like wa2: MessageBox(mod_.hMainWindow, "ERROR: plugin can only handle 8/16-bit samples\n", "ERROR: plugin can only handle 8/16-bit samples", 0); */ + fprintf(stderr, "libxmms-flac: can't handle %d bit output\n", stream_data_.bits_per_sample); + safe_decoder_finish_(decoder_); + return; + } + } + FLAC__replaygain_synthesis__init_dither_context(&stream_data_.dither_context, stream_data_.sample_format_bytes_per_sample * 8, flac_cfg.output.resolution.replaygain.noise_shaping); + stream_data_.is_playing = true; + + if(flac_ip.output->open_audio(stream_data_.sample_format, stream_data_.sample_rate, stream_data_.channels) == 0) { + audio_error_ = true; + safe_decoder_finish_(decoder_); + return; + } + + stream_data_.title = flac_format_song_title(filename); + flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample, stream_data_.sample_rate, stream_data_.channels); + + stream_data_.seek_to_in_sec = -1; + stream_data_.play_thread_open = true; + decode_thread_ = g_thread_create((GThreadFunc)play_loop_, NULL, TRUE, NULL); +} + +void FLAC_XMMS__stop() +{ + if(stream_data_.is_playing) { + stream_data_.is_playing = false; + if(stream_data_.play_thread_open) { + stream_data_.play_thread_open = false; + g_thread_join(decode_thread_); + } + flac_ip.output->close_audio(); + safe_decoder_finish_(decoder_); + } +} + +void FLAC_XMMS__pause(short p) +{ + flac_ip.output->pause(p); +} + +void FLAC_XMMS__seek(int time) +{ + if(!stream_data_.is_http_source) { + stream_data_.seek_to_in_sec = time; + stream_data_.eof = false; + + while(stream_data_.seek_to_in_sec != -1) + xmms_usleep(10000); + } +} + +int FLAC_XMMS__get_time() +{ + if(audio_error_) + return -2; + if(!stream_data_.is_playing || (stream_data_.eof && !flac_ip.output->buffer_playing())) + return -1; + else + return flac_ip.output->output_time(); +} + +void FLAC_XMMS__cleanup() +{ + g_free(flac_ip.description); + flac_ip.description = NULL; + + if (flac_cfg.title.tag_format) { + free(flac_cfg.title.tag_format); + flac_cfg.title.tag_format = NULL; + } + + if (flac_cfg.title.user_char_set) { + free(flac_cfg.title.user_char_set); + flac_cfg.title.user_char_set = NULL; + } + + if (flac_cfg.stream.proxy_host) { + free(flac_cfg.stream.proxy_host); + flac_cfg.stream.proxy_host = NULL; + } + + if (flac_cfg.stream.proxy_user) { + free(flac_cfg.stream.proxy_user); + flac_cfg.stream.proxy_user = NULL; + + } + + if (flac_cfg.stream.proxy_pass) { + free(flac_cfg.stream.proxy_pass); + flac_cfg.stream.proxy_pass = NULL; + } + + safe_decoder_delete_(decoder_); + decoder_ = 0; +} + +void FLAC_XMMS__get_song_info(char *filename, char **title, int *length_in_msec) +{ + FLAC__StreamMetadata streaminfo; + + if(0 == filename) + filename = ""; + + if(!FLAC__metadata_get_streaminfo(filename, &streaminfo)) { + /* @@@ how to report the error? */ + if(title) { + if (!is_http_source(filename)) { + static const char *errtitle = "Invalid FLAC File: "; + *title = g_malloc(strlen(errtitle) + 1 + strlen(filename) + 1 + 1); + sprintf(*title, "%s\"%s\"", errtitle, filename); + } else { + *title = NULL; + } + } + if(length_in_msec) + *length_in_msec = -1; + return; + } + + if(title) { + *title = flac_format_song_title(filename); + } + if(length_in_msec) { + FLAC__uint64 l = (FLAC__uint64)((double)streaminfo.data.stream_info.total_samples / (double)streaminfo.data.stream_info.sample_rate * 1000.0 + 0.5); + if (l > INT_MAX) + l = INT_MAX; + *length_in_msec = (int)l; + } +} + +/*********************************************************************** + * local routines + **********************************************************************/ + +void *play_loop_(void *arg) +{ + unsigned written_time_last = 0, bh_index_last_w = 0, bh_index_last_o = BITRATE_HIST_SIZE, blocksize = 1; + FLAC__uint64 decode_position_last = 0, decode_position_frame_last = 0, decode_position_frame = 0; + + (void)arg; + + while(stream_data_.is_playing) { + if(!stream_data_.eof) { + while(sample_buffer_last_ - sample_buffer_first_ < SAMPLES_PER_WRITE) { + unsigned s; + + s = sample_buffer_last_ - sample_buffer_first_; + if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_END_OF_STREAM) { + stream_data_.eof = true; + break; + } + else if(!FLAC__stream_decoder_process_single(decoder_)) { + /*@@@ this should probably be a dialog */ + fprintf(stderr, "libxmms-flac: READ ERROR processing frame\n"); + stream_data_.eof = true; + break; + } + blocksize = sample_buffer_last_ - sample_buffer_first_ - s; + decode_position_frame_last = decode_position_frame; + if(stream_data_.is_http_source || !FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) + decode_position_frame = 0; + } + if(sample_buffer_last_ - sample_buffer_first_ > 0) { + const unsigned n = min(sample_buffer_last_ - sample_buffer_first_, SAMPLES_PER_WRITE); + int bytes = n * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; + FLAC__byte *sample_buffer_start = sample_buffer_ + sample_buffer_first_ * stream_data_.channels * stream_data_.sample_format_bytes_per_sample; + unsigned written_time, bh_index_w; + FLAC__uint64 decode_position; + + sample_buffer_first_ += n; + while(flac_ip.output->buffer_free() < (int)bytes && stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) + xmms_usleep(10000); + if(stream_data_.is_playing && stream_data_.seek_to_in_sec == -1) + produce_audio(flac_ip.output->written_time(), stream_data_.sample_format, + stream_data_.channels, bytes, sample_buffer_start, NULL); + + /* compute current bitrate */ + + written_time = flac_ip.output->written_time(); + bh_index_w = written_time / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; + if(bh_index_w != bh_index_last_w) { + bh_index_last_w = bh_index_w; + decode_position = decode_position_frame - (double)(sample_buffer_last_ - sample_buffer_first_) * (double)(decode_position_frame - decode_position_frame_last) / (double)blocksize; + bitrate_history_[(bh_index_w + BITRATE_HIST_SIZE - 1) % BITRATE_HIST_SIZE] = + decode_position > decode_position_last && written_time > written_time_last ? + 8000 * (decode_position - decode_position_last) / (written_time - written_time_last) : + stream_data_.sample_rate * stream_data_.channels * stream_data_.bits_per_sample; + decode_position_last = decode_position; + written_time_last = written_time; + } + } + else { + stream_data_.eof = true; + xmms_usleep(10000); + } + } + else + xmms_usleep(10000); + if(!stream_data_.is_http_source && stream_data_.seek_to_in_sec != -1) { + const double distance = (double)stream_data_.seek_to_in_sec * 1000.0 / (double)stream_data_.length_in_msec; + FLAC__uint64 target_sample = (FLAC__uint64)(distance * (double)stream_data_.total_samples); + if(stream_data_.total_samples > 0 && target_sample >= stream_data_.total_samples) + target_sample = stream_data_.total_samples - 1; + if(FLAC__stream_decoder_seek_absolute(decoder_, target_sample)) { + flac_ip.output->flush(stream_data_.seek_to_in_sec * 1000); + bh_index_last_w = bh_index_last_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; + if(!FLAC__stream_decoder_get_decode_position(decoder_, &decode_position_frame)) + decode_position_frame = 0; + stream_data_.eof = false; + sample_buffer_first_ = sample_buffer_last_ = 0; + } + else if(FLAC__stream_decoder_get_state(decoder_) == FLAC__STREAM_DECODER_SEEK_ERROR) { + /*@@@ this should probably be a dialog */ + fprintf(stderr, "libxmms-flac: SEEK ERROR\n"); + FLAC__stream_decoder_flush(decoder_); + stream_data_.eof = false; + sample_buffer_first_ = sample_buffer_last_ = 0; + } + stream_data_.seek_to_in_sec = -1; + } + else { + /* display the right bitrate from history */ + unsigned bh_index_o = flac_ip.output->output_time() / BITRATE_HIST_SEGMENT_MSEC % BITRATE_HIST_SIZE; + if(bh_index_o != bh_index_last_o && bh_index_o != bh_index_last_w && bh_index_o != (bh_index_last_w + 1) % BITRATE_HIST_SIZE) { + bh_index_last_o = bh_index_o; + flac_ip.set_info(stream_data_.title, stream_data_.length_in_msec, bitrate_history_[bh_index_o], stream_data_.sample_rate, stream_data_.channels); + } + } + } + + safe_decoder_finish_(decoder_); + + /* are these two calls necessary? */ + flac_ip.output->buffer_free(); + flac_ip.output->buffer_free(); + + g_free(stream_data_.title); + + g_thread_exit(NULL); + return 0; /* to silence the compiler warning about not returning a value */ +} + +FLAC__bool safe_decoder_init_(char *filename, FLAC__StreamDecoder *decoder) +{ + if(decoder == 0) + return false; + + safe_decoder_finish_(decoder); + + 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__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(stream_data_.is_http_source) { + flac_http_open(filename, 0); + if(FLAC__stream_decoder_init_stream(decoder, http_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return false; + } + else { + if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, /*client_data=*/&stream_data_) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return false; + } + + if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) + return false; + + return true; +} + +void safe_decoder_finish_(FLAC__StreamDecoder *decoder) +{ + if(decoder && FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) + FLAC__stream_decoder_finish(decoder); + if(stream_data_.is_http_source) + flac_http_close(); +} + +void safe_decoder_delete_(FLAC__StreamDecoder *decoder) +{ + if(decoder) { + safe_decoder_finish_(decoder); + FLAC__stream_decoder_delete(decoder); + } +} + +FLAC__StreamDecoderReadStatus http_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) +{ + (void)decoder; + (void)client_data; + *bytes = flac_http_read(buffer, *bytes); + return *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; +} + +FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data) +{ + stream_data_struct *stream_data = (stream_data_struct *)client_data; + const unsigned channels = stream_data->channels, wide_samples = frame->header.blocksize; + const unsigned bits_per_sample = stream_data->bits_per_sample; + FLAC__byte *sample_buffer_start; + + (void)decoder; + + if(stream_data->abort_flag) + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + + if((sample_buffer_last_ + wide_samples) > (SAMPLE_BUFFER_SIZE / (channels * stream_data->sample_format_bytes_per_sample))) { + memmove(sample_buffer_, sample_buffer_ + sample_buffer_first_ * channels * stream_data->sample_format_bytes_per_sample, (sample_buffer_last_ - sample_buffer_first_) * channels * stream_data->sample_format_bytes_per_sample); + sample_buffer_last_ -= sample_buffer_first_; + sample_buffer_first_ = 0; + } + sample_buffer_start = sample_buffer_ + sample_buffer_last_ * channels * stream_data->sample_format_bytes_per_sample; + if(stream_data->has_replaygain && flac_cfg.output.replaygain.enable) { + FLAC__replaygain_synthesis__apply_gain( + sample_buffer_start, + !is_big_endian_host_, + stream_data->sample_format_bytes_per_sample == 1, /* unsigned_data_out */ + buffer, + wide_samples, + channels, + bits_per_sample, + stream_data->sample_format_bytes_per_sample * 8, + stream_data->replay_scale, + flac_cfg.output.replaygain.hard_limit, + flac_cfg.output.resolution.replaygain.dither, + &stream_data->dither_context + ); + } + else if(is_big_endian_host_) { + FLAC__plugin_common__pack_pcm_signed_big_endian( + sample_buffer_start, + buffer, + wide_samples, + channels, + bits_per_sample, + stream_data->sample_format_bytes_per_sample * 8 + ); + } + else { + FLAC__plugin_common__pack_pcm_signed_little_endian( + sample_buffer_start, + buffer, + wide_samples, + channels, + bits_per_sample, + stream_data->sample_format_bytes_per_sample * 8 + ); + } + + sample_buffer_last_ += wide_samples; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + stream_data_struct *stream_data = (stream_data_struct *)client_data; + (void)decoder; + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + stream_data->total_samples = metadata->data.stream_info.total_samples; + stream_data->bits_per_sample = metadata->data.stream_info.bits_per_sample; + stream_data->channels = metadata->data.stream_info.channels; + stream_data->sample_rate = metadata->data.stream_info.sample_rate; + { + FLAC__uint64 l = (FLAC__uint64)((double)stream_data->total_samples / (double)stream_data->sample_rate * 1000.0 + 0.5); + if (l > INT_MAX) + l = INT_MAX; + stream_data->length_in_msec = (int)l; + } + } + else if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + double reference, gain, peak; + if(grabbag__replaygain_load_from_vorbiscomment(metadata, flac_cfg.output.replaygain.album_mode, /*strict=*/false, &reference, &gain, &peak)) { + stream_data->has_replaygain = true; + stream_data->replay_scale = grabbag__replaygain_compute_scale_factor(peak, gain, (double)flac_cfg.output.replaygain.preamp, /*prevent_clipping=*/!flac_cfg.output.replaygain.hard_limit); + } + } +} + +void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + stream_data_struct *stream_data = (stream_data_struct *)client_data; + (void)decoder; + if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC) + stream_data->abort_flag = true; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,24 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 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. + */ + +#ifndef FLAC__PLUGIN_XMMS__PLUGIN_H +#define FLAC__PLUGIN_XMMS__PLUGIN_H + +void set_track_info(const char* title, int length_in_msec); + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/Makefile Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,28 @@ +include ../../../mk/rules.mk +include ../../../mk/init.mk + +CFLAGS += $(PICFLAGS) -I.. -I../../.. + +OBJECTIVE_LIBS_NOINST = libplugin_common.a + +noinst_HEADERS = \ + all.h \ + charset.h \ + defs.h \ + dither.h \ + locale_hack.h \ + tags.h \ + replaygain.h + +SOURCES = \ + charset.c \ + dither.c \ + tags.c \ + replaygain.c + +OBJECTS = ${SOURCES:.c=.o} + +libplugin_common.a: $(OBJECTS) + $(AR) cq $@ $(OBJECTS) + +include ../../../mk/objective.mk diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/all.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/all.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,27 @@ +/* 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. + */ + +#ifndef FLAC__PLUGIN_COMMON__ALL_H +#define FLAC__PLUGIN_COMMON__ALL_H + +#include "charset.h" +#include "dither.h" +#include "locale_hack.h" +#include "tags.h" + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/charset.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/charset.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,156 @@ +/* plugin_common - Routines common to several plugins + * Copyright (C) 2002,2003,2004,2005 Josh Coalson + * + * Only slightly modified charset.c from: + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 Håvard Kvålen + * + * 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. + */ + +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_ICONV +#include +#endif + +#ifdef HAVE_LANGINFO_CODESET +#include +#endif + +#include "charset.h" + + +/************* + * Functions * + *************/ + +char* FLAC_plugin__charset_get_current (void) +{ + char *charset = getenv("CHARSET"); + +#ifdef HAVE_LANGINFO_CODESET + if (!charset) + charset = nl_langinfo(CODESET); +#endif + + if (charset) + return strdup(charset); + + return strdup("ISO-8859-1"); +} + + +#ifdef HAVE_ICONV +char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) +{ + size_t outleft, outsize, length; + iconv_t cd; + char *out, *outptr; + const char *input = string; + + if (!string) + return NULL; + + length = strlen(string); + + if ((cd = iconv_open(to, from)) == (iconv_t)-1) + { +#ifdef DEBUG + fprintf(stderr, "convert_string(): Conversion not supported. Charsets: %s -> %s", from, to); +#endif + return strdup(string); + } + + /* Due to a GLIBC bug, round outbuf_size up to a multiple of 4 */ + /* + 1 for nul in case len == 1 */ + outsize = ((length + 3) & ~3) + 1; + out = (char*)malloc(outsize); + outleft = outsize - 1; + outptr = out; + +retry: +#if defined __OpenBSD__ || defined __NetBSD__ + if (iconv(cd, &input, &length, &outptr, &outleft) == (size_t)-1) +#else + if (iconv(cd, (char**)&input, &length, &outptr, &outleft) == (size_t)-1) +#endif + { + int used; + switch (errno) + { + case E2BIG: + used = outptr - out; + outsize = (outsize - 1) * 2 + 1; + out = realloc(out, outsize); + outptr = out + used; + outleft = outsize - 1 - used; + goto retry; + case EINVAL: + break; + case EILSEQ: + /* Invalid sequence, try to get the rest of the string */ + input++; + length = strlen(input); + goto retry; + default: +#ifdef DEBUG + fprintf(stderr, "convert_string(): Conversion failed. Inputstring: %s; Error: %s", string, strerror(errno)); +#endif + break; + } + } + *outptr = '\0'; + + iconv_close(cd); + return out; +} +#else +char* FLAC_plugin__charset_convert_string (const char *string, char *from, char *to) +{ + (void)from, (void)to; + if (!string) + return NULL; + return strdup(string); +} +#endif + +#ifdef HAVE_ICONV +int FLAC_plugin__charset_test_conversion (char *from, char *to) +{ + iconv_t cd; + + if ((cd=iconv_open(to,from)) == (iconv_t)-1) + { + /* Conversion not supported */ + return 0; + } + iconv_close(cd); + return 1; +} +#else +int FLAC_plugin__charset_test_conversion (char *from, char *to) +{ + (void)from, (void)to; + return 1; +} +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/charset.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/charset.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,39 @@ +/* plugin_common - Routines common to several plugins + * Copyright (C) 2002,2003,2004,2005 Josh Coalson + * + * Only slightly modified charset.h from: + * charset.h - 2001/12/04 + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 H蛆ard Kvè™±en + * + * 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. + */ + + +#ifndef FLAC__PLUGIN_COMMON__CHARSET_H +#define FLAC__PLUGIN_COMMON__CHARSET_H + + +/************** + * Prototypes * + **************/ + +char *FLAC_plugin__charset_get_current(); +char *FLAC_plugin__charset_convert_string(const char *string, char *from, char *to); + +/* returns 1 for success, 0 for failure or no iconv */ +int FLAC_plugin__charset_test_conversion(char *from, char *to); + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/defs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/defs.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,24 @@ +/* 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. + */ + +#ifndef FLAC__PLUGIN_COMMON__DEFS_H +#define FLAC__PLUGIN_COMMON__DEFS_H + +#define FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS 2 + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/dither.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/dither.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,260 @@ +/* plugin_common - Routines common to several plugins + * Copyright (C) 2002,2003,2004,2005 Josh Coalson + * + * dithering routine derived from (other GPLed source): + * mad - MPEG audio decoder + * Copyright (C) 2000-2001 Robert Leslie + * + * 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. + */ + +#include "dither.h" +#include "FLAC/assert.h" + +#ifdef max +#undef max +#endif +#define max(a,b) ((a)>(b)?(a):(b)) + + +#if defined _MSC_VER +#define FLAC__INLINE __inline +#else +#define FLAC__INLINE +#endif + +/* 32-bit pseudo-random number generator + * + * @@@ According to Miroslav, this one is poor quality, the one from the + * @@@ original replaygain code is much better + */ +static FLAC__INLINE FLAC__uint32 prng(FLAC__uint32 state) +{ + return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL; +} + +/* dither routine derived from MAD winamp plugin */ + +typedef struct { + FLAC__int32 error[3]; + FLAC__int32 random; +} dither_state; + +static FLAC__INLINE FLAC__int32 linear_dither(unsigned source_bps, unsigned target_bps, FLAC__int32 sample, dither_state *dither, const FLAC__int32 MIN, const FLAC__int32 MAX) +{ + unsigned scalebits; + FLAC__int32 output, mask, random; + + FLAC__ASSERT(source_bps < 32); + FLAC__ASSERT(target_bps <= 24); + FLAC__ASSERT(target_bps <= source_bps); + + /* noise shape */ + sample += dither->error[0] - dither->error[1] + dither->error[2]; + + dither->error[2] = dither->error[1]; + dither->error[1] = dither->error[0] / 2; + + /* bias */ + output = sample + (1L << (source_bps - target_bps - 1)); + + scalebits = source_bps - target_bps; + mask = (1L << scalebits) - 1; + + /* dither */ + random = (FLAC__int32)prng(dither->random); + output += (random & mask) - (dither->random & mask); + + dither->random = random; + + /* clip */ + if(output > MAX) { + output = MAX; + + if(sample > MAX) + sample = MAX; + } + else if(output < MIN) { + output = MIN; + + if(sample < MIN) + sample = MIN; + } + + /* quantize */ + output &= ~mask; + + /* error feedback */ + dither->error[0] = sample - output; + + /* scale */ + return output >> scalebits; +} + +size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps) +{ + static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS]; + FLAC__byte * const start = data; + FLAC__int32 sample; + const FLAC__int32 *input_; + unsigned samples, channel; + const unsigned bytes_per_sample = target_bps / 8; + const unsigned incr = bytes_per_sample * channels; + + FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS); + FLAC__ASSERT(source_bps < 32); + FLAC__ASSERT(target_bps <= 24); + FLAC__ASSERT(target_bps <= source_bps); + FLAC__ASSERT((source_bps & 7) == 0); + FLAC__ASSERT((target_bps & 7) == 0); + + if(source_bps != target_bps) { + const FLAC__int32 MIN = -(1L << (source_bps - 1)); + const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */ + + for(channel = 0; channel < channels; channel++) { + + samples = wide_samples; + data = start + bytes_per_sample * channel; + input_ = input[channel]; + + while(samples--) { + sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX); + + switch(target_bps) { + case 8: + data[0] = sample ^ 0x80; + break; + case 16: + data[0] = (FLAC__byte)(sample >> 8); + data[1] = (FLAC__byte)sample; + break; + case 24: + data[0] = (FLAC__byte)(sample >> 16); + data[1] = (FLAC__byte)(sample >> 8); + data[2] = (FLAC__byte)sample; + break; + } + + data += incr; + } + } + } + else { + for(channel = 0; channel < channels; channel++) { + samples = wide_samples; + data = start + bytes_per_sample * channel; + input_ = input[channel]; + + while(samples--) { + sample = *input_++; + + switch(target_bps) { + case 8: + data[0] = sample ^ 0x80; + break; + case 16: + data[0] = (FLAC__byte)(sample >> 8); + data[1] = (FLAC__byte)sample; + break; + case 24: + data[0] = (FLAC__byte)(sample >> 16); + data[1] = (FLAC__byte)(sample >> 8); + data[2] = (FLAC__byte)sample; + break; + } + + data += incr; + } + } + } + + return wide_samples * channels * (target_bps/8); +} + +size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps) +{ + static dither_state dither[FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS]; + FLAC__byte * const start = data; + FLAC__int32 sample; + const FLAC__int32 *input_; + unsigned samples, channel; + const unsigned bytes_per_sample = target_bps / 8; + const unsigned incr = bytes_per_sample * channels; + + FLAC__ASSERT(channels > 0 && channels <= FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS); + FLAC__ASSERT(source_bps < 32); + FLAC__ASSERT(target_bps <= 24); + FLAC__ASSERT(target_bps <= source_bps); + FLAC__ASSERT((source_bps & 7) == 0); + FLAC__ASSERT((target_bps & 7) == 0); + + if(source_bps != target_bps) { + const FLAC__int32 MIN = -(1L << (source_bps - 1)); + const FLAC__int32 MAX = ~MIN; /*(1L << (source_bps-1)) - 1 */ + + for(channel = 0; channel < channels; channel++) { + + samples = wide_samples; + data = start + bytes_per_sample * channel; + input_ = input[channel]; + + while(samples--) { + sample = linear_dither(source_bps, target_bps, *input_++, &dither[channel], MIN, MAX); + + switch(target_bps) { + case 8: + data[0] = sample ^ 0x80; + break; + case 24: + data[2] = (FLAC__byte)(sample >> 16); + /* fall through */ + case 16: + data[1] = (FLAC__byte)(sample >> 8); + data[0] = (FLAC__byte)sample; + } + + data += incr; + } + } + } + else { + for(channel = 0; channel < channels; channel++) { + samples = wide_samples; + data = start + bytes_per_sample * channel; + input_ = input[channel]; + + while(samples--) { + sample = *input_++; + + switch(target_bps) { + case 8: + data[0] = sample ^ 0x80; + break; + case 24: + data[2] = (FLAC__byte)(sample >> 16); + /* fall through */ + case 16: + data[1] = (FLAC__byte)(sample >> 8); + data[0] = (FLAC__byte)sample; + } + + data += incr; + } + } + } + + return wide_samples * channels * (target_bps/8); +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/dither.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/dither.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef FLAC__PLUGIN_COMMON__DITHER_H +#define FLAC__PLUGIN_COMMON__DITHER_H + +#include /* for size_t */ +#include "defs.h" /* buy FLAC_PLUGIN__MAX_SUPPORTED_CHANNELS for the caller */ +#include "FLAC/ordinals.h" + +size_t FLAC__plugin_common__pack_pcm_signed_big_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps); +size_t FLAC__plugin_common__pack_pcm_signed_little_endian(FLAC__byte *data, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, unsigned source_bps, unsigned target_bps); + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/locale_hack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/locale_hack.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,55 @@ +/* plugin_common - Routines common to several plugins + * Copyright (C) 2002,2003,2004,2005 Josh Coalson + * + * Based on: + * locale.h - 2000/05/05 13:10 Jerome Couderc + * EasyTAG - Tag editor for MP3 and OGG files + * Copyright (C) 1999-2001 H蛆ard Kvè™±en + * + * 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. + */ +/* + * Gettext support for EasyTAG + */ + + +#ifndef FLAC__PLUGIN_COMMON__LOCALE_HACK_H +#define FLAC__PLUGIN_COMMON__LOCALE_HACK_H + +#include + +/* + * Standard gettext macros. + */ +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/replaygain.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/replaygain.c Mon Oct 23 19:51:39 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 +#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; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/replaygain.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/replaygain.h Mon Oct 23 19:51:39 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 diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/tags.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/tags.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,307 @@ +/* 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. + */ + +#include +#include +#include + +#include "tags.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" + + +static __inline unsigned local__wide_strlen(const FLAC__uint16 *s) +{ + unsigned n = 0; + while(*s++) + n++; + return n; +} + +static __inline unsigned local__utf8len(const FLAC__byte *utf8) +{ + FLAC__ASSERT(0 != utf8); + if ((utf8[0] & 0x80) == 0) + return 1; + else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) + return 2; + else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) + return 3; + else + return 0; +} + +static __inline unsigned local__utf8_to_ucs2(const FLAC__byte *utf8, FLAC__uint16 *ucs2) +{ + const unsigned len = local__utf8len(utf8); + + FLAC__ASSERT(0 != ucs2); + + if (len == 1) + *ucs2 = *utf8; + else if (len == 2) + *ucs2 = (*utf8 & 0x3F)<<6 | (*(utf8+1) & 0x3F); + else if (len == 3) + *ucs2 = (*utf8 & 0x1F)<<12 | (*(utf8+1) & 0x3F)<<6 | (*(utf8+2) & 0x3F); + + return len; +} + +static FLAC__uint16 *local__convert_utf8_to_ucs2(const char *src, unsigned length) +{ + FLAC__uint16 *out; + unsigned chars = 0; + + FLAC__ASSERT(0 != src); + + /* calculate length */ + { + const char *s, *end; + for (s=src, end=src+length; s> 6); + utf8[1] = 0x80 | (ucs2 & 0x3f); + return 2; + } + else { + utf8[0] = 0xe0 | (ucs2 >> 12); + utf8[1] = 0x80 | ((ucs2 >> 6) & 0x3f); + utf8[2] = 0x80 | (ucs2 & 0x3f); + return 3; + } +} + +static char *local__convert_ucs2_to_utf8(const FLAC__uint16 *src, unsigned length) +{ + char *out; + unsigned len = 0; + + FLAC__ASSERT(0 != src); + + /* calculate length */ + { + unsigned i; + for (i = 0; i < length; i++) + len += local__ucs2len(src[i]); + } + + /* allocate */ + out = (char*)malloc(len * sizeof(char)); + if (0 == out) + return 0; + + /* convert */ + { + unsigned char *u = (unsigned char*) out; + for ( ; *src; src++) + u += local__ucs2_to_utf8(*src, u); + local__ucs2_to_utf8(*src, u); + } + + return out; +} + + +FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags) +{ + if(!FLAC__metadata_get_tags(filename, tags)) + if(0 == (*tags = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT))) + return false; + return true; +} + +FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags) +{ + FLAC__Metadata_Chain *chain; + FLAC__Metadata_Iterator *iterator; + FLAC__StreamMetadata *block; + FLAC__bool got_vorbis_comments = false; + FLAC__bool ok; + + if(0 == (chain = FLAC__metadata_chain_new())) + return false; + + if(!FLAC__metadata_chain_read(chain, filename)) { + FLAC__metadata_chain_delete(chain); + return false; + } + + if(0 == (iterator = FLAC__metadata_iterator_new())) { + FLAC__metadata_chain_delete(chain); + return false; + } + + FLAC__metadata_iterator_init(iterator, chain); + + do { + if(FLAC__metadata_iterator_get_block_type(iterator) == FLAC__METADATA_TYPE_VORBIS_COMMENT) + got_vorbis_comments = true; + } while(!got_vorbis_comments && FLAC__metadata_iterator_next(iterator)); + + if(0 == (block = FLAC__metadata_object_clone(tags))) { + FLAC__metadata_chain_delete(chain); + FLAC__metadata_iterator_delete(iterator); + return false; + } + + if(got_vorbis_comments) + ok = FLAC__metadata_iterator_set_block(iterator, block); + else + ok = FLAC__metadata_iterator_insert_block_after(iterator, block); + + FLAC__metadata_iterator_delete(iterator); + + if(ok) { + FLAC__metadata_chain_sort_padding(chain); + ok = FLAC__metadata_chain_write(chain, /*use_padding=*/true, /*preserve_file_stats=*/true); + } + + FLAC__metadata_chain_delete(chain); + + return ok; +} + +void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags) +{ + FLAC__metadata_object_delete(*tags); + *tags = 0; +} + +const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name) +{ + const int i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name); + return (i < 0? 0 : strchr((const char*)tags->data.vorbis_comment.comments[i].entry, '=')+1); +} + +FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name) +{ + const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name); + if(0 == utf8) + return 0; + return local__convert_utf8_to_ucs2(utf8, strlen(utf8)+1); /* +1 for terminating null */ +} + +int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name) +{ + return FLAC__metadata_object_vorbiscomment_remove_entries_matching(tags, name); +} + +int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags) +{ + int n = (int)tags->data.vorbis_comment.num_comments; + if(n > 0) { + if(!FLAC__metadata_object_vorbiscomment_resize_comments(tags, 0)) + n = -1; + } + return n; +} + +FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator) +{ + int i; + + FLAC__ASSERT(0 != tags); + FLAC__ASSERT(0 != name); + FLAC__ASSERT(0 != value); + + if(separator && (i = FLAC__metadata_object_vorbiscomment_find_entry_from(tags, /*offset=*/0, name)) >= 0) { + FLAC__StreamMetadata_VorbisComment_Entry *entry = tags->data.vorbis_comment.comments+i; + const size_t value_len = strlen(value); + const size_t separator_len = strlen(separator); + FLAC__byte *new_entry; + if(0 == (new_entry = (FLAC__byte*)realloc(entry->entry, entry->length + value_len + separator_len + 1))) + return false; + memcpy(new_entry+entry->length, separator, separator_len); + entry->length += separator_len; + memcpy(new_entry+entry->length, value, value_len); + entry->length += value_len; + new_entry[entry->length] = '\0'; + entry->entry = new_entry; + } + else { + FLAC__StreamMetadata_VorbisComment_Entry entry; + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, value)) + return false; + FLAC__metadata_object_vorbiscomment_append_comment(tags, entry, /*copy=*/false); + } + return true; +} + +FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all) +{ + FLAC__StreamMetadata_VorbisComment_Entry entry; + + FLAC__ASSERT(0 != tags); + FLAC__ASSERT(0 != name); + FLAC__ASSERT(0 != value); + + { + char *utf8 = local__convert_ucs2_to_utf8(value, local__wide_strlen(value)+1); /* +1 for the terminating null */ + if(0 == utf8) + return false; + if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, name, utf8)) { + free(utf8); + return false; + } + free(utf8); + } + if(!FLAC__metadata_object_vorbiscomment_replace_comment(tags, entry, replace_all, /*copy=*/false)) + return false; + return true; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/plugin_common/tags.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/plugin_common/tags.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,74 @@ +/* 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. + */ + +#ifndef FLAC__PLUGIN_COMMON__TAGS_H +#define FLAC__PLUGIN_COMMON__TAGS_H + +#include "FLAC/format.h" + +FLAC__bool FLAC_plugin__tags_get(const char *filename, FLAC__StreamMetadata **tags); +FLAC__bool FLAC_plugin__tags_set(const char *filename, const FLAC__StreamMetadata *tags); + +/* + * Deletes the tags object and sets '*tags' to NULL. + */ +void FLAC_plugin__tags_destroy(FLAC__StreamMetadata **tags); + +/* + * Gets the value (in UTF-8) of the first tag with the given name (NULL if no + * such tag exists). + */ +const char *FLAC_plugin__tags_get_tag_utf8(const FLAC__StreamMetadata *tags, const char *name); + +/* + * Gets the value (in UCS-2) of the first tag with the given name (NULL if no + * such tag exists). + * + * NOTE: the returned string is malloc()ed and must be free()d by the caller. + */ +FLAC__uint16 *FLAC_plugin__tags_get_tag_ucs2(const FLAC__StreamMetadata *tags, const char *name); + +/* + * Removes all tags with the given 'name'. Returns the number of tags removed, + * or -1 on memory allocation error. + */ +int FLAC_plugin__tags_delete_tag(FLAC__StreamMetadata *tags, const char *name); + +/* + * Removes all tags. Returns the number of tags removed, or -1 on memory + * allocation error. + */ +int FLAC_plugin__tags_delete_all(FLAC__StreamMetadata *tags); + +/* + * Adds a "name=value" tag to the tags. 'value' must be in UTF-8. If + * 'separator' is non-NULL and 'tags' already contains a tag for 'name', the + * first such tag's value is appended with separator, then value. + */ +FLAC__bool FLAC_plugin__tags_add_tag_utf8(FLAC__StreamMetadata *tags, const char *name, const char *value, const char *separator); + +/* + * Adds a "name=value" tag to the tags. 'value' must be in UCS-2. If 'tags' + * already contains a tag or tags for 'name', then they will be replaced + * according to 'replace_all': if 'replace_all' is false, only the first such + * tag will be replaced; if true, all matching tags will be replaced by the one + * new tag. + */ +FLAC__bool FLAC_plugin__tags_set_tag_ucs2(FLAC__StreamMetadata *tags, const char *name, const FLAC__uint16 *value, FLAC__bool replace_all); + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/replaygain.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/replaygain.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,665 @@ +/* grabbag - Convenience lib for various routines common to several tools + * 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 + * 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. + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include "grabbag.h" +#include "replaygain_analysis.h" +#include "FLAC/assert.h" +#include "FLAC/metadata.h" +#include "FLAC/stream_decoder.h" +#include +#include +#include +#include +#include +#if defined _MSC_VER || defined __MINGW32__ +#include /* for chmod() */ +#endif +#include /* for stat(), maybe chmod() */ + +#ifdef local_min +#undef local_min +#endif +#define local_min(a,b) ((a)<(b)?(a):(b)) + +#ifdef local_max +#undef local_max +#endif +#define local_max(a,b) ((a)>(b)?(a):(b)) + +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 double album_peak_, title_peak_; + +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) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + return (0 == stat(filename, stats)); +} + +static void set_file_stats_(const char *filename, struct stat *stats) +{ + FLAC__ASSERT(0 != filename); + FLAC__ASSERT(0 != stats); + + (void)chmod(filename, stats->st_mode); +} + +static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value) +{ + char buffer[256]; + char *saved_locale; + FLAC__StreamMetadata_VorbisComment_Entry entry; + + FLAC__ASSERT(0 != block); + FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + FLAC__ASSERT(0 != format); + FLAC__ASSERT(0 != name); + + buffer[sizeof(buffer)-1] = '\0'; + /* + * We need to save the old locale and switch to "C" because the locale + * influences the formatting of %f and we want it a certain way. + */ + saved_locale = setlocale(LC_ALL, 0); + setlocale(LC_ALL, "C"); +#if defined _MSC_VER || defined __MINGW32__ + _snprintf(buffer, sizeof(buffer)-1, format, name, value); +#else + snprintf(buffer, sizeof(buffer)-1, format, name, value); +#endif + setlocale(LC_ALL, saved_locale); + + entry.entry = (FLAC__byte *)buffer; + entry.length = strlen(buffer); + + return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true); +} + +FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency) +{ + static const unsigned valid_sample_rates[] = { + 8000, + 11025, + 12000, + 16000, + 22050, + 24000, + 32000, + 44100, + 48000 + }; + static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]); + + unsigned i; + + for(i = 0; i < n_valid_sample_rates; i++) + if(sample_frequency == valid_sample_rates[i]) + return true; + return false; +} + +FLAC__bool grabbag__replaygain_init(unsigned sample_frequency) +{ + title_peak_ = album_peak_ = 0.0; + return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK; +} + +FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples) +{ + /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */ + static Float_t lbuffer[2048], rbuffer[2048]; + static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]); + FLAC__int32 block_peak = 0, s; + unsigned i, j; + + FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE); + FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4); + /* + * We use abs() on a FLAC__int32 which is undefined for the most negative value. + * If the reference codec ever handles 32bps we will have to write a special + * case here. + */ + FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32); + + if(bps == 16) { + if(is_stereo) { + j = 0; + while(samples > 0) { + const unsigned n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (Float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + + s = input[1][j]; + rbuffer[i] = (Float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) + return false; + } + } + else { + j = 0; + while(samples > 0) { + const unsigned n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (Float_t)s; + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) + return false; + } + } + } + else { /* bps must be < 32 according to above assertion */ + const double scale = ( + (bps > 16)? + (double)1. / (double)(1u << (bps - 16)) : + (double)(1u << (16 - bps)) + ); + + if(is_stereo) { + j = 0; + while(samples > 0) { + const unsigned n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (Float_t)(scale * (double)s); + s = abs(s); + block_peak = local_max(block_peak, s); + + s = input[1][j]; + rbuffer[i] = (Float_t)(scale * (double)s); + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK) + return false; + } + } + else { + j = 0; + while(samples > 0) { + const unsigned n = local_min(samples, nbuffer); + for(i = 0; i < n; i++, j++) { + s = input[0][j]; + lbuffer[i] = (Float_t)(scale * (double)s); + s = abs(s); + block_peak = local_max(block_peak, s); + } + samples -= n; + if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK) + return false; + } + } + } + + { + const double peak_scale = (double)(1u << (bps - 1)); + double peak = (double)block_peak / peak_scale; + if(peak > title_peak_) + title_peak_ = peak; + if(peak > album_peak_) + album_peak_ = peak; + } + + return true; +} + +void grabbag__replaygain_get_album(float *gain, float *peak) +{ + *gain = (float)GetAlbumGain(); + *peak = (float)album_peak_; + album_peak_ = 0.0; +} + +void grabbag__replaygain_get_title(float *gain, float *peak) +{ + *gain = (float)GetTitleGain(); + *peak = (float)title_peak_; + title_peak_ = 0.0; +} + + +typedef struct { + unsigned channels; + unsigned bits_per_sample; + unsigned sample_rate; + FLAC__bool error; +} DecoderInstance; + +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; + const unsigned channels = frame->header.channels; + const unsigned sample_rate = frame->header.sample_rate; + const unsigned samples = frame->header.blocksize; + + (void)decoder; + + if( + !instance->error && + (channels == 2 || channels == 1) && + bits_per_sample == instance->bits_per_sample && + channels == instance->channels && + sample_rate == instance->sample_rate + ) { + instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples); + } + else { + instance->error = true; + } + + if(!instance->error) + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; + else + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; +} + +static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + DecoderInstance *instance = (DecoderInstance*)client_data; + + (void)decoder; + + if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + instance->bits_per_sample = metadata->data.stream_info.bits_per_sample; + instance->channels = metadata->data.stream_info.channels; + instance->sample_rate = metadata->data.stream_info.sample_rate; + + if(instance->channels != 1 && instance->channels != 2) { + instance->error = true; + return; + } + + if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) { + instance->error = true; + return; + } + } +} + +static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) +{ + DecoderInstance *instance = (DecoderInstance*)client_data; + + (void)decoder, (void)status; + + instance->error = true; +} + +const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak) +{ + DecoderInstance instance; + FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); + + if(0 == decoder) + return "memory allocation error"; + + instance.error = false; + + /* It does these three by default but lets be explicit: */ + 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); + + 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__stream_decoder_process_until_end_of_stream(decoder) || instance.error) { + FLAC__stream_decoder_delete(decoder); + return "decoding file"; + } + + FLAC__stream_decoder_delete(decoder); + + grabbag__replaygain_get_title(title_gain, title_peak); + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak) +{ + 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; + + if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) + return error; + + 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 *)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, 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"; + + return 0; +} + +const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_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 *)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, 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"; + + return 0; +} + +static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block) +{ + FLAC__Metadata_Iterator *iterator; + const char *error; + FLAC__bool found_vc_block = false; + + if(0 == (*chain = FLAC__metadata_chain_new())) + return "memory allocation error"; + + if(!FLAC__metadata_chain_read(*chain, filename)) { + error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; + FLAC__metadata_chain_delete(*chain); + return error; + } + + if(0 == (iterator = FLAC__metadata_iterator_new())) { + FLAC__metadata_chain_delete(*chain); + return "memory allocation error"; + } + + FLAC__metadata_iterator_init(iterator, *chain); + + do { + *block = FLAC__metadata_iterator_get_block(iterator); + if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) + found_vc_block = true; + } while(!found_vc_block && FLAC__metadata_iterator_next(iterator)); + + if(!found_vc_block) { + /* create a new block */ + *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + if(0 == *block) { + FLAC__metadata_chain_delete(*chain); + FLAC__metadata_iterator_delete(iterator); + return "memory allocation error"; + } + while(FLAC__metadata_iterator_next(iterator)) + ; + if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) { + error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)]; + FLAC__metadata_chain_delete(*chain); + FLAC__metadata_iterator_delete(iterator); + return error; + } + /* iterator is left pointing to new block */ + FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block); + } + + FLAC__metadata_iterator_delete(iterator); + + FLAC__ASSERT(0 != *block); + FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT); + + return 0; +} + +static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime) +{ + struct stat stats; + const FLAC__bool have_stats = get_file_stats_(filename, &stats); + + (void)grabbag__file_change_stats(filename, /*read_only=*/false); + + FLAC__metadata_chain_sort_padding(chain); + if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) { + FLAC__metadata_chain_delete(chain); + return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)]; + } + + FLAC__metadata_chain_delete(chain); + + if(have_stats) + set_file_stats_(filename, &stats); + + return 0; +} + +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) +{ + 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(block, album_gain, album_peak, title_gain, title_peak))) { + 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_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; + 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_album(block, album_gain, album_peak))) { + 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_title(const char *filename, float title_gain, float title_peak, 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_title(block, title_gain, title_peak))) { + FLAC__metadata_chain_delete(chain); + return error; + } + + if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime))) + return error; + + return 0; +} + +static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val) +{ + char s[32], *end; + const char *p, *q; + double v; + + FLAC__ASSERT(0 != entry); + FLAC__ASSERT(0 != val); + + p = (const char *)entry->entry; + q = strchr(p, '='); + if(0 == q) + return false; + q++; + memset(s, 0, sizeof(s)-1); + strncpy(s, q, local_min(sizeof(s)-1, entry->length - (q-p))); + + v = strtod(s, &end); + if(end == s) + return false; + + *val = v; + return true; +} + +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 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); + + /* 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 !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 !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak); + + return true; +} + +double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping) +{ + double scale; + FLAC__ASSERT(peak >= 0.0); + gain += preamp; + scale = (float) pow(10.0, gain * 0.05); + if(prevent_clipping && peak > 0.0) { + const double max_scale = (float)(1.0 / peak); + if(scale > max_scale) + scale = max_scale; + } + return scale; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/replaygain_analysis.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/replaygain_analysis.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,419 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * original coding by Glen Sawyer (glensawyer@hotmail.com) + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * + * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ ) + * -- credit him for all the _good_ programming ;) + * + * minor cosmetic tweaks to integrate with FLAC by Josh Coalson + * + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +/* + * Here's the deal. Call + * + * InitGainAnalysis ( long samplefreq ); + * + * to initialize everything. Call + * + * AnalyzeSamples ( const Float_t* left_samples, + * const Float_t* right_samples, + * size_t num_samples, + * int num_channels ); + * + * as many times as you want, with as many or as few samples as you want. + * If mono, pass the sample buffer in through left_samples, leave + * right_samples NULL, and make sure num_channels = 1. + * + * GetTitleGain() + * + * will return the recommended dB level change for all samples analyzed + * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis(). + * + * GetAlbumGain() + * + * will return the recommended dB level change for all samples analyzed + * since InitGainAnalysis() was called and finalized with GetTitleGain(). + * + * Pseudo-code to process an album: + * + * Float_t l_samples [4096]; + * Float_t r_samples [4096]; + * size_t num_samples; + * unsigned int num_songs; + * unsigned int i; + * + * InitGainAnalysis ( 44100 ); + * for ( i = 1; i <= num_songs; i++ ) { + * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 ) + * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 ); + * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() ); + * } + * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() ); + */ + +/* + * So here's the main source of potential code confusion: + * + * The filters applied to the incoming samples are IIR filters, + * meaning they rely on up to number of previous samples + * AND up to number of previous filtered samples. + * + * I set up the AnalyzeSamples routine to minimize memory usage and interface + * complexity. The speed isn't compromised too much (I don't think), but the + * internal complexity is higher than it should be for such a relatively + * simple routine. + * + * Optimization/clarity suggestions are welcome. + */ + +#if HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "replaygain_analysis.h" + +Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */ + +typedef unsigned short Uint16_t; +typedef signed short Int16_t; +typedef unsigned int Uint32_t; +typedef signed int Int32_t; + +#define YULE_ORDER 10 +#define BUTTER_ORDER 2 +#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */ +#define MAX_SAMP_FREQ 48000. /* maximum allowed sample frequency [Hz] */ +#define RMS_WINDOW_TIME 0.050 /* Time slice size [s] */ +#define STEPS_per_dB 100. /* Table entries per dB */ +#define MAX_dB 120. /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */ + +#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER) +/* [JEC] the following was originally #defined as: + * (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME) + * but that seemed to fail to take into account the ceil() part of the + * sampleWindow calculation in ResetSampleFrequency(), and was causing + * buffer overflows for 48kHz analysis, hence the +1. + */ +#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.) /* max. Samples per Time slice */ +#define PINK_REF 64.82 /* 298640883795 */ /* calibration value */ + +static Float_t linprebuf [MAX_ORDER * 2]; +static Float_t* linpre; /* left input samples, with pre-buffer */ +static Float_t lstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; +static Float_t* lstep; /* left "first step" (i.e. post first filter) samples */ +static Float_t loutbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; +static Float_t* lout; /* left "out" (i.e. post second filter) samples */ +static Float_t rinprebuf [MAX_ORDER * 2]; +static Float_t* rinpre; /* right input samples ... */ +static Float_t rstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; +static Float_t* rstep; +static Float_t routbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER]; +static Float_t* rout; +static unsigned int sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */ +static unsigned long totsamp; +static double lsum; +static double rsum; +static int freqindex; +static Uint32_t A [(size_t)(STEPS_per_dB * MAX_dB)]; +static Uint32_t B [(size_t)(STEPS_per_dB * MAX_dB)]; + +/* for each filter: + [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */ + +#ifdef WIN32 +#pragma warning ( disable : 4305 ) +#endif + +static const Float_t AYule [9] [11] = { + { 1., -3.84664617118067, 7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294, 9.48293806319790, -5.87257861775999, 2.75465861874613, -0.86984376593551, 0.13919314567432 }, + { 1., -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280, -8.81498681370155, 6.85401540936998, -4.39470996079559, 2.19611684890774, -0.75104302451432, 0.13149317958808 }, + { 1., -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713, -1.67148153367602, 1.00595954808547, -0.45953458054983, 0.16378164858596, -0.05032077717131, 0.02347897407020 }, + { 1., -1.61273165137247, 1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906, 0.39120800788284, -0.22138138954925, 0.04500235387352, 0.02005851806501, 0.00302439095741 }, + { 1., -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438, 0.47854794562326, -0.12453458140019, -0.04067510197014, 0.08333755284107, -0.04237348025746, 0.02977207319925 }, + { 1., -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124, -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683, 0.05784820375801, 0.03222754072173 }, + { 1., -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858, 0.45054734505008, -0.33032403314006, 0.06739368333110, -0.04784254229033, 0.01639907836189, 0.01807364323573 }, + { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477, 0.14728154134330, 0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053, 0.02442357316099, 0.01818801111503 }, + { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242, 0.26408300200955, 0.15113130533216, -0.17556493366449, -0.18823009262115, 0.05477720428674, 0.04704409688120 } +}; + +static const Float_t BYule [9] [11] = { + { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619, 0.02161526843274, -0.02074045215285, 0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916 }, + { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936, 0.02245293253339, -0.02596338512915, 0.01624864962975, -0.00240879051584, 0.00674613682247, -0.00187763777362 }, + { 0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798, -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049, -0.01390589421898, 0.00651420667831, -0.00881362733839 }, + { 0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913, 0.06276101321749, -0.00000828086748, 0.00205861885564, -0.02950134983287 }, + { 0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440, 0.05724228140351, 0.00832043980773, -0.01635381384540, -0.01760176568150 }, + { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551, 0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251, -0.01863887810927, -0.03193428438915, 0.00541907748707 }, + { 0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672, -0.18901604199609, 0.30931782841830, -0.27562961986224, 0.00647310677246, 0.08647503780351, -0.03788984554840, -0.00588215443421 }, + { 0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522, 0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333, 0.06920467763959, -0.03721611395801, -0.00749618797172 }, + { 0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415, -0.10214864179676, 0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000, 0.04788665548180, -0.02217936801134 } +}; + +static const Float_t AButter [9] [3] = { + { 1., -1.97223372919527, 0.97261396931306 }, + { 1., -1.96977855582618, 0.97022847566350 }, + { 1., -1.95835380975398, 0.95920349965459 }, + { 1., -1.95002759149878, 0.95124613669835 }, + { 1., -1.94561023566527, 0.94705070426118 }, + { 1., -1.92783286977036, 0.93034775234268 }, + { 1., -1.91858953033784, 0.92177618768381 }, + { 1., -1.91542108074780, 0.91885558323625 }, + { 1., -1.88903307939452, 0.89487434461664 } +}; + +static const Float_t BButter [9] [3] = { + { 0.98621192462708, -1.97242384925416, 0.98621192462708 }, + { 0.98500175787242, -1.97000351574484, 0.98500175787242 }, + { 0.97938932735214, -1.95877865470428, 0.97938932735214 }, + { 0.97531843204928, -1.95063686409857, 0.97531843204928 }, + { 0.97316523498161, -1.94633046996323, 0.97316523498161 }, + { 0.96454515552826, -1.92909031105652, 0.96454515552826 }, + { 0.96009142950541, -1.92018285901082, 0.96009142950541 }, + { 0.95856916599601, -1.91713833199203, 0.95856916599601 }, + { 0.94597685600279, -1.89195371200558, 0.94597685600279 } +}; + +#ifdef WIN32 +#pragma warning ( default : 4305 ) +#endif + +/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */ + +static void +filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order ) +{ + double y; + size_t i; + size_t k; + + for ( i = 0; i < nSamples; i++ ) { + y = input[i] * b[0]; + for ( k = 1; k <= order; k++ ) + y += input[i-k] * b[k] - output[i-k] * a[k]; + output[i] = (Float_t)y; + } +} + +/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */ + +int +ResetSampleFrequency ( long samplefreq ) { + int i; + + /* zero out initial values */ + for ( i = 0; i < MAX_ORDER; i++ ) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.; + + switch ( (int)(samplefreq) ) { + case 48000: freqindex = 0; break; + case 44100: freqindex = 1; break; + case 32000: freqindex = 2; break; + case 24000: freqindex = 3; break; + case 22050: freqindex = 4; break; + case 16000: freqindex = 5; break; + case 12000: freqindex = 6; break; + case 11025: freqindex = 7; break; + case 8000: freqindex = 8; break; + default: return INIT_GAIN_ANALYSIS_ERROR; + } + + sampleWindow = (int) ceil (samplefreq * RMS_WINDOW_TIME); + + lsum = 0.; + rsum = 0.; + totsamp = 0; + + memset ( A, 0, sizeof(A) ); + + return INIT_GAIN_ANALYSIS_OK; +} + +int +InitGainAnalysis ( long samplefreq ) +{ + if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) { + return INIT_GAIN_ANALYSIS_ERROR; + } + + linpre = linprebuf + MAX_ORDER; + rinpre = rinprebuf + MAX_ORDER; + lstep = lstepbuf + MAX_ORDER; + rstep = rstepbuf + MAX_ORDER; + lout = loutbuf + MAX_ORDER; + rout = routbuf + MAX_ORDER; + + memset ( B, 0, sizeof(B) ); + + return INIT_GAIN_ANALYSIS_OK; +} + +/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */ + +int +AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels ) +{ + const Float_t* curleft; + const Float_t* curright; + long batchsamples; + long cursamples; + long cursamplepos; + int i; + + if ( num_samples == 0 ) + return GAIN_ANALYSIS_OK; + + cursamplepos = 0; + batchsamples = num_samples; + + switch ( num_channels) { + case 1: right_samples = left_samples; + case 2: break; + default: return GAIN_ANALYSIS_ERROR; + } + + if ( num_samples < MAX_ORDER ) { + memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) ); + memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) ); + } + else { + memcpy ( linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t) ); + memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t) ); + } + + while ( batchsamples > 0 ) { + cursamples = batchsamples > (long)(sampleWindow-totsamp) ? (long)(sampleWindow - totsamp) : batchsamples; + if ( cursamplepos < MAX_ORDER ) { + curleft = linpre+cursamplepos; + curright = rinpre+cursamplepos; + if (cursamples > MAX_ORDER - cursamplepos ) + cursamples = MAX_ORDER - cursamplepos; + } + else { + curleft = left_samples + cursamplepos; + curright = right_samples + cursamplepos; + } + + filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER ); + filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER ); + + filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER ); + filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER ); + + for ( i = 0; i < cursamples; i++ ) { /* Get the squared values */ + lsum += lout [totsamp+i] * lout [totsamp+i]; + rsum += rout [totsamp+i] * rout [totsamp+i]; + } + + batchsamples -= cursamples; + cursamplepos += cursamples; + totsamp += cursamples; + if ( totsamp == sampleWindow ) { /* Get the Root Mean Square (RMS) for this set of samples */ + double val = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 ); + int ival = (int) val; + if ( ival < 0 ) ival = 0; + if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1; + A [ival]++; + lsum = rsum = 0.; + memmove ( loutbuf , loutbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); + memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); + memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); + memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) ); + totsamp = 0; + } + if ( totsamp > sampleWindow ) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */ + return GAIN_ANALYSIS_ERROR; + } + if ( num_samples < MAX_ORDER ) { + memmove ( linprebuf, linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); + memmove ( rinprebuf, rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) ); + memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(Float_t) ); + memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(Float_t) ); + } + else { + memcpy ( linprebuf, left_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); + memcpy ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) ); + } + + return GAIN_ANALYSIS_OK; +} + + +static Float_t +analyzeResult ( Uint32_t* Array, size_t len ) +{ + Uint32_t elems; + Int32_t upper; + size_t i; + + elems = 0; + for ( i = 0; i < len; i++ ) + elems += Array[i]; + if ( elems == 0 ) + return GAIN_NOT_ENOUGH_SAMPLES; + + upper = (Int32_t) ceil (elems * (1. - RMS_PERCENTILE)); + for ( i = len; i-- > 0; ) { + if ( (upper -= Array[i]) <= 0 ) + break; + } + + return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB); +} + + +Float_t +GetTitleGain ( void ) +{ + Float_t retval; + unsigned int i; + + retval = analyzeResult ( A, sizeof(A)/sizeof(*A) ); + + for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) { + B[i] += A[i]; + A[i] = 0; + } + + for ( i = 0; i < MAX_ORDER; i++ ) + linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f; + + totsamp = 0; + lsum = rsum = 0.; + return retval; +} + + +Float_t +GetAlbumGain ( void ) +{ + return analyzeResult ( B, sizeof(B)/sizeof(*B) ); +} + +/* end of replaygain_analysis.c */ diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/replaygain_analysis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/replaygain_analysis.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,58 @@ +/* + * ReplayGainAnalysis - analyzes input samples and give the recommended dB change + * Copyright (C) 2001 David Robinson and Glen Sawyer + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * concept and filter values by David Robinson (David@Robinson.org) + * -- blame him if you think the idea is flawed + * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA + * -- blame him if you think this runs too slowly, or the coding is otherwise flawed + * minor cosmetic tweaks to integrate with FLAC by Josh Coalson + * + * For an explanation of the concepts and the basic algorithms involved, go to: + * http://www.replaygain.org/ + */ + +#ifndef GAIN_ANALYSIS_H +#define GAIN_ANALYSIS_H + +#include + +#define GAIN_NOT_ENOUGH_SAMPLES -24601 +#define GAIN_ANALYSIS_ERROR 0 +#define GAIN_ANALYSIS_OK 1 + +#define INIT_GAIN_ANALYSIS_ERROR 0 +#define INIT_GAIN_ANALYSIS_OK 1 + +#ifdef __cplusplus +extern "C" { +#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 ); +int ResetSampleFrequency ( long samplefreq ); +Float_t GetTitleGain ( void ); +Float_t GetAlbumGain ( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* GAIN_ANALYSIS_H */ diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/replaygain_synthesis.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/replaygain_synthesis.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,465 @@ +/* replaygain_synthesis - Routines for applying ReplayGain to a signal + * 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. + */ +/* + * This is an aggregation of pieces of code from John Edwards' WaveGain + * program. Mostly cosmetic changes were made; otherwise, the dithering + * code is almost untouched and the gain processing was converted from + * processing a whole file to processing chunks of samples. + * + * The original copyright notices for WaveGain's dither.c and wavegain.c + * appear below: + */ +/* + * (c) 2002 John Edwards + * mostly lifted from work by Frank Klemm + * random functions for dithering. + */ +/* + * Copyright (C) 2002 John Edwards + * Additional code by Magnus Holmgren and Gian-Carlo Pascutto + */ + +#include /* for memset() */ +#include +#include "fast_float_math_hack.h" +#include "replaygain_synthesis.h" +#include "FLAC/assert.h" + +#if defined _MSC_VER +#define FLAC__INLINE __inline +#else +#define FLAC__INLINE +#endif + +/* adjust for compilers that can't understand using LL suffix for int64_t literals */ +#ifdef _MSC_VER +#define FLAC__I64L(x) x +#else +#define FLAC__I64L(x) x##LL +#endif + + +/* + * the following is based on parts of dither.c + */ + + +/* + * This is a simple random number generator with good quality for audio purposes. + * It consists of two polycounters with opposite rotation direction and different + * periods. The periods are coprime, so the total period is the product of both. + * + * ------------------------------------------------------------------------------------------------- + * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| + * | ------------------------------------------------------------------------------------------------- + * | | | | | | | + * | +--+--+--+-XOR-+--------+ + * | | + * +--------------------------------------------------------------------------------------+ + * + * ------------------------------------------------------------------------------------------------- + * |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+ + * ------------------------------------------------------------------------------------------------- | + * | | | | | + * +--+----XOR----+--+ | + * | | + * +----------------------------------------------------------------------------------------+ + * + * + * The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481, + * which gives a period of 18.410.713.077.675.721.215. The result is the + * XORed values of both generators. + */ + +static unsigned int random_int_() +{ + static const unsigned char parity_[256] = { + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1, + 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0 + }; + static unsigned int r1_ = 1; + static unsigned int r2_ = 1; + + unsigned int t1, t2, t3, t4; + + /* Parity calculation is done via table lookup, this is also available + * on CPUs without parity, can be implemented in C and avoid unpredictable + * jumps and slow rotate through the carry flag operations. + */ + t3 = t1 = r1_; t4 = t2 = r2_; + t1 &= 0xF5; t2 >>= 25; + t1 = parity_[t1]; t2 &= 0x63; + t1 <<= 31; t2 = parity_[t2]; + + return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 ); +} + +/* gives a equal distributed random number */ +/* between -2^31*mult and +2^31*mult */ +static double random_equi_(double mult) +{ + return mult * (int) random_int_(); +} + +/* gives a triangular distributed random number */ +/* between -2^32*mult and +2^32*mult */ +static double random_triangular_(double mult) +{ + return mult * ( (double) (int) random_int_() + (double) (int) random_int_() ); +} + + +static const float F44_0 [16 + 32] = { + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, + (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0 +}; + + +static const float F44_1 [16 + 32] = { /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */ + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, + + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, + + (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833, + (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967, + (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116, + (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024, +}; + + +static const float F44_2 [16 + 32] = { /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */ + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, + + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, + + (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437, + (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264, + (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562, + (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816, +}; + + +static const float F44_3 [16 + 32] = { /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */ + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, + + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099, + + (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515, + (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785, + (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927, + (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099 +}; + + +static double scalar16_(const float* x, const float* y) +{ + return + x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] + + x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] + + x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] + + x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15]; +} + + +void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype) +{ + static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67, 0, 0 }; + static const float* F [] = { F44_0, F44_1, F44_2, F44_3 }; + + int index; + + if (shapingtype < 0) shapingtype = 0; + if (shapingtype > 3) shapingtype = 3; + d->ShapingType = (NoiseShaping)shapingtype; + index = bits - 11 - shapingtype; + if (index < 0) index = 0; + if (index > 9) index = 9; + + memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) ); + memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) ); + + d->FilterCoeff = F [shapingtype]; + d->Mask = ((FLAC__uint64)-1) << (32 - bits); + d->Add = 0.5 * ((1L << (32 - bits)) - 1); + d->Dither = 0.01f*default_dither[index] / (((FLAC__int64)1) << bits); + d->LastHistoryIndex = 0; +} + +/* + * the following is based on parts of wavegain.c + */ + +static FLAC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k) +{ + union { + double d; + FLAC__int64 i; + } doubletmp; + double Sum2; + FLAC__int64 val; + +#define ROUND64(x) ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) ) + + if(do_dithering) { + if(shapingtype == 0) { + double tmp = random_equi_(d->Dither); + Sum2 = tmp - d->LastRandomNumber [k]; + d->LastRandomNumber [k] = (int)tmp; + Sum2 = Sum += Sum2; + val = ROUND64(Sum2) & d->Mask; + } + else { + Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i); + Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2; + Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i); + val = ROUND64(Sum2) & d->Mask; + d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val); + } + return val; + } + else + return ROUND64(Sum); + +#undef ROUND64 +} + +#if 0 + float peak = 0.f, + new_peak, + factor_clip + double scale, + dB; + + ... + + peak is in the range -32768.0 .. 32767.0 + + /* calculate factors for ReplayGain and ClippingPrevention */ + *track_gain = GetTitleGain() + settings->man_gain; + scale = (float) pow(10., *track_gain * 0.05); + if(settings->clip_prev) { + factor_clip = (float) (32767./( peak + 1)); + if(scale < factor_clip) + factor_clip = 1.f; + else + factor_clip /= scale; + scale *= factor_clip; + } + new_peak = (float) peak * scale; + + dB = 20. * log10(scale); + *track_gain = (float) dB; + + const double scale = pow(10., (double)gain * 0.05); +#endif + + +size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context) +{ + static const FLAC__int32 conv_factors_[33] = { + -1, /* 0 bits-per-sample (not supported) */ + -1, /* 1 bits-per-sample (not supported) */ + -1, /* 2 bits-per-sample (not supported) */ + -1, /* 3 bits-per-sample (not supported) */ + 268435456, /* 4 bits-per-sample */ + 134217728, /* 5 bits-per-sample */ + 67108864, /* 6 bits-per-sample */ + 33554432, /* 7 bits-per-sample */ + 16777216, /* 8 bits-per-sample */ + 8388608, /* 9 bits-per-sample */ + 4194304, /* 10 bits-per-sample */ + 2097152, /* 11 bits-per-sample */ + 1048576, /* 12 bits-per-sample */ + 524288, /* 13 bits-per-sample */ + 262144, /* 14 bits-per-sample */ + 131072, /* 15 bits-per-sample */ + 65536, /* 16 bits-per-sample */ + 32768, /* 17 bits-per-sample */ + 16384, /* 18 bits-per-sample */ + 8192, /* 19 bits-per-sample */ + 4096, /* 20 bits-per-sample */ + 2048, /* 21 bits-per-sample */ + 1024, /* 22 bits-per-sample */ + 512, /* 23 bits-per-sample */ + 256, /* 24 bits-per-sample */ + 128, /* 25 bits-per-sample */ + 64, /* 26 bits-per-sample */ + 32, /* 27 bits-per-sample */ + 16, /* 28 bits-per-sample */ + 8, /* 29 bits-per-sample */ + 4, /* 30 bits-per-sample */ + 2, /* 31 bits-per-sample */ + 1 /* 32 bits-per-sample */ + }; + static const FLAC__int64 hard_clip_factors_[33] = { + 0, /* 0 bits-per-sample (not supported) */ + 0, /* 1 bits-per-sample (not supported) */ + 0, /* 2 bits-per-sample (not supported) */ + 0, /* 3 bits-per-sample (not supported) */ + -8, /* 4 bits-per-sample */ + -16, /* 5 bits-per-sample */ + -32, /* 6 bits-per-sample */ + -64, /* 7 bits-per-sample */ + -128, /* 8 bits-per-sample */ + -256, /* 9 bits-per-sample */ + -512, /* 10 bits-per-sample */ + -1024, /* 11 bits-per-sample */ + -2048, /* 12 bits-per-sample */ + -4096, /* 13 bits-per-sample */ + -8192, /* 14 bits-per-sample */ + -16384, /* 15 bits-per-sample */ + -32768, /* 16 bits-per-sample */ + -65536, /* 17 bits-per-sample */ + -131072, /* 18 bits-per-sample */ + -262144, /* 19 bits-per-sample */ + -524288, /* 20 bits-per-sample */ + -1048576, /* 21 bits-per-sample */ + -2097152, /* 22 bits-per-sample */ + -4194304, /* 23 bits-per-sample */ + -8388608, /* 24 bits-per-sample */ + -16777216, /* 25 bits-per-sample */ + -33554432, /* 26 bits-per-sample */ + -67108864, /* 27 bits-per-sample */ + -134217728, /* 28 bits-per-sample */ + -268435456, /* 29 bits-per-sample */ + -536870912, /* 30 bits-per-sample */ + -1073741824, /* 31 bits-per-sample */ + (FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */ + }; + const FLAC__int32 conv_factor = conv_factors_[target_bps]; + const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps]; + /* + * The integer input coming in has a varying range based on the + * source_bps. We want to normalize it to [-1.0, 1.0) so instead + * of doing two multiplies on each sample, we just multiple + * 'scale' by 1/(2^(source_bps-1)) + */ + const double multi_scale = scale / (double)(1u << (source_bps-1)); + + FLAC__byte * const start = data_out; + unsigned i, channel; + const FLAC__int32 *input_; + double sample; + const unsigned bytes_per_sample = target_bps / 8; + const unsigned last_history_index = dither_context->LastHistoryIndex; + NoiseShaping noise_shaping = dither_context->ShapingType; + FLAC__int64 val64; + FLAC__int32 val32; + FLAC__int32 uval32; + const FLAC__uint32 twiggle = 1u << (target_bps - 1); + + FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS); + FLAC__ASSERT(source_bps >= 4); + FLAC__ASSERT(target_bps >= 4); + FLAC__ASSERT(source_bps <= 32); + FLAC__ASSERT(target_bps < 32); + FLAC__ASSERT((target_bps & 7) == 0); + + for(channel = 0; channel < channels; channel++) { + const unsigned incr = bytes_per_sample * channels; + data_out = start + bytes_per_sample * channel; + input_ = input[channel]; + for(i = 0; i < wide_samples; i++, data_out += incr) { + sample = (double)input_[i] * multi_scale; + + if(hard_limit) { + /* hard 6dB limiting */ + if(sample < -0.5) + sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5; + else if(sample > 0.5) + sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5; + } + sample *= 2147483647.f; + + val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor; + + val32 = (FLAC__int32)val64; + if(val64 >= -hard_clip_factor) + val32 = (FLAC__int32)(-(hard_clip_factor+1)); + else if(val64 < hard_clip_factor) + val32 = (FLAC__int32)hard_clip_factor; + + uval32 = (FLAC__uint32)val32; + if (unsigned_data_out) + uval32 ^= twiggle; + + if (little_endian_data_out) { + switch(target_bps) { + case 24: + data_out[2] = (FLAC__byte)(uval32 >> 16); + /* fall through */ + case 16: + data_out[1] = (FLAC__byte)(uval32 >> 8); + /* fall through */ + case 8: + data_out[0] = (FLAC__byte)uval32; + break; + } + } + else { + switch(target_bps) { + case 24: + data_out[0] = (FLAC__byte)(uval32 >> 16); + data_out[1] = (FLAC__byte)(uval32 >> 8); + data_out[2] = (FLAC__byte)uval32; + break; + case 16: + data_out[0] = (FLAC__byte)(uval32 >> 8); + data_out[1] = (FLAC__byte)uval32; + break; + case 8: + data_out[0] = (FLAC__byte)uval32; + break; + } + } + } + } + dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32; + + return wide_samples * channels * (target_bps/8); +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/replaygain_synthesis.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/replaygain_synthesis.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,51 @@ +/* replaygain_synthesis - Routines for applying ReplayGain to a signal + * 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. + */ + +#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H +#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H + +#include /* for size_t */ +#include "FLAC/ordinals.h" + +#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2 + +typedef enum { + NOISE_SHAPING_NONE = 0, + NOISE_SHAPING_LOW = 1, + NOISE_SHAPING_MEDIUM = 2, + NOISE_SHAPING_HIGH = 3 +} NoiseShaping; + +typedef struct { + const float* FilterCoeff; + FLAC__uint64 Mask; + double Add; + float Dither; + float ErrorHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; /* 16th order Noise shaping */ + float DitherHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; + int LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS]; + unsigned LastHistoryIndex; + NoiseShaping ShapingType; +} DitherContext; + +void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype); + +/* scale = (float) pow(10., (double)replaygain * 0.05); */ +size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context); + +#endif diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/tag.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/tag.c Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,149 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2000,2001,2002,2003,2004,2005 Josh Coalson + * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura + * + * Based on FLAC plugin.c and mpg123 plugin + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "FLAC/metadata.h" +#include "plugin_common/tags.h" +#include "charset.h" +#include "configure.h" + +/* + * Function local__extname (filename) + * + * Return pointer within filename to its extenstion, or NULL if + * filename has no extension. + * + */ +static char *local__extname(const char *filename) +{ + char *ext = strrchr(filename, '.'); + + if (ext != NULL) + ++ext; + + return ext; +} + +static char *local__getstr(char* str) +{ + if (str && strlen(str) > 0) + return g_strdup(str); + return NULL; +} + +static int local__getnum(char* str) +{ + if (str && strlen(str) > 0) + return atoi(str); + return 0; +} + +static char *local__getfield(const FLAC__StreamMetadata *tags, const char *name) +{ + if (0 != tags) { + const char *utf8 = FLAC_plugin__tags_get_tag_utf8(tags, name); + if (0 != utf8) { + if(flac_cfg.title.convert_char_set) + return convert_from_utf8_to_user(utf8); + else + return strdup(utf8); + } + } + + return 0; +} + +/* + * Function flac_format_song_title (tag, filename) + * + * Create song title according to `tag' and/or `filename' and + * return it. The title must be subsequently freed using g_free(). + * + */ +TitleInput *flac_get_tuple(char *filename) +{ + TitleInput *input = NULL; + FLAC__StreamMetadata *tags; + FLAC__StreamMetadata info; + char *title, *artist, *performer, *album, *date, *tracknumber, *genre, *description; + gchar *filename_proxy = g_strdup(filename); + + FLAC_plugin__tags_get(filename_proxy, &tags); + + title = local__getfield(tags, "TITLE"); + artist = local__getfield(tags, "ARTIST"); + performer = local__getfield(tags, "PERFORMER"); + album = local__getfield(tags, "ALBUM"); + date = local__getfield(tags, "DATE"); + tracknumber = local__getfield(tags, "TRACKNUMBER"); + genre = local__getfield(tags, "GENRE"); + description = local__getfield(tags, "DESCRIPTION"); + + input = bmp_title_input_new(); + + input->performer = local__getstr(performer); + if(!input->performer) + input->performer = local__getstr(artist); + input->album_name = local__getstr(album); + input->track_name = local__getstr(title); + input->track_number = local__getnum(tracknumber); + input->year = local__getnum(date); + input->genre = local__getstr(genre); + input->comment = local__getstr(description); + + input->file_name = g_path_get_basename(filename_proxy); + input->file_path = g_path_get_dirname(filename_proxy); + input->file_ext = local__extname(filename_proxy); + + FLAC__metadata_get_streaminfo(filename, &info); + + input->length = (unsigned)((double)info.data.stream_info.total_samples / (double)info.data.stream_info.sample_rate * 1000.0 + 0.5); + + return input; +} + +gchar *flac_format_song_title(gchar *filename) +{ + gchar *ret = NULL; + TitleInput *tuple = flac_get_tuple(filename); + + ret = xmms_get_titlestring(flac_cfg.title.tag_override ? flac_cfg.title.tag_format : xmms_get_gentitle_format(), tuple); + + if (!ret) { + /* + * Format according to filename. + */ + ret = g_strdup(g_basename(filename)); + if (local__extname(ret) != NULL) + *(local__extname(ret) - 1) = '\0'; /* removes period */ + } + + bmp_title_input_free(tuple); + + return ret; +} diff -r aff1cf3e86dd -r 117bc56d906b src/flac113/tag.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/flac113/tag.h Mon Oct 23 19:51:39 2006 -0700 @@ -0,0 +1,25 @@ +/* libxmms-flac - XMMS FLAC input plugin + * Copyright (C) 2002,2003,2004,2005 Daisuke Shimamura + * + * 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. + */ + +#ifndef __FLAC__PLUGIN_XMMS__TAG_H__ +#define __FLAC__PLUGIN_XMMS__TAG_H__ + +TitleInput *flac_get_tuple(gchar * filename); +gchar *flac_format_song_title(gchar * filename); + +#endif