diff --git a/INSTALL b/INSTALL
index 3a1671a82..22a06fa62 100644
--- a/INSTALL
+++ b/INSTALL
@@ -104,6 +104,9 @@ For MIDI support (DO NOT USE - use libwildmidi instead)
 libwildmidi - http://wildmidi.sourceforge.net/
 For MIDI support.
 
+libsndfile - http://www.mega-nerd.com/libsndfile/
+WAVE, AIFF, and many others.
+
 
 Optional Miscellaneous Dependencies
 -----------------------------------
diff --git a/Makefile.am b/Makefile.am
index 19658d77c..37d5b3a62 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -325,6 +325,7 @@ endif
 DECODER_CFLAGS = \
 	$(VORBIS_CFLAGS) $(TREMOR_CFLAGS) \
 	$(patsubst -I%/FLAC,-I%,$(FLAC_CFLAGS)) \
+	$(SNDFILE_CFLAGS) \
 	$(AUDIOFILE_CFLAGS) \
 	$(LIBMIKMOD_CFLAGS) \
 	$(MODPLUG_CFLAGS) \
@@ -338,6 +339,7 @@ DECODER_CFLAGS = \
 DECODER_LIBS = \
 	$(VORBIS_LIBS) $(TREMOR_LIBS) \
 	$(FLAC_LIBS) \
+	$(SNDFILE_LIBS) \
 	$(AUDIOFILE_LIBS) $(LIBMIKMOD_LIBS) \
 	$(MODPLUG_LIBS) \
 	$(SIDPLAY_LIBS) \
@@ -420,6 +422,10 @@ if HAVE_FFMPEG
 DECODER_SRC += src/decoder/ffmpeg_plugin.c
 endif
 
+if ENABLE_SNDFILE
+DECODER_SRC += src/decoder/sndfile_decoder_plugin.c
+endif
+
 # encoder plugins
 
 ENCODER_CFLAGS = \
diff --git a/NEWS b/NEWS
index 047fa10b9..cea099966 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ ver 0.16 (20??/??/??)
   - id3: revised "performer" tag support
 * decoders:
   - ffmpeg: support multiple tags
+  - sndfile: new decoder plugin based on libsndfile
 * mixers:
   - removed support for legacy mixer configuration
   - reimplemented software volume as mixer+filter plugin
diff --git a/configure.ac b/configure.ac
index c082bf1cd..667f53b5d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -470,6 +470,27 @@ AC_ARG_ENABLE(vorbis,
 		[disable Ogg Vorbis support (default: enable)]),,
 	enable_vorbis=yes)
 
+AC_ARG_ENABLE(sndfile,
+	AS_HELP_STRING([--enable-sndfile],
+		[enable sndfile support]),,
+	enable_sndfile=auto)
+
+if test x$enable_sndfile = xauto && test x$enable_modplug = xyes; then
+	dnl If modplug is enabled, enable sndfile only if explicitly
+	dnl requested - modplug's modplug/sndfile.h is known to
+	dnl conflict with libsndfile's sndfile.h.
+	AC_MSG_NOTICE([disabling libsndfile auto-detection, because the modplug decoder is enabled])
+	enable_sndfile=no
+fi
+
+MPD_AUTO_PKG(sndfile, SNDFILE, [sndfile],
+	[libsndfile decoder plugin], [libsndfile not found])
+AM_CONDITIONAL(ENABLE_SNDFILE, test x$enable_sndfile = xyes)
+if test x$enable_sndfile = xyes; then
+	AC_DEFINE(ENABLE_SNDFILE, 1, [Define to enable the sndfile decoder plugin])
+fi
+
+
 dnl ###
 dnl Ogg Tremor
 dnl ###
@@ -1380,6 +1401,12 @@ else
 	echo " Ogg Vorbis support ............disabled"
 fi
 
+if test x$enable_sndfile = xyes; then
+	echo " libsndfile ....................enabled"
+else
+	echo " libsndfile ....................disabled"
+fi
+
 if test x$enable_audiofile = xyes; then
 	echo " Wave file support .............enabled"
 else
@@ -1492,6 +1519,11 @@ echo ""
 echo "##########################################"
 echo ""
 
+if test x$enable_sndfile = xyes && test x$enable_modplug = xyes; then
+	AC_MSG_WARN([compilation may fail, because libmodplug conflicts with libsndfile])
+	AC_MSG_WARN([libmodplug ships modplug/sndfile.h, which hides libsndfile's sndfile.h])
+fi
+
 echo "Generating needed files for compilation"
 echo ""
 
diff --git a/src/decoder/sndfile_decoder_plugin.c b/src/decoder/sndfile_decoder_plugin.c
new file mode 100644
index 000000000..0c5d2f063
--- /dev/null
+++ b/src/decoder/sndfile_decoder_plugin.c
@@ -0,0 +1,246 @@
+/*
+ * 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.
+ */
+
+#include "decoder_api.h"
+
+#include <sndfile.h>
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "sndfile"
+
+static sf_count_t
+sndfile_vio_get_filelen(void *user_data)
+{
+	const struct input_stream *is = user_data;
+
+	return is->size;
+}
+
+static sf_count_t
+sndfile_vio_seek(sf_count_t offset, int whence, void *user_data)
+{
+	struct input_stream *is = user_data;
+	bool success;
+
+	success = input_stream_seek(is, offset, whence);
+	if (!success)
+		return -1;
+
+	return is->offset;
+}
+
+static sf_count_t
+sndfile_vio_read(void *ptr, sf_count_t count, void *user_data)
+{
+	struct input_stream *is = user_data;
+	size_t nbytes;
+
+	nbytes = input_stream_read(is, ptr, count);
+	if (nbytes == 0 && is->error != 0)
+		return -1;
+
+	return nbytes;
+}
+
+static sf_count_t
+sndfile_vio_write(G_GNUC_UNUSED const void *ptr,
+		  G_GNUC_UNUSED sf_count_t count,
+		  G_GNUC_UNUSED void *user_data)
+{
+	/* no writing! */
+	return -1;
+}
+
+static sf_count_t
+sndfile_vio_tell(void *user_data)
+{
+	const struct input_stream *is = user_data;
+
+	return is->offset;
+}
+
+/**
+ * This SF_VIRTUAL_IO implementation wraps MPD's #input_stream to a
+ * libsndfile stream.
+ */
+static SF_VIRTUAL_IO vio = {
+	.get_filelen = sndfile_vio_get_filelen,
+	.seek = sndfile_vio_seek,
+	.read = sndfile_vio_read,
+	.write = sndfile_vio_write,
+	.tell = sndfile_vio_tell,
+};
+
+/**
+ * Converts a frame number to a timestamp (in seconds).
+ */
+static float
+frame_to_time(sf_count_t frame, const struct audio_format *audio_format)
+{
+	return (float)frame / (float)audio_format->sample_rate;
+}
+
+/**
+ * Converts a timestamp (in seconds) to a frame number.
+ */
+static sf_count_t
+time_to_frame(float t, const struct audio_format *audio_format)
+{
+	return (sf_count_t)(t * audio_format->sample_rate);
+}
+
+static void
+sndfile_stream_decode(struct decoder *decoder, struct input_stream *is)
+{
+	SNDFILE *sf;
+	SF_INFO info;
+	struct audio_format audio_format;
+	size_t frame_size;
+	sf_count_t read_frames, num_frames, position = 0;
+	int buffer[4096];
+	enum decoder_command cmd;
+
+	info.format = 0;
+
+	sf = sf_open_virtual(&vio, SFM_READ, &info, is);
+	if (sf == NULL) {
+		g_warning("sf_open_virtual() failed");
+		return;
+	}
+
+	audio_format.sample_rate = info.samplerate;
+	/* for now, always read 32 bit samples.  Later, we could lower
+	   MPD's CPU usage by reading 16 bit samples with
+	   sf_readf_short() on low-quality source files. */
+	audio_format.bits = 32;
+	audio_format.channels = info.channels;
+
+	if (!audio_format_valid(&audio_format)) {
+		g_warning("invalid audio format");
+		return;
+	}
+
+	decoder_initialized(decoder, &audio_format, info.seekable,
+			    frame_to_time(info.frames, &audio_format));
+
+	frame_size = audio_format_frame_size(&audio_format);
+	read_frames = sizeof(buffer) / frame_size;
+
+	do {
+		num_frames = sf_readf_int(sf, buffer, read_frames);
+		if (num_frames <= 0)
+			break;
+
+		cmd = decoder_data(decoder, is,
+				   buffer, num_frames * frame_size,
+				   frame_to_time(position, &audio_format),
+				   0, NULL);
+		if (cmd == DECODE_COMMAND_SEEK) {
+			sf_count_t c =
+				time_to_frame(decoder_seek_where(decoder),
+					      &audio_format);
+			c = sf_seek(sf, c, SEEK_SET);
+			if (c < 0)
+				decoder_seek_error(decoder);
+			else
+				decoder_command_finished(decoder);
+			cmd = DECODE_COMMAND_NONE;
+		}
+	} while (cmd == DECODE_COMMAND_NONE);
+
+	sf_close(sf);
+}
+
+static struct tag *
+sndfile_tag_dup(const char *path_fs)
+{
+	SNDFILE *sf;
+	SF_INFO info;
+	struct tag *tag;
+	const char *p;
+
+	info.format = 0;
+
+	sf = sf_open(path_fs, SFM_READ, &info);
+	if (sf == NULL)
+		return NULL;
+
+	if (!audio_valid_sample_rate(info.samplerate)) {
+		sf_close(sf);
+		g_warning("Invalid sample rate in %s\n", path_fs);
+		return NULL;
+	}
+
+	tag = tag_new();
+	tag->time = info.frames / info.samplerate;
+
+	p = sf_get_string(sf, SF_STR_TITLE);
+	if (p != NULL)
+		tag_add_item(tag, TAG_ITEM_TITLE, p);
+
+	p = sf_get_string(sf, SF_STR_ARTIST);
+	if (p != NULL)
+		tag_add_item(tag, TAG_ITEM_ARTIST, p);
+
+	p = sf_get_string(sf, SF_STR_DATE);
+	if (p != NULL)
+		tag_add_item(tag, TAG_ITEM_DATE, p);
+
+	sf_close(sf);
+
+	return tag;
+}
+
+static const char *const sndfile_suffixes[] = {
+	"wav", "aiff", "aif", /* Microsoft / SGI / Apple */
+	"au", "snd", /* Sun / DEC / NeXT */
+	"paf", /* Paris Audio File */
+	"iff", "svx", /* Commodore Amiga IFF / SVX */
+	"sf", /* IRCAM */
+	"voc", /* Creative */
+	"w64", /* Soundforge */
+	"pvf", /* Portable Voice Format */
+	"xi", /* Fasttracker */
+	"htk", /* HMM Tool Kit */
+	"caf", /* Apple */
+	"sd2", /* Sound Designer II */
+
+	/* libsndfile also supports FLAC and Ogg Vorbis, but only by
+	   linking with libFLAC and libvorbis - we can do better, we
+	   have native plugins for these libraries */
+
+	NULL
+};
+
+static const char *const sndfile_mime_types[] = {
+	"audio/x-wav",
+	"audio/x-aiff",
+
+	/* what are the MIME types of the other supported formats? */
+
+	NULL
+};
+
+const struct decoder_plugin sndfile_decoder_plugin = {
+	.name = "sndfile",
+	.stream_decode = sndfile_stream_decode,
+	.tag_dup = sndfile_tag_dup,
+	.suffixes = sndfile_suffixes,
+	.mime_types = sndfile_mime_types,
+};
diff --git a/src/decoder_list.c b/src/decoder_list.c
index a42585e34..177ac46e4 100644
--- a/src/decoder_list.c
+++ b/src/decoder_list.c
@@ -31,6 +31,7 @@ extern const struct decoder_plugin mad_decoder_plugin;
 extern const struct decoder_plugin vorbis_decoder_plugin;
 extern const struct decoder_plugin flac_decoder_plugin;
 extern const struct decoder_plugin oggflac_decoder_plugin;
+extern const struct decoder_plugin sndfile_decoder_plugin;
 extern const struct decoder_plugin audiofile_decoder_plugin;
 extern const struct decoder_plugin mp4ff_decoder_plugin;
 extern const struct decoder_plugin faad_decoder_plugin;
@@ -56,6 +57,9 @@ static const struct decoder_plugin *const decoder_plugins[] = {
 #ifdef HAVE_FLAC
 	&flac_decoder_plugin,
 #endif
+#ifdef ENABLE_SNDFILE
+	&sndfile_decoder_plugin,
+#endif
 #ifdef HAVE_AUDIOFILE
 	&audiofile_decoder_plugin,
 #endif