diff --git a/Makefile.am b/Makefile.am
index 58d1964e4..3ca89e165 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -116,7 +116,7 @@ mpd_headers = \
 	src/mixer/pulse_mixer_plugin.h \
 	src/daemon.h \
 	src/normalize.h \
-	src/compress.h \
+	src/AudioCompress/compress.h \
 	src/buffer.h \
 	src/pipe.h \
 	src/chunk.h \
@@ -253,7 +253,7 @@ src_mpd_SOURCES = \
 	src/event_pipe.c \
 	src/daemon.c \
 	src/normalize.c \
-	src/compress.c \
+	src/AudioCompress/compress.c \
 	src/buffer.c \
 	src/pipe.c \
 	src/chunk.c \
diff --git a/NEWS b/NEWS
index 60a19799a..ab17b672e 100644
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,7 @@ ver 0.16 (20??/??/??)
   - support .mpdignore files in the music directory
   - sort songs by album name first, then disc/track number
   - rescan after metadata_to_use change
+* normalize: upgraded to AudioCompress 2.0
 * log unused/unknown block parameters
 * removed the deprecated "error_file" option
 * save state when stopped
diff --git a/src/AudioCompress/compress.c b/src/AudioCompress/compress.c
new file mode 100644
index 000000000..bf72b2eab
--- /dev/null
+++ b/src/AudioCompress/compress.c
@@ -0,0 +1,184 @@
+/* compress.c
+ * Compressor logic
+ *
+ * (c)2007 busybee (http://beesbuzz.biz/
+ * Licensed under the terms of the LGPL. See the file COPYING for details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+#include "compress.h"
+
+struct Compressor {
+        //! The compressor's preferences
+        struct CompressorConfig prefs;
+        
+        //! History of the peak values
+        int *peaks;
+                
+        //! History of the gain values
+        int *gain;
+        
+        //! History of clip amounts
+        int *clipped;
+        
+        unsigned int pos;
+        unsigned int bufsz;
+};
+
+struct Compressor *Compressor_new(unsigned int history)
+{
+	struct Compressor *obj = malloc(sizeof(struct Compressor));
+
+	obj->prefs.target = TARGET;
+	obj->prefs.maxgain = GAINMAX;
+	obj->prefs.smooth = GAINSMOOTH;
+
+        obj->peaks = obj->gain = obj->clipped = NULL;
+	obj->bufsz = 0;
+        obj->pos = 0;
+        
+        Compressor_setHistory(obj, history);
+        
+        return obj;
+}
+
+void Compressor_delete(struct Compressor *obj)
+{
+	if (obj->peaks)
+		free(obj->peaks);
+	if (obj->gain)
+		free(obj->gain);
+	if (obj->clipped)
+		free(obj->clipped);
+	free(obj);
+}
+
+static int *resizeArray(int *data, int newsz, int oldsz)
+{
+        data = realloc(data, newsz*sizeof(int));
+        if (newsz > oldsz)
+                memset(data + oldsz, 0, sizeof(int)*(newsz - oldsz));
+        return data;
+}
+
+void Compressor_setHistory(struct Compressor *obj, unsigned int history)
+{
+	if (!history)
+                history = BUCKETS;
+        
+        obj->peaks = resizeArray(obj->peaks, history, obj->bufsz);
+        obj->gain = resizeArray(obj->gain, history, obj->bufsz);
+        obj->clipped = resizeArray(obj->clipped, history, obj->bufsz);
+        obj->bufsz = history;
+}
+
+struct CompressorConfig *Compressor_getConfig(struct Compressor *obj)
+{
+        return &obj->prefs;
+}
+
+void Compressor_Process_int16(struct Compressor *obj, int16_t *audio, 
+                              unsigned int count)
+{
+        struct CompressorConfig *prefs = Compressor_getConfig(obj);
+	int16_t *ap;
+	unsigned int i;
+        int *peaks = obj->peaks;
+        int curGain = obj->gain[obj->pos];
+        int newGain;
+        int peakVal = 1;
+        int peakPos = 0;
+        int slot = (obj->pos + 1) % obj->bufsz;
+        int *clipped = obj->clipped + slot;
+        unsigned int ramp = count;
+        int delta;
+        
+	ap = audio;
+	for (i = 0; i < count; i++)
+	{
+		int val = *ap++;
+                if (val < 0)
+                        val = -val;
+		if (val > peakVal)
+                {
+			peakVal = val;
+                        peakPos = i;
+                }
+	}
+	peaks[slot] = peakVal;
+
+
+	for (i = 0; i < obj->bufsz; i++)
+	{
+		if (peaks[i] > peakVal)
+		{
+			peakVal = peaks[i];
+			peakPos = 0;
+		}
+	}
+
+	//! Determine target gain
+	newGain = (1 << 10)*prefs->target/peakVal;
+        
+        //! Adjust the gain with inertia from the previous gain value
+        newGain = (curGain*((1 << prefs->smooth) - 1) + newGain) 
+                >> prefs->smooth;
+        
+        //! Make sure it's no more than the maximum gain value
+        if (newGain > (prefs->maxgain << 10))
+                newGain = prefs->maxgain << 10;
+        
+        //! Make sure it's no less than 1:1
+	if (newGain < (1 << 10))
+		newGain = 1 << 10;
+
+        //! Make sure the adjusted gain won't cause clipping
+        if ((peakVal*newGain >> 10) > 32767)
+        {
+                newGain = (32767 << 10)/peakVal;
+                //! Truncate the ramp time
+                ramp = peakPos;
+        }
+        
+        //! Record the new gain
+        obj->gain[slot] = newGain;
+
+        if (!ramp)
+                ramp = 1;
+        if (!curGain)
+                curGain = 1 << 10;
+	delta = (newGain - curGain) / (int)ramp;
+
+	ap = audio;
+        *clipped = 0;
+	for (i = 0; i < count; i++)
+	{
+		int sample;
+
+		//! Amplify the sample
+		sample = *ap*curGain >> 10;
+		if (sample < -32768)
+		{
+			*clipped += -32768 - sample;
+			sample = -32768;
+		} else if (sample > 32767)
+		{
+			*clipped += sample - 32767;
+			sample = 32767;
+		}
+		*ap++ = sample;
+
+                //! Adjust the gain
+                if (i < ramp)
+                        curGain += delta;
+                else
+                        curGain = newGain;
+	}
+
+        obj->pos = slot;
+}
+
diff --git a/src/AudioCompress/compress.h b/src/AudioCompress/compress.h
new file mode 100644
index 000000000..cc875c6da
--- /dev/null
+++ b/src/AudioCompress/compress.h
@@ -0,0 +1,40 @@
+/*! compress.h
+ *  interface to audio compression
+ *
+ *  (c)2007 busybee (http://beesbuzz.biz/)
+ *  Licensed under the terms of the LGPL. See the file COPYING for details.
+ */
+
+#ifndef COMPRESS_H
+#define COMPRESS_H
+
+#include <sys/types.h>
+
+//! Configuration values for the compressor object
+struct CompressorConfig {
+	int target;
+	int maxgain;
+	int smooth;
+};
+
+struct Compressor;
+
+//! Create a new compressor (use history value of 0 for default)
+struct Compressor *Compressor_new(unsigned int history);
+
+//! Delete a compressor
+void Compressor_delete(struct Compressor *);
+
+//! Set the history length
+void Compressor_setHistory(struct Compressor *, unsigned int history);
+
+//! Get the configuration for a compressor
+struct CompressorConfig *Compressor_getConfig(struct Compressor *);
+
+//! Process 16-bit signed data
+void Compressor_Process_int16(struct Compressor *, int16_t *data, unsigned int count);
+
+//! TODO: Compressor_Process_int32, Compressor_Process_float, others as needed
+
+//! TODO: functions for getting at the peak/gain/clip history buffers (for monitoring)
+#endif
diff --git a/src/compress.c b/src/compress.c
deleted file mode 100644
index 27f223bd7..000000000
--- a/src/compress.c
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2003-2009 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Imported from AudioCompress by J. Shagam <fluffy@beesbuzz.biz>
- */
-
-#include "config.h"
-#include "compress.h"
-
-#include <glib.h>
-
-#include <stdint.h>
-#include <string.h>
-
-#ifdef USE_X
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-static Display *display;
-static Window window;
-static Visual *visual;
-static int screen;
-static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
-#endif
-
-static int *peaks;
-static int gainCurrent, gainTarget;
-
-static struct {
-	int show_mon;
-	int anticlip;
-	int target;
-	int gainmax;
-	int gainsmooth;
-	unsigned buckets;
-} prefs;
-
-#ifdef USE_X
-static int mon_init;
-#endif
-
-void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
-		 int gainsmooth, unsigned buckets)
-{
-	static unsigned lastsize;
-
-	prefs.show_mon = show_mon;
-	prefs.anticlip = anticlip;
-	prefs.target = target;
-	prefs.gainmax = gainmax;
-	prefs.gainsmooth = gainsmooth;
-	prefs.buckets = buckets;
-
-	/* Allocate the peak structure */
-	peaks = g_realloc(peaks, sizeof(int)*prefs.buckets);
-
-	if (prefs.buckets > lastsize)
-		memset(peaks + lastsize, 0, sizeof(int)*(prefs.buckets
-							 - lastsize));
-	lastsize = prefs.buckets;
-
-#ifdef USE_X
-	/* Configure the monitor window if needed */
-	if (show_mon && !mon_init)
-	{
-		display = XOpenDisplay(getenv("DISPLAY"));
-
-		/* We really shouldn't try to init X if there's no X */
-		if (!display)
-		{
-			fprintf(stderr,
-				"X not detected; disabling monitor window\n");
-			show_mon = prefs.show_mon = 0;
-		}
-	}
-
-	if (show_mon && !mon_init)
-	{
-		XGCValues gcv;
-		XColor col;
-	
-		gainCurrent = gainTarget = (1 << GAINSHIFT);
-
-
-
-		screen = DefaultScreen(display);
-		visual = DefaultVisual(display, screen);
-		window = XCreateSimpleWindow(display,
-					     RootWindow(display, screen),
-					     0, 0, prefs.buckets, 128 + 8, 0,
-					     BlackPixel(display, screen),
-					     WhitePixel(display, screen));
-		XStoreName(display, window, "AudioCompress monitor");
-	
-		gcv.foreground = BlackPixel(display, screen);
-		blackGC = XCreateGC(display, window, GCForeground, &gcv);
-		gcv.foreground = WhitePixel(display, screen);
-		whiteGC = XCreateGC(display, window, GCForeground, &gcv);
-		col.red = 0;
-		col.green = 0;
-		col.blue = 65535;
-		XAllocColor(display, DefaultColormap(display, screen), &col);
-		gcv.foreground = col.pixel;
-		blueGC = XCreateGC(display, window, GCForeground, &gcv);
-		col.red = 65535;
-		col.green = 65535;
-		col.blue = 0;
-		XAllocColor(display, DefaultColormap(display, screen), &col);
-		gcv.foreground = col.pixel;
-		yellowGC = XCreateGC(display, window, GCForeground, &gcv);
-		col.red = 32767;
-		col.green = 32767;
-		col.blue = 0;
-		XAllocColor(display, DefaultColormap(display, screen), &col);
-		gcv.foreground = col.pixel;
-		dkyellowGC = XCreateGC(display, window, GCForeground, &gcv);
-		col.red = 65535;
-		col.green = 0;
-		col.blue = 0;
-		XAllocColor(display, DefaultColormap(display, screen), &col);
-		gcv.foreground = col.pixel;
-		redGC = XCreateGC(display, window, GCForeground, &gcv);
-		mon_init = 1;
-	}
-
-	if (mon_init)
-	{
-		if (show_mon)
-			XMapWindow(display, window);
-		else
-			XUnmapWindow(display, window);
-		XResizeWindow(display, window, prefs.buckets, 128 + 8);
-		XFlush(display);
-	}
-#endif
-}
-
-void CompressFree(void)
-{
-#ifdef USE_X
-	if (mon_init)
-	{
-		XFreeGC(display, blackGC);
-		XFreeGC(display, whiteGC);
-		XFreeGC(display, blueGC);
-		XFreeGC(display, yellowGC);
-		XFreeGC(display, dkyellowGC);
-		XFreeGC(display, redGC);
-		XDestroyWindow(display, window);
-		XCloseDisplay(display);
-	}
-#endif
-
-	g_free(peaks);
-}
-
-void CompressDo(void *data, unsigned int length)
-{
-	int16_t *audio = (int16_t *)data, *ap;
-	int peak;
-	unsigned int i, pos;
-	int gr, gf, gn;
-	static int pn = -1;
-#ifdef STATS
-	static int clip;
-#endif
-	static int clipped;
-
-	if (!peaks)
-		return;
-
-	if (pn == -1)
-	{
-		for (i = 0; i < prefs.buckets; i++)
-			peaks[i] = 0;
-	}
-	pn = (pn + 1)%prefs.buckets;
-
-#ifdef DEBUG
-	fprintf(stderr, "modifyNative16(0x%08x, %d)\n",(unsigned int)data,
-		length);
-#endif
-
-	/* Determine peak's value and position */
-	peak = 1;
-	pos = 0;
-
-#ifdef DEBUG
-	fprintf(stderr, "finding peak(b=%d)\n", pn);
-#endif
-
-	ap = audio;
-	for (i = 0; i < length/2; i++)
-	{
-		int val = *ap;
-		if (val > peak)
-		{
-			peak = val;
-			pos = i;
-		} else if (-val > peak)
-		{
-			peak = -val;
-			pos = i;
-		}
-		ap++;
-	}
-	peaks[pn] = peak;
-
-	/* Only draw if needed, of course */
-#ifdef USE_X
-	if (prefs.show_mon)
-	{
-		/* current amplitude */
-		XDrawLine(display, window, whiteGC,
-			  pn, 0,
-			  pn,
-			  127 -
-			  (peaks[pn]*gainCurrent >> (GAINSHIFT + 8)));
-
-		/* amplification */
-		XDrawLine(display, window, yellowGC,
-			  pn,
-			  127 - (peaks[pn]*gainCurrent
-				 >> (GAINSHIFT + 8)),
-			  pn, 127);
-
-		/* peak */
-		XDrawLine(display, window, blackGC,
-			  pn, 127 - (peaks[pn] >> 8), pn, 127);
-
-		/* clip indicator */
-		if (clipped)
-			XDrawLine(display, window, redGC,
-				  (pn + prefs.buckets - 1)%prefs.buckets,
-				  126 - clipped/(length*512),
-				  (pn + prefs.buckets - 1)%prefs.buckets,
-				  127);
-		clipped = 0;
-
-		/* target line */
-		/* XDrawPoint(display, window, redGC, */
-		/*         pn, 127 - TARGET/256); */
-		/* amplification edge */
-		XDrawLine(display, window, dkyellowGC,
-			  pn,
-			  127 - (peaks[pn]*gainCurrent
-				 >> (GAINSHIFT + 8)),
-			  pn - 1,
-			  127 -
-			  (peaks[(pn + prefs.buckets
-				  - 1)%prefs.buckets]*gainCurrent
-			   >> (GAINSHIFT + 8)));
-	}
-#endif
-
-	for (i = 0; i < prefs.buckets; i++)
-	{
-		if (peaks[i] > peak)
-		{
-			peak = peaks[i];
-			pos = 0;
-		}
-	}
-
-	/* Determine target gain */
-	gn = (1 << GAINSHIFT)*prefs.target/peak;
-
-	if (gn <(1 << GAINSHIFT))
-		gn = 1 << GAINSHIFT;
-
-	gainTarget = (gainTarget *((1 << prefs.gainsmooth) - 1) + gn)
-				      >> prefs.gainsmooth;
-
-	/* Give it an extra insignifigant nudge to counteract possible
-	** rounding error
-	*/
-
-	if (gn < gainTarget)
-		gainTarget--;
-	else if (gn > gainTarget)
-		gainTarget++;
-
-	if (gainTarget > prefs.gainmax << GAINSHIFT)
-		gainTarget = prefs.gainmax << GAINSHIFT;
-
-
-#ifdef USE_X
-	if (prefs.show_mon)
-	{
-		int x;
-
-		/* peak*gain */
-		XDrawPoint(display, window, redGC,
-			   pn,
-			   127 - (peak*gainCurrent
-				  >> (GAINSHIFT + 8)));
-
-		/* gain indicator */
-		XFillRectangle(display, window, whiteGC, 0, 128,
-			       prefs.buckets, 8);
-		x = (gainTarget - (1 << GAINSHIFT))*prefs.buckets
-			/ ((prefs.gainmax - 1) << GAINSHIFT);
-		XDrawLine(display, window, redGC, x,
-			  128, x, 128 + 8);
-
-		x = (gn - (1 << GAINSHIFT))*prefs.buckets
-			/ ((prefs.gainmax - 1) << GAINSHIFT);
-
-		XDrawLine(display, window, blackGC,
-			  x, 132 - 1,
-			  x, 132 + 1);
-
-		/* blue peak line */
-		XDrawLine(display, window, blueGC,
-			  0, 127 - (peak >> 8), prefs.buckets,
-			  127 - (peak >> 8));
-		XFlush(display);
-		XDrawLine(display, window, whiteGC,
-			  0, 127 - (peak >> 8), prefs.buckets,
-			  127 - (peak >> 8));
-	}
-#endif
-
-	/* See if a peak is going to clip */
-	gn = (1 << GAINSHIFT)*32768/peak;
-
-	if (gn < gainTarget)
-	{
-		gainTarget = gn;
-
-		if (prefs.anticlip)
-			pos = 0;
-
-	} else
-	{
-		/* We're ramping up, so draw it out over the whole frame */
-		pos = length;
-	}
-
-	/* Determine gain rate necessary to make target */
-	if (!pos)
-		pos = 1;
-
-	gr = ((gainTarget - gainCurrent) << 16)/(int)pos;
-
-	/* Do the shiznit */
-	gf = gainCurrent << 16;
-
-#ifdef STATS
-	fprintf(stderr, "\rgain = %2.2f%+.2e ",
-		gainCurrent*1.0/(1 << GAINSHIFT),
-		(gainTarget - gainCurrent)*1.0/(1 << GAINSHIFT));
-#endif
-
-	ap = audio;
-	for (i = 0; i < length/2; i++)
-	{
-		int sample;
-
-		/* Interpolate the gain */
-		gainCurrent = gf >> 16;
-		if (i < pos)
-			gf += gr;
-		else if (i == pos)
-			gf = gainTarget << 16;
-
-		/* Amplify */
-		sample = (*ap)*gainCurrent >> GAINSHIFT;
-		if (sample < -32768)
-		{
-#ifdef STATS
-			clip++;
-#endif
-			clipped += -32768 - sample;
-			sample = -32768;
-		} else if (sample > 32767)
-		{
-#ifdef STATS
-			clip++;
-#endif
-			clipped += sample - 32767;
-			sample = 32767;
-		}
-		*ap++ = sample;
-	}
-#ifdef STATS
-	fprintf(stderr, "clip %d b%-3d ", clip, pn);
-#endif
-
-#ifdef DEBUG
-	fprintf(stderr, "\ndone\n");
-#endif
-}
-
diff --git a/src/compress.h b/src/compress.h
deleted file mode 100644
index 3e3afb565..000000000
--- a/src/compress.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2003-2009 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/*
- * Imported from AudioCompress by J. Shagam <fluffy@beesbuzz.biz>
- */
-
-#ifndef MPD_COMPRESS_H
-#define MPD_COMPRESS_H
-
-/* These are copied from the AudioCompress config.h, mainly because CompressDo
- * needs GAINSHIFT defined.  The rest are here so they can be used as defaults
- * to pass to CompressCfg(). -- jat */
-#define ANTICLIP 0		/* Strict clipping protection */
-#define TARGET 25000		/* Target level */
-#define GAINMAX 32		/* The maximum amount to amplify by */
-#define GAINSHIFT 10		/* How fine-grained the gain is */
-#define GAINSMOOTH 8		/* How much inertia ramping has*/
-#define BUCKETS 400		/* How long of a history to store */
-
-void CompressCfg(int monitor,
-		 int anticlip,
-		 int target,
-		 int maxgain,
-		 int smooth,
-		 unsigned buckets);
-
-void CompressDo(void *data, unsigned int numSamples);
-
-void CompressFree(void);
-
-#endif
diff --git a/src/normalize.c b/src/normalize.c
index f8304cd1f..f9201df64 100644
--- a/src/normalize.c
+++ b/src/normalize.c
@@ -19,7 +19,7 @@
 
 #include "config.h"
 #include "normalize.h"
-#include "compress.h"
+#include "AudioCompress/compress.h"
 #include "conf.h"
 #include "audio_format.h"
 
@@ -27,24 +27,27 @@
 
 int normalizationEnabled;
 
+static struct Compressor *compressor;
+
 void initNormalization(void)
 {
 	normalizationEnabled = config_get_bool(CONF_VOLUME_NORMALIZATION,
 					       DEFAULT_VOLUME_NORMALIZATION);
 
 	if (normalizationEnabled)
-		CompressCfg(0, ANTICLIP, TARGET, GAINMAX, GAINSMOOTH, BUCKETS);
+		compressor = Compressor_new(0);
 }
 
 void finishNormalization(void)
 {
-	if (normalizationEnabled) CompressFree();
+	if (normalizationEnabled)
+		Compressor_delete(compressor);
 }
 
-void normalizeData(char *buffer, int bufferSize,
+void normalizeData(void *buffer, int bufferSize,
 		   const struct audio_format *format)
 {
 	if ((format->bits != 16) || (format->channels != 2)) return;
 
-	CompressDo(buffer, bufferSize);
+	Compressor_Process_int16(compressor, buffer, bufferSize / 2);
 }
diff --git a/src/normalize.h b/src/normalize.h
index a8144951d..2834f07fd 100644
--- a/src/normalize.h
+++ b/src/normalize.h
@@ -28,7 +28,7 @@ void initNormalization(void);
 
 void finishNormalization(void);
 
-void normalizeData(char *buffer, int bufferSize,
+void normalizeData(void *buffer, int bufferSize,
 		   const struct audio_format *format);
 
 #endif /* !NORMALIZE_H */