32bit pcm and float support in .wav Input plugin

Dirk Jagdmann <[email protected]> Tue, 21 Dec 2004 20:59:00 +0100
Newsgroups gmane.comp.multimedia.xmms.devel
Organization Cubic
Message-ID <[email protected]>
Hello developers,

I have added 32bit pcm and float support for the wav Input plugin. While 
doing so, I have refactored three different .wav detection routines into 
one and could afterwards remove several no longer needed helper 
functions. Thus this patch looks big and ugly, but it should provide a 
much nicer infrastructure for future work on the .wav code.

In the future I'll get to this again and implement the following which 
this plugin is still missing:
- 12 and 24 bit pcm
- 64 bit float
- a dither algorithm to 16 bit

But I'd like to see this new code in the CVS tree and the next release 
of xmms.

-- 
---> doj / cubic
----> http://cubic.org/~doj
-----> http://llg.cubic.org

_______________________________________________
xmms-devel mailing list
[email protected]
http://lists.xmms.org/mailman/listinfo/xmms-devel
wav.patch (text/plain, 17.7 KB)
? wav.patch
Index: wav.c
===================================================================
RCS file: /cvs/xmms/Input/wav/wav.c,v
retrieving revision 1.14
diff -u -r1.14 wav.c
--- wav.c	6 Nov 2003 23:16:49 -0000	1.14
+++ wav.c	21 Dec 2004 19:46:52 -0000
@@ -1,5 +1,5 @@
 /*  XMMS - Cross-platform multimedia player
- *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1998-2005  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
  *
  *  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
@@ -15,38 +15,46 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
-#include "wav.h"
+
+/*
+  2004-12-21 Dirk Jagdmann <[email protected]>
+  - added 32bit support
+
+  TODO:
+  - dither to 16 bits
+  - implement 12 and 24 bit pcm
+*/
+
 #include "libxmms/util.h"
 #include "libxmms/titlestring.h"
 #include "xmms/i18n.h"
+#include "xmms/plugin.h"
+#include "config.h"
 
-InputPlugin wav_ip =
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+extern InputPlugin wav_ip;
+
+#define WAVDEBUG(f, a...) printf(f, ##a)
+
+#define	WAVE_FORMAT_PCM        0x0001
+#define WAVE_FORMAT_IEEE_FLOAT 0x0003
+
+typedef struct
 {
-	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
-};
+	FILE *file;
+	short format_tag, channels, block_align, bits_per_sample;
+	long 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;
+}
+WaveFile;
 
 static WaveFile *wav_file = NULL;
 static pthread_t decode_thread;
@@ -58,130 +66,6 @@
 	return &wav_ip;
 }
 
-static void wav_init(void)
-{
-}
-
-/* needed for is_our_file() */
-static int read_n_bytes(FILE * file, guint8 * buf, int n)
-{
-
-	if (fread(buf, 1, n, file) != n)
-	{
-		return FALSE;
-	}
-	return TRUE;
-}
-
-static guint32 convert_to_header(guint8 * buf)
-{
-
-	return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
-}
-
-static guint32 convert_to_long(guint8 * buf)
-{
-
-	return (buf[3] << 24) + (buf[2] << 16) + (buf[1] << 8) + buf[0];
-}
-
-static guint16 read_wav_id(char *filename)
-{
-	FILE *file;
-	guint16 wavid;
-	guint8 buf[4];
-	guint32 head;
-	long seek;
-
-	if (!(file = fopen(filename, "rb")))
-	{			/* Could not open file */
-		return 0;
-	}
-	if (!(read_n_bytes(file, buf, 4)))
-	{
-		fclose(file);
-		return 0;
-	}
-	head = convert_to_header(buf);
-	if (head == ('R' << 24) + ('I' << 16) + ('F' << 8) + 'F')
-	{			/* Found a riff -- maybe WAVE */
-		if (fseek(file, 4, SEEK_CUR) != 0)
-		{		/* some error occured */
-			fclose(file);
-			return 0;
-		}
-		if (!(read_n_bytes(file, buf, 4)))
-		{
-			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 (fseek(file, seek, SEEK_CUR) != 0)
-					{	/* some error occured */
-						fclose(file);
-						return 0;
-					}
-				}
-				if (!(read_n_bytes(file, buf, 4)))
-				{
-					fclose(file);
-					return 0;
-				}
-				head = convert_to_header(buf);
-				if (!(read_n_bytes(file, buf, 4)))
-				{
-					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)))
-					{
-						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 */
-					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 */
-	fclose(file);
-	return 0;
-}
-
-static int is_our_file(char *filename)
-{
-	gchar *ext;
-
-	ext = strrchr(filename, '.');
-	if (ext)
-		if (!strcasecmp(ext, ".wav"))
-			if (read_wav_id(filename) == WAVE_FORMAT_PCM)
-				return TRUE;
-	return FALSE;
-}
-
 static gchar *get_title(gchar *filename)
 {
 	TitleInput *input;
@@ -235,6 +119,52 @@
 	return TRUE;
 }
 
+static void convert(char *data, int* bytes)
+{
+	if(wav_file->format_tag == WAVE_FORMAT_PCM)
+	{
+		switch(wav_file->bits_per_sample)
+		{
+		case 8:
+		case 16:
+		default:
+			return;
+
+		case 12: /*todo*/
+		case 24: /*todo*/
+
+		case 32:
+		{
+			signed short *dst=(signed short*)data;
+			signed long *src=(signed long*)data;
+			int dst_=0, src_ = *bytes / sizeof(signed long);
+			while(src_--)
+				*dst++=(signed short)(*src++ / 65536) , ++dst_;
+			*bytes=dst_ * sizeof(signed short);
+		}
+		break;
+		}
+	}
+	else if(wav_file->format_tag == WAVE_FORMAT_IEEE_FLOAT)
+	{
+		if(wav_file->bits_per_sample == 32)
+		{
+			signed short *dst=(signed short*)data;
+			float *src=(float*)data;
+			int dst_=0, src_ = *bytes / sizeof(float);
+			while(src_--)
+			{
+				float f = *src++;
+				if(f>1.0f) f=1.0f;
+				else if(f<-1.0f) f=-1.0f;
+				*dst++=f * 32767.0f;
+				++dst_;
+			}
+			*bytes=dst_ * sizeof(signed short);
+		}
+	}
+}
+
 static void *play_loop(void *arg)
 {
 	char *data;
@@ -258,14 +188,15 @@
 
 				if (actual_read == 0)
 				{
-					wav_file->eof = 1;
+					wav_file->eof = TRUE;
 					wav_ip.output->buffer_free();
 					wav_ip.output->buffer_free();
 				}
 				else
 				{
-					wav_ip.add_vis_pcm(wav_ip.output->written_time(), (wav_file->bits_per_sample == 16) ? FMT_S16_LE : FMT_U8,
-					   wav_file->channels, bytes, data);
+					convert(data, &bytes);
+
+					wav_ip.add_vis_pcm(wav_ip.output->written_time(), wav_file->afmt, wav_file->channels, bytes, data);
 					while(wav_ip.output->buffer_free() < bytes && wav_file->going && wav_file->seek_to == -1)
 						xmms_usleep(10000);
 					if(wav_file->going && wav_file->seek_to == -1)
@@ -297,132 +228,148 @@
 	pthread_exit(NULL);
 }
 
-static void play_file(char *filename)
+static WaveFile* construct_WaveFile(char *filename)
 {
-	char magic[4], *name;
 	unsigned long len;
-	int rate;
+	char magic[4];
 
-	audio_error = FALSE;
+	/* alloc mem for struct */
+	WaveFile *wav=g_malloc0(sizeof(WaveFile));
+	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))
+		goto exit_on_error;
+	read_le_long(wav->file, &len);
 
-	wav_file = g_malloc0(sizeof (WaveFile));
-	if ((wav_file->file = fopen(filename, "rb")))
+	fread(magic, 1, 4, wav->file);
+	if (strncmp(magic, "WAVE", 4))
+		goto exit_on_error;
+
+	/* wait for fmt chunk */
+	for (;;)
 	{
-		fread(magic, 1, 4, wav_file->file);
-		if (strncmp(magic, "RIFF", 4))
-		{
-			fclose(wav_file->file);
-			g_free(wav_file);
-			wav_file = NULL;
-			return;
-		}
-		read_le_long(wav_file->file, &len);
-		fread(magic, 1, 4, wav_file->file);
-		if (strncmp(magic, "WAVE", 4))
-		{
-			fclose(wav_file->file);
-			g_free(wav_file);
-			wav_file = NULL;
-			return;
-		}
-		for (;;)
-		{
-			fread(magic, 1, 4, wav_file->file);
-			if (!read_le_long(wav_file->file, &len))
-			{
-				fclose(wav_file->file);
-				g_free(wav_file);
-				wav_file = NULL;
-				return;
-			}
-			if (!strncmp("fmt ", magic, 4))
-				break;
-			fseek(wav_file->file, len, SEEK_CUR);
-		}
-		if (len < 16)
-		{
-			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:
-				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)
-		{
-			fclose(wav_file->file);
-			g_free(wav_file);
-			wav_file = NULL;
-			return;
-		}
-		len -= 16;
-		if (len)
-			fseek(wav_file->file, len, SEEK_CUR);
+		fread(magic, 1, 4, wav->file);
+		if (!read_le_long(wav->file, &len))
+			goto exit_on_error;
 
-		for (;;)
-		{
-			fread(magic, 4, 1, wav_file->file);
+		if (!strncmp("fmt ", magic, 4))
+			break;
+		fseek(wav->file, len, SEEK_CUR);
+	}
 
-			if (!read_le_long(wav_file->file, &len))
-			{
-				fclose(wav_file->file);
-				g_free(wav_file);
-				wav_file = NULL;
-				return;
-			}
-			if (!strncmp("data", magic, 4))
-				break;
-			fseek(wav_file->file, len, SEEK_CUR);
+	/* 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);
+
+	/* check for valid formats */
+	if(wav->format_tag == WAVE_FORMAT_PCM)
+	{
+		switch(wav->bits_per_sample)
+		{
+		case 8: wav->afmt=FMT_U8; break;
+#if 0
+		case 12:
+		case 24:
+#endif
+		case 16:
+		case 32: wav->afmt=FMT_S16_LE; break;
+		default: goto exit_on_error;
 		}
-		wav_file->data_offset = ftell(wav_file->file);
-		wav_file->length = len;
+	}
+	else if(wav->format_tag == WAVE_FORMAT_IEEE_FLOAT)
+	{
+		if(wav->bits_per_sample == 32)
+			wav->afmt=FMT_S16_LE;
+		else
+			goto exit_on_error;
+	}
+	else
+		goto exit_on_error;
 
-		wav_file->position = 0;
-		wav_file->going = 1;
+	/* skip any superflous bytes */
+	len -= 16;
+	if (len)
+	{
+		fseek(wav->file, len, SEEK_CUR);
+	}
 
-		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;
-			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;
-		pthread_create(&decode_thread, NULL, play_loop, NULL);
+	/* 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;
+
+	wav->position = 0;
+	wav->going = TRUE;
+
+	return wav;
+
+ exit_on_error:
+	if(wav->file)
+		fclose(wav->file);
+	g_free(wav);
+	return 0;
+}
+
+static void play_file(char *filename)
+{
+	char *name;
+	int rate;
+
+	audio_error = FALSE;
+
+	if((wav_file = construct_WaveFile(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);
 }
 
 static void stop(void)
 {
 	if (wav_file && wav_file->going)
 	{
-		wav_file->going = 0;
+		wav_file->going = FALSE;
 		pthread_join(decode_thread, NULL);
 		wav_ip.output->close_audio();
 		g_free(wav_file);
@@ -461,108 +408,42 @@
 
 static void get_song_info(char *filename, char **title, int *length)
 {
-	char magic[4];
-	unsigned long len;
-	int rate;
-	WaveFile *wav_file;
+	WaveFile *wav;
 
-	wav_file = g_malloc(sizeof (WaveFile));
-	memset(wav_file, 0, sizeof (WaveFile));
-	if (!(wav_file->file = fopen(filename, "rb")))
+	if(! (wav=construct_WaveFile(filename)))
 		return;
 
-	fread(magic, 1, 4, wav_file->file);
-	if (strncmp(magic, "RIFF", 4))
-	{
-		fclose(wav_file->file);
-		g_free(wav_file);
-		wav_file = NULL;
-		return;
-	}
-	read_le_long(wav_file->file, &len);
-	fread(magic, 1, 4, wav_file->file);
-	if (strncmp(magic, "WAVE", 4))
-	{
-		fclose(wav_file->file);
-		g_free(wav_file);
-		wav_file = NULL;
-		return;
-	}
-	for (;;)
-	{
-		fread(magic, 1, 4, wav_file->file);
-		if (!read_le_long(wav_file->file, &len))
-		{
-			fclose(wav_file->file);
-			g_free(wav_file);
-			wav_file = NULL;
-			return;
-		}
-		if (!strncmp("fmt ", magic, 4))
-			break;
-		fseek(wav_file->file, len, SEEK_CUR);
-	}
-	if (len < 16)
-	{
-		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:
-			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)
-	{
-		fclose(wav_file->file);
-		g_free(wav_file);
-		wav_file = NULL;
-		return;
-	}
-	len -= 16;
-	if (len)
-		fseek(wav_file->file, len, SEEK_CUR);
+	*length = 1000 * (wav->length / (wav->samples_per_sec * wav->channels * (wav->bits_per_sample / 8)) );
+	*title  = get_title(filename);
 
-	for (;;)
-	{
-		fread(magic, 4, 1, wav_file->file);
+	fclose(wav->file);
+	g_free(wav);
+	wav = NULL;
+}
 
-		if (!read_le_long(wav_file->file, &len))
-		{
-			fclose(wav_file->file);
-			g_free(wav_file);
-			wav_file = NULL;
-			return;
-		}
-		if (!strncmp("data", magic, 4))
-			break;
-		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);
+static int is_our_file(char *filename)
+{
+	int ret=FALSE;
+	WaveFile *wav;
+	if(! (wav=construct_WaveFile(filename)))
+		return FALSE;
 
-	fclose(wav_file->file);
-	g_free(wav_file);
-	wav_file = NULL;
+	if(wav->format_tag == WAVE_FORMAT_PCM)
+		ret=TRUE;
+	if(wav->format_tag == WAVE_FORMAT_IEEE_FLOAT)
+		ret=TRUE;
+
+	g_free(wav);
+	return ret;
 }
+
+InputPlugin wav_ip =
+{
+	.is_our_file = is_our_file,
+	.play_file = play_file,
+	.stop = stop,
+	.pause = wav_pause,
+	.seek = seek,
+	.get_time = get_time,
+	.get_song_info = get_song_info,
+};
Index: wav.h
===================================================================
RCS file: /cvs/xmms/Input/wav/wav.h,v
retrieving revision 1.4
diff -u -r1.4 wav.h
--- wav.h	27 Feb 2002 21:56:48 -0000	1.4
+++ wav.h	21 Dec 2004 19:46:52 -0000
@@ -1,5 +1,5 @@
 /*  XMMS - Cross-platform multimedia player
- *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ *  Copyright (C) 1998-2005  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
  *
  *  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,57 +18,6 @@
 #ifndef WAV_H
 #define WAV_H
 
-#include "config.h"
-
-#include <pthread.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-
-#include <glib.h>
-
-#include "xmms/plugin.h"
-
-#define	WAVE_FORMAT_UNKNOWN		(0x0000)
-#define	WAVE_FORMAT_PCM			(0x0001)
-#define	WAVE_FORMAT_ADPCM		(0x0002)
-#define	WAVE_FORMAT_ALAW		(0x0006)
-#define	WAVE_FORMAT_MULAW		(0x0007)
-#define	WAVE_FORMAT_OKI_ADPCM		(0x0010)
-#define	WAVE_FORMAT_DIGISTD		(0x0015)
-#define	WAVE_FORMAT_DIGIFIX		(0x0016)
-#define	IBM_FORMAT_MULAW         	(0x0101)
-#define	IBM_FORMAT_ALAW			(0x0102)
-#define	IBM_FORMAT_ADPCM         	(0x0103)
-
-extern InputPlugin wav_ip;
-
-typedef struct
-{
-	FILE *file;
-	short format_tag, channels, block_align, bits_per_sample, eof, going;
-	long samples_per_sec, avg_bytes_per_sec;
-	unsigned long position, length;
-	int seek_to, data_offset;
-	pid_t pid;
-}
-WaveFile;
-
-static void wav_init(void);
-static int is_our_file(char *filename);
-static void play_file(char *filename);
-static void stop(void);
-static void seek(int time);
-static void wav_pause(short p);
-static int get_time(void);
-static void get_song_info(char *filename, char **title, int *length);
+#error this file should be removed from CVS
 
 #endif
-
-
-
-
-
-
-