Mercurial > audlegacy-plugins
changeset 2394:a702f8d4fc14
results from madplug_x has been merged into madplug. thus madplug_x is unnecessary now.
author | Yoshiki Yazawa <yaz@cc.rim.or.jp> |
---|---|
date | Fri, 15 Feb 2008 19:27:14 +0900 |
parents | 6d47059bce36 |
children | 97e9de0a3ff1 |
files | src/madplug_x/Makefile src/madplug_x/configure.c src/madplug_x/decoder.c src/madplug_x/input.c src/madplug_x/input.h src/madplug_x/plugin.c src/madplug_x/plugin.h src/madplug_x/replaygain.c src/madplug_x/replaygain.h src/madplug_x/tuple.c src/madplug_x/tuple.h src/madplug_x/xing.c src/madplug_x/xing.h |
diffstat | 13 files changed, 0 insertions(+), 3296 deletions(-) [+] |
line wrap: on
line diff
--- a/src/madplug_x/Makefile Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -PLUGIN = madplug_x${PLUGIN_SUFFIX} - -SRCS = configure.c \ - input.c \ - replaygain.c \ - decoder.c \ - tuple.c \ - plugin.c \ - xing.c - -include ../../buildsys.mk -include ../../extra.mk - -plugindir := ${plugindir}/${INPUT_PLUGIN_DIR} - -CFLAGS += ${PLUGIN_CFLAGS} -CPPFLAGS += ${PLUGIN_CPPFLAGS} ${DBUS_CFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} ${PANGO_CFLAGS} ${MOWGLI_CFLAGS} ${ARCH_DEFINES} ${SIMD_CFLAGS} ${MAD_CFLAGS} -I../.. -LDFLAGS += ${AUDLDFLAGS} -LIBS += ${MAD_LIBS} -laudid3tag ${GTK_LIBS} ${GLIB_LIBS} ${PANGO_LIBS} ${MOWGLI_LIBS}
--- a/src/madplug_x/configure.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,348 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 - */ - -/* #define AUD_DEBUG 1 */ - -#include "plugin.h" - -#include <gtk/gtk.h> -#include <math.h> -#include <audacious/configdb.h> - -static GtkWidget *configure_win = NULL; -static audmad_config_t *oldconfig = NULL; // undo storage - -static audmad_config_t * -duplicate_config(audmad_config_t *orig) -{ - audmad_config_t *copy = g_memdup(orig, sizeof(audmad_config_t)); - - copy->id3_format = g_strdup(orig->id3_format); - - return copy; -} - -static void -dispose_config(audmad_config_t *config) -{ - g_free(config->id3_format); - g_free(config); -} - -static void -update_config(gpointer widgets) -{ - const gchar *text = NULL; - - AUDDBG("updating\n"); - - GtkWidget *reopen = g_object_get_data(widgets, "reopen"); - GtkWidget *fast_playback = g_object_get_data(widgets, "fast_playback"); - GtkWidget *use_xing = g_object_get_data(widgets, "use_xing"); - GtkWidget *sjis = g_object_get_data(widgets, "sjis"); - GtkWidget *show_avg = g_object_get_data(widgets, "show_avg"); - GtkWidget *title_override = g_object_get_data(widgets, "title_override"); - GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry"); - - //audio - audmad_config->force_reopen_audio = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(reopen)); - - //metadata - audmad_config->fast_play_time_calc = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(fast_playback)); - audmad_config->use_xing = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_xing)); - audmad_config->sjis = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sjis)); - - //misc - audmad_config->show_avg_vbr_bitrate = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(show_avg)); - - //text - audmad_config->title_override = - gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override)); - - text = gtk_entry_get_text(GTK_ENTRY(title_id3_entry)); - g_free(audmad_config->id3_format); - audmad_config->id3_format = g_strdup(text); - -} - -static void -save_config(void) -{ - ConfigDb *db = aud_cfg_db_open(); - - AUDDBG("saving\n"); - - //audio - aud_cfg_db_set_bool(db, "MAD", "force_reopen_audio", - audmad_config->force_reopen_audio); - //metadata - aud_cfg_db_set_bool(db, "MAD", "fast_play_time_calc", - audmad_config->fast_play_time_calc); - aud_cfg_db_set_bool(db, "MAD", "use_xing", audmad_config->use_xing); - aud_cfg_db_set_bool(db, "MAD", "sjis", audmad_config->sjis); - - //misc - aud_cfg_db_set_bool(db, "MAD", "show_avg_vbr_bitrate", - audmad_config->show_avg_vbr_bitrate); - - //text - aud_cfg_db_set_bool(db, "MAD", "title_override", audmad_config->title_override); - aud_cfg_db_set_string(db, "MAD", "id3_format", audmad_config->id3_format); - - aud_cfg_db_close(db); -} - -static void -configure_win_cancel(GtkWidget *widget, gpointer widgets) -{ - AUDDBG("cancel\n"); - dispose_config(audmad_config); - audmad_config = oldconfig; - oldconfig = NULL; - save_config(); - gtk_widget_destroy(configure_win); - g_object_unref(widgets); -} - -static void -configure_win_ok(GtkWidget *widget, gpointer widgets) -{ - AUDDBG("ok\n"); - update_config(widgets); - save_config(); - gtk_widget_destroy(configure_win); - g_object_unref(widgets); - dispose_config(oldconfig); - oldconfig = NULL; -} - -static void -configure_destroy(GtkWidget *w, gpointer data) -{ -} - -static void -simple_update_cb(GtkWidget *w, gpointer widgets) -{ - update_config(widgets); - save_config(); -} - -static void -entry_changed_cb(GtkWidget *w, gpointer widgets) -{ - simple_update_cb(w, widgets); -} - -static void -title_override_cb(GtkWidget *w, gpointer widgets) -{ - GtkWidget *title_override = g_object_get_data(widgets, "title_override"); - GtkWidget *title_id3_entry = g_object_get_data(widgets, "title_id3_entry"); - GtkWidget *title_id3_label = g_object_get_data(widgets, "title_id3_label"); - gboolean override = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_override)); - - update_config(widgets); - save_config(); - - gtk_widget_set_sensitive(title_id3_entry, override); - gtk_widget_set_sensitive(title_id3_label, override); -} - -void -audmad_configure(void) -{ - GtkWidget *vbox; - GtkWidget *bbox, *ok, *cancel; - GtkWidget *notebook, *vbox2, *title_id3_label, *title_id3_box; - GtkWidget *fast_playback, *use_xing, *sjis, *show_avg, *reopen; - GtkWidget *title_override, *title_id3_entry; - GtkWidget *metadataFrame, *audioFrame, *miscFrame; - GtkWidget *metadata_vbox, *audio_vbox, *misc_vbox; - - gpointer widgets = g_object_new(G_TYPE_OBJECT, NULL); - - if(oldconfig) { - dispose_config(oldconfig); - oldconfig = NULL; - } - - oldconfig = duplicate_config(audmad_config); //for undo - - if (configure_win != NULL) { - gtk_widget_show(configure_win); - return; - } - - configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_type_hint(GTK_WINDOW(configure_win), GDK_WINDOW_TYPE_HINT_DIALOG); - - g_signal_connect(G_OBJECT(configure_win), "destroy", - G_CALLBACK(gtk_widget_destroyed), &configure_win); - g_signal_connect(G_OBJECT(configure_win), "destroy", - G_CALLBACK(configure_destroy), &configure_win); - - gtk_window_set_title(GTK_WINDOW(configure_win), - _("MPEG Audio Plugin Configuration")); - gtk_window_set_policy(GTK_WINDOW(configure_win), FALSE, FALSE, FALSE); - gtk_container_border_width(GTK_CONTAINER(configure_win), 10); - - vbox = gtk_vbox_new(FALSE, 10); - gtk_container_add(GTK_CONTAINER(configure_win), vbox); - - notebook = gtk_notebook_new(); - gtk_box_pack_start(GTK_BOX(vbox), notebook, FALSE, FALSE, 0); - - - /********************************************************************************/ - - - vbox2 = gtk_vbox_new(FALSE, 5); - - // audio frame - audioFrame = gtk_frame_new(_("Audio Settings")); - gtk_container_border_width(GTK_CONTAINER(audioFrame), 5); - - audio_vbox = gtk_vbox_new(FALSE, 5); - - gtk_container_add(GTK_CONTAINER(audioFrame), audio_vbox); - gtk_container_add(GTK_CONTAINER(vbox2), audioFrame); - - reopen = gtk_check_button_new_with_label(_("Force reopen audio when audio type changed")); - g_object_set_data(widgets, "reopen", reopen); - gtk_box_pack_start(GTK_BOX(audio_vbox), reopen, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reopen), - audmad_config->force_reopen_audio); - g_signal_connect(G_OBJECT(reopen), "clicked", G_CALLBACK(simple_update_cb), widgets); - - - // metadata frame - metadataFrame = gtk_frame_new(_("Metadata Settings")); - gtk_container_border_width(GTK_CONTAINER(metadataFrame), 5); - - metadata_vbox = gtk_vbox_new(FALSE, 5); - - gtk_container_add(GTK_CONTAINER(metadataFrame), metadata_vbox); - gtk_container_add(GTK_CONTAINER(vbox2), metadataFrame); - - fast_playback = - gtk_check_button_new_with_label(_("Enable fast play-length calculation")); - g_object_set_data(widgets, "fast_playback", fast_playback); - gtk_box_pack_start(GTK_BOX(metadata_vbox), fast_playback, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fast_playback), - audmad_config->fast_play_time_calc); - g_signal_connect(G_OBJECT(fast_playback), "clicked", G_CALLBACK(simple_update_cb), widgets); - - use_xing = gtk_check_button_new_with_label(_("Parse XING headers")); - g_object_set_data(widgets, "use_xing", use_xing); - gtk_box_pack_start(GTK_BOX(metadata_vbox), use_xing, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(use_xing), - audmad_config->use_xing); - g_signal_connect(G_OBJECT(use_xing), "clicked", G_CALLBACK(simple_update_cb), widgets); - - sjis = gtk_check_button_new_with_label(_("Use SJIS to write ID3 tags (not recommended)")); - g_object_set_data(widgets, "sjis", sjis); - gtk_box_pack_start(GTK_BOX(metadata_vbox), sjis, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(sjis), audmad_config->sjis); - g_signal_connect(G_OBJECT(sjis), "clicked", G_CALLBACK(simple_update_cb), widgets); - - // misc frame - miscFrame = gtk_frame_new(_("Miscellaneous Settings")); - gtk_container_border_width(GTK_CONTAINER(miscFrame), 5); - - misc_vbox = gtk_vbox_new(FALSE, 5); - - gtk_container_add(GTK_CONTAINER(miscFrame), misc_vbox); - gtk_container_add(GTK_CONTAINER(vbox2), miscFrame); - - - show_avg = gtk_check_button_new_with_label(_("Display average bitrate for VBR")); - g_object_set_data(widgets, "show_avg", show_avg); - gtk_box_pack_start(GTK_BOX(misc_vbox), show_avg, FALSE, FALSE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_avg), - audmad_config->show_avg_vbr_bitrate); - g_signal_connect(G_OBJECT(show_avg), "clicked", G_CALLBACK(simple_update_cb), widgets); - - // add to notebook - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("General"))); - - - - vbox2 = gtk_vbox_new(FALSE, 5); - - title_override = gtk_check_button_new_with_label(_("Override generic titles")); - g_object_set_data(widgets, "title_override", title_override); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(title_override), - audmad_config->title_override); - gtk_box_pack_start(GTK_BOX(vbox2), title_override, FALSE, - FALSE, 0); - g_signal_connect(G_OBJECT(title_override), "clicked", - G_CALLBACK(title_override_cb), widgets); - - title_id3_box = gtk_hbox_new(FALSE, 5); - gtk_box_pack_start(GTK_BOX(vbox2), title_id3_box, FALSE, FALSE, 0); - - title_id3_label = gtk_label_new(_("ID3 format:")); - g_object_set_data(widgets, "title_id3_label", title_id3_label); - gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_label, FALSE, FALSE, 0); - gtk_widget_set_sensitive(title_id3_label, audmad_config->title_override); - - title_id3_entry = gtk_entry_new(); - g_object_set_data(widgets, "title_id3_entry", title_id3_entry); - gtk_entry_set_text(GTK_ENTRY(title_id3_entry), audmad_config->id3_format); - gtk_box_pack_start(GTK_BOX(title_id3_box), title_id3_entry, TRUE, TRUE, 0); - g_signal_connect(title_id3_entry, "changed", G_CALLBACK(entry_changed_cb), widgets); - gtk_widget_set_sensitive(title_id3_entry, audmad_config->title_override); - - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new(_("Title"))); - - - - /*********************************************************************************/ - - - 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); - - cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - - g_signal_connect(G_OBJECT(cancel), "clicked", - G_CALLBACK(configure_win_cancel), widgets); - - gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); - - ok = gtk_button_new_from_stock(GTK_STOCK_OK); - - g_signal_connect(G_OBJECT(ok), "clicked", - G_CALLBACK(configure_win_ok), widgets); - - gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); - gtk_widget_grab_default(ok); - - gtk_widget_show_all(configure_win); -}
--- a/src/madplug_x/decoder.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,607 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 - */ - -/* #define AUD_DEBUG 1 */ - -#include <math.h> -#include <assert.h> -#include <pthread.h> -#include <signal.h> - -#include <audacious/plugin.h> -#include <audacious/output.h> -#include <audacious/util.h> -#include <sys/time.h> -#include "plugin.h" -#include "input.h" - -#define BUFFER_SIZE 16*1024 -#define N_AVERAGE_FRAMES 10 - -void -write_output(struct mad_info_t *info, struct mad_pcm *pcm, - struct mad_header *header) -{ - unsigned int nsamples; - mad_fixed_t const *left_ch, *right_ch; - mad_fixed_t *output; - int outlen = 0; - int outbyte = 0; - int pos = 0; - - nsamples = pcm->length; - left_ch = pcm->samples[0]; - right_ch = pcm->samples[1]; - outlen = nsamples * MAD_NCHANNELS(header); - outbyte = outlen * sizeof(mad_fixed_t); - - output = (mad_fixed_t *) g_malloc(outbyte); - - while (nsamples--) { - output[pos++] = *left_ch++; - - if (MAD_NCHANNELS(header) == 2) { - output[pos++] = *right_ch++; - } - } - - assert(pos == outlen); - if (!info->playback->playing) { - g_free(output); - return; - } - - info->playback->pass_audio(info->playback, - info->fmt, MAD_NCHANNELS(header), outbyte, output, - &(info->playback->playing)); - g_free(output); -} - -/** - * Decode all headers in the file and fill in stats - * @return FALSE if scan failed. - */ -gboolean -scan_file(struct mad_info_t * info, gboolean fast) -{ - struct mad_stream stream; - struct mad_header header; - int remainder = 0; - int data_used = 0; - int len = 0; - int tagsize = 0; - unsigned char buffer[BUFFER_SIZE]; - struct mad_frame frame; /* to read xing data */ - gboolean has_xing = FALSE; - guint bitrate_frames = 0; - double xing_bitrate = 0.0; - double accum_bitrate = 0.0; - - mad_stream_init(&stream); - mad_stream_options(&stream, 0); // check CRC - mad_header_init(&header); - mad_frame_init(&frame); - xing_init(&info->xing); - - info->bitrate = 0; - info->pos = mad_timer_zero; - info->duration = mad_timer_zero; // should be cleared before loop, if we use it as break condition. - - if(info->fileinfo_request == TRUE) { - aud_tuple_associate_int(info->tuple, FIELD_LENGTH, NULL, -1); - info->fileinfo_request = FALSE; - } - - AUDDBG("f: scan_file\n"); - AUDDBG("scan_file frames = %d\n", info->frames); - - while (1) { - remainder = stream.bufend - stream.next_frame; - - /* - if (remainder >= BUFFER_SIZE) - { - printf("oh dear.. remainder = %d\n", remainder); - } - */ - - memcpy(buffer, stream.this_frame, remainder); - len = input_get_data(info, buffer + remainder, - BUFFER_SIZE - remainder); - - if (len <= 0) { - AUDDBG("scan_file: len <= 0 len = %d\n", len); - break; - } - - mad_stream_buffer(&stream, buffer, len + remainder); - - while (!fast || (fast && info->frames < N_AVERAGE_FRAMES)) { - if (mad_header_decode(&header, &stream) == -1) { - if (stream.error == MAD_ERROR_BUFLEN) { - break; - } - if (!MAD_RECOVERABLE(stream.error)) { - AUDDBG("(fatal) error decoding header %d: %s\n", - info->frames, mad_stream_errorstr(&stream)); - AUDDBG("remainder = %d\n", remainder); - AUDDBG("len = %d\n", len); - break; - } - if (stream.error == MAD_ERROR_LOSTSYNC) { - /* ignore LOSTSYNC due to ID3 tags */ - tagsize = id3_tag_query(stream.this_frame, - stream.bufend - - stream.this_frame); - if (tagsize > 0) { - AUDDBG("skipping id3_tag: %d\n", tagsize); - mad_stream_skip(&stream, tagsize); - continue; - } - } - - AUDDBG("(recovered) error decoding header %d: %s\n", - info->frames, mad_stream_errorstr(&stream)); - AUDDBG("remainder = %d\n", remainder); - AUDDBG("len = %d\n", len); - - continue; - } - info->frames++; - -#ifdef DEBUG_INTENSIVELY - AUDDBG("header bitrate = %ld\n", header.bitrate); - AUDDBG("duration = %ul\n", - mad_timer_count(header.duration, - MAD_UNITS_MILLISECONDS)); - AUDDBG("size = %d\n", stream.next_frame - stream.this_frame); -#endif - if(aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL) == -1) - mad_timer_add(&info->duration, header.duration); - else { - gint length = aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL); - - info->duration.seconds = length / 1000; - info->duration.fraction = length % 1000; - } - data_used += stream.next_frame - stream.this_frame; - if (info->frames == 1) { - /* most of these *should* remain constant */ - info->bitrate = header.bitrate; - info->freq = header.samplerate; - info->channels = MAD_NCHANNELS(&header); - info->mpeg_layer = header.layer; - info->mode = header.mode; - - if (audmad_config->use_xing) { - frame.header = header; - if (mad_frame_decode(&frame, &stream) == -1) { - AUDDBG("xing frame decode failed\n"); - goto no_xing; - } - if (xing_parse(&info->xing, stream.anc_ptr, stream.anc_bitlen) == 0) { - AUDDBG("xing header found\n"); - has_xing = TRUE; - info->vbr = TRUE; /* otherwise xing header would have been 'Info' */ - - AUDDBG("xing: bytes = %ld frames = %ld\n", info->xing.bytes, info->xing.frames); - - /* we have enough info to calculate bitrate and duration */ - if(info->xing.bytes && info->xing.frames) { - xing_bitrate = 8 * (double)info->xing.bytes * 38 / (double)info->xing.frames; //38fps in MPEG1. -#ifdef AUD_DEBUG - { - gint tmp = (gint)(info->xing.bytes * 8 / xing_bitrate); - AUDDBG("xing: bitrate = %4.1f kbps\n", xing_bitrate / 1000); - AUDDBG("xing: duration = %d:%02d\n", tmp / 60, tmp % 60); - } -#endif - } - continue; - } -#ifdef AUD_DEBUG - else { - AUDDBG("no usable xing header\n"); - continue; - } -#endif - } /* xing */ - - } - else { - /* perhaps we have a VBR file */ - if (info->bitrate != header.bitrate) - info->vbr = TRUE; - if (info->vbr) { - accum_bitrate += (double)header.bitrate; - bitrate_frames++; - } - /* check for changin layer/samplerate/channels */ - if (info->mpeg_layer != header.layer) - g_warning("layer varies!!"); - if (info->freq != header.samplerate) - g_warning("samplerate varies!!"); - if (info->channels != MAD_NCHANNELS(&header)) - g_warning("number of channels varies!!"); - } - no_xing: - if (fast && info->frames >= N_AVERAGE_FRAMES) { - float frame_size = ((double) data_used) / N_AVERAGE_FRAMES; - - AUDDBG("bitrate = %ld samplerate = %d\n", header.bitrate, header.samplerate); - AUDDBG("data_used = %d info->frames = %d info->size = %d tagsize = %d frame_size = %lf\n", - data_used, info->frames, info->size, tagsize, frame_size); - - if(info->size != 0) - info->frames = (info->size - tagsize) / frame_size; - - AUDDBG("info->frames = %d\n", info->frames); - - if(aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL) == -1) { - if(xing_bitrate > 0.0) { - /* calc duration with xing info */ - double tmp = 8 * (double)info->xing.bytes * 1000 / xing_bitrate; - info->duration.seconds = (guint)(tmp / 1000); - info->duration.fraction = (guint)(tmp - info->duration.seconds * 1000); - } - else { - info->duration.seconds /= N_AVERAGE_FRAMES; - info->duration.fraction /= N_AVERAGE_FRAMES; - mad_timer_multiply(&info->duration, info->frames); - } - } - else { - gint length = aud_tuple_get_int(info->tuple, FIELD_LENGTH, NULL); - - info->duration.seconds = length / 1000; - info->duration.fraction = length % 1000; - } -#ifdef AUD_DEBUG - AUDDBG("using fast playtime calculation\n"); - AUDDBG("data used = %d [tagsize=%d framesize=%f]\n", - data_used, tagsize, frame_size); - AUDDBG("frames = %d, frequency = %d, channels = %d\n", - info->frames, info->freq, info->channels); - long millis = mad_timer_count(info->duration, - MAD_UNITS_MILLISECONDS); - AUDDBG("duration = %ld:%02ld\n", millis / 1000 / 60, (millis / 1000) % 60); -#endif /* DEBUG */ - break; - } - } /* while */ - if (stream.error != MAD_ERROR_BUFLEN) - break; - } - - if (info->xing.frames) - info->frames = info->xing.frames; - - if (info->vbr && xing_bitrate != 0) { - info->bitrate = (guint)xing_bitrate; - } - else if (info->vbr && xing_bitrate == 0 && bitrate_frames != 0) { - info->bitrate = accum_bitrate / bitrate_frames; - } - - aud_tuple_associate_int(info->tuple, FIELD_BITRATE, NULL, info->bitrate / 1000); - - mad_frame_finish(&frame); - mad_header_finish(&header); - mad_stream_finish(&stream); - xing_finish(&info->xing); - - AUDDBG("scan_file: info->frames = %d\n", info->frames); - AUDDBG("e: scan_file\n"); - - return (info->frames != 0 || info->remote == TRUE); -} - -/* sanity check for audio open parameters */ -static gboolean -check_audio_param(struct mad_info_t *info) -{ - if(info->fmt != FMT_FIXED32 && (info->fmt < FMT_U8 || info->fmt > FMT_S16_NE)) - return FALSE; - if(info->freq < 0) // not sure about maximum frequency. --yaz - return FALSE; - if(info->channels < 1 || info->channels > 2) - return FALSE; - - return TRUE; -} - -gpointer -decode_loop(gpointer arg) -{ - unsigned char buffer[BUFFER_SIZE]; - int len; - gboolean seek_skip = FALSE; - int remainder = 0; - gint tlen; - unsigned int iteration = 0; - - /* mad structs */ - struct mad_stream stream; - struct mad_frame frame; - struct mad_synth synth; - - /* track info is passed in as thread argument */ - struct mad_info_t *info = (struct mad_info_t *) arg; - - AUDDBG("f: decode\n"); - - /* init mad stuff */ - mad_frame_init(&frame); - mad_stream_init(&stream); - mad_stream_options(&stream, MAD_OPTION_IGNORECRC); - mad_synth_init(&synth); - - if(!info->playback){ - AUDDBG("decode: playback == NULL\n"); - return NULL; - } - - AUDDBG("decode: fmt = %d freq = %d channels = %d\n", info->fmt, info->freq, info->channels); - - if(check_audio_param(info) == FALSE) - return NULL; - - if (!info->playback->output->open_audio(info->fmt, info->freq, info->channels)) { - g_mutex_lock(pb_mutex); - info->playback->error = TRUE; - info->playback->eof = 1; - g_mutex_unlock(pb_mutex); - g_message("failed to open audio output: %s", - info->playback->output->description); - return NULL; - } - - /* set mainwin title */ - if (info->title) - g_free(info->title); - info->title = aud_tuple_formatter_make_title_string(info->tuple, audmad_config->title_override == TRUE ? - audmad_config->id3_format : aud_get_gentitle_format()); - - tlen = (gint) mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS), - info->playback->set_params(info->playback, info->title, - (tlen == 0 || info->size <= 0) ? -1 : tlen, - info->bitrate, info->freq, info->channels); - - AUDDBG("decode: tlen = %d\n", tlen); - - /* main loop */ - do { - if (!info->playback->playing) { - AUDDBG("decode: stop signaled\n"); - break; - } - if (seek_skip) - remainder = 0; - else { - remainder = stream.bufend - stream.next_frame; - memcpy(buffer, stream.this_frame, remainder); - } - len = input_get_data(info, buffer + remainder, - BUFFER_SIZE - remainder); - - input_process_remote_metadata(info); - - if (len <= 0) { - AUDDBG("finished decoding\n"); - break; - } - len += remainder; - if (len < MAD_BUFFER_GUARD) { - int i; - for (i = len; i < MAD_BUFFER_GUARD; i++) - buffer[i] = 0; - len = MAD_BUFFER_GUARD; - } - - mad_stream_buffer(&stream, buffer, len); - - if (seek_skip) { - - AUDDBG("skipping: %d\n", seek_skip); - - int skip = 2; - do { - if (mad_frame_decode(&frame, &stream) == 0) { - mad_timer_add(&info->pos, frame.header.duration); - if (--skip == 0) - mad_synth_frame(&synth, &frame); - } - else if (!MAD_RECOVERABLE(stream.error)) { - g_mutex_lock(pb_mutex); - info->playback->error = TRUE; - info->playback->eof = 1; - g_mutex_unlock(pb_mutex); - break; - } - } - while (skip); - seek_skip = FALSE; - } - - while (info->playback->playing) { - if (info->seek != -1 && info->size > 0) { - - AUDDBG("seeking: %ld\n", info->seek); - - int new_position; - gulong milliseconds = - mad_timer_count(info->duration, MAD_UNITS_MILLISECONDS); - if (info->seek >= milliseconds) - info->seek = milliseconds; - - mad_timer_set(&info->pos, 0, info->seek, 1000); // in millisecond - new_position = - ((double) info->seek / (double) milliseconds) * info->size; - - if(new_position < 0) - new_position = 0; - - AUDDBG("seeking to: %d bytes\n", new_position); - - if (aud_vfs_fseek(info->infile, new_position, SEEK_SET) == -1) - audmad_error("failed to seek to: %d", new_position); - mad_frame_mute(&frame); - mad_synth_mute(&synth); - stream.error = MAD_ERROR_BUFLEN; - info->playback->output->flush(mad_timer_count(info->pos, MAD_UNITS_MILLISECONDS)); - stream.sync = 0; - info->seek = -1; - seek_skip = TRUE; - break; - } - - if (mad_header_decode(&frame.header, &stream) == -1) { - if (!MAD_RECOVERABLE(stream.error)) { - break; - } - if (stream.error == MAD_ERROR_LOSTSYNC) { - /* ignore LOSTSYNC due to ID3 tags */ - int tagsize = id3_tag_query(stream.this_frame, - stream.bufend - - stream.this_frame); - if (tagsize > 0) { - mad_stream_skip(&stream, tagsize); - continue; - } - } - - AUDDBG("(recovered) error decoding header %d: %s\n", - info->current_frame, - mad_stream_errorstr(&stream)); - - continue; - } - - info->bitrate = frame.header.bitrate; - - if (!audmad_config->show_avg_vbr_bitrate && info->vbr && (iteration % 40 == 0)) { - -#ifdef DEBUG_INTENSIVELY - AUDDBG("decode vbr tlen = %d\n", tlen); -#endif - info->playback->set_params(info->playback, info->title, - (tlen == 0 || info->size <= 0) ? -1 : tlen, - info->bitrate, info->freq, info->channels); - } - iteration++; - - if (mad_frame_decode(&frame, &stream) == -1) { - if (!MAD_RECOVERABLE(stream.error)) - break; - - AUDDBG("(recovered) error decoding frame %d: %s\n", - info->current_frame, - mad_stream_errorstr(&stream)); - - } - - info->current_frame++; - - if (info->freq != frame.header.samplerate - || info->channels != - (guint) MAD_NCHANNELS(&frame.header)) { - - AUDDBG("change in audio type detected\n"); - AUDDBG("old: frequency = %d, channels = %d\n", info->freq, - info->channels); - AUDDBG("new: frequency = %d, channels = %d\n", - frame.header.samplerate, - (guint) MAD_NCHANNELS(&frame.header)); - - info->freq = frame.header.samplerate; - info->channels = MAD_NCHANNELS(&frame.header); - - if(audmad_config->force_reopen_audio && check_audio_param(info)) { - gint current_time = info->playback->output->output_time(); - - AUDDBG("re-opening audio due to change in audio type\n"); - - info->playback->output->close_audio(); - if (!info->playback->output->open_audio(info->fmt, info->freq, - info->channels)) { - g_mutex_lock(pb_mutex); - info->playback->error = TRUE; - info->playback->eof = 1; - g_mutex_unlock(pb_mutex); - g_message("failed to re-open audio output: %s", - info->playback->output->description); - return NULL; - } - // restore time and advance 0.5sec - info->seek = current_time + 500; - } - } - - if (!info->playback->playing) - break; - mad_synth_frame(&synth, &frame); - mad_stream_sync(&stream); - - write_output(info, &synth.pcm, &frame.header); - - mad_timer_add(&info->pos, frame.header.duration); - } - } - while (stream.error == MAD_ERROR_BUFLEN); - - /* free mad stuff */ - mad_frame_finish(&frame); - mad_stream_finish(&stream); - mad_synth_finish(&synth); - - if (info->playback->playing) { - GTimeVal sleeptime; - - info->playback->output->buffer_free(); - info->playback->output->buffer_free(); - while (info->playback->output->buffer_playing()) { - - AUDDBG("f: buffer_playing=%d\n", info->playback->output->buffer_playing()); - - g_get_current_time(&sleeptime); - g_time_val_add(&sleeptime, 500000); - - g_mutex_lock(mad_mutex); - g_cond_timed_wait(mad_cond, mad_mutex, &sleeptime); - g_mutex_unlock(mad_mutex); - if (!info->playback->playing) { - break; - } - - } - } - - AUDDBG("e: decode\n"); - - aud_tuple_free(info->tuple); - info->tuple = NULL; - - info->playback->output->close_audio(); - g_mutex_lock(mad_mutex); - info->playback->playing = 0; - g_mutex_unlock(mad_mutex); - return NULL; /* dummy */ -}
--- a/src/madplug_x/input.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,628 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 - */ - -#include "config.h" - -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif /* HAVE_ASSERT_H */ - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif /* HAVE_SYS_TYPES_H */ - -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif /* HAVE_SYS_SOCKET_H */ - -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif /* HAVE_NETINET_IN_H */ - -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif /* HAVE_ARPA_INET_H */ - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif /* HAVE_NETDB_H */ - -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif /* HAVE_SYS_STAT_H */ - -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif /* HAVE_SYS_TIME_H */ - -#include <fcntl.h> -#include <errno.h> -#include <audacious/util.h> - -#include "input.h" -#include "replaygain.h" - -#define DIR_SEPARATOR '/' -#define HEADER_SIZE 256 -#define LINE_LENGTH 256 - -extern gboolean scan_file(struct mad_info_t *info, gboolean fast); - -/** - * init the mad_info_t struct. - */ -gboolean -input_init(struct mad_info_t * info, const char *url, VFSFile *fd) -{ - AUDDBG("f: input_init\n"); - - memset(info, 0, sizeof(struct mad_info_t)); // all fields are cleared to 0 --yaz - - info->fmt = FMT_FIXED32; - info->channels = -1; - info->mpeg_layer = -1; - info->size = -1; - info->freq = -1; - info->seek = -1; - info->duration = mad_timer_zero; - info->pos = mad_timer_zero; - info->url = g_strdup(url); - info->filename = g_strdup(url); - - // from input_read_replaygain() - info->replaygain_track_peak = 0.0; - info->replaygain_track_scale = 0.0; - info->replaygain_album_peak = 0.0; - info->replaygain_album_scale = 0.0; - info->mp3gain_undo = -77; - info->mp3gain_minmax = -77; - - if(!fd){ - info->infile = aud_vfs_fopen(info->filename, "rb"); - if (info->infile == NULL) { - return FALSE; - } - } - else{ - AUDDBG("input_init: aud_vfs_dup\n"); - - info->infile = aud_vfs_dup(fd); - } - - // obtain file size - info->size = aud_vfs_fsize(info->infile); - info->remote = info->size == 0 ? TRUE : FALSE; //proxy connection may result in non-zero size. - if(aud_vfs_is_remote((gchar *)url)) - info->remote = TRUE; - - info->fileinfo_request = FALSE; - - AUDDBG("i: info->size = %lu\n", (long unsigned int)info->size); - AUDDBG("e: input_init\n"); - - return TRUE; -} - -/* return length in letters */ -size_t -mad_ucs4len(id3_ucs4_t *ucs) -{ - id3_ucs4_t *ptr = ucs; - size_t len = 0; - - while(*ptr++ != 0) - len++; - - return len; -} - -/* duplicate id3_ucs4_t string. new string will be terminated with 0. */ -id3_ucs4_t * -mad_ucs4dup(id3_ucs4_t *org) -{ - id3_ucs4_t *new = NULL; - size_t len = mad_ucs4len(org); - - new = g_malloc0((len + 1) * sizeof(id3_ucs4_t)); - memcpy(new, org, len * sizeof(id3_ucs4_t)); - *(new + len) = 0; //terminate - - return new; -} - -#define BYTES(x) ((x) * sizeof(id3_ucs4_t)) - -id3_ucs4_t * -mad_parse_genre(const id3_ucs4_t *string) -{ - id3_ucs4_t *ret = NULL; - id3_ucs4_t *tmp = NULL; - id3_ucs4_t *genre = NULL; - id3_ucs4_t *ptr, *end, *tail, *tp; - size_t ret_len = 0; //num of ucs4 char! - size_t tmp_len = 0; - size_t string_len = 0; - gboolean is_num = TRUE; - - if(!string) - return NULL; - - string_len = mad_ucs4len((id3_ucs4_t *)string); - tail = (id3_ucs4_t *)string + string_len; - - if(BYTES(string_len + 1) > 1024) { - ret = g_malloc0(BYTES(string_len + 1)); - } - else { - ret = g_malloc0(1024); - } - - for(ptr = (id3_ucs4_t *)string; ptr <= tail && *ptr != 0; ptr++) { - if(*ptr == '(') { - if(ptr < tail && *(++ptr) == '(') { // escaped text like: ((something) - for(end = ptr; *end != ')' && *end != 0;) { // copy "(something)" - end++; - } - end++; //include trailing ')' - memcpy(ret, ptr, BYTES(end - ptr)); - ret_len += (end - ptr); - *(ret + ret_len) = 0; //terminate - ptr = end + 1; - } - else if (ptr <= tail && *ptr != 0) { - // reference to an id3v1 genre code - for(end = ptr; *end != ')' && *end != 0;) { - end++; - } - - tmp = g_malloc0(BYTES(end - ptr + 1)); - memcpy(tmp, ptr, BYTES(end - ptr)); - *(tmp + (end - ptr)) = 0; //terminate - ptr += end - ptr; - - genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp); - - g_free(tmp); - tmp = NULL; - - tmp_len = mad_ucs4len(genre); - - memcpy(ret + ret_len, genre, BYTES(tmp_len)); - - ret_len += tmp_len; - *(ret + ret_len) = 0; //terminate - } - } - else { - for(end = ptr; *end != '(' && *end != 0; ) { - end++; - } - // scan string to determine whether a genre code number or not - tp = ptr; - is_num = TRUE; - while(tp < end) { - if(*tp < '0' || *tp > '9') { // anything else than number appears. - is_num = FALSE; - break; - } - tp++; - } - - if(is_num) { - AUDDBG("is_num!\n"); - - tmp = g_malloc0(BYTES(end - ptr + 1)); - memcpy(tmp, ptr, BYTES(end - ptr)); - *(tmp + (end - ptr)) = 0; //terminate - ptr += end - ptr; - - genre = (id3_ucs4_t *)id3_genre_name((const id3_ucs4_t *)tmp); - AUDDBG("genre length = %d\n", mad_ucs4len(genre)); - - g_free(tmp); - tmp = NULL; - - tmp_len = mad_ucs4len(genre); - - memcpy(ret + ret_len, genre, BYTES(tmp_len)); - - ret_len += tmp_len; - *(ret + ret_len) = 0; //terminate - } - else { // plain text - AUDDBG("plain!\n"); - AUDDBG("ret_len = %d\n", ret_len); - AUDDBG("end - ptr = %d\n", BYTES(end - ptr)); - - memcpy(ret + ret_len, ptr, BYTES(end - ptr)); - ret_len = ret_len + (end - ptr); - *(ret + ret_len) = 0; //terminate - ptr += (end - ptr); - } - } - } - return ret; -} - -gchar * -input_id3_get_string(struct id3_tag * tag, const gchar *frame_name) -{ - gchar *rtn0 = NULL, *rtn = NULL; - const id3_ucs4_t *string_const = NULL; - id3_ucs4_t *string = NULL; - struct id3_frame *frame; - union id3_field *field; - int encoding = -1; - - frame = id3_tag_findframe(tag, frame_name, 0); - if (!frame) - return NULL; - - field = id3_frame_field(frame, 0); - encoding = id3_field_gettextencoding(field); - - if (!strcmp(frame_name, ID3_FRAME_COMMENT)) - field = id3_frame_field(frame, 3); - else - field = id3_frame_field(frame, 1); - - if (!field) - return NULL; - - if (!strcmp(frame_name, ID3_FRAME_COMMENT)) - string_const = id3_field_getfullstring(field); - else - string_const = id3_field_getstrings(field, 0); - - if (!string_const) - return NULL; - - if (!strcmp(frame_name, ID3_FRAME_GENRE)) { - string = mad_parse_genre(string_const); - } - else { - string = mad_ucs4dup((id3_ucs4_t *)string_const); - } - - if (!string) - return NULL; - - switch (encoding) { - case ID3_FIELD_TEXTENCODING_ISO_8859_1: - rtn0 = (gchar *)id3_ucs4_latin1duplicate(string); - rtn = aud_str_to_utf8(rtn0); - g_free(rtn0); - break; - case ID3_FIELD_TEXTENCODING_UTF_8: - default: - rtn = (gchar *)id3_ucs4_utf8duplicate(string); - break; - } - g_free((void *)string); - - AUDDBG("i: string = %s\n", rtn); - - return rtn; -} - -static void -input_set_and_free_tag(struct id3_tag *tag, Tuple *tuple, const gchar *frame, const gint nfield) -{ - gchar *scratch = input_id3_get_string(tag, frame); - - aud_tuple_associate_string(tuple, nfield, NULL, scratch); - aud_tuple_associate_string(tuple, -1, frame, scratch); - - g_free(scratch); -} - -static void -input_alloc_tag(struct mad_info_t *info) -{ - Tuple *tuple; - - if (info->tuple == NULL) { - tuple = aud_tuple_new(); - info->tuple = tuple; - aud_tuple_associate_int(info->tuple, FIELD_LENGTH, NULL, -1); - } -} - -/** - * read the ID3 tag - */ -static void -input_read_tag(struct mad_info_t *info) -{ - gchar *string = NULL; - Tuple *tuple; - glong curpos = 0; - - AUDDBG("f: input_read_tag\n"); - - if (info->tuple != NULL) - aud_tuple_free(info->tuple); - - tuple = aud_tuple_new_from_filename(info->filename); - info->tuple = tuple; - - if(info->infile) { - curpos = aud_vfs_ftell(info->infile); - info->id3file = id3_file_vfsopen(info->infile, ID3_FILE_MODE_READONLY); - } - else { - info->id3file = id3_file_open(info->filename, ID3_FILE_MODE_READONLY); - } - - if (!info->id3file) { - AUDDBG("read_tag: no id3file\n"); - return; - } - - info->tag = id3_file_tag(info->id3file); - if (!info->tag) { - AUDDBG("read_tag: no tag\n"); - return; - } - - input_set_and_free_tag(info->tag, tuple, ID3_FRAME_ARTIST, FIELD_ARTIST); - input_set_and_free_tag(info->tag, tuple, ID3_FRAME_TITLE, FIELD_TITLE); - input_set_and_free_tag(info->tag, tuple, ID3_FRAME_ALBUM, FIELD_ALBUM); - input_set_and_free_tag(info->tag, tuple, ID3_FRAME_GENRE, FIELD_GENRE); - input_set_and_free_tag(info->tag, tuple, ID3_FRAME_COMMENT, FIELD_COMMENT); - - string = input_id3_get_string(info->tag, ID3_FRAME_TRACK); - if (string) { - aud_tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, atoi(string)); - g_free(string); - string = NULL; - } - - // year - string = NULL; - string = input_id3_get_string(info->tag, ID3_FRAME_YEAR); //TDRC - if (!string) - string = input_id3_get_string(info->tag, "TYER"); - - if (string) { - aud_tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(string)); - g_free(string); - string = NULL; - } - - // length - string = input_id3_get_string(info->tag, "TLEN"); - if (string && atoi(string)) { - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, atoi(string)); - AUDDBG("input_read_tag: TLEN = %d\n", atoi(string)); - g_free(string); - string = NULL; - } else - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1); - - aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, "MPEG Audio (MP3)"); - aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, "lossy"); - - info->title = aud_tuple_formatter_make_title_string(tuple, audmad_config->title_override == TRUE ? - audmad_config->id3_format : aud_get_gentitle_format()); - - // for connection via proxy, we have to stop transfer once. I can't explain the reason. - if (info->infile != NULL) { - aud_vfs_fseek(info->infile, -1, SEEK_SET); // an impossible request - aud_vfs_fseek(info->infile, curpos, SEEK_SET); - } - - AUDDBG("e: input_read_tag\n"); -} - -void -input_process_remote_metadata(struct mad_info_t *info) -{ - gboolean metadata = FALSE; - - if(info->remote && mad_timer_count(info->duration, MAD_UNITS_SECONDS) <= 0){ - gchar *tmp = NULL; - -#ifdef DEBUG_INTENSIVELY - AUDDBG("process_remote_meta\n"); -#endif - g_free(info->title); - info->title = NULL; - aud_tuple_disassociate(info->tuple, FIELD_TITLE, NULL); - aud_tuple_disassociate(info->tuple, FIELD_ALBUM, NULL); - - tmp = aud_vfs_get_metadata(info->infile, "track-name"); - if(tmp){ - metadata = TRUE; - gchar *scratch; - - scratch = aud_str_to_utf8(tmp); - aud_tuple_associate_string(info->tuple, FIELD_TITLE, NULL, scratch); - g_free(scratch); - - g_free(tmp); - tmp = NULL; - } - - tmp = aud_vfs_get_metadata(info->infile, "stream-name"); - if(tmp){ - metadata = TRUE; - gchar *scratch; - - scratch = aud_str_to_utf8(tmp); - aud_tuple_associate_string(info->tuple, FIELD_ALBUM, NULL, scratch); - aud_tuple_associate_string(info->tuple, -1, "stream", scratch); - g_free(scratch); - - g_free(tmp); - tmp = NULL; - } - - if (metadata) - tmp = aud_tuple_formatter_process_string(info->tuple, "${?title:${title}}${?stream: (${stream})}"); - else { - gchar *realfn = g_filename_from_uri(info->filename, NULL, NULL); - gchar *tmp2 = g_path_get_basename(realfn ? realfn : info->filename); // info->filename is uri. --yaz - tmp = aud_str_to_utf8(tmp2); - g_free(tmp2); tmp2 = NULL; - g_free(realfn); realfn = NULL; -// tmp = g_strdup(g_basename(info->filename)); //XXX maybe ok. --yaz - } - - /* call set_info only if tmp is different from prev_tmp */ - if ( ( ( info->prev_title != NULL ) && ( strcmp(info->prev_title,tmp) ) ) || - ( info->prev_title == NULL ) ) - { - info->playback->set_params(info->playback, tmp, - -1, // indicate the stream is unseekable - info->bitrate, info->freq, info->channels); - if (info->prev_title) - g_free(info->prev_title); - info->prev_title = g_strdup(tmp); - } - - g_free(tmp); - } -} - - -/** - * Retrieve meta-information about URL. - * For local files this means ID3 tag etc. - */ -gboolean -input_get_info(struct mad_info_t *info, gboolean fast_scan) -{ -#ifdef AUD_DEBUG - gchar *tmp = g_filename_to_utf8(info->filename, -1, NULL, NULL, NULL); - AUDDBG("f: input_get_info: %s, fast_scan = %s\n", tmp, fast_scan ? "TRUE" : "FALSE"); - g_free(tmp); -#endif /* DEBUG */ - - input_alloc_tag(info); - input_read_tag(info); - - if(!info->remote) { // reduce startup delay - read_replaygain(info); - } - - /* scan mp3 file, decoding headers */ - if (scan_file(info, fast_scan) == FALSE) { - AUDDBG("input_get_info: scan_file failed\n"); - return FALSE; - } - - /* reset the input file to the start */ - aud_vfs_fseek(info->infile, 0, SEEK_SET); - info->offset = 0; - - /* use the filename for the title as a last resort */ - if (!info->title) { - char *pos = strrchr(info->filename, DIR_SEPARATOR); //XXX info->filename is uri. --yaz - if (pos) - info->title = g_strdup(pos + 1); - else - info->title = g_strdup(info->filename); //XXX info->filename is uri. --yaz - } - - AUDDBG("e: input_get_info\n"); - return TRUE; -} - - - -/** - * Read data from the source given my madinfo into the buffer - * provided. Return the number of bytes read. - * @return 0 on EOF - * @return -1 on error - */ -// this function may be called before info->playback initialized. -int -input_get_data(struct mad_info_t *info, guchar * buffer, - int buffer_size) -{ - int len = 0; -#ifdef DEBUG_INTENSIVELY - AUDDBG ("f: input_get_data: %d\n", buffer_size); -#endif - /* simply read to data from the file */ - len = aud_vfs_fread(buffer, 1, buffer_size, info->infile); //aud_vfs_fread returns num of elements. - - if(len == 0 && info->playback){ - info->playback->eof = TRUE; - } - -#ifdef DEBUG_INTENSIVELY - AUDDBG ("e: input_get_data: size=%d offset=%d\n", len, info->offset); -#endif - - info->offset += len; - return len; -} - -/** - * Free up all mad_info_t related resourses. - */ -gboolean -input_term(struct mad_info_t * info) -{ - AUDDBG("f: input_term\n"); - - if (info->title) - g_free(info->title); - if (info->url) - g_free(info->url); - if (info->filename) - g_free(info->filename); - if (info->infile) - aud_vfs_fclose(info->infile); - if (info->id3file) - id3_file_close(info->id3file); - - if (info->replaygain_album_str) - g_free(info->replaygain_album_str); - if (info->replaygain_track_str) - g_free(info->replaygain_track_str); - if (info->replaygain_album_peak_str) - g_free(info->replaygain_album_peak_str); - if (info->replaygain_track_peak_str) - g_free(info->replaygain_track_peak_str); - if (info->mp3gain_undo_str) - g_free(info->mp3gain_undo_str); - if (info->mp3gain_minmax_str) - g_free(info->mp3gain_minmax_str); - - if (info->tuple) { - aud_tuple_free(info->tuple); - info->tuple = NULL; - } - - if (info->prev_title) - g_free(info->prev_title); - - /* set everything to zero in case it gets used again. */ - memset(info, 0, sizeof(struct mad_info_t)); - - AUDDBG("e: input_term\n"); - - return TRUE; -}
--- a/src/madplug_x/input.h Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 INPUT_H -#define INPUT_H - -#include "plugin.h" -gboolean input_init(struct mad_info_t *songinfo, const gchar * url, VFSFile *fd); -gboolean input_term(struct mad_info_t *songinfo); -gboolean input_get_info(struct mad_info_t *songinfo, gboolean fast_scan); -gint input_get_data(struct mad_info_t *songinfo, guchar * buffer, - gint buffer_size); -gchar *input_id3_get_string(struct id3_tag *tag, const gchar *frame_name); - -#endif /* ! INPUT_H */
--- a/src/madplug_x/plugin.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,781 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 - */ - -/* #define AUD_DEBUG 1 */ - -#include "config.h" -#include "plugin.h" -#include "input.h" - -#include <math.h> - -#include <gtk/gtk.h> -#include <audacious/util.h> -#include <audacious/configdb.h> -#include <stdarg.h> -#include <fcntl.h> -#include <audacious/vfs.h> -#include <sys/stat.h> -#include "tuple.h" - -/* - * Global variables - */ -audmad_config_t *audmad_config; /**< global configuration */ -GMutex *mad_mutex; -GMutex *pb_mutex; -GCond *mad_cond; - -/* - * static variables - */ -static GThread *decode_thread; /**< the single decoder thread */ -static struct mad_info_t info; /**< info for current track */ - -#ifndef NOGUI -static GtkWidget *error_dialog = 0; -#endif - -extern gboolean scan_file(struct mad_info_t *info, gboolean fast); - -static gint mp3_bitrate_table[5][16] = { - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, /* MPEG1 L1 */ - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, /* MPEG1 L2 */ - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 }, /* MPEG1 L3 */ - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1 }, /* MPEG2(.5) L1 */ - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 } /* MPEG2(.5) L2,L3 */ -}; - -static gint mp3_samplerate_table[4][4] = { - { 11025, 12000, 8000, -1 }, /* MPEG2.5 */ - { -1, -1, -1, -1 }, /* Reserved */ - { 22050, 24000, 16000, -1 }, /* MPEG2 */ - { 44100, 48000, 32000, -1 } /* MPEG1 */ -}; - -/* - * Function extname (filename) - * - * Return pointer within filename to its extenstion, or NULL if - * filename has no extension. - * - */ -static gchar * -extname(const char *filename) -{ - gchar *ext = strrchr(filename, '.'); - - if (ext != NULL) - ++ext; - - return ext; -} - - -static void -audmad_init() -{ - ConfigDb *db = NULL; - - audmad_config = g_malloc0(sizeof(audmad_config_t)); - - audmad_config->dither = TRUE; - audmad_config->force_reopen_audio = FALSE; - audmad_config->fast_play_time_calc = TRUE; - audmad_config->use_xing = TRUE; - audmad_config->sjis = FALSE; - audmad_config->show_avg_vbr_bitrate = TRUE; - audmad_config->title_override = FALSE; - - - db = aud_cfg_db_open(); - if (db) { - //audio - aud_cfg_db_get_bool(db, "MAD", "dither", &audmad_config->dither); - aud_cfg_db_get_bool(db, "MAD", "force_reopen_audio", - &audmad_config->force_reopen_audio); - - //metadata - aud_cfg_db_get_bool(db, "MAD", "fast_play_time_calc", - &audmad_config->fast_play_time_calc); - aud_cfg_db_get_bool(db, "MAD", "use_xing", - &audmad_config->use_xing); - aud_cfg_db_get_bool(db, "MAD", "sjis", &audmad_config->sjis); - - //misc - aud_cfg_db_get_bool(db, "MAD", "show_avg_vbr_bitrate", - &audmad_config->show_avg_vbr_bitrate); - - //text - aud_cfg_db_get_bool(db, "MAD", "title_override", - &audmad_config->title_override); - aud_cfg_db_get_string(db, "MAD", "id3_format", - &audmad_config->id3_format); - - aud_cfg_db_close(db); - } - - mad_mutex = g_mutex_new(); - pb_mutex = g_mutex_new(); - mad_cond = g_cond_new(); - - if (!audmad_config->id3_format) - audmad_config->id3_format = g_strdup("(none)"); - - aud_mime_set_plugin("audio/mpeg", mad_plugin); -} - -static void -audmad_cleanup() -{ - g_free(audmad_config->id3_format); - g_free(audmad_config); - - g_cond_free(mad_cond); - g_mutex_free(mad_mutex); - g_mutex_free(pb_mutex); -} - -static gboolean -mp3_head_check(guint32 head, gint *frameSize) -{ - gint version, layer, bitIndex, bitRate, sampleIndex, sampleRate, padding; - - /* http://www.mp3-tech.org/programmer/frame_header.html - * Bits 21-31 must be set (frame sync) - */ - if ((head & 0xffe00000) != 0xffe00000) - return FALSE; - - /* check if layer bits (17-18) are good */ - layer = (head >> 17) & 0x3; - if (!layer) - return FALSE; /* 00 = reserved */ - layer = 4 - layer; - - /* check if bitrate index bits (12-15) are acceptable */ - bitIndex = (head >> 12) & 0xf; - - /* 1111 and 0000 are reserved values for all layers */ - if (bitIndex == 0xf || bitIndex == 0) - return FALSE; - - /* check samplerate index bits (10-11) */ - sampleIndex = (head >> 10) & 0x3; - if (sampleIndex == 0x3) - return FALSE; - - /* check version bits (19-20) and get bitRate */ - version = (head >> 19) & 0x03; - switch (version) { - case 0: /* 00 = MPEG Version 2.5 */ - case 2: /* 10 = MPEG Version 2 */ - if (layer == 1) - bitRate = mp3_bitrate_table[3][bitIndex]; - else - bitRate = mp3_bitrate_table[4][bitIndex]; - break; - - case 1: /* 01 = reserved */ - return FALSE; - - case 3: /* 11 = MPEG Version 1 */ - bitRate = mp3_bitrate_table[layer][bitIndex]; - break; - - default: - return FALSE; - } - - /* check layer II restrictions vs. bitrate */ - if (layer == 2) { - gint chanMode = (head >> 6) & 0x3; - - if (chanMode == 0x3) { - /* single channel with bitrate > 192 */ - if (bitRate > 192) - return FALSE; - } else { - /* any other mode with bitrates 32-56 and 80. - * NOTICE! this check is not entirely correct, but I think - * it is sufficient in most cases. - */ - if (((bitRate >= 32 && bitRate <= 56) || bitRate == 80)) - return FALSE; - } - } - - /* calculate approx. frame size */ - padding = (head >> 9) & 1; - sampleRate = mp3_samplerate_table[version][sampleIndex]; - if (layer == 1) - *frameSize = ((12 * bitRate * 1000 / sampleRate) + padding) * 4; - else - *frameSize = (144 * bitRate * 1000) / (sampleRate + padding); - - /* check if bits 16 - 19 are all set (MPEG 1 Layer I, not protected?) */ - if (((head >> 19) & 1) == 1 && - ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1) - return FALSE; - - /* not sure why we check this, but ok! */ - if ((head & 0xffff0000) == 0xfffe0000) - return FALSE; - - return TRUE; -} - -static int -mp3_head_convert(const guchar * hbuf) -{ - return ((unsigned long) hbuf[0] << 24) | - ((unsigned long) hbuf[1] << 16) | - ((unsigned long) hbuf[2] << 8) | (unsigned long) hbuf[3]; -} - -// audacious vfs fast version -static int -audmad_is_our_fd(char *filename, VFSFile *fin) -{ - guint32 check; - gchar *ext = extname(filename); - gint cyc = 0, chkcount = 0, chksize = 4096; - guchar buf[4]; - guchar tmp[4096]; - gint ret, i, frameSize; - - info.remote = aud_vfs_is_remote(filename); - - /* I've seen some flac files beginning with id3 frames.. - so let's exclude known non-mp3 filename extensions */ - if ((ext != NULL) && - (!strcasecmp("flac", ext) || !strcasecmp("mpc", ext) || - !strcasecmp("tta", ext) || !strcasecmp("ogg", ext) || - !strcasecmp("wma", ext) ) - ) - return 0; - - if (fin == NULL) { - g_message("fin = NULL"); - return 0; - } - - if(aud_vfs_fread(buf, 1, 4, fin) == 0) { - gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); - g_message("aud_vfs_fread failed @1 %s", tmp); - g_free(tmp); - return 0; - } - - check = mp3_head_convert(buf); - - if (memcmp(buf, "ID3", 3) == 0) - return 1; - else if (memcmp(buf, "OggS", 4) == 0) - return 0; - else if (memcmp(buf, "RIFF", 4) == 0) - { - aud_vfs_fseek(fin, 4, SEEK_CUR); - if(aud_vfs_fread(buf, 1, 4, fin) == 0) { - gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); - g_message("aud_vfs_fread failed @2 %s", tmp); - g_free(tmp); - return 0; - } - - if (memcmp(buf, "RMP3", 4) == 0) - return 1; - } - - // check data for frame header - while (!mp3_head_check(check, &frameSize)) - { - if((ret = aud_vfs_fread(tmp, 1, chksize, fin)) == 0){ - gchar *tmp = g_filename_to_utf8(filename, -1, NULL, NULL, NULL); - g_message("aud_vfs_fread failed @3 %s", tmp); - g_free(tmp); - return 0; - } - for (i = 0; i < ret; i++) - { - check <<= 8; - check |= tmp[i]; - - if (mp3_head_check(check, &frameSize)) { - /* when the first matching frame header is found, we check for - * another frame by seeking to the approximate start of the - * next header ... also reduce the check size. - */ - if (++chkcount >= 3) return 1; - aud_vfs_fseek(fin, frameSize-4, SEEK_CUR); - check = 0; - chksize = 8; - } - } - - if (++cyc > 32) - return 0; - } - - return 1; -} - -// audacious vfs version -static int -audmad_is_our_file(char *filename) -{ - VFSFile *fin = NULL; - gint rtn; - - fin = aud_vfs_fopen(filename, "rb"); - - if (fin == NULL) - return 0; - - rtn = audmad_is_our_fd(filename, fin); - aud_vfs_fclose(fin); - - return rtn; -} - -static void -audmad_stop(InputPlayback *playback) -{ - AUDDBG("f: audmad_stop\n"); - g_mutex_lock(mad_mutex); - info.playback = playback; - g_mutex_unlock(mad_mutex); - - if (decode_thread) { - - g_mutex_lock(mad_mutex); - info.playback->playing = 0; - g_mutex_unlock(mad_mutex); - g_cond_signal(mad_cond); - - AUDDBG("waiting for thread\n"); - g_thread_join(decode_thread); - AUDDBG("thread done\n"); - - input_term(&info); - decode_thread = NULL; - - } - AUDDBG("e: audmad_stop\n"); -} - -static void -audmad_play_file(InputPlayback *playback) -{ - gboolean rtn; - gchar *url = playback->filename; - ReplayGainInfo rg_info; - -#ifdef AUD_DEBUG - { - gchar *tmp = g_filename_to_utf8(url, -1, NULL, NULL, NULL); - AUDDBG("playing %s\n", tmp); - g_free(tmp); - } -#endif /* DEBUG */ - - if (input_init(&info, url, NULL) == FALSE) { - g_message("error initialising input"); - return; - } - - // remote access must use fast scan. - rtn = input_get_info(&info, aud_vfs_is_remote(url) ? TRUE : audmad_config->fast_play_time_calc); - - if (rtn == FALSE) { - g_message("error reading input info"); - /* - * return; - * commenting this return seems to be a hacky fix for the damn lastfm plugin playback - * that used to work only for nenolod because of his fsck-ing lastfm subscription :p - */ - } - - rg_info.track_gain = info.replaygain_track_scale; - rg_info.track_peak = info.replaygain_track_peak; - rg_info.album_gain = info.replaygain_album_scale; - rg_info.album_peak = info.replaygain_album_peak; - AUDDBG("Replay Gain info:\n"); - AUDDBG("* track gain: %+f dB\n", rg_info.track_gain); - AUDDBG("* track peak: %f\n", rg_info.track_peak); - AUDDBG("* album gain: %+f dB\n", rg_info.album_gain); - AUDDBG("* album peak: %f\n", rg_info.album_peak); - playback->set_replaygain_info(playback, &rg_info); - - g_mutex_lock(pb_mutex); - info.playback = playback; - info.playback->playing = 1; - g_mutex_unlock(pb_mutex); - - decode_thread = g_thread_self(); - playback->set_pb_ready(playback); - decode_loop(&info); -} - -static void -audmad_pause(InputPlayback *playback, short paused) -{ - g_mutex_lock(pb_mutex); - info.playback = playback; - g_mutex_unlock(pb_mutex); - playback->output->pause(paused); -} - -static void -audmad_mseek(InputPlayback *playback, gulong millisecond) -{ - g_mutex_lock(pb_mutex); - info.playback = playback; - info.seek = millisecond; - g_mutex_unlock(pb_mutex); -} - -static void -audmad_seek(InputPlayback *playback, gint time) -{ - audmad_mseek(playback, time * 1000); -} - -/** - * Scan the given file or URL. - * Fills in the title string and the track length in milliseconds. - */ -static void -audmad_get_song_info(char *url, char **title, int *length) -{ - struct mad_info_t myinfo; -#ifdef AUD_DEBUG - gchar *tmp = g_filename_to_utf8(url, -1, NULL, NULL, NULL); - AUDDBG("f: audmad_get_song_info: %s\n", tmp); - g_free(tmp); -#endif /* DEBUG */ - - if (input_init(&myinfo, url, NULL) == FALSE) { - AUDDBG("error initialising input\n"); - return; - } - - if (input_get_info(&myinfo, info.remote ? TRUE : audmad_config->fast_play_time_calc) == TRUE) { - if(aud_tuple_get_string(myinfo.tuple, -1, "track-name")) - *title = g_strdup(aud_tuple_get_string(myinfo.tuple, -1, "track-name")); - else - *title = g_strdup(url); - - *length = aud_tuple_get_int(myinfo.tuple, FIELD_LENGTH, NULL); - if(*length == -1) - *length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS); - } - else { - *title = g_strdup(url); - *length = -1; - } - input_term(&myinfo); - AUDDBG("e: audmad_get_song_info\n"); -} - -static gboolean -audmad_fill_info(struct mad_info_t *info, VFSFile *fd) -{ - if (fd == NULL || info == NULL) return FALSE; - AUDDBG("f: audmad_fill_info(): %s\n", fd->uri); - - if (input_init(info, fd->uri, fd) == FALSE) { - AUDDBG("audmad_fill_info(): error initialising input\n"); - return FALSE; - } - - info->fileinfo_request = FALSE; /* we don't need to read tuple again */ - return input_get_info(info, aud_vfs_is_remote(fd->uri) ? TRUE : audmad_config->fast_play_time_calc); -} - -static void -audmad_about() -{ - static GtkWidget *aboutbox; - gchar *scratch; - - if (aboutbox != NULL) - return; - - scratch = g_strdup_printf( - _("Audacious MPEG Audio Plugin\n" - "\n" - "Compiled against libMAD version: %d.%d.%d%s\n" - "\n" - "Written by:\n" - " William Pitcock <nenolod@sacredspiral.co.uk>\n" - " Yoshiki Yazawa <yaz@cc.rim.or.jp>\n" - "\n" - "Portions derived from XMMS-MAD by:\n" - " Sam Clegg\n" - "\n" - "ReplayGain support by:\n" - " Samuel Krempp"), - MAD_VERSION_MAJOR, MAD_VERSION_MINOR, MAD_VERSION_PATCH, - MAD_VERSION_EXTRA); - - aboutbox = audacious_info_dialog(_("About MPEG Audio Plugin"), - scratch, - _("Ok"), FALSE, NULL, NULL); - - g_free(scratch); - - g_signal_connect(G_OBJECT(aboutbox), "destroy", - G_CALLBACK(gtk_widget_destroyed), &aboutbox); -} - -/** - * Display a GTK box containing the given error message. - * Taken from mpg123 plugin. - */ -void -audmad_error(char *error, ...) -{ -#ifndef NOGUI - if (!error_dialog) { - va_list args; - char string[256]; - va_start(args, error); - vsnprintf(string, 256, error, args); - va_end(args); - GDK_THREADS_ENTER(); - error_dialog = - audacious_info_dialog(_("Error"), string, _("Ok"), FALSE, 0, 0); - gtk_signal_connect(GTK_OBJECT(error_dialog), "destroy", - GTK_SIGNAL_FUNC(gtk_widget_destroyed), - &error_dialog); - GDK_THREADS_LEAVE(); - } -#endif /* !NOGUI */ -} - -extern void audmad_configure(); - -static void -__set_and_free(Tuple *tuple, gint nfield, gchar *name, gchar *value) -{ - aud_tuple_associate_string(tuple, nfield, name, value); - g_free(value); -} - -// tuple stuff -static Tuple * -__audmad_get_song_tuple(char *filename, VFSFile *fd) -{ - Tuple *tuple = NULL; - gchar *string = NULL; - - struct id3_file *id3file = NULL; - struct id3_tag *tag = NULL; - - struct mad_info_t myinfo; - - gboolean local_fd = FALSE; - int length; - -#ifdef AUD_DEBUG - string = aud_str_to_utf8(filename); - AUDDBG("f: mad: audmad_get_song_tuple: %s\n", string); - g_free(string); - string = NULL; -#endif - - /* isn't is obfuscated? --eugene */ - - if(info.remote && mad_timer_count(info.duration, MAD_UNITS_SECONDS) <= 0){ - if((fd && aud_vfs_is_streaming(fd)) || (info.playback && info.playback->playing)) { - gchar *tmp = NULL; - tuple = aud_tuple_new_from_filename(filename); - -#ifdef AUD_DEBUG - if(info.playback) - AUDDBG("info.playback->playing = %d\n",info.playback->playing); -#endif - tmp = aud_vfs_get_metadata(info.infile ? info.infile : fd, "track-name"); - if(tmp){ - gchar *scratch; - - scratch = aud_str_to_utf8(tmp); - aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, scratch); - g_free(tmp); - g_free(scratch); - - tmp = NULL; - } - tmp = aud_vfs_get_metadata(info.infile ? info.infile : fd, "stream-name"); - if(tmp){ - gchar *scratch; - - scratch = aud_str_to_utf8(tmp); - aud_tuple_associate_string(tuple, FIELD_TITLE, NULL, scratch); - g_free(tmp); - g_free(scratch); - - tmp = NULL; - } - - AUDDBG("audmad_get_song_tuple: track_name = %s\n", aud_tuple_get_string(tuple, -1, "track-name")); - AUDDBG("audmad_get_song_tuple: stream_name = %s\n", aud_tuple_get_string(tuple, -1, "stream-name")); - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1); - aud_tuple_associate_int(tuple, FIELD_MTIME, NULL, 0); // this indicates streaming - AUDDBG("get_song_tuple: remote: tuple\n"); - return tuple; - } - AUDDBG("get_song_tuple: remote: NULL\n"); - } /* info.remote */ - - // if !fd, pre-open the file with aud_vfs_fopen() and reuse fd. - if(!fd) { - fd = aud_vfs_fopen(filename, "rb"); - if(!fd) - return NULL; - local_fd = TRUE; - } - - if (!audmad_fill_info(&myinfo, fd)) { - AUDDBG("get_song_tuple: error obtaining info\n"); - if (local_fd) aud_vfs_fclose(fd); - return NULL; - } - - tuple = aud_tuple_new(); - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, -1); - - id3file = id3_file_vfsopen(fd, ID3_FILE_MODE_READONLY); - - if (id3file) { - - tag = id3_file_tag(id3file); - if (tag) { - __set_and_free(tuple, FIELD_ARTIST, NULL, input_id3_get_string(tag, ID3_FRAME_ARTIST)); - __set_and_free(tuple, FIELD_ALBUM, NULL, input_id3_get_string(tag, ID3_FRAME_ALBUM)); - __set_and_free(tuple, FIELD_TITLE, NULL, input_id3_get_string(tag, ID3_FRAME_TITLE)); - - // year - string = NULL; - string = input_id3_get_string(tag, ID3_FRAME_YEAR); //TDRC - if (!string) - string = input_id3_get_string(tag, "TYER"); - - if (string) { - aud_tuple_associate_int(tuple, FIELD_YEAR, NULL, atoi(string)); - g_free(string); - string = NULL; - } - - __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename)); - __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename)); - aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename)); - - // length - length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS); - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, length); - - // track number - string = input_id3_get_string(tag, ID3_FRAME_TRACK); - if (string) { - aud_tuple_associate_int(tuple, FIELD_TRACK_NUMBER, NULL, atoi(string)); - g_free(string); - string = NULL; - } - // genre - __set_and_free(tuple, FIELD_GENRE, NULL, input_id3_get_string(tag, ID3_FRAME_GENRE)); - __set_and_free(tuple, FIELD_COMMENT, NULL, input_id3_get_string(tag, ID3_FRAME_COMMENT)); - AUDDBG("genre = %s\n", aud_tuple_get_string(tuple, FIELD_GENRE, NULL)); - } - id3_file_close(id3file); - } // id3file - else { // no id3tag - __set_and_free(tuple, FIELD_FILE_NAME, NULL, aud_uri_to_display_basename(filename)); - __set_and_free(tuple, FIELD_FILE_PATH, NULL, aud_uri_to_display_dirname(filename)); - aud_tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, extname(filename)); - // length - length = mad_timer_count(myinfo.duration, MAD_UNITS_MILLISECONDS); - aud_tuple_associate_int(tuple, FIELD_LENGTH, NULL, length); - } - - aud_tuple_associate_string(tuple, FIELD_QUALITY, NULL, "lossy"); - aud_tuple_associate_int(tuple, FIELD_BITRATE, NULL, myinfo.bitrate / 1000); - - string = g_strdup_printf("MPEG-1 Audio Layer %d", myinfo.mpeg_layer); - aud_tuple_associate_string(tuple, FIELD_CODEC, NULL, string); - g_free(string); - - aud_tuple_associate_string(tuple, FIELD_MIMETYPE, NULL, "audio/mpeg"); - - input_term(&myinfo); - - if(local_fd) - aud_vfs_fclose(fd); - - AUDDBG("e: mad: audmad_get_song_tuple\n"); - return tuple; -} - -static Tuple * -audmad_get_song_tuple(char *filename) -{ - return __audmad_get_song_tuple(filename, NULL); -} - -static Tuple * -audmad_probe_for_tuple(char *filename, VFSFile *fd) -{ - if (!audmad_is_our_fd(filename, fd)) - return NULL; - - aud_vfs_rewind(fd); - - return __audmad_get_song_tuple(filename, fd); -} - -static gchar *fmts[] = { "mp3", "mp2", "mpg", "bmu", NULL }; - -InputPlugin mad_ip = { - .description = "MPEG Audio Plugin (experimental)", - .init = audmad_init, - .about = audmad_about, - .configure = audmad_configure, - .is_our_file = audmad_is_our_file, - .play_file = audmad_play_file, - .stop = audmad_stop, - .pause = audmad_pause, - .seek = audmad_seek, - .cleanup = audmad_cleanup, - .get_song_info = audmad_get_song_info, - .get_song_tuple = audmad_get_song_tuple, - .is_our_file_from_vfs = audmad_is_our_fd, - .vfs_extensions = fmts, - .mseek = audmad_mseek, - .probe_for_tuple = audmad_probe_for_tuple, - .update_song_tuple = audmad_update_song_tuple, -}; - -InputPlugin *madplug_iplist[] = { &mad_ip, NULL }; - -SIMPLE_INPUT_PLUGIN(madplug, madplug_iplist); - -InputPlugin *mad_plugin = &mad_ip;
--- a/src/madplug_x/plugin.h Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,133 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 AUD_MAD_H -#define AUD_MAD_H - -/* #define AUD_DEBUG 1 */ -/* #define DEBUG_INTENSIVELY 1 */ -/* #define DEBUG_DITHER 1 */ - -#undef G_LOG_DOMAIN -#define G_LOG_DOMAIN "MADPlug" - -#undef PACKAGE -#define PACKAGE "audacious-plugins" - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <audacious/plugin.h> -#include <audacious/main.h> -#include <audacious/util.h> -#include <audacious/strings.h> -#include <audacious/i18n.h> -#include <audacious/id3tag.h> -#include <mad.h> - -#include "xing.h" - -struct mad_info_t -{ - /* InputPlayback */ - InputPlayback *playback; - - /* seek time */ - gulong seek; /**< seek time in milliseconds */ - - /* state */ - guint current_frame;/**< current mp3 frame */ - mad_timer_t pos; /**< current play position */ - - /* song info */ - guint vbr; /**< bool: is vbr? */ - guint bitrate; /**< avg. bitrate */ - guint freq; /**< sample freq. */ - guint mpeg_layer; /**< mpeg layer */ - guint mode; /**< mpeg stereo mode */ - guint channels; - gint frames; /**< total mp3 frames or -1 */ - gint fmt; /**< sample format */ - gint size; /**< file size in bytes or -1 */ - gchar *title; /**< title for xmms */ - mad_timer_t duration; /**< total play time */ - struct id3_tag *tag; - struct id3_file *id3file; - struct xing xing; - Tuple *tuple; /* audacious tuple data */ - gchar *prev_title; /* used to optimize set_info calls */ - - /* replay parameters */ - double replaygain_album_scale; - double replaygain_track_scale; - gchar *replaygain_album_str; - gchar *replaygain_track_str; - double replaygain_album_peak; /* 0 if gain/peak pair not set */ - double replaygain_track_peak; /* 0 if gain/peak pair not set */ - gchar *replaygain_album_peak_str; - gchar *replaygain_track_peak_str; - double mp3gain_undo; // -1 if not set - double mp3gain_minmax; - gchar *mp3gain_undo_str; - gchar *mp3gain_minmax_str; - - /* data access */ - gchar *url; - gchar *filename; - VFSFile *infile; - gint offset; - - /* flags */ - gboolean remote; - gboolean fileinfo_request; - -}; - -typedef struct audmad_config_t -{ - gboolean fast_play_time_calc; - gboolean use_xing; - gboolean dither; - gboolean sjis; - gboolean title_override; - gchar *id3_format; - gboolean show_avg_vbr_bitrate; - gboolean force_reopen_audio; -} audmad_config_t; - -// global variables -extern InputPlugin *mad_plugin; -extern audmad_config_t *audmad_config; - -// gcond -extern GMutex *mad_mutex; -extern GMutex *pb_mutex; -extern GCond *mad_cond; - -// prototypes -void audmad_config_compute(struct audmad_config_t *config); -void input_process_remote_metadata(struct mad_info_t *info); -gpointer decode_loop(gpointer arg); -void audmad_error(gchar * fmt, ...); -void audmad_configure(void); - -#endif /* !AUD_MAD_H */
--- a/src/madplug_x/replaygain.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,340 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * Copyright (C) 2001-2007 Samuel Krempp - * - * 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; under version 2 of the License. - * - * 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 - */ - -#include "plugin.h" -#include <stdlib.h> -#include <math.h> -#include <ctype.h> -#include <assert.h> -#include "replaygain.h" - -static unsigned long -Read_LE_Uint32(const unsigned char *p) -{ - return ((unsigned long) p[0] << 0) | - ((unsigned long) p[1] << 8) | - ((unsigned long) p[2] << 16) | ((unsigned long) p[3] << 24); -} - -static int -uncase_strcmp(const char *s1, const char *s2) -{ - int l1 = strlen(s1); - int l2 = strlen(s2); - int i; - for (i = 0; i < l1 && i < l2; ++i) { - if (toupper(s1[i]) < toupper(s2[i])) - return -1; - } - if (l1 == l2) - return 0; - return (l1 < l2) ? -1 : +1; -} - -static gdouble -strgain2double(gchar * s, int len) -{ - gchar *strval = g_strndup(s, len); - gdouble res = g_strtod(s, NULL); // gain, in dB. - g_free(strval); - return res; -} - -// Reads APE v2.0 tag ending at current pos in fp - -static int -ReadAPE2Tag(VFSFile * fp, struct mad_info_t *file_info) -{ - unsigned long vsize; - unsigned long isize; - unsigned long flags; - char *buff; - char *p; - char *end; - struct APETagFooterStruct T, *tp; - unsigned long TagLen; - unsigned long TagCount; - - tp = &T; - - if (aud_vfs_fseek(fp, -sizeof(T), SEEK_CUR) != 0) - return 18; - if (aud_vfs_fread(tp, 1, sizeof(T), fp) != sizeof T) - return 2; - if (memcmp(tp->ID, "APETAGEX", sizeof(tp->ID)) != 0) - return 3; - if (Read_LE_Uint32(tp->Version) != 2000) - return 4; - TagLen = Read_LE_Uint32(tp->Length); - if (TagLen < sizeof(T)) - return 5; - if (aud_vfs_fseek(fp, -TagLen, SEEK_CUR) != 0) - return 6; - if ((buff = (char *) malloc(TagLen)) == NULL) { - return 7; - } - if (aud_vfs_fread(buff, 1, TagLen - sizeof(T), fp) != TagLen - sizeof(T)) { - free(buff); - return 8; - } - - AUDDBG("ver = %ld\n", Read_LE_Uint32(tp->Version)); - AUDDBG("taglen = %ld\n", TagLen); - - TagCount = Read_LE_Uint32(tp->TagCount); - end = buff + TagLen - sizeof(T); - for (p = buff; p < end && TagCount--;) { - vsize = Read_LE_Uint32((unsigned char *)p); - p += 4; - flags = Read_LE_Uint32((unsigned char *)p); - p += 4; - isize = strlen((char *) p); - - if (isize > 0 && vsize > 0) { - gdouble *scale = NULL; - gchar **str = NULL; - if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_GAIN") == 0) { - scale = &file_info->replaygain_album_scale; - str = &file_info->replaygain_album_str; - } - if (uncase_strcmp(p, "REPLAYGAIN_TRACK_GAIN") == 0) { - scale = &file_info->replaygain_track_scale; - str = &file_info->replaygain_track_str; - } - if (str != NULL) { - assert(scale != NULL); - *scale = strgain2double(p + isize + 1, vsize); - *str = g_strndup(p + isize + 1, vsize); - } - //* case of peak info tags : */ - str = NULL; - if (uncase_strcmp(p, "REPLAYGAIN_TRACK_PEAK") == 0) { - scale = &file_info->replaygain_track_peak; - str = &file_info->replaygain_track_peak_str; - } - if (uncase_strcmp(p, "REPLAYGAIN_ALBUM_PEAK") == 0) { - scale = &file_info->replaygain_album_peak; - str = &file_info->replaygain_album_peak_str; - } - if (str != NULL) { - *scale = strgain2double(p + isize + 1, vsize); - *str = g_strndup(p + isize + 1, vsize); - } - - /* mp3gain additional tags : - the gain tag translates to scale = 2^(gain/4), - i.e., in dB : 20*log(2)/log(10)*gain/4 - -> 1.501*gain dB - */ - if (uncase_strcmp(p, "MP3GAIN_UNDO") == 0) { - str = &file_info->mp3gain_undo_str; - scale = &file_info->mp3gain_undo; - assert(4 < vsize); /* this tag is +left,+right */ - *str = g_strndup(p + isize + 1, vsize); - *scale = 1.50515 * atoi(*str); - } - if (uncase_strcmp(p, "MP3GAIN_MINMAX") == 0) { - str = &file_info->mp3gain_minmax_str; - scale = &file_info->mp3gain_minmax; - *str = g_strndup(p + isize + 1, vsize); - assert(4 < vsize); /* this tag is min,max */ - *scale = 1.50515 * (atoi((*str) + 4) - atoi(*str)); - } - } - p += isize + 1 + vsize; - } - - free(buff); - - return 0; -} - -static int -find_offset(VFSFile * fp) -{ - static const char *key = "APETAGEX"; - char buff[20000]; - int N = 0; - if (aud_vfs_fseek(fp, -20000, SEEK_CUR) != 0); - if ((N = aud_vfs_fread(buff, 1, 20000, fp)) < 16) - return 1; - int matched = 0; - int i, last_match = -1; - for (i = 0; i < N; ++i) { - if (buff[i] == key[matched]) - ++matched; - else { - if (matched == 5 && buff[i] == 'P') - matched = 2; // got "APET" + "AP" - else - matched = 0; - } - if (matched == 8) { - last_match = i; - matched = 0; - } - } - if (last_match == -1) - return 1; - return last_match + 1 - 8 + sizeof(struct APETagFooterStruct) - N; -} - -/* Eugene Zagidullin: - * Read ReplayGain info from foobar2000-style id3v2 frames */ - -static int -ReadId3v2TXXX(struct mad_info_t *file_info) -{ - int i; - char *key; - char *value; - struct id3_frame *frame; - - AUDDBG("f: ReadId3v2TXXX\n"); - - /* tag must be read before! */ - if (! file_info->tag ) { - AUDDBG("id3v2 not found\n"); - return 0; - } - - /* Partially based on code from MPD (http://www.musicpd.org/) */ - for (i = 0; (frame = id3_tag_findframe(file_info->tag, "TXXX", i)); i++) { - if (frame->nfields < 3) - continue; - - key = (char *) - id3_ucs4_latin1duplicate(id3_field_getstring - (&frame->fields[1])); - value = (char *) - id3_ucs4_latin1duplicate(id3_field_getstring - (&frame->fields[2])); - - if (strcasecmp(key, "replaygain_track_gain") == 0) { - file_info->replaygain_track_scale = strgain2double(value, strlen(value)); - file_info->replaygain_track_str = g_strdup(value); - } else if (strcasecmp(key, "replaygain_album_gain") == 0) { - file_info->replaygain_album_scale = strgain2double(value, strlen(value)); - file_info->replaygain_album_str = g_strdup(value); - } else if (strcasecmp(key, "replaygain_track_peak") == 0) { - file_info->replaygain_track_peak = g_strtod(value, NULL); - file_info->replaygain_track_peak_str = g_strdup(value); - } else if (strcasecmp(key, "replaygain_album_peak") == 0) { - file_info->replaygain_album_peak = g_strtod(value, NULL); - file_info->replaygain_album_peak_str = g_strdup(value); - } - - free(key); - free(value); - } - - return 0; -} - -void -read_replaygain(struct mad_info_t *file_info) -{ - VFSFile *fp; - glong curpos = 0; - - AUDDBG("f: read_replaygain\n"); - - file_info->replaygain_track_peak = 0.0; - file_info->replaygain_track_scale = 0.0; - file_info->replaygain_album_peak = 0.0; - file_info->replaygain_album_scale = 0.0; - file_info->mp3gain_undo = -77; - file_info->mp3gain_minmax = -77; - - if (ReadId3v2TXXX(file_info)) { - AUDDBG("found ReplayGain info in id3v2 tag\n"); -#ifdef AUD_DEBUG - gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL); - - AUDDBG("RG album scale= %g, RG track scale = %g, in %s\n", - file_info->replaygain_album_scale, - file_info->replaygain_track_scale, tmp); - g_free(tmp); -#endif - return; - } - - - /* APEv2 stuff */ - if (file_info->infile) { - fp = aud_vfs_dup(file_info->infile); - curpos = aud_vfs_ftell(fp); - } - else { - if ((fp = aud_vfs_fopen(file_info->filename, "rb")) == NULL) - return; - } - - if (aud_vfs_fseek(fp, 0L, SEEK_END) != 0) { - aud_vfs_fclose(fp); - return; - } - - long pos = aud_vfs_ftell(fp); - int res = -1; - int try = 0; - while (res != 0 && try < 10) { - // try skipping an id3 tag - aud_vfs_fseek(fp, pos, SEEK_SET); - aud_vfs_fseek(fp, try * -128, SEEK_CUR); - res = ReadAPE2Tag(fp, file_info); - ++try; - } - if (res != 0) { - // try brute search (don't want to parse all possible kinds of tags..) - aud_vfs_fseek(fp, pos, SEEK_SET); - int offs = find_offset(fp); - if (offs <= 0) { // found ! - aud_vfs_fseek(fp, pos, SEEK_SET); - aud_vfs_fseek(fp, offs, SEEK_CUR); - res = ReadAPE2Tag(fp, file_info); - if (res != 0) { - g_message - ("hmpf, was supposed to find a tag.. offs=%d, res=%d", - offs, res); - } - } - else - AUDDBG("replaygain: not found\n"); - } -#ifdef AUD_DEBUG - if (res == 0) { // got APE tags, show the result - gchar *tmp = g_filename_to_utf8(file_info->filename, -1, NULL, NULL, NULL); - AUDDBG("RG album scale= %g, RG track scale = %g, in %s\n", - file_info->replaygain_album_scale, - file_info->replaygain_track_scale, tmp); - g_free(tmp); - } -#endif - - if (file_info->infile) - aud_vfs_fseek(fp, curpos, SEEK_SET); - - aud_vfs_fclose(fp); - - AUDDBG("e: read_replaygain\n"); -}
--- a/src/madplug_x/replaygain.h Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * Copyright (C) 2001-2007 Samuel Krempp - * - * 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; under version 2 of the License. - * - * 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 - */ - -#include "plugin.h" -#include "stdlib.h" -#include "math.h" -#include "ctype.h" - -#ifndef __replaygain_h__ -#define __replaygain_h__ - -struct APETagFooterStruct -{ - unsigned char ID[8]; - unsigned char Version[4]; - unsigned char Length[4]; - unsigned char TagCount[4]; - unsigned char Flags[4]; - unsigned char Reserved[8]; -}; - -/* prototypes */ -void read_replaygain(struct mad_info_t *file_info); - -#endif
--- a/src/madplug_x/tuple.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,188 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 - */ - -#include "config.h" - -#include "plugin.h" -#include "tuple.h" -#include "input.h" - -#include <math.h> -#include <string.h> - -#include <glib.h> -#include <glib/gprintf.h> - -#include <audacious/util.h> -#include <audacious/plugin.h> -#include <audacious/id3tag.h> - -#include <langinfo.h> - -static void -update_id3_frame(struct id3_tag *tag, const char *frame_name, const char *data, int sjis) -{ - int res; - struct id3_frame *frame; - union id3_field *field; - id3_ucs4_t *ucs4; - - if (data == NULL) - return; - - /* printf ("updating id3: %s: %s\n", frame_name, data); - - - An empty string removes the frame altogether. - */ - if (strlen(data) == 0) { - while ((frame = id3_tag_findframe(tag, frame_name, 0))) { - AUDDBG("madplug: detachframe\n"); - id3_tag_detachframe(tag, frame); - } - return; - } - - frame = id3_tag_findframe(tag, frame_name, 0); - if (!frame) { - AUDDBG("frame_new\n"); - frame = id3_frame_new(frame_name); - id3_tag_attachframe(tag, frame); - } - - /* setup ucs4 string */ - if(sjis) { - ucs4 = id3_latin1_ucs4duplicate((id3_latin1_t *) data); - } - else { - ucs4 = id3_utf8_ucs4duplicate((id3_utf8_t *) data); - } - - /* set encoding */ - field = id3_frame_field(frame, 0); - id3_field_settextencoding(field, sjis ? ID3_FIELD_TEXTENCODING_ISO_8859_1 : - ID3_FIELD_TEXTENCODING_UTF_8); - - /* setup genre code */ - if (!strcmp(frame_name, ID3_FRAME_GENRE)) { - char *tmp; - int index = id3_genre_number(ucs4); - g_free(ucs4); - - if(index == -1) { /* unknown genre. remove TCON frame. */ - AUDDBG("madplug: remove genre frame\n"); - id3_tag_detachframe(tag, frame); - } - else { /* meaningful genre */ - tmp = g_strdup_printf("%d", index); - ucs4 = id3_latin1_ucs4duplicate((unsigned char *) tmp); - } - - } - - /* write string */ - if (!strcmp(frame_name, ID3_FRAME_COMMENT)) { - field = id3_frame_field(frame, 3); - field->type = ID3_FIELD_TYPE_STRINGFULL; - res = id3_field_setfullstring(field, ucs4); - } - else { - field = id3_frame_field(frame, 1); - field->type = ID3_FIELD_TYPE_STRINGLIST; - res = id3_field_setstrings(field, 1, &ucs4); - } - - if (res != 0) - g_print("error setting id3 field: %s\n", frame_name); -} - -static void -update_id3_frame_from_tuple(struct id3_tag *id3tag, const char *field, Tuple *tuple, int fieldn, int sjis) -{ - int val; - char *text, *text2; - const char *encoding = sjis ? "SJIS" : "UTF-8"; - - if(aud_tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_INT) { - val = aud_tuple_get_int(tuple, fieldn, NULL); - if(val > 0) { - text2 = g_strdup_printf("%d", val); - AUDDBG("madplug: updating field:\"%s\"=\"%s\", enc %s\n", field, text2, encoding); - update_id3_frame(id3tag, field, text2, 0); - g_free(text2); - } else { - update_id3_frame(id3tag, field, "", 0); /* will be detached */ - } - - } else if(aud_tuple_get_value_type(tuple, fieldn, NULL) == TUPLE_STRING) { - text = (char*)aud_tuple_get_string(tuple, fieldn, NULL); - text2 = g_convert(text, strlen(text), encoding, "UTF-8", NULL, NULL, NULL); - AUDDBG("madplug: updating field:\"%s\"=\"%s\", enc %s\n", field, text2, encoding); - update_id3_frame(id3tag, field, text2, sjis); - g_free(text2); - } -} - -gboolean -audmad_update_song_tuple(Tuple *tuple, VFSFile *fd) -{ - struct id3_file *id3file; - struct id3_tag *id3tag; - gchar *text; - struct mad_info_t songinfo; - - if ((id3file = id3_file_vfsopen(fd, ID3_FILE_MODE_READWRITE)) == NULL) return FALSE; - - id3tag = id3_file_tag(id3file); - if (!id3tag) { - AUDDBG("no id3tag\n. append new tag.\n"); - id3tag = id3_tag_new(); - id3_tag_clearframes(id3tag); - id3tag->options |= ID3_TAG_OPTION_APPENDEDTAG | ID3_TAG_OPTION_ID3V1; - } - - id3_tag_options(id3tag, ID3_TAG_OPTION_ID3V1, ~0); /* enables id3v1. TODO: make id3v1 optional */ - - update_id3_frame_from_tuple(id3tag, ID3_FRAME_TITLE, tuple, FIELD_TITLE, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_ARTIST, tuple, FIELD_ARTIST, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_ALBUM, tuple, FIELD_ALBUM, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_YEAR, tuple, FIELD_YEAR, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_COMMENT, tuple, FIELD_COMMENT, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_TRACK, tuple, FIELD_TRACK_NUMBER, audmad_config->sjis); - update_id3_frame_from_tuple(id3tag, ID3_FRAME_GENRE, tuple, FIELD_GENRE, audmad_config->sjis); - - if(!id3_tag_findframe(id3tag, "TLEN", 0) && input_init(&songinfo, fd->uri, fd) && !songinfo.remote) { - AUDDBG("update TLEN frame\n"); - songinfo.fileinfo_request = FALSE; /* we don't need to read tuple again */ - input_get_info(&songinfo, FALSE); - text = g_strdup_printf("%ld", mad_timer_count(songinfo.duration, MAD_UNITS_MILLISECONDS)); - AUDDBG("TLEN: \"%s\"\n", text); - update_id3_frame(id3tag, "TLEN", text, 0); - g_free(text); - input_term(&songinfo); - } - - if (id3_file_update(id3file) != 0) return FALSE; - - id3_file_close(id3file); - return TRUE; -} -
--- a/src/madplug_x/tuple.h Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa, Eugene Zagidullin - * - * Portions derived from xmms-mad: - * Copyright (C) 2001-2002 Sam Clegg - See COPYING - * - * 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; under version 2 of the License. - * - * 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 TUPLE_H -#define TUPLE_H - -#include <glib.h> -#include <audacious/plugin.h> - -gboolean audmad_update_song_tuple(Tuple *tuple, VFSFile *fd); - -#endif
--- a/src/madplug_x/xing.c Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * mad plugin for audacious - * Copyright (C) 2005-2007 William Pitcock, Yoshiki Yazawa - * - * Derived from: 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; under version 2 of the License. - * - * 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 - */ - -#include <mad.h> - -#include "xing.h" - -#define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g') - -/* - * NAME: xing->init() - * DESCRIPTION: initialize Xing structure - */ -void -xing_init(struct xing *xing) -{ - xing->flags = 0; - xing->frames = 0; - xing->bytes = 0; - xing->toc[0] = '\0'; - xing->scale = 0; -} - -/* - * NAME: xing->parse() - * DESCRIPTION: parse a Xing VBR header - */ -int -xing_parse(struct xing *xing, struct mad_bitptr ptr, - unsigned int bitlen) -{ - if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) - goto fail; - - xing->flags = mad_bit_read(&ptr, 32); - bitlen -= 64; - - if (xing->flags & XING_FRAMES) { - if (bitlen < 32) - goto fail; - - xing->frames = mad_bit_read(&ptr, 32); - bitlen -= 32; - } - - if (xing->flags & XING_BYTES) { - if (bitlen < 32) - goto fail; - - xing->bytes = mad_bit_read(&ptr, 32); - bitlen -= 32; - } - - if (xing->flags & XING_TOC) { - int i; - - if (bitlen < 800) - goto fail; - - for (i = 0; i < 100; ++i) - xing->toc[i] = mad_bit_read(&ptr, 8); - - bitlen -= 800; - } - - if (xing->flags & XING_SCALE) { - if (bitlen < 32) - goto fail; - - xing->scale = mad_bit_read(&ptr, 32); - bitlen -= 32; - } - - return 0; - - fail: - xing->flags = 0; - return -1; -}
--- a/src/madplug_x/xing.h Fri Feb 15 19:19:09 2008 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -/* - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef XING_H -#define XING_H - -#include "mad.h" - -struct xing -{ - long flags; /* valid fields (see below) */ - unsigned long frames; /* total number of frames */ - unsigned long bytes; /* total number of bytes */ - unsigned char toc[100]; /* 100-point seek table */ - long scale; /* ?? */ -}; - -enum -{ - XING_FRAMES = 0x00000001L, - XING_BYTES = 0x00000002L, - XING_TOC = 0x00000004L, - XING_SCALE = 0x00000008L -}; - -void xing_init(struct xing *); - -#define xing_finish(xing) /* nothing */ - -int xing_parse(struct xing *, struct mad_bitptr, unsigned int); - -#endif