changeset 1104:c2fc86e40fba trunk

[svn] oops. wasn't going to check the XMMS updates in until it was actually working.
author nemo
date Wed, 24 May 2006 16:31:15 -0700
parents 8bdcd65a57b7
children 4be4d74db123
files Plugins/Input/wav/wav.c
diffstat 1 files changed, 485 insertions(+), 586 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Input/wav/wav.c	Tue May 23 16:05:38 2006 -0700
+++ b/Plugins/Input/wav/wav.c	Wed May 24 16:31:15 2006 -0700
@@ -1,7 +1,8 @@
-/*  XMMS - Cross-platform multimedia player
- *  Copyright (C) 1998-2005  Peter Alm, Mikael Alm, Olle Hallnas,
- *                           Thomas Nilsson and 4Front Technologies
- *  Copyright (C) 1999-2005  Haavard Kvaalen
+/*  BMP - Cross-platform multimedia player
+ *  Copyright (C) 2003-2004  BMP development team.
+ *
+ *  Based on XMMS:
+ *  Copyright (C) 1998-2003  XMMS development team.
  *
  *  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
@@ -18,647 +19,545 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-/*
- * 2004-12-21 Dirk Jagdmann <doj@cubic.org>
- * - added 32bit pcm,float support
- *
- * 2004-12-22 Dirk Jagdmann <doj@cubic.org>
- * - added 12bit pcm support
- * - added 24bit pcm support
- * - added 64bit float support
- * - fixed big endian
- *
- * TODO:
- * - dither to 16 bits
- */
+#include "wav.h"
 
-#include "libaudacious/util.h"
-#include "libaudacious/titlestring.h"
-#include "xmms/i18n.h"
-#include "xmms/plugin.h"
-#include "config.h"
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <string.h>
 
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <pthread.h>
-#include <math.h>
+#include <libaudacious/util.h>
+#include <libaudacious/titlestring.h>
+#include "audacious/output.h"
+
 
-static InputPlugin wav_ip;
-
-#if 0
-#define WAVDEBUGf
-#define WAVDEBUG(f, a...) printf(f, ##a)
-#else
-#define WAVDEBUG(f, a...)
-#endif
-
-#define	WAVE_FORMAT_PCM        0x0001
-#define WAVE_FORMAT_IEEE_FLOAT 0x0003
-#define	WAVE_FORMAT_ALAW       0x0006
-#define	WAVE_FORMAT_MULAW      0x0007
-#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
-
-struct wave_file
-{
-	FILE *file;
-	unsigned short format_tag;
-	guint16 channels, block_align, bits_per_sample, bits_per_sample_out;
-	guint32 samples_per_sec, avg_bytes_per_sec;
-	unsigned long position, length;
-	int seek_to, data_offset;
-	pid_t pid;
-	volatile gboolean going, eof;
-	int afmt;
-	gint16 *table;
+InputPlugin wav_ip = {
+    NULL,
+    NULL,
+    NULL,                       /* Description */
+    wav_init,
+    NULL,
+    NULL,
+    is_our_file,
+    NULL,
+    play_file,
+    stop,
+    wav_pause,
+    seek,
+    NULL,
+    get_time,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    get_song_info,
+    NULL,                       /* file_info_box */
+    NULL
 };
 
-static struct wave_file *wav_file = NULL;
-static pthread_t decode_thread;
+WaveFile *wav_file = NULL;
+static GThread *decode_thread;
 static gboolean audio_error = FALSE;
 
-InputPlugin *get_iplugin_info(void)
+InputPlugin *
+get_iplugin_info(void)
 {
-	wav_ip.description = g_strdup_printf(_("Wave Player %s"), VERSION);
-	return &wav_ip;
+    wav_ip.description = g_strdup_printf(_("WAV Audio Plugin"));
+    return &wav_ip;
 }
 
-static gint16 *get_alaw_table(void)
+static void
+wav_init(void)
 {
-	static gint16 *table;
-
-	if (!table)
-	{
-		int i;
-		table = g_malloc(128 * sizeof (gint16));
-		for (i = 0; i < 128; i++)
-		{
-			int v = i ^ 0x55;
-			int seg = (v >> 4) & 7;
-
-			table[i] = (((v & 0x0f) << 4) + (seg ? 0x108 : 8)) <<
-				(seg ? seg - 1 : 0);
-		}
-	}
-	return table;
+    /* empty */
 }
 
-static gint16 *get_mulaw_table(void)
+/* needed for is_our_file() */
+static gint
+read_n_bytes(VFSFile * file, guint8 * buf, gsize n)
 {
-	static gint16 *table;
-
-	if (!table)
-	{
-		int i;
-		table = g_malloc(128 * sizeof (gint16));
-		for (i = 0; i < 128; i++) {
-			table[127 - i] = ((((i & 0x0f) << 3) + 0x84) <<
-					  ((i >> 4) & 7)) - 0x84;
-		}
-	}
-	return table;
+    if (vfs_fread(buf, 1, n, file) != n) {
+        return FALSE;
+    }
+    return TRUE;
 }
 
-static char *get_title(gchar *filename)
+static guint32
+convert_to_header(guint8 * buf)
 {
-	TitleInput *input;
-	char *temp, *ext, *title, *path, *temp2;
-
-	XMMS_NEW_TITLEINPUT(input);
 
-	path = g_strdup(filename);
-	temp = g_strdup(filename);
-	ext = strrchr(temp, '.');
-	if (ext)
-		*ext = '\0';
-	temp2 = strrchr(path, '/');
-	if (temp2)
-		*temp2 = '\0';
+    return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+}
 
-	input->file_name = g_basename(filename);
-	input->file_ext = ext ? ext+1 : NULL;
-	input->file_path = g_strdup_printf("%s/", path);
+static guint32
+convert_to_long(guint8 * buf)
+{
 
-	title = xmms_get_titlestring(xmms_get_gentitle_format(), input);
-	if (title == NULL)
-		title = g_strdup(input->file_name);
-
-	g_free(temp);
-	g_free(path);
-	g_free(input);
-
-	return title;
+    return (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
 }
 
-static float convert_ieee_float32(guint32 data)
+static guint16
+read_wav_id(gchar * filename)
 {
-	gint32 sign, exponent, mantissa;
-	float value;
-
-	sign = (data & 0x80000000) != 0;
-	exponent = (data & 0x7f800000) >> 23;
-	mantissa = data & 0x7fffff;
-
-	if (exponent == 0xff)
-		value = G_MAXFLOAT;
-	else if (!exponent && !mantissa)
-		value = 0.0;
-	else
-	{
-		if (exponent)
-		{
-			exponent -= 127;
-			mantissa |= 0x800000;
-		}
-		else
-			exponent = -126;
-		value = ldexp((float) mantissa / 0x800000, exponent);
-	}
-	if (sign)
-		value *= -1;
-	return value;
-}
+    VFSFile *file;
+    guint16 wavid;
+    guint8 buf[4];
+    guint32 head;
+    glong seek;
 
-static double convert_ieee_float64(guint64 data)
-{
-	int sign, exponent;
-	guint64 mantissa;
-	double value;
-
-	sign = (data & 0x8000000000000000ULL) != 0;
-	exponent = (data & 0x7ff0000000000000ULL) >> 52;
-	mantissa = data & 0xfffffffffffffLL;
-
-	if (exponent == 0x7ff)
-		value = G_MAXDOUBLE;
-	else if (!exponent && !mantissa)
-		value = 0.0;
-	else
-	{
-		if (exponent)
-		{
-			exponent -= 1023;
-			mantissa |= 0x10000000000000ULL;
-		}
-		else
-			exponent = -1022;
-
-		value = ldexp((double) mantissa / 0x10000000000000LL, exponent);
-	}
-	if (sign)
-		value *= -1;
-	return value;
+    if (!(file = vfs_fopen(filename, "rb"))) {  /* Could not open file */
+        return 0;
+    }
+    if (!(read_n_bytes(file, buf, 4))) {
+        vfs_fclose(file);
+        return 0;
+    }
+    head = convert_to_header(buf);
+    if (head == ('R' << 24) + ('I' << 16) + ('F' << 8) + 'F') { /* Found a riff -- maybe WAVE */
+        if (vfs_fseek(file, 4, SEEK_CUR) != 0) {    /* some error occured */
+            vfs_fclose(file);
+            return 0;
+        }
+        if (!(read_n_bytes(file, buf, 4))) {
+            vfs_fclose(file);
+            return 0;
+        }
+        head = convert_to_header(buf);
+        if (head == ('W' << 24) + ('A' << 16) + ('V' << 8) + 'E') { /* Found a WAVE */
+            seek = 0;
+            do {                /* we'll be looking for the fmt-chunk which comes before the data-chunk */
+                /* A chunk consists of an header identifier (4 bytes), the length of the chunk
+                   (4 bytes), and the chunkdata itself, padded to be an even number of bytes.
+                   We'll skip all chunks until we find the "data"-one which could contain
+                   mpeg-data */
+                if (seek != 0) {
+                    if (vfs_fseek(file, seek, SEEK_CUR) != 0) { /* some error occured */
+                        vfs_fclose(file);
+                        return 0;
+                    }
+                }
+                if (!(read_n_bytes(file, buf, 4))) {
+                    vfs_fclose(file);
+                    return 0;
+                }
+                head = convert_to_header(buf);
+                if (!(read_n_bytes(file, buf, 4))) {
+                    vfs_fclose(file);
+                    return 0;
+                }
+                seek = convert_to_long(buf);
+                seek = seek + (seek % 2);   /* Has to be even (padding) */
+                if (seek >= 2
+                    && head == ('f' << 24) + ('m' << 16) + ('t' << 8) + ' ') {
+                    if (!(read_n_bytes(file, buf, 2))) {
+                        vfs_fclose(file);
+                        return 0;
+                    }
+                    wavid = buf[0] + 256 * buf[1];
+                    seek -= 2;
+                    /* we could go on looking for other things, but all we wanted was the wavid */
+                    vfs_fclose(file);
+                    return wavid;
+                }
+            }
+            while (head != ('d' << 24) + ('a' << 16) + ('t' << 8) + 'a');
+            /* it's RIFF WAVE */
+        }
+        /* it's RIFF */
+    }
+    /* it's not even RIFF */
+    vfs_fclose(file);
+    return 0;
 }
 
-static unsigned int convert(void *data, int in)
+static const gchar *
+get_extension(const gchar * filename)
 {
-	int out = 0;
+    const gchar *ext = strrchr(filename, '.');
+    return ext ? ext + 1 : NULL;
+}
 
-	if (wav_file->format_tag == WAVE_FORMAT_PCM)
-	{
-		switch (wav_file->bits_per_sample)
-		{
-			case 8:
-			case 12:
-			case 16:
-			default:
-				return in;
+static gboolean
+is_our_file(gchar * filename)
+{
+    gchar *ext;
 
-			case 24:
-			{
-				char *dst = data;
-				char *src = data;
+    ext = strrchr(filename, '.');
+    if (ext)
+        if (!strcasecmp(ext, ".wav"))
+            if (read_wav_id(filename) == WAVE_FORMAT_PCM)
+                return TRUE;
+    return FALSE;
+}
+
 
-				while (in > 0)
-				{
-					out += 2;
-					in -= 3;
-					src++;		/* skip low byte */
-					*dst++ = *src++;/* copy 16bit */
-					*dst++ = *src++;
-				}
-			}
-			break;
+static gchar *
+get_title(const gchar * filename)
+{
+    TitleInput *input;
+    gchar *title;
+
+    input = bmp_title_input_new();
+
+    input->file_name = g_path_get_basename(filename);
+    input->file_ext = get_extension(filename);
+    input->file_path = g_path_get_dirname(filename);
 
-			case 32:
-			{
-				guint16 *dst = data;
-				guint16 *src = data;
-				int i;
-				out = in / sizeof(guint16);
-				for (i = 0; i < out; i++)
-				{
-					src++;		/* skip low word */
-					*dst++ = *src++;/* copy 16 bit */
-				}
-			}
-			break;
-		}
-	}
-	else if (wav_file->format_tag == WAVE_FORMAT_IEEE_FLOAT)
-	{
-		if (wav_file->bits_per_sample == 32)
-		{
-			guint16 *dst = data;
-			guint32 *src = data;
-			int i;
-			out = in / 2;
-			for (i = 0; i < in / 4; i++)
-			{
-				float f;
-				f = convert_ieee_float32(GUINT32_FROM_LE(*src));
-				*dst++ = CLAMP(f, -1.0, 1.0) * 32767;
-				src++;
-			}
-		}
-		else if (wav_file->bits_per_sample == 64)
-		{
-			gint16 *dst = data;
-			guint64 *src = data;
-			int i;
-			out = in / 4;
-			for (i = 0; i < in / 8; i++)
-			{
-				double f;
-				f = convert_ieee_float64(GUINT64_FROM_LE(*src));
-				*dst++ = CLAMP(f, -1.0, 1.0) * 32767;
-				src++;
-			}
-		}
-	}
-	else if (wav_file->format_tag == WAVE_FORMAT_ALAW ||
-		 wav_file->format_tag == WAVE_FORMAT_MULAW)
-	{
-		int i;
-		guint8 *src = data;
-		guint16 *dst = data;
-		for (i = in - 1; i >= 0; i--)
-		{
-			dst[i] = wav_file->table[src[i] & 0x7f];
-			if (src[i] & 0x80)
-				dst[i] *= -1;
-		}
-		out = in * 2;
-	}
-	return out;
+    if (!(title = xmms_get_titlestring(xmms_get_gentitle_format(), input)))
+        title = g_strdup(input->file_name);
+
+    g_free(input->file_path);
+    g_free(input->file_name);
+    g_free(input);
+
+    return title;
+}
+
+static gint
+read_le_long(VFSFile * file, glong * ret)
+{
+    guchar buf[4];
+
+    if (vfs_fread(buf, 1, 4, file) != 4)
+        return 0;
+
+    *ret = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+    return TRUE;
+}
+
+#define read_le_ulong(file,ret) read_le_long(file,(long*)ret)
+
+static int
+read_le_short(VFSFile * file, gshort * ret)
+{
+    guchar buf[2];
+
+    if (vfs_fread(buf, 1, 2, file) != 2)
+        return 0;
+
+    *ret = (buf[1] << 8) | buf[0];
+    return TRUE;
 }
 
-static void *play_loop(void *arg)
+static gpointer
+play_loop(gpointer arg)
 {
-	void *data;
-	int input, output, blk_size, rate;
-	int actual_read;
+    gchar data[2048 * 2];
+    gsize bytes, blk_size, rate;
+    gint actual_read;
 
-	blk_size = 512 * (wav_file->bits_per_sample / 8) * wav_file->channels;
-	rate = wav_file->samples_per_sec * wav_file->channels *
-		(wav_file->bits_per_sample / 8);
-	data = g_malloc(512 * (MAX(wav_file->bits_per_sample,
-				   wav_file->bits_per_sample_out) / 8) *
-			wav_file->channels);
-	while (wav_file->going)
-	{
-		if (!wav_file->eof)
-		{
-			input = MIN(blk_size, wav_file->length - wav_file->position);
-
-			if (input > 0 &&
-			    (actual_read = fread(data, 1, input, wav_file->file)) > 0)
-			{
-				output = convert(data, input);
+    blk_size = 512 * (wav_file->bits_per_sample / 8) * wav_file->channels;
+    rate =
+        wav_file->samples_per_sec * wav_file->channels *
+        (wav_file->bits_per_sample / 8);
+    while (wav_file->going) {
+        if (!wav_file->eof) {
+            bytes = blk_size;
+            if (wav_file->length - wav_file->position < bytes)
+                bytes = wav_file->length - wav_file->position;
+            if (bytes > 0) {
+                actual_read = vfs_fread(data, 1, bytes, wav_file->file);
 
-				wav_ip.add_vis_pcm(wav_ip.output->written_time(),
-						   wav_file->afmt, wav_file->channels,
-						   output, data);
-				while (wav_ip.output->buffer_free() < output &&
-				       wav_file->going && wav_file->seek_to == -1)
-					xmms_usleep(10000);
-				if (wav_file->going && wav_file->seek_to == -1)
-					wav_ip.output->write_audio(data, output);
-				wav_file->position += actual_read;
-			}
-			else
-			{
-				wav_file->eof = TRUE;
-				wav_ip.output->buffer_free();
-				wav_ip.output->buffer_free();
-				xmms_usleep(10000);
-			}
-		}
-		else
-			xmms_usleep(10000);
-		if (wav_file->seek_to != -1)
-		{
-			wav_file->position = wav_file->seek_to * rate;
-			fseek(wav_file->file, wav_file->position +
-			      wav_file->data_offset, SEEK_SET);
-			wav_ip.output->flush(wav_file->seek_to * 1000);
-			wav_file->seek_to = -1;
-		}
+                if (actual_read == 0) {
+                    wav_file->eof = 1;
+                    wav_ip.output->buffer_free();
+                    wav_ip.output->buffer_free();
+                }
+                else {
+                    if (wav_file->seek_to == -1)
+                        produce_audio(wav_ip.output->written_time(),
+                                      (wav_file->bits_per_sample ==
+                                       16) ? FMT_S16_LE : FMT_U8,
+                                      wav_file->channels, bytes, data,
+                                      &wav_file->going);
+                    wav_file->position += actual_read;
+                }
+            }
+            else {
+                wav_file->eof = TRUE;
+                wav_ip.output->buffer_free();
+                wav_ip.output->buffer_free();
+                xmms_usleep(10000);
+            }
+        }
+        else
+            xmms_usleep(10000);
+        if (wav_file->seek_to != -1) {
+            wav_file->position = wav_file->seek_to * rate;
+            vfs_fseek(wav_file->file,
+                      wav_file->position + wav_file->data_offset, SEEK_SET);
+            wav_ip.output->flush(wav_file->seek_to * 1000);
+            wav_file->seek_to = -1;
+        }
 
-	}
-	g_free(data);
-	fclose(wav_file->file);
-	pthread_exit(NULL);
-}
+    }
+    vfs_fclose(wav_file->file);
 
-static int read_le_long(FILE * file, guint32 *ret)
-{
-	guint32 l;
-	if (fread(&l, sizeof (l), 1, file) != 1)
-		return 0;
-	*ret = GUINT32_FROM_LE(l);
-	return TRUE;
-}
-
-static int read_le_short(FILE * file, guint16 *ret)
-{
-	guint16 s;
-	if (fread(&s, sizeof (s), 1, file) != 1)
-		return 0;
-	*ret = GUINT16_FROM_LE(s);
-	return TRUE;
+    g_thread_exit(NULL);
+    return NULL;
 }
 
-static struct wave_file* construct_wave_file(char *filename)
+static void
+play_file(gchar * filename)
 {
-	guint32 len;
-	char magic[4] = {0};
-
-	/* alloc mem for struct */
-	struct wave_file *wav = g_malloc0(sizeof (*wav));
-	if (!wav)
-		return wav;
-
-	/* open file */
-	wav->file = fopen(filename, "rb");
-	if (!wav->file)
-		goto exit_on_error;
-
-	/* check for RIFF chunk */
-	fread(magic, 1, 4, wav->file);
-	if (strncmp(magic, "RIFF", 4) ||
-	    !read_le_long(wav->file, &len))
-		goto exit_on_error;
-
-	fread(magic, 1, 4, wav->file);
-	if (strncmp(magic, "WAVE", 4))
-		goto exit_on_error;
+    gchar magic[4], *name;
+    gulong len;
+    gint rate;
 
-	/* wait for fmt chunk */
-	for (;;)
-	{
-		if (fread(magic, 1, 4, wav->file) != 4 ||
-		    !read_le_long(wav->file, &len))
-			goto exit_on_error;
-
-		if (!strncmp("fmt ", magic, 4))
-			break;
-		if (fseek(wav->file, len, SEEK_CUR))
-			goto exit_on_error;
-	}
-
-	/* check length of fmt chunk */
-	if (len < 16)
-		goto exit_on_error;
-
-	/* read format */
-	read_le_short(wav->file, &wav->format_tag);
-	read_le_short(wav->file, &wav->channels);
-	read_le_long (wav->file, &wav->samples_per_sec);
-	read_le_long (wav->file, &wav->avg_bytes_per_sec);
-	read_le_short(wav->file, &wav->block_align);
-	read_le_short(wav->file, &wav->bits_per_sample);
-
-	len -= 16;
-
-	/* check for valid formats */
-	if (wav->format_tag == WAVE_FORMAT_EXTENSIBLE)
-	{
-		if (len < 24 ||
-		    fseek(wav->file, 8, SEEK_CUR) ||
-		    !read_le_short(wav->file, &wav->format_tag))
-			goto exit_on_error;
-		len -= 10;
-	}
+    audio_error = FALSE;
 
-	if (wav->format_tag == WAVE_FORMAT_PCM)
-	{
-		switch (wav->bits_per_sample)
-		{
-			case 8:
-				wav->afmt = FMT_U8;
-				break;
-			case 12:
-			case 16:
-			case 24:
-			case 32:
-				wav->afmt = FMT_S16_LE;
-				break;
-			default:
-				goto exit_on_error;
-		}
-	}
-	else if (wav->format_tag == WAVE_FORMAT_IEEE_FLOAT)
-	{
-		if (wav->bits_per_sample == 32 ||
-		    wav->bits_per_sample == 64)
-			wav->afmt = FMT_S16_LE;
-		else
-			goto exit_on_error;
-	}
-	else if (wav->format_tag == WAVE_FORMAT_ALAW)
-	{
-		if (wav->bits_per_sample != 8)
-			goto exit_on_error;
-		wav->afmt = FMT_S16_LE;
-		wav->bits_per_sample_out = 16;
-		wav->table = get_alaw_table();
-	}
-	else if (wav->format_tag == WAVE_FORMAT_MULAW)
-	{
-		if (wav->bits_per_sample != 8)
-			goto exit_on_error;
-		wav->afmt = FMT_S16_LE;
-		wav->bits_per_sample_out = 16;
-		wav->table = get_mulaw_table();
-	}
-	else
-		goto exit_on_error;
+    wav_file = g_new0(WaveFile, 1);
+    if ((wav_file->file = vfs_fopen(filename, "rb"))) {
+        vfs_fread(magic, 1, 4, wav_file->file);
+        if (strncmp(magic, "RIFF", 4)) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        read_le_ulong(wav_file->file, &len);
+        vfs_fread(magic, 1, 4, wav_file->file);
+        if (strncmp(magic, "WAVE", 4)) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        for (;;) {
+            vfs_fread(magic, 1, 4, wav_file->file);
+            if (!read_le_ulong(wav_file->file, &len)) {
+                vfs_fclose(wav_file->file);
+                g_free(wav_file);
+                wav_file = NULL;
+                return;
+            }
+            if (!strncmp("fmt ", magic, 4))
+                break;
+            vfs_fseek(wav_file->file, len, SEEK_CUR);
+        }
+        if (len < 16) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        read_le_short(wav_file->file, &wav_file->format_tag);
+        switch (wav_file->format_tag) {
+        case WAVE_FORMAT_UNKNOWN:
+        case WAVE_FORMAT_ALAW:
+        case WAVE_FORMAT_MULAW:
+        case WAVE_FORMAT_ADPCM:
+        case WAVE_FORMAT_OKI_ADPCM:
+        case WAVE_FORMAT_DIGISTD:
+        case WAVE_FORMAT_DIGIFIX:
+        case IBM_FORMAT_MULAW:
+        case IBM_FORMAT_ALAW:
+        case IBM_FORMAT_ADPCM:
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        read_le_short(wav_file->file, &wav_file->channels);
+        read_le_long(wav_file->file, &wav_file->samples_per_sec);
+        read_le_long(wav_file->file, &wav_file->avg_bytes_per_sec);
+        read_le_short(wav_file->file, &wav_file->block_align);
+        read_le_short(wav_file->file, &wav_file->bits_per_sample);
+        if (wav_file->bits_per_sample != 8 && wav_file->bits_per_sample != 16) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        len -= 16;
+        if (len)
+            vfs_fseek(wav_file->file, len, SEEK_CUR);
 
-	if (wav->channels < 1 || wav->channels > 2)
-		goto exit_on_error;
+        for (;;) {
+            vfs_fread(magic, 4, 1, wav_file->file);
 
-	/* skip any superflous bytes */
-	if (len)
-		fseek(wav->file, len, SEEK_CUR);
+            if (!read_le_ulong(wav_file->file, &len)) {
+                vfs_fclose(wav_file->file);
+                g_free(wav_file);
+                wav_file = NULL;
+                return;
+            }
+            if (!strncmp("data", magic, 4))
+                break;
+            vfs_fseek(wav_file->file, len, SEEK_CUR);
+        }
+        wav_file->data_offset = vfs_ftell(wav_file->file);
+        wav_file->length = len;
+
+        wav_file->position = 0;
+        wav_file->going = 1;
 
-	/* wait for data chunk */
-	for (;;)
-	{
-		fread(magic, 4, 1, wav->file);
-		if (!read_le_long(wav->file, &len))
-			goto exit_on_error;
-		if (!strncmp("data", magic, 4))
-			break;
-		fseek(wav->file, len, SEEK_CUR);
-	}
-	wav->data_offset = ftell(wav->file);
-	wav->length = len;
+        if (wav_ip.output->
+            open_audio((wav_file->bits_per_sample ==
+                        16) ? FMT_S16_LE : FMT_U8,
+                       wav_file->samples_per_sec, wav_file->channels) == 0) {
+            audio_error = TRUE;
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        name = get_title(filename);
+        rate =
+            wav_file->samples_per_sec * wav_file->channels *
+            (wav_file->bits_per_sample / 8);
+        wav_ip.set_info(name, 1000 * (wav_file->length / rate), 8 * rate,
+                        wav_file->samples_per_sec, wav_file->channels);
+        g_free(name);
+        wav_file->seek_to = -1;
+        decode_thread = g_thread_create(play_loop, NULL, TRUE, NULL);
+    }
+}
 
-	wav->position = 0;
-	wav->going = TRUE;
-
-	return wav;
-
- exit_on_error:
-	if (wav->file)
-		fclose(wav->file);
-	g_free(wav);
-	return 0;
+static void
+stop(void)
+{
+    if (wav_file && wav_file->going) {
+        wav_file->going = 0;
+        g_thread_join(decode_thread);
+        wav_ip.output->close_audio();
+        g_free(wav_file);
+        wav_file = NULL;
+    }
 }
 
-static void play_file(char *filename)
+static void
+wav_pause(gshort p)
 {
-	char *name;
-	int rate;
-
-	audio_error = FALSE;
-
-	if ((wav_file = construct_wave_file(filename)) == 0)
-		return;
-
-	/* open audio channel according to wav format */
-	if (wav_ip.output->open_audio(wav_file->afmt,
-				      wav_file->samples_per_sec,
-				      wav_file->channels) == 0)
-	{
-		audio_error = TRUE;
-		fclose(wav_file->file);
-		g_free(wav_file);
-		wav_file = NULL;
-		return;
-	}
-
-	/* set some xmms config */
-	name = get_title(filename);
-	rate = wav_file->samples_per_sec * wav_file->channels *
-		(wav_file->bits_per_sample / 8);
-	wav_ip.set_info(name, 1000 * (wav_file->length / rate), 8 * rate,
-			wav_file->samples_per_sec, wav_file->channels);
-	g_free(name);
-	wav_file->seek_to = -1;
-
-	/* create play thread */
-	pthread_create(&decode_thread, NULL, play_loop, NULL);
+    wav_ip.output->pause(p);
 }
 
-static void stop(void)
+static void
+seek(gint time)
 {
-	if (wav_file && wav_file->going)
-	{
-		wav_file->going = FALSE;
-		pthread_join(decode_thread, NULL);
-		wav_ip.output->close_audio();
-		g_free(wav_file);
-		wav_file = NULL;
-	}
+    wav_file->seek_to = time;
+
+    wav_file->eof = FALSE;
+
+    while (wav_file->seek_to != -1)
+        xmms_usleep(10000);
 }
 
-static void wav_pause(short p)
-{
-	wav_ip.output->pause(p);
-}
-
-static void seek(int time)
+static int
+get_time(void)
 {
-	wav_file->seek_to = time;
-
-	wav_file->eof = FALSE;
-
-	while (wav_file->seek_to != -1)
-		xmms_usleep(10000);
+    if (audio_error)
+        return -2;
+    if (!wav_file)
+        return -1;
+    if (!wav_file->going
+        || (wav_file->eof && !wav_ip.output->buffer_playing()))
+        return -1;
+    else {
+        return wav_ip.output->output_time();
+    }
 }
 
-static int get_time(void)
+static void
+get_song_info(gchar * filename, gchar ** title, gint * length)
 {
-	if (audio_error)
-		return -2;
-	if (!wav_file)
-		return -1;
-	if (!wav_file->going || (wav_file->eof && !wav_ip.output->buffer_playing()))
-		return -1;
-	else
-	{
-		return wav_ip.output->output_time();
-	}
-}
-
-static void get_song_info(char *filename, char **title, int *length)
-{
-	struct wave_file *wav;
+    gchar magic[4];
+    gulong len;
+    gint rate;
+    WaveFile *wav_file;
 
-	if (!(wav = construct_wave_file(filename)))
-		return;
-
-	*length = 1000 * (wav->length / (wav->samples_per_sec * wav->channels *
-					 (wav->bits_per_sample / 8)) );
-	*title  = get_title(filename);
-
-	fclose(wav->file);
-	g_free(wav);
-	wav = NULL;
-}
-
-static int is_our_file(char *filename)
-{
-	struct wave_file *wav;
-
-	if (!(wav = construct_wave_file(filename)))
-		return FALSE;
-
-	g_free(wav);
-	return TRUE;
-}
+    wav_file = g_malloc(sizeof(WaveFile));
+    memset(wav_file, 0, sizeof(WaveFile));
+    if (!(wav_file->file = vfs_fopen(filename, "rb")))
+        return;
 
-static void plugin_init(void)
-{
-#ifdef WAVDEBUGf
-	printf("wav.c compiled " __DATE__ " " __TIME__ " : ");
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
-	printf("little endian");
-#elif G_BYTE_ORDER == G_BIG_ENDIAN
-	printf("big endian");
-#elif G_BYTE_ORDER == G_PDP_ENDIAN
-	printf("pdp endian");
-#else
-	printf("unknown endian");
-#endif
-	printf("\n");
-#endif
-}
+    vfs_fread(magic, 1, 4, wav_file->file);
+    if (strncmp(magic, "RIFF", 4)) {
+        vfs_fclose(wav_file->file);
+        g_free(wav_file);
+        wav_file = NULL;
+        return;
+    }
+    read_le_ulong(wav_file->file, &len);
+    vfs_fread(magic, 1, 4, wav_file->file);
+    if (strncmp(magic, "WAVE", 4)) {
+        vfs_fclose(wav_file->file);
+        g_free(wav_file);
+        wav_file = NULL;
+        return;
+    }
+    for (;;) {
+        vfs_fread(magic, 1, 4, wav_file->file);
+        if (!read_le_ulong(wav_file->file, &len)) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        if (!strncmp("fmt ", magic, 4))
+            break;
+        vfs_fseek(wav_file->file, len, SEEK_CUR);
+    }
+    if (len < 16) {
+        vfs_fclose(wav_file->file);
+        g_free(wav_file);
+        wav_file = NULL;
+        return;
+    }
+    read_le_short(wav_file->file, &wav_file->format_tag);
+    switch (wav_file->format_tag) {
+    case WAVE_FORMAT_UNKNOWN:
+    case WAVE_FORMAT_ALAW:
+    case WAVE_FORMAT_MULAW:
+    case WAVE_FORMAT_ADPCM:
+    case WAVE_FORMAT_OKI_ADPCM:
+    case WAVE_FORMAT_DIGISTD:
+    case WAVE_FORMAT_DIGIFIX:
+    case IBM_FORMAT_MULAW:
+    case IBM_FORMAT_ALAW:
+    case IBM_FORMAT_ADPCM:
+        vfs_fclose(wav_file->file);
+        g_free(wav_file);
+        wav_file = NULL;
+        return;
+    }
+    read_le_short(wav_file->file, &wav_file->channels);
+    read_le_long(wav_file->file, &wav_file->samples_per_sec);
+    read_le_long(wav_file->file, &wav_file->avg_bytes_per_sec);
+    read_le_short(wav_file->file, &wav_file->block_align);
+    read_le_short(wav_file->file, &wav_file->bits_per_sample);
+    if (wav_file->bits_per_sample != 8 && wav_file->bits_per_sample != 16) {
+        vfs_fclose(wav_file->file);
+        g_free(wav_file);
+        wav_file = NULL;
+        return;
+    }
+    len -= 16;
+    if (len)
+        vfs_fseek(wav_file->file, len, SEEK_CUR);
 
-static InputPlugin wav_ip =
-{
-	NULL,
-	NULL,
-	NULL,
-	plugin_init,
-	NULL,
-	NULL,
-	is_our_file,
-	NULL,
-	play_file,
-	stop,
-	wav_pause,
-	seek,
-	NULL,
-	get_time,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	NULL,
-	get_song_info,
-};
+    for (;;) {
+        vfs_fread(magic, 4, 1, wav_file->file);
+
+        if (!read_le_ulong(wav_file->file, &len)) {
+            vfs_fclose(wav_file->file);
+            g_free(wav_file);
+            wav_file = NULL;
+            return;
+        }
+        if (!strncmp("data", magic, 4))
+            break;
+        vfs_fseek(wav_file->file, len, SEEK_CUR);
+    }
+    rate =
+        wav_file->samples_per_sec * wav_file->channels *
+        (wav_file->bits_per_sample / 8);
+    (*length) = 1000 * (len / rate);
+    (*title) = get_title(filename);
+
+    vfs_fclose(wav_file->file);
+    g_free(wav_file);
+    wav_file = NULL;
+}