Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 18229 Details for
Bug 29477
XMMS RVA Patch (Relative Volume Adjustment)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
The RVA patch
xmms-1.2.8-rva.patch (text/plain), 24.76 KB, created by
Jasmin Buchert
on 2003-09-23 19:05:23 UTC
(
hide
)
Description:
The RVA patch
Filename:
MIME Type:
Creator:
Jasmin Buchert
Created:
2003-09-23 19:05:23 UTC
Size:
24.76 KB
patch
obsolete
>diff -ruN xmms-old/Input/mpg123/Makefile.am xmms-new/Input/mpg123/Makefile.am >--- xmms-old/Input/mpg123/Makefile.am 2003-03-18 15:59:36.000000000 +0100 >+++ xmms-new/Input/mpg123/Makefile.am 2003-09-23 11:46:29.000000000 +0200 >@@ -6,11 +6,11 @@ > COMMON_SRC = mpg123.c configure.c fileinfo.c common.c \ > decode_2to1.c decode_4to1.c \ > layer1.c layer2.c layer3.c \ >-tabinit.c equalizer.c http.c \ >+tabinit.c equalizer.c http.c voladjust.c \ > huffman.h mpg123.h l2tables.h getbits.h \ > dxhead.c dxhead.h \ > id3.c id3.h id3_frame.c id3_frame_content.c id3_frame_text.c \ >-id3_frame_url.c id3_header.h id3_tag.c >+id3_frame_url.c id3_frame_volume.c id3_header.h id3_tag.c > > if ARCH_X86 > >diff -ruN xmms-old/Input/mpg123/configure.c xmms-new/Input/mpg123/configure.c >--- xmms-old/Input/mpg123/configure.c 2002-10-06 18:35:23.000000000 +0200 >+++ xmms-new/Input/mpg123/configure.c 2003-09-23 11:48:54.000000000 +0200 >@@ -27,6 +27,10 @@ > static GtkWidget *streaming_proxy_hbox, *streaming_proxy_auth_hbox, *streaming_save_dirbrowser; > static GtkWidget *streaming_save_hbox, *title_id3_box, *title_tag_desc; > static GtkWidget *title_override, *title_id3_entry, *title_id3v2_disable; >+static GtkWidget *volume_rva2_enable, *volume_boost_enable, *volume_dither_enable; >+static GtkWidget *volume_gain_label, *volume_clip_frame; >+static GtkWidget *volume_limiter_enable, *volume_reducegain_enable; >+static gchar volume_gaintext[24]; > > MPG123Config mpg123_cfg; > >@@ -105,6 +109,14 @@ > mpg123_cfg.disable_id3v2 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(title_id3v2_disable)); > g_free(mpg123_cfg.id3_format); > mpg123_cfg.id3_format = g_strdup(gtk_entry_get_text(GTK_ENTRY(title_id3_entry))); >+ mpg123_cfg.use_rva2 = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(volume_rva2_enable)); >+ mpg123_cfg.use_boost = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(volume_boost_enable)); >+ mpg123_cfg.enable_dither = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(volume_dither_enable)); >+ if (GTK_TOGGLE_BUTTON(volume_limiter_enable)->active) >+ mpg123_cfg.anticlip_mode = 0; >+ else if (GTK_TOGGLE_BUTTON(volume_reducegain_enable)->active) >+ mpg123_cfg.anticlip_mode = 1; >+ mpg123_voladjust_update(NULL); > > filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); > cfg = xmms_cfg_open_file(filename); >@@ -135,6 +147,10 @@ > xmms_cfg_write_boolean(cfg, "MPG123", "disable_id3v2", mpg123_cfg.disable_id3v2); > xmms_cfg_write_string(cfg, "MPG123", "id3_format", mpg123_cfg.id3_format); > xmms_cfg_write_int(cfg, "MPG123", "detect_by", mpg123_cfg.detect_by); >+ xmms_cfg_write_boolean(cfg, "MPG123", "use_rva2", mpg123_cfg.use_rva2); >+ xmms_cfg_write_boolean(cfg, "MPG123", "use_boost", mpg123_cfg.use_boost); >+ xmms_cfg_write_boolean(cfg, "MPG123", "enable_dither", mpg123_cfg.enable_dither); >+ xmms_cfg_write_int(cfg, "MPG123", "anticlip_mode", mpg123_cfg.anticlip_mode); > #ifdef USE_SIMD > xmms_cfg_write_int(cfg, "MPG123", "default_synth", mpg123_cfg.default_synth); > #endif >@@ -212,6 +228,16 @@ > gtk_widget_set_sensitive(title_tag_desc, override); > } > >+static void volume_rva2_cb(GtkWidget * w, gpointer data) >+{ >+ gboolean rva2_on; >+ rva2_on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(volume_rva2_enable)); >+ gtk_widget_set_sensitive(volume_boost_enable, rva2_on); >+ gtk_widget_set_sensitive(volume_dither_enable, rva2_on); >+ gtk_widget_set_sensitive(volume_clip_frame, rva2_on); >+ gtk_widget_set_sensitive(volume_gain_label, rva2_on); >+} >+ > static void configure_destroy(GtkWidget * w, gpointer data) > { > if (streaming_save_dirbrowser) >@@ -230,6 +256,7 @@ > GtkWidget *streaming_save_label, *streaming_save_browse; > GtkWidget *streaming_cast_frame, *streaming_cast_vbox; > GtkWidget *title_frame, *title_id3_vbox, *title_id3_label; >+ GtkWidget *volume_frame, *volume_vbox, *volume_clip_vbox; > GtkWidget *bbox, *ok, *cancel; > > char *temp; >@@ -578,6 +605,67 @@ > gtk_box_pack_start(GTK_BOX(title_id3_vbox), title_tag_desc, FALSE, FALSE, 0); > gtk_notebook_append_page(GTK_NOTEBOOK(notebook), title_frame, gtk_label_new(_("Title"))); > >+ /* >+ * Volume adjustment config >+ */ >+ volume_frame = gtk_frame_new(_("Volume Adjustment:")); >+ gtk_container_border_width(GTK_CONTAINER(volume_frame), 5); >+ >+ volume_vbox = gtk_vbox_new(FALSE, 10); >+ gtk_container_border_width(GTK_CONTAINER(volume_vbox), 5); >+ gtk_container_add(GTK_CONTAINER(volume_frame), volume_vbox); >+ >+ volume_rva2_enable = gtk_check_button_new_with_label(_("Enable ID3 relative volume adjust")); >+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(volume_rva2_enable), >+ mpg123_cfg.use_rva2); >+ gtk_signal_connect(GTK_OBJECT(volume_rva2_enable), "clicked", volume_rva2_cb, NULL); >+ gtk_box_pack_start(GTK_BOX(volume_vbox), volume_rva2_enable, FALSE, FALSE, 0); >+ >+ volume_boost_enable = gtk_check_button_new_with_label(_("Enable 6dB boost")); >+ gtk_widget_set_sensitive(volume_boost_enable, mpg123_cfg.use_rva2); >+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(volume_boost_enable), >+ mpg123_cfg.use_boost); >+ gtk_box_pack_start(GTK_BOX(volume_vbox), volume_boost_enable, FALSE, FALSE, 0); >+ >+ volume_dither_enable = gtk_check_button_new_with_label(_("Enable dithering")); >+ gtk_widget_set_sensitive(volume_dither_enable, mpg123_cfg.use_rva2); >+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(volume_dither_enable), >+ mpg123_cfg.enable_dither); >+ gtk_box_pack_start(GTK_BOX(volume_vbox), volume_dither_enable, FALSE, FALSE, 0); >+ >+ volume_clip_frame = gtk_frame_new(_("Clipping Prevention:")); >+ gtk_widget_set_sensitive(volume_clip_frame, mpg123_cfg.use_rva2); >+ gtk_container_border_width(GTK_CONTAINER(volume_clip_frame), 5); >+ >+ volume_clip_vbox = gtk_vbox_new(FALSE, 10); >+ gtk_container_border_width(GTK_CONTAINER(volume_clip_vbox), 5); >+ gtk_container_add(GTK_CONTAINER(volume_clip_frame), volume_clip_vbox); >+ >+ volume_limiter_enable = gtk_radio_button_new_with_label(NULL, _("Use limiter")); >+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(volume_limiter_enable), >+ mpg123_cfg.anticlip_mode == 0); >+ gtk_box_pack_start(GTK_BOX(volume_clip_vbox), volume_limiter_enable, FALSE, FALSE, 0); >+ >+ volume_reducegain_enable = gtk_radio_button_new_with_label(gtk_radio_button_group(GTK_RADIO_BUTTON(volume_limiter_enable)), _("Reduce gain")); >+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(volume_reducegain_enable), >+ mpg123_cfg.anticlip_mode == 1); >+ gtk_box_pack_start(GTK_BOX(volume_clip_vbox), volume_reducegain_enable, FALSE, FALSE, 0); >+ >+ gtk_box_pack_start(GTK_BOX(volume_vbox), volume_clip_frame, FALSE, FALSE, 0); >+ >+ if (fabs(mpg123_current_gain) < 0.0001) >+ strcpy(volume_gaintext, _("Current gain: none")); >+ else >+ g_snprintf(volume_gaintext, 24, _("Current gain: %0.2fdB"), >+ mpg123_current_gain); >+ volume_gain_label = gtk_label_new(volume_gaintext); >+ gtk_widget_set_sensitive(volume_gain_label, mpg123_cfg.use_rva2); >+ gtk_box_pack_end(GTK_BOX(volume_vbox), volume_gain_label, FALSE, FALSE, 0); >+ >+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), volume_frame, gtk_label_new(_("Volume"))); >+ >+ >+ > 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); >diff -ruN xmms-old/Input/mpg123/id3.h xmms-new/Input/mpg123/id3.h >--- xmms-old/Input/mpg123/id3.h 2003-06-10 15:05:29.000000000 +0200 >+++ xmms-new/Input/mpg123/id3.h 2003-09-23 11:46:29.000000000 +0200 >@@ -140,6 +140,40 @@ > > > /* >+ * Structure describing volume adjustment info in an RVA2 frame. >+ */ >+struct id3_gain { >+ struct { >+ >+ /* gain in decibels */ >+ float ch_gain; >+ >+ /* We shift peak values to be 32 bits, e.g. a 17-bit peak is >+ * left shifted 15 (the low 15 bits are padded with zero). >+ * This way, we can always treat the peak as being out of 32 >+ * bits. RVA2 peak values can be up to 255 bits, but the high >+ * 32 bits should more than suffice for us. */ >+ guint32 ch_peak; >+ >+ } channel[9]; >+}; >+ >+/* >+ * These are both RVA2 channel type numbers, and indexes into the >+ * channel element of struct id3_gain. >+ */ >+#define ID3_CHANNEL_OTHER 0x00 >+#define ID3_CHANNEL_MASTER 0x01 >+#define ID3_CHANNEL_FRIGHT 0x02 >+#define ID3_CHANNEL_FLEFT 0x03 >+#define ID3_CHANNEL_BRIGHT 0x04 >+#define ID3_CHANNEL_BLEFT 0x05 >+#define ID3_CHANNEL_FCENTER 0x06 >+#define ID3_CHANNEL_BCENTER 0x07 >+#define ID3_CHANNEL_SUB 0x08 >+ >+ >+/* > * Text encodings. > */ > #define ID3_ENCODING_ISO_8859_1 0x00 >@@ -359,6 +393,9 @@ > char *id3_get_url(struct id3_frame *); > char *id3_get_url_desc(struct id3_frame *); > >+/* From id3_frame_volume.c */ >+int id3_get_rva2_gain(struct id3_frame *frame, struct id3_gain *gn); >+ > /* From id3_tag.c */ > void id3_init_tag(struct id3_tag *id3); > int id3_read_tag(struct id3_tag *id3); >diff -ruN xmms-old/Input/mpg123/id3_frame_volume.c xmms-new/Input/mpg123/id3_frame_volume.c >--- xmms-old/Input/mpg123/id3_frame_volume.c 1970-01-01 01:00:00.000000000 +0100 >+++ xmms-new/Input/mpg123/id3_frame_volume.c 2003-09-23 11:46:29.000000000 +0200 >@@ -0,0 +1,144 @@ >+/********************************************************************* >+ * >+ * Filename: id3_frame_volume.c >+ * Description: Code for handling ID3 relative volume adjust frames. >+ * Author: Chris Vaill <cvaill@cs.columbia.edu> >+ * Created at: Thu Sep 26 23:57:00 2002 >+ * >+ * 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. >+ * >+ ********************************************************************/ >+#include <stdio.h> >+#include <string.h> >+ >+#include "id3.h" >+ >+ >+/* Assume buf points to the beginning of one channel's data in an RVA2 >+ * frame. Return the encoded gain, in decibels. */ >+static float decode_rva2_gain(const char *buf) >+{ >+ int gain_fp; /* fixed-point */ >+ >+ gain_fp = *(signed char *)(buf + 1) << 8; /* first byte of gain */ >+ gain_fp |= *(unsigned char *)(buf + 2); /* second byte of gain */ >+ >+ return gain_fp / 512.0; >+} >+ >+ >+/* Assume buf points to the beginning of one channel's peak data in an >+ * RVA2 frame (i.e. the fourth byte in the channel's data). Return >+ * the encoded peak, shifted to be a 32-bit value. */ >+static guint32 decode_rva2_peak(const unsigned char *buf) >+{ >+ unsigned int peakbits = (unsigned int)*buf++; >+ int shift, peakbytes; >+ guint32 peak = 0; >+ >+ /* fast path for the common case */ >+ if (peakbits == 16) >+ return (buf[0] << 24) + (buf[1] << 16); >+ >+ /* >+ * We only care about the high 32 bits, so we care about the first >+ * 5 bytes, because unfortunately, sizes that are not whole bytes >+ * are padded on the msb side. >+ * >+ * e.g. a 33 bit peak has its first 7 bits zeroed, followed by 1 >+ * bit and four bytes of peak data. We take the first four bytes >+ * and shift left by 7, giving us 25 bits total. We then take the >+ * top 7 bits of the fifth byte to get our full 32 bits. >+ */ >+ peakbytes = (peakbits + 7) >> 3; >+ if (peakbytes > 4) >+ peakbytes = 4; >+ shift = ((8 - (peakbits & 7)) & 7) + (4 - peakbytes) * 8; >+ >+ /* get up to the first 4 bytes of the peak... */ >+ for (; peakbytes; peakbytes--) { >+ peak <<= 8; >+ peak += (unsigned int)*buf++; >+ } >+ >+ /* ...and shift, so the value is out of 32 bits... */ >+ peak <<= shift; >+ >+ /* ...and finally, add part of the fifth byte, if necessary */ >+ if (peakbits > 32) >+ peak += (unsigned int)*buf >> (8 - shift); >+ >+ return peak; >+} >+ >+ >+/* >+ * Function id3_get_rva2_gain (frame) >+ * >+ * Get the gain and peak info, that is coded in the RVA2 frame, and >+ * return it in the gn struct. Return 0, or -1 on error. >+ */ >+int id3_get_rva2_gain(struct id3_frame *frame, struct id3_gain *gn) >+{ >+ const unsigned char *data; >+ float gain; >+ int i, chan, peakbytes; >+ guint32 peak; >+ >+ /* Type check */ >+ if (frame->fr_desc->fd_id != ID3_RVA2) >+ return -1; >+ >+ /* Check if frame is compressed */ >+ if (id3_decompress_frame(frame) == -1) >+ return -1; >+ >+ /* init gains and peaks to 0 */ >+ memset(gn, 0, sizeof(struct id3_gain)); >+ >+ data = (char *)frame->fr_data; >+ >+ /* skip past identification string */ >+ for (i = 0; i < frame->fr_size; i++) >+ if (data[i] == '\0') >+ break; >+ if (i >= frame->fr_size) >+ return -1; /* ident string not terminated; bad frame data */ >+ >+ /* cycle through channel fields */ >+ i++; >+ while (i + 3 < frame->fr_size) { >+ >+ chan = data[i]; >+ >+ /* decode the gain for this channel */ >+ gain = decode_rva2_gain(data + i); >+ i += 3; >+ >+ /* decode the peak for this channel */ >+ peakbytes = (data[i] + 7) / 8; >+ if (i + peakbytes >= frame->fr_size) >+ break; >+ peak = decode_rva2_peak(data + i); >+ i += 1 + peakbytes; >+ >+ if (chan <= 8) { >+ gn->channel[chan].ch_gain = gain; >+ gn->channel[chan].ch_peak = peak; >+ } >+ } >+ >+ return 0; >+} >diff -ruN xmms-old/Input/mpg123/layer1.c xmms-new/Input/mpg123/layer1.c >--- xmms-old/Input/mpg123/layer1.c 2000-08-02 13:47:50.000000000 +0200 >+++ xmms-new/Input/mpg123/layer1.c 2003-09-23 11:46:29.000000000 +0200 >@@ -176,7 +176,10 @@ > while (mpg123_ip.output->buffer_free() < mpg123_pcm_point && mpg123_info->going && mpg123_info->jump_to_time == -1) > xmms_usleep(10000); > if (mpg123_info->going && mpg123_info->jump_to_time == -1) >+ { >+ mpg123_voladjust(mpg123_pcm_sample, mpg123_pcm_point); > mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); >+ } > } > mpg123_pcm_point = 0; > } >diff -ruN xmms-old/Input/mpg123/layer2.c xmms-new/Input/mpg123/layer2.c >--- xmms-old/Input/mpg123/layer2.c 2002-09-30 16:03:18.000000000 +0200 >+++ xmms-new/Input/mpg123/layer2.c 2003-09-23 11:46:29.000000000 +0200 >@@ -330,7 +330,10 @@ > while (mpg123_ip.output->buffer_free() < mpg123_pcm_point && mpg123_info->going && mpg123_info->jump_to_time == -1) > xmms_usleep(10000); > if (mpg123_info->going && mpg123_info->jump_to_time == -1) >+ { >+ mpg123_voladjust(mpg123_pcm_sample, mpg123_pcm_point); > mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); >+ } > > > } >diff -ruN xmms-old/Input/mpg123/layer3.c xmms-new/Input/mpg123/layer3.c >--- xmms-old/Input/mpg123/layer3.c 2003-03-18 15:59:40.000000000 +0100 >+++ xmms-new/Input/mpg123/layer3.c 2003-09-23 11:46:29.000000000 +0200 >@@ -1947,7 +1947,10 @@ > mpg123_info->going && mpg123_info->jump_to_time == -1) > xmms_usleep(10000); > if (mpg123_info->going && mpg123_info->jump_to_time == -1) >+ { >+ mpg123_voladjust(mpg123_pcm_sample, mpg123_pcm_point); > mpg123_ip.output->write_audio(mpg123_pcm_sample, mpg123_pcm_point); >+ } > } > mpg123_pcm_point = 0; > } >diff -ruN xmms-old/Input/mpg123/mpg123.c xmms-new/Input/mpg123/mpg123.c >--- xmms-old/Input/mpg123/mpg123.c 2003-09-23 11:41:01.000000000 +0200 >+++ xmms-new/Input/mpg123/mpg123.c 2003-09-23 11:49:49.000000000 +0200 >@@ -200,6 +200,10 @@ > if (!xmms_cfg_read_string(cfg, "MPG123", "id3_format", &mpg123_cfg.id3_format)) > mpg123_cfg.id3_format = g_strdup("%p - %t"); > xmms_cfg_read_int(cfg, "MPG123", "detect_by", &mpg123_cfg.detect_by); >+ xmms_cfg_read_boolean(cfg, "MPG123", "use_rva2", &mpg123_cfg.use_rva2); >+ xmms_cfg_read_boolean(cfg, "MPG123", "use_boost", &mpg123_cfg.use_boost); >+ xmms_cfg_read_boolean(cfg, "MPG123", "enable_dither", &mpg123_cfg.enable_dither); >+ xmms_cfg_read_boolean(cfg, "MPG123", "anticlip_mode", &mpg123_cfg.anticlip_mode); > xmms_cfg_read_int(cfg, "MPG123", "default_synth", &mpg123_cfg.default_synth); > > xmms_cfg_free(cfg); >@@ -920,6 +924,7 @@ > mpg123_info->num_frames * mpg123_info->tpf * 1000; > if (!mpg123_title) > mpg123_title = get_song_title(NULL,filename); >+ mpg123_voladjust_update(filename); > } > else > { >@@ -1076,6 +1081,7 @@ > g_free(mpg123_pcm_sample); > mpg123_filename = NULL; > g_free(filename); >+ mpg123_voladjust_cleanup(); > pthread_exit(NULL); > } > >diff -ruN xmms-old/Input/mpg123/mpg123.h xmms-new/Input/mpg123/mpg123.h >--- xmms-old/Input/mpg123/mpg123.h 2003-09-04 15:48:34.000000000 +0200 >+++ xmms-new/Input/mpg123/mpg123.h 2003-09-23 11:50:18.000000000 +0200 >@@ -157,6 +157,8 @@ > gchar *id3_format; > gboolean title_override, disable_id3v2; > int detect_by; >+ gboolean use_rva2, use_boost, enable_dither; >+ gint anticlip_mode; > int default_synth; > } > MPG123Config; >@@ -300,6 +302,11 @@ > gchar *mpg123_format_song_title(struct id3tag_t *tag, gchar *filename); > double mpg123_relative_pos(void); > >+extern float mpg123_current_gain; >+void mpg123_voladjust_cleanup(void); >+void mpg123_voladjust_update(char *filename); >+void mpg123_voladjust(void *ptr, int length); >+ > > > extern unsigned char *mpg123_conv16to8; >diff -ruN xmms-old/Input/mpg123/voladjust.c xmms-new/Input/mpg123/voladjust.c >--- xmms-old/Input/mpg123/voladjust.c 1970-01-01 01:00:00.000000000 +0100 >+++ xmms-new/Input/mpg123/voladjust.c 2003-09-23 11:46:29.000000000 +0200 >@@ -0,0 +1,356 @@ >+#include "mpg123.h" >+#include <string.h> >+#include <stdlib.h> >+ >+ >+#define ROUND(x) ((int)floor((x) + 0.5)) >+ >+extern gchar *mpg123_filename; >+ >+float mpg123_current_gain = 0.0; >+ >+/* lookup table for fast gain adjustments */ >+static gint32 *volume_lut = NULL; >+static struct id3_gain gain_info; >+static int adjusting = FALSE; >+ >+/* track details of the lookup table, so we only rebuild if we need to */ >+static struct { >+ AFormat lut_fmt; >+ float lut_gain; >+ int lut_limit; >+ int lut_boost; >+} lut_data; >+ >+/* >+ * A buffer of 8192 random numbers makes the period of the noise about >+ * 85 ms, or 11.7 Hz, for 48 kHz stereo. This should be low enough to >+ * be unrecognizable except as noise. >+ */ >+#define NOISEBUF_SZ 8192 >+static char *noisebuf; >+static int noisebufi = 0; >+ >+/* >+ * Returns 8 random bits, ie a number from -128 to +127. >+ * Used for dithering. >+ */ >+static int >+rand8(void) >+{ >+ int retval = (int)noisebuf[noisebufi]; >+ noisebufi = (noisebufi + 1) % NOISEBUF_SZ; >+ return retval; >+} >+ >+ >+/* >+ * Limiter function: >+ * >+ * / tanh((x + lev) / (1-lev)) * (1-lev) - lev (for x < -lev) >+ * | >+ * x' = | x (for |x| <= lev) >+ * | >+ * \ tanh((x - lev) / (1-lev)) * (1-lev) + lev (for x > lev) >+ * >+ * With limiter level = 0, this is equivalent to a tanh() function; >+ * with limiter level = 1, this is equivalent to clipping. >+ */ >+#define lmtr_lvl 0.5 >+static double >+limiter(double x) >+{ >+ double xp; >+ >+ if (x < -lmtr_lvl) >+ xp = tanh((x + lmtr_lvl) / (1-lmtr_lvl)) * (1-lmtr_lvl) - lmtr_lvl; >+ else if (x <= lmtr_lvl) >+ xp = x; >+ else >+ xp = tanh((x - lmtr_lvl) / (1-lmtr_lvl)) * (1-lmtr_lvl) + lmtr_lvl; >+ >+ return xp; >+} >+ >+ >+void mpg123_voladjust_cleanup(void) >+{ >+ adjusting = FALSE; >+ if (noisebuf) >+ g_free(noisebuf); >+ noisebuf = NULL; >+ if (volume_lut) >+ g_free(volume_lut - 0x8000); >+ volume_lut = NULL; >+ return; >+} >+ >+ >+static void update_dither(void) >+{ >+ int i; >+ >+ if (mpg123_cfg.use_rva2 && mpg123_cfg.enable_dither) >+ { >+ /* fill the noise buffer, which we will cycle through >+ when dithering */ >+ if (noisebuf == NULL) { >+ noisebuf = g_malloc(NOISEBUF_SZ); >+ for (i = 0; i < (NOISEBUF_SZ / sizeof(int)); i++) >+ ((int *)noisebuf)[i] = rand(); >+ noisebufi = 0; >+ /* Note: noise shaping on the dithering noise >+ is not implemented, but this would be the >+ place to do it */ >+ } >+ } >+ else >+ { >+ if (noisebuf) >+ g_free(noisebuf); >+ noisebuf = NULL; >+ } >+} >+ >+ >+static int gain_from_id3_tag(char *filename, struct id3_gain *gn) >+{ >+ FILE *file; >+ struct id3_tag *id3d; >+ struct id3_frame *id3frm; >+ >+ file = fopen(filename, "rb"); >+ if (file == NULL) >+ goto err_out; >+ >+ id3d = id3_open_fp(file, 0); >+ if (id3d == NULL) >+ goto err_closefile; >+ >+ id3frm = id3_get_frame(id3d, ID3_RVA2, 1); >+ if (id3frm == NULL) >+ goto err_closeid3; >+ >+ if (id3_get_rva2_gain(id3frm, gn) == -1) >+ goto err_closeid3; >+ >+ id3_close(id3d); >+ fclose(file); >+ return 1; >+ >+ err_closeid3: >+ id3_close(id3d); >+ err_closefile: >+ fclose(file); >+ err_out: >+ memset(gn, 0, sizeof(struct id3_gain)); >+ return 0; >+} >+ >+ >+void mpg123_voladjust_update(char *filename) >+{ >+ struct id3_gain newgain; >+ float gain_db, gain_mult, scale; >+ int i, use_boost, use_limiter = TRUE, need_update = FALSE; >+ int samplemin, samplemax, center; >+ int lut_samplemin, lut_samplemax, lut_center; >+ AFormat fmt; >+ guint32 peak; >+ >+ if (!mpg123_cfg.use_rva2) >+ { >+ mpg123_voladjust_cleanup(); >+ return; >+ } >+ >+ update_dither(); >+ >+ if (filename == NULL) >+ filename = mpg123_filename; >+ >+ if (filename == NULL) >+ return; >+ >+ if (!gain_from_id3_tag(filename, &newgain)) >+ { >+ adjusting = FALSE; >+ mpg123_current_gain = 0.0; >+ memset(&gain_info, 0, sizeof(struct id3_gain)); >+ return; >+ } >+ >+ fmt = mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8; >+ peak = newgain.channel[ID3_CHANNEL_MASTER].ch_peak; >+ gain_db = newgain.channel[ID3_CHANNEL_MASTER].ch_gain; >+ >+ if (volume_lut == NULL) >+ { >+ /* the lookup table is 256k, but is deallocated if >+ volume adjustment is disabled */ >+ volume_lut = g_malloc(0x40000); >+ /* move the pointer to the center of the allocated >+ region, so that we can use negative indices */ >+ volume_lut += 0x8000; >+ need_update = TRUE; >+ } >+ >+ gain_mult = pow(10, gain_db / 20.0); >+ use_boost = mpg123_cfg.use_boost; >+ if (use_boost) >+ gain_mult *= 2; >+ >+ if (peak) >+ { >+ /* >+ * Figure out if the peak, multiplied by the gain, >+ * would clip. >+ * >+ * Some trickery here: we don't want to multiply our >+ * 32-bit peak by the gain, since it may overflow. >+ * Instead, we round it off to 24 bits. We then >+ * compare with 0xFFFF80, instead of 0xFFFFFF, to >+ * leave room for dithering. >+ */ >+ peak = ((peak >> 7) + 1) >> 1; >+ if (peak * gain_mult <= 0xFFFF80) >+ use_limiter = FALSE; >+ >+ if (use_limiter && mpg123_cfg.anticlip_mode == 1) >+ { >+ /* Reduce gain until the peak won't clip. */ >+ gain_mult = 0xFFFF80 / (float)peak; >+ use_limiter = FALSE; >+ } >+ } >+ >+ if (!need_update >+ && lut_data.lut_fmt == fmt >+ && lut_data.lut_limit == use_limiter >+ && lut_data.lut_boost == use_boost >+ && fabs(lut_data.lut_gain - gain_db) < 0.0001) >+ { >+ /* the existing lookup table we have will work, no >+ need to build a new one */ >+ adjusting = TRUE; >+ return; >+ } >+ >+ /* We store 8 extra bits of precision in the table, for use in >+ * dithering. We can make this happen by simply multiplying >+ * the gain by 256. */ >+ gain_mult *= 256.0; >+ >+ if (fmt == FMT_U8) >+ { >+ samplemax = 0xFF; >+ samplemin = 0; >+ lut_samplemax = 0xFFFF; >+ lut_samplemin = 0; >+ } >+ else >+ { /* fmt == FMT_S16_NE */ >+ samplemax = 0x7FFF; >+ samplemin = ~samplemax; >+ lut_samplemax = 0x7FFFFF; >+ lut_samplemin = ~lut_samplemax; >+ } >+ >+ /* leave space for dither, which ranges from -128 to +127 */ >+ lut_samplemax -= 127; >+ lut_samplemin += 128; >+ >+ center = (samplemax + samplemin + 1) >> 1; >+ lut_center = (lut_samplemax + lut_samplemin + 1) >> 1; >+ >+ /* >+ * Build the lookup table >+ */ >+ if (use_limiter) >+ { >+ /* apply gain, and use limiter to avoid clipping */ >+ scale = lut_center - lut_samplemin; >+ for (i = samplemin; i < 0; i++) >+ volume_lut[i] = lut_center + ROUND(scale * limiter((i-center) * gain_mult / scale)); >+ scale = lut_samplemax - lut_center; >+ for (; i <= samplemax; i++) >+ volume_lut[i] = lut_center + ROUND(scale * limiter((i-center) * gain_mult / scale)); >+ } >+ else >+ { >+ /* just apply gain if it wouldn't clip anyway */ >+ for (i = samplemin; i <= samplemax; i++) >+ volume_lut[i] = lut_center + ROUND((i-center) * gain_mult); >+ } >+ >+ lut_data.lut_fmt = fmt; >+ lut_data.lut_gain = gain_db; >+ lut_data.lut_limit = use_limiter; >+ lut_data.lut_boost = use_boost; >+ mpg123_current_gain = gain_db; >+ adjusting = TRUE; >+ >+ return; >+} >+ >+ >+void mpg123_voladjust(void *ptr, int length) >+{ >+ AFormat fmt; >+ int i; >+ long sample; >+ gint16 *ptr16 = NULL; >+ guint8 *ptru8 = NULL; >+ >+ if (!adjusting || !mpg123_cfg.use_rva2 || volume_lut == NULL) >+ return; >+ >+ fmt = mpg123_cfg.resolution == 16 ? FMT_S16_NE : FMT_U8; >+ >+ if (fmt == FMT_U8) >+ { >+ ptru8 = (guint8 *)ptr; >+ if (mpg123_cfg.enable_dither) >+ { >+ for (i = 0; i < length; i++) >+ { >+ sample = volume_lut[*ptru8]; >+ sample += rand8(); >+ sample >>= 8; >+ *ptru8 = sample; >+ ptru8++; >+ } >+ } >+ else >+ { >+ for (i = 0; i < length; i++) >+ { >+ *ptru8 = volume_lut[*ptru8] >> 8; >+ ptru8++; >+ } >+ } >+ } >+ else >+ { /* fmt == FMT_S16_NE */ >+ ptr16 = (gint16 *)ptr; >+ if (mpg123_cfg.enable_dither) >+ { >+ for (i = 0; i < length; i += 2) >+ { >+ sample = volume_lut[*ptr16]; >+ sample += rand8(); >+ sample >>= 8; >+ *ptr16 = sample; >+ ptr16++; >+ } >+ } >+ else >+ { >+ for (i = 0; i < length; i += 2) >+ { >+ *ptr16 = volume_lut[*ptr16] >> 8; >+ ptr16++; >+ } >+ } >+ } >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 29477
: 18229 |
18230