changeset 810:e9509e909193 trunk

[svn] ported xmms-arts 0.7.1 to audacious and integrated it in the build process
author giacomo
date Thu, 09 Mar 2006 09:55:56 -0800
parents 79da0e6ed790
children 86ca43d8a845
files Plugins/Output/Makefile.in Plugins/Output/arts/Makefile.in Plugins/Output/arts/arts.c Plugins/Output/arts/arts.h Plugins/Output/arts/arts_helper/Makefile.in Plugins/Output/arts/arts_helper/arts_helper.c Plugins/Output/arts/arts_helper/arts_helper.h Plugins/Output/arts/audio.c Plugins/Output/arts/configure.c Plugins/Output/arts/convert.c configure.ac m4/arts.m4 mk/rules.mk.in
diffstat 13 files changed, 1460 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/Plugins/Output/Makefile.in	Wed Mar 08 11:16:59 2006 -0800
+++ b/Plugins/Output/Makefile.in	Thu Mar 09 09:55:56 2006 -0800
@@ -1,5 +1,5 @@
 include ../../mk/rules.mk
 include ../../mk/objective.mk
 
-ALL_PLUGINS = OSS alsa disk_writer esd jack
+ALL_PLUGINS = OSS alsa disk_writer esd jack arts
 SUBDIRS = @OUTPUT_PLUGINS@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/Makefile.in	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,15 @@
+include ../../../mk/rules.mk
+include ../../../mk/objective.mk
+
+SUBDIRS = arts_helper
+
+SOURCES = arts.c configure.c audio.c convert.c
+
+OBJECTIVE_LIBS = libarts.so
+
+LIBDIR = $(plugindir)/$(OUTPUT_PLUGIN_DIR)
+
+CFLAGS += -fPIC -DPIC $(GTK_CFLAGS) -Wall $(ARTSC_CFLAGS) -I../../../intl -I../../..
+LIBADD = $(GTK_LIBS) $(ARTSC_LIBS) -lpthread
+
+OBJECTS = ${SOURCES:.c=.o}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/arts.c	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,60 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+#include "arts.h"
+#include "libaudacious/configfile.h"
+#include "libaudacious/util.h"
+
+static void about(void)
+{
+	static GtkWidget *dialog;
+	
+	if (dialog)
+		return;
+
+	dialog = xmms_show_message("About aRts Output",
+				   "aRts output plugin by "
+				   "H\303\245vard Kv\303\245len <havardk@xmms.org>\n"
+				   "Audacious port by Giacomo Lozito from develia.org",
+				   "Ok", FALSE, NULL, NULL);
+	gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
+			   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+			   &dialog);
+}
+
+
+OutputPlugin arts_op =
+{
+	NULL,
+	NULL,
+	"aRts Output Plugin 0.7.1",
+	artsxmms_init,
+	NULL,
+	about,
+	artsxmms_configure,
+	artsxmms_get_volume,
+	artsxmms_set_volume,
+	artsxmms_open,
+	artsxmms_write,
+	artsxmms_close,
+	artsxmms_flush,
+	artsxmms_pause,
+	artsxmms_free,
+	artsxmms_playing,
+	artsxmms_get_output_time,
+	artsxmms_get_written_time,
+	artsxmms_tell_audio
+};
+
+OutputPlugin *get_oplugin_info(void)
+{
+	return &arts_op;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/arts.h	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,70 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+#ifndef XMMS_ARTS_H
+#define XMMS_ARTS_H
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "audacious/plugin.h"
+#include "libaudacious/configfile.h"
+
+struct arts_config
+{
+	int buffer_size;
+};
+
+struct params_info
+{
+	AFormat format;
+	int frequency;
+	int channels;
+
+	/* Cache these */
+	int bps;
+	int resolution;
+};
+
+extern struct arts_config artsxmms_cfg;
+
+void artsxmms_init(void);
+void artsxmms_about(void);
+void artsxmms_configure(void);
+
+void artsxmms_tell_audio( AFormat * , gint * , gint * );
+
+void artsxmms_get_volume(int *l, int *r);
+void artsxmms_set_volume(int l, int r);
+
+int artsxmms_playing(void);
+int artsxmms_free(void);
+void artsxmms_write(void *ptr, int length);
+void artsxmms_close(void);
+void artsxmms_flush(int time);
+void artsxmms_pause(short p);
+int artsxmms_open(AFormat fmt, int rate, int nch);
+int artsxmms_get_output_time(void);
+int artsxmms_get_written_time(void);
+
+int (*arts_get_convert_func(int input))(void **, int);
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/arts_helper/Makefile.in	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,16 @@
+include ../../../../mk/rules.mk
+include ../../../../mk/objective.mk
+
+SOURCES = arts_helper.c arts_helper.h
+
+OBJECTIVE_BINS = audacious-arts-helper
+
+LDFLAGS = -Wl,-export-dynamic
+LDADD = $(ARTSC_LIBS)
+
+CFLAGS += $(ARTSC_CFLAGS) -I../../../../intl -I../../../..
+
+OBJECTS = ${SOURCES:.c=.o}
+
+audacious-arts-helper: $(OBJECTS)
+	$(CC) $(LDFLAGS) $(LDADD) -o $@ $(OBJECTS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/arts_helper/arts_helper.c	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,446 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+#include "arts_helper.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/select.h>
+
+#include <artsc.h>
+
+#define FALSE 0
+#define TRUE (!FALSE)
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+
+#ifdef WORDS_BIGENDIAN
+#define INT16_FROM_LE(val) ((val & 0xff) << 8 | (val & 0xff00) >> 8)
+#define INT16_TO_LE(val)  ((val & 0xff) << 8 | (val & 0xff00) >> 8)
+#else
+#define INT16_FROM_LE(val) (val)
+#define INT16_TO_LE(val) (val)
+#endif
+
+/* This is not quite portable, but should be ok anyway */
+typedef short int16;
+
+static arts_stream_t handle;
+
+static int going, paused, inited;
+static struct params_info output_params;
+
+struct {
+	int left, right;
+} volume = {100, 100};
+
+struct params_info
+{
+	int resolution;
+	int frequency;
+	int channels;
+
+	/* Cache */
+	int bps;
+};
+
+static struct {
+	unsigned int bsize, latency, psize;
+} arts_params;
+
+static struct {
+	char *ptr;
+	int size;
+	int rd, wr;
+} ring_buffer;
+
+static void artsxmms_set_params(struct params_info *params, int resolution, int rate, int nch)
+{
+	params->frequency = rate;
+	params->channels = nch;
+
+	params->bps = rate * nch;
+	params->resolution = resolution;
+	if (resolution == 16)
+		params->bps *= 2;
+}
+
+static int artsxmms_free(void)
+{
+	if (ring_buffer.rd > ring_buffer.wr)
+		return ring_buffer.rd - ring_buffer.wr - 1;
+	return ring_buffer.size - (ring_buffer.wr - ring_buffer.rd);
+}
+
+static int artsxmms_buffer_used(void)
+{
+	return ring_buffer.size - artsxmms_free();
+}
+
+static int artsxmms_get_output_latency(void) 
+{
+	int latency;
+	long long w;
+	
+	if (!going)
+		return 0;
+
+	w = artsxmms_buffer_used();
+	w += arts_params.bsize - arts_stream_get(handle, ARTS_P_BUFFER_SPACE);
+	latency =  (w * 1000) / output_params.bps;
+
+	if (!paused)
+		latency += arts_params.latency;
+
+	return latency;
+}
+
+static int artsxmms_playing(void)
+{
+	if (!going)
+		return FALSE;
+	
+	if (!paused)
+	{
+		int t;
+		t = arts_stream_get(handle, ARTS_P_BUFFER_SPACE);
+		return t < arts_params.bsize - arts_params.psize;
+	}
+
+	return TRUE;
+}
+
+static void artsxmms_open_stream(struct params_info *params, int buffer_time)
+{
+	int buffersize = buffer_time * params->bps / 1000;
+	handle = arts_play_stream(params->frequency, params->resolution,
+				  params->channels, "XMMS");
+	arts_params.bsize = arts_stream_set(handle, ARTS_P_BUFFER_SIZE,
+					    buffersize);
+	arts_params.latency = arts_stream_get(handle, ARTS_P_SERVER_LATENCY);
+	arts_params.psize = arts_stream_get(handle, ARTS_P_PACKET_SIZE);
+}
+
+static void artsxmms_set_volume(int l, int r)
+{
+	volume.left = l;
+	volume.right = r;
+}
+
+static void volume_adjust(void* data, int length)
+{
+	int i;
+
+	if ((volume.left == 100 && volume.right == 100) ||
+	    (output_params.channels == 1 &&
+	     (volume.left == 100 || volume.right == 100)))
+		return;
+
+	if (output_params.resolution == 16)
+	{
+		int16 *ptr = data;
+		if (output_params.channels == 2)
+			for (i = 0; i < length; i += 4)
+			{
+				*ptr = INT16_TO_LE(INT16_FROM_LE(*ptr) *
+						   volume.left / 100);
+				ptr++;
+				*ptr = INT16_TO_LE(INT16_FROM_LE(*ptr) *
+						   volume.right / 100);
+				ptr++;
+			}
+		else
+		{
+			int vol = MAX(volume.left, volume.right);
+			for (i = 0; i < length; i += 2, ptr++)
+			{
+				*ptr = INT16_TO_LE(INT16_FROM_LE(*ptr) *
+						   vol / 100);
+			}
+		}
+	}
+	else
+	{
+		unsigned char *ptr = data;
+		if (output_params.channels == 2)
+			for (i = 0; i < length; i += 2)
+			{
+				*ptr = *ptr * volume.left / 100;
+				ptr++;
+				*ptr = *ptr * volume.right / 100;
+				ptr++;
+			}
+		else
+		{
+			int vol = MAX(volume.left, volume.right);
+			for (i = 0; i < length; i++, ptr++)
+			{
+				*ptr = *ptr * vol / 100;
+			}
+		}
+	}
+}
+
+static void artsxmms_write(char *ptr, int length)
+{
+	int cnt;
+
+	/* FIXME: Check that length is not too large? */
+	while (length > 0)
+	{
+		cnt = MIN(length, ring_buffer.size - ring_buffer.wr);
+		memcpy(ring_buffer.ptr + ring_buffer.wr, ptr, cnt);
+		ring_buffer.wr = (ring_buffer.wr + cnt) % ring_buffer.size;
+		length -= cnt;
+		ptr += cnt;
+	}
+}
+
+static void artsxmms_write_arts(void)
+{
+	int ret, cnt, space;
+	char *ptr;
+
+	if (ring_buffer.wr == ring_buffer.rd || paused)
+		return;
+	
+	space = arts_stream_get(handle, ARTS_P_BUFFER_SPACE);
+
+	while (space > 0 && ring_buffer.wr != ring_buffer.rd)
+	{
+		if (ring_buffer.wr > ring_buffer.rd)
+			cnt = MIN(space, ring_buffer.wr - ring_buffer.rd);
+		else
+			cnt = MIN(space, ring_buffer.size - ring_buffer.rd);
+
+		ptr = ring_buffer.ptr + ring_buffer.rd;
+
+		volume_adjust(ptr, cnt);
+		ret = arts_write(handle, ptr, cnt);
+		if (ret < 0)
+		{
+			/* FIXME: handle this better? */
+			fprintf(stderr, "artsxmms_write(): write error: %s\n",
+				arts_error_text(ret));
+			return;
+		}
+
+		ring_buffer.rd = (ring_buffer.rd + cnt) % ring_buffer.size;
+		space -= cnt;
+	}
+}
+
+static void artsxmms_close(void)
+{
+	going = 0;
+	arts_close_stream(handle);
+	arts_free();
+}
+
+static int read_all(int fd, void *buf, size_t count)
+{
+	size_t left = count;
+	int r;
+	do {
+		r = read(fd, buf, left);
+		if (r < 0)
+			return -1;
+		left -= r;
+		buf = (char *)buf + r;
+	} while (left > 0 && r > 0);
+	return count - left;
+}
+
+static int write_all(int fd, const void *buf, size_t count)
+{
+	size_t left = count;
+	int w;
+	do {
+		w = write(fd, buf, left);
+		
+		if (w < 0)
+			return -1;
+		left -= w;
+		buf = (char *)buf + w;
+	} while (left > 0 && w > 0);
+	return count - left;
+}
+
+
+static int init_ring_buffer(int size)
+{
+	free(ring_buffer.ptr);
+	/* Make the ring buffer always end on a sample boundary */
+	size -= size % 4;
+	ring_buffer.size = size;
+	ring_buffer.ptr = malloc(size);
+	ring_buffer.rd = 0;
+	ring_buffer.wr = 0;
+	if (ring_buffer.ptr == NULL)
+		return -1;
+	return 0;
+}
+
+static int helper_init(struct init_data *init)
+{
+	int buffer_time = MAX(init->buffer_time, 50);
+	if (init->version != HELPER_VERSION) {
+		fprintf(stderr,
+			"Fatal: Version mismatch between arts output plugin and\n"
+			"       audacious-arts-helper program.\n");
+		return -1;
+	}
+	if (!inited)
+		return -1;
+	artsxmms_set_params(&output_params, init->resolution, init->rate,
+			    init->nchannels);
+
+	if (init_ring_buffer((buffer_time * 2 * output_params.bps) / 1000))
+		return -1;
+
+	if (handle)
+		arts_close_stream(handle);
+	artsxmms_open_stream(&output_params, buffer_time);
+
+	going = 1;
+	return 0;
+}
+
+static int process_cmd(int fd)
+{
+	struct command inp;
+	struct response outp;
+	void *data = NULL;
+	int retval = 0;
+
+	if (read_all(fd, &inp, sizeof(inp)) != sizeof(inp)) {
+		fprintf(stderr, "read short, giving up\n");
+		return -1;
+	}
+	if (inp.data_length > 0) {
+		data = malloc(inp.data_length);
+		if (data == NULL)
+			return -1;
+		if (read_all(fd, data, inp.data_length) != inp.data_length) {
+			fprintf(stderr, "data read short, giving up\n");
+			return -1;
+		}
+	}
+	outp.cmd = inp.cmd;
+	outp.status = STATUS_OK;
+	outp.data = 0;
+/*  	fprintf(stderr, "Recieved %d; ", inp.cmd); */
+	switch (inp.cmd) {
+		case CMD_QUIT:
+			artsxmms_close();
+			retval = 1;
+			break;
+		case CMD_INIT:
+			if (inp.data_length != sizeof (struct init_data))
+				outp.status = STATUS_FAILED;
+			else if (helper_init(data))
+				outp.status = STATUS_FAILED;
+			break;
+		case CMD_PAUSE:
+			paused = inp.data;
+			break;
+		case CMD_SET_VOLUME: {
+			int *vol = data;
+			if (inp.data_length < 2 * sizeof(int)) {
+				outp.status = STATUS_FAILED;
+				break;
+			}
+			artsxmms_set_volume(vol[0], vol[1]);
+			break;
+		}
+		case CMD_WRITE:
+			artsxmms_write(data, inp.data_length);
+			break;
+		case CMD_FREE:
+			outp.data = artsxmms_free();
+			break;
+		case CMD_GET_OUTPUT_LATENCY:
+			outp.data = artsxmms_get_output_latency();
+			break;
+		case CMD_QUERY_PLAYING:
+			outp.data = artsxmms_playing();
+			break;
+		default:
+			outp.status = STATUS_UNKNOWN;
+			fprintf(stderr, "Unknown command %d\n", inp.cmd);
+	}
+	free(data);
+	if (write_all(fd, &outp, sizeof (outp)) != sizeof (outp))
+		return -1;
+	return retval;
+}
+
+
+static int main_loop(int fd)
+{
+	int retval = 0, sr;
+	struct timeval timeout;
+	fd_set rdfs;
+
+	for (;;) {
+		FD_ZERO(&rdfs);
+		FD_SET(fd, &rdfs);
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 20000;
+		sr = select(fd + 1, &rdfs, NULL, NULL, &timeout);
+		if (sr < 0) {
+			fprintf(stderr, "audacious-arts-helper select failed: %s\n",
+				strerror(errno));
+			retval = -1;
+			break;
+		} else if (sr) {
+			int p = process_cmd(fd);
+			if (p < 0) {
+				fprintf(stderr, "cmd failed\n");
+				retval = 1;
+				break;
+			} else if (p)
+				break;
+		}
+
+		artsxmms_write_arts();
+	}
+	return retval;
+}
+
+int main(int argc, char **argv)
+{
+	int fd, err, ret;
+
+	if (argc != 2 || (fd = atoi(argv[1])) < 1)
+	{
+		fprintf(stderr, "Usage: audacious-arts-helper fd\n");
+		return 1;
+	}
+
+	inited = 1;
+
+	if ((err = arts_init()) != 0)
+	{
+		fprintf(stderr, "artsxmms_open(): Unable to initialize aRts: %s\n",
+			  arts_error_text(err));
+		inited = 0;
+	}
+
+	ret = main_loop(fd);
+	close(fd);
+/* 	fprintf(stderr, "helper exits\n"); */
+	return ret < 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/arts_helper/arts_helper.h	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,52 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003,2004  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+struct command
+{
+	int cmd;
+	int data;
+	int data_length;
+};
+
+struct response
+{
+	int cmd;
+	int status;
+	int data;
+};
+
+#define HELPER_VERSION 0x000700
+
+struct init_data
+{
+	int version;
+	int resolution, rate, nchannels;
+	int buffer_time;
+};
+
+enum {
+	CMD_INIT = 1,
+	CMD_QUIT,
+	CMD_PAUSE,
+	CMD_FLUSH,
+	CMD_SET_VOLUME,
+	CMD_WRITE,
+	CMD_FREE,
+	CMD_GET_OUTPUT_LATENCY,
+	CMD_QUERY_PLAYING,
+};
+
+enum {
+	STATUS_OK = 0,
+	STATUS_FAILED,
+	STATUS_UNKNOWN,
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/audio.c	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,430 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+#include "arts.h"
+#include "arts_helper/arts_helper.h"
+#include <errno.h>
+#include <signal.h>
+#include <pthread.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static gboolean going, paused, helper_failed;
+static guint64 written;
+static struct params_info input_params, output_params;
+static int helperfd;
+static pid_t helper_pid;
+
+static int (*arts_convert_func)(void **data, int length);
+struct arts_config artsxmms_cfg;
+
+struct {
+	int left, right;
+} volume = {100, 100};
+
+
+typedef struct format_info {
+  AFormat format;
+  long    frequency;
+  int     channels;
+  long    bps;
+} format_info_t;
+
+static format_info_t input;
+static format_info_t effect;
+static format_info_t output;
+
+
+void artsxmms_tell_audio(AFormat * fmt, gint * srate, gint * nch)
+{
+	(*fmt) = input.format;
+	(*srate) = input.frequency;
+	(*nch) = input.channels;
+}
+
+
+void artsxmms_init(void)
+{
+	ConfigFile *cfgfile;
+
+	memset(&artsxmms_cfg, 0, sizeof (artsxmms_cfg));
+
+	artsxmms_cfg.buffer_size = 400;
+	
+	cfgfile = xmms_cfg_open_default_file();
+	xmms_cfg_read_int(cfgfile, "arts", "buffer_size",
+			  &artsxmms_cfg.buffer_size);
+	xmms_cfg_free(cfgfile);
+}
+
+
+static int read_all(int fd, void *buf, size_t count)
+{
+	size_t left = count;
+	int r;
+	do {
+		r = read(fd, buf, left);
+		if (r < 0)
+			return -1;
+		left -= r;
+		buf = (char *)buf + r;
+	} while (left > 0 && r > 0);
+	return count - left;
+}
+
+static int write_all(int fd, const void *buf, size_t count)
+{
+	size_t left = count;
+	int w;
+	do {
+		w = write(fd, buf, left);
+		if (w < 0)
+			return -1;
+		left -= w;
+		buf = (char *)buf + w;
+	} while (left > 0 && w > 0);
+/* 	g_message("wrote: %d", count - left); */
+	return count - left;
+}
+
+static int wait_for_helper(int fd)
+{
+	struct timeval timeout;
+	fd_set rdfs;
+	int sr;
+
+	FD_ZERO(&rdfs);
+	FD_SET(fd, &rdfs);
+
+	timeout.tv_sec = 10;
+	timeout.tv_usec = 0;
+
+	sr = select(fd + 1, &rdfs, NULL, NULL, &timeout);
+	if (sr < 0) {
+		g_message("wait_for_helper(): select failed: %s",
+			  strerror(errno));
+		return -1;
+	} else if (!sr) {
+		g_message("wait_for_helper(): Timed out waiting for helper");
+		return -1;
+	}
+	return 0;
+}
+
+static int xx;
+
+static int helper_cmd_data(int cmd, int idata, void* ptr, int data_length)
+{
+	static pthread_mutex_t artsm = PTHREAD_MUTEX_INITIALIZER;
+	struct command out;
+	struct response in;
+	int status;
+
+	out.cmd = cmd;
+	out.data = idata;
+	out.data_length = data_length;
+	xx++;
+
+	if (helper_failed)
+		goto failed;
+
+	pthread_mutex_lock(&artsm);
+/*  	fprintf(stderr, "Sending %d; ", out.cmd); */
+	if (write_all(helperfd, &out, sizeof (out)) != sizeof (out))
+		goto failed;
+	if (data_length > 0)
+		if (write_all(helperfd, ptr, data_length) != data_length)
+			goto failed;
+
+	if (wait_for_helper(helperfd)) {
+		g_message("waiting failed: %d", cmd);
+		goto failed;
+	}
+
+	if (read_all(helperfd, &in, sizeof (in)) != sizeof (in))
+	{
+		g_message("read failed: %d", cmd);
+		goto failed;
+	}
+
+/*  	fprintf(stderr, "%d complete\n", out.cmd); */
+	pthread_mutex_unlock(&artsm);
+
+	if (in.status)
+		return -in.status;
+	return in.data;
+
+ failed:
+	g_message("helper_cmd_data(): failed");
+	helper_failed = TRUE;
+	if (helper_pid && waitpid(helper_pid, &status, WNOHANG)) {
+		if (status)
+			g_message("helper terminated abnormally: %d", status);
+		else
+			g_message("helper terminated normally");
+		helper_pid = 0;
+	} else if (helper_pid)
+		g_message("helper has not terminated");
+	pthread_mutex_unlock(&artsm);
+	return -STATUS_FAILED;
+}
+
+static int helper_cmd(int cmd, int idata)
+{
+	return helper_cmd_data(cmd, idata, NULL, 0);
+}
+
+static int artsxmms_helper_init(struct params_info *params)
+{
+	int ret;
+	struct init_data id;
+
+	id.version = HELPER_VERSION;
+	id.resolution = params->resolution;
+	id.rate= params->frequency;
+	id.nchannels = params->channels;
+	id.buffer_time = artsxmms_cfg.buffer_size;
+
+	ret = helper_cmd_data(CMD_INIT, 0, &id, sizeof (id));
+	if (ret) {
+		g_message("Init failed: %d", -ret);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void artsxmms_set_params(struct params_info *params, AFormat fmt, int rate, int nch)
+{
+	params->format = fmt;
+	params->frequency = rate;
+	params->channels = nch;
+
+	params->bps = rate * nch;
+	params->resolution = 8;
+	if (!(fmt == FMT_U8 || fmt == FMT_S8))
+	{
+		params->bps *= 2;
+		params->resolution = 16;
+	}
+}
+
+int artsxmms_get_written_time(void)
+{
+	if (!going)
+		return 0;
+
+	return (written * 1000) / output_params.bps;
+}
+
+int artsxmms_get_output_time(void) 
+{
+	int time;
+
+	if (!going)
+		return 0;
+	if (helper_failed)
+		return -2;
+
+	time = artsxmms_get_written_time();
+	time -= helper_cmd(CMD_GET_OUTPUT_LATENCY, 0);
+
+	if (time < 0)
+		return 0;
+	return time;
+}
+
+int artsxmms_playing(void)
+{
+	if (!going)
+		return FALSE;
+	
+	if (!paused)
+	{
+		if (helper_cmd(CMD_QUERY_PLAYING, 0) <= 0)
+			return FALSE;
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+int artsxmms_free(void)
+{
+	int space;
+
+	if (!going)
+		return 0;
+
+	space = helper_cmd(CMD_FREE, 0);
+	if (space < 0)
+		return 0;
+
+	return space;
+}
+
+void artsxmms_write(gpointer ptr, int length)
+{
+	AFormat new_format;
+	int new_frequency, new_channels;
+	EffectPlugin *ep;
+	
+	new_format = input_params.format;
+	new_frequency = input_params.frequency;
+	new_channels = input_params.channels;
+
+	ep = get_current_effect_plugin();
+	if (effects_enabled() && ep && ep->query_format)
+		ep->query_format(&new_format, &new_frequency, &new_channels);
+	
+	if (new_format != output_params.format ||
+	    new_frequency != output_params.frequency ||
+	    new_channels != output_params.channels)
+	{
+		/*
+		 * The effect plugins has changed the format of the stream.
+		 */
+
+		guint64 offset = (written * 1000) / output_params.bps;
+		artsxmms_set_params(&output_params, new_format,
+				    new_frequency, new_channels);
+		arts_convert_func = arts_get_convert_func(output_params.format);
+	
+		written = (offset * output_params.bps) / 1000;
+
+		artsxmms_helper_init(&output_params);
+	}
+
+	/*
+	 * Doing the effect plugin processing here adds some latency,
+	 * but the alternative is just too frigging hairy.
+	 */
+	
+	if (effects_enabled() && ep && ep->mod_samples)
+		length = ep->mod_samples(&ptr, length, input_params.format,
+					 input_params.frequency,
+					 input_params.channels);
+
+	if (arts_convert_func)
+		arts_convert_func(ptr, length);
+
+	helper_cmd_data(CMD_WRITE, 0, ptr, length);
+	written += length;
+}
+
+void artsxmms_close(void)
+{
+	int status;
+	going = 0;
+/* 	g_message("sending quit cmd"); */
+	if (!helper_cmd(CMD_QUIT, 0)) {
+		waitpid(helper_pid, &status, 0);
+		if (status)
+			g_message("artsxmms_close(): Child exited abnormally: %d",
+				  status);
+	}
+}
+
+void artsxmms_flush(int time)
+{
+	/*
+	 * Argh, no way to flush the stream from the C api.
+	 */
+	written = (time / 10) * (output_params.bps / 100);
+
+}
+
+void artsxmms_pause(short p)
+{
+	paused = p;
+	helper_cmd(CMD_PAUSE, p);
+}
+
+static int artsxmms_start_helper()
+{
+	int sockets[2];
+
+	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
+	{
+		g_message("artsxmms_start_helper(): "
+			  "Failed to create socketpair: %s", strerror(errno));
+		return -1;
+	}
+	
+	if ((helper_pid = fork()) == 0)
+	{
+		/* Child */
+		char sockfdstr[10];
+		close(sockets[1]);
+		sprintf(sockfdstr, "%d", sockets[0]);
+		execlp("audacious-arts-helper", "audacious-arts-helper",
+		       sockfdstr, NULL);
+		g_warning("artsxmms_start_helper(): "
+			  "Failed to start audacious-arts-helper: %s", strerror(errno));
+		close(sockets[0]);
+		_exit(1);
+	}
+	close(sockets[0]);
+	helperfd = sockets[1];
+
+	if (helper_pid < 0)
+	{
+		g_message("artsxmms_start_helper(): "
+			  "Failed to fork() helper process: %s", strerror(errno));
+		close(sockets[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+int artsxmms_open(AFormat fmt, int rate, int nch)
+{
+	if (artsxmms_start_helper() < 0)
+		return 0;
+
+	artsxmms_set_params(&input_params, fmt, rate, nch);
+	artsxmms_set_params(&output_params, fmt, rate, nch);
+
+	arts_convert_func = arts_get_convert_func(output_params.format);
+	
+	written = 0;
+	paused = 0;
+	helper_failed = FALSE;
+
+	if (artsxmms_helper_init(&output_params)) {
+		artsxmms_close();
+		return 0;
+	}
+	artsxmms_set_volume(volume.left, volume.right);
+
+	going = 1;
+	return 1;
+}
+
+void artsxmms_get_volume(int *l, int *r)
+{
+	*l = volume.left;
+	*r = volume.right;
+}
+
+void artsxmms_set_volume(int l, int r)
+{
+	int vol[2];
+	volume.left = l;
+	volume.right = r;
+	vol[0] = l;
+	vol[1] = r;
+	helper_cmd_data(CMD_SET_VOLUME, 0, vol, sizeof(vol));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/configure.c	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,106 @@
+/*
+ *  aRts ouput plugin for xmms
+ *
+ *  Copyright (C) 2000,2003  Haavard Kvaalen <havardk@xmms.org>
+ *
+ *  Licenced under GNU GPL version 2.
+ *
+ *  Audacious port by Giacomo Lozito from develia.org
+ *
+ */
+
+#include "arts.h"
+#define _(string) (string)
+
+#include <gtk/gtk.h>
+
+static GtkWidget *configure_win = NULL;
+static GtkWidget *buffer_size_spin;
+
+static void configure_win_ok_cb(GtkWidget * w, gpointer data)
+{
+	ConfigFile *cfgfile;
+
+	artsxmms_cfg.buffer_size =
+		gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(buffer_size_spin));
+	
+	cfgfile = xmms_cfg_open_default_file();
+	xmms_cfg_write_int(cfgfile, "arts", "buffer_size", artsxmms_cfg.buffer_size);
+	xmms_cfg_write_default_file(cfgfile);
+	xmms_cfg_free(cfgfile);
+
+	gtk_widget_destroy(configure_win);
+}
+
+
+void artsxmms_configure(void)
+{
+	GtkWidget *vbox, *notebook;
+	GtkWidget *buffer_frame, *buffer_vbox, *buffer_table;
+	GtkWidget *buffer_size_box, *buffer_size_label;
+	GtkWidget *bbox, *ok, *cancel;
+
+	GtkObject *buffer_size_adj;
+
+	if (configure_win)
+		return;
+	
+	configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_type_hint( GTK_WINDOW(configure_win), GDK_WINDOW_TYPE_HINT_DIALOG );
+	gtk_signal_connect(GTK_OBJECT(configure_win), "destroy",
+			   GTK_SIGNAL_FUNC(gtk_widget_destroyed), &configure_win);
+	gtk_window_set_title(GTK_WINDOW(configure_win), _("aRts Driver configuration"));
+	gtk_window_set_policy(GTK_WINDOW(configure_win), FALSE, FALSE, FALSE);
+	gtk_window_set_position(GTK_WINDOW(configure_win), GTK_WIN_POS_MOUSE);
+	gtk_container_border_width(GTK_CONTAINER(configure_win), 10);
+	
+	vbox = gtk_vbox_new(FALSE, 10);
+	gtk_container_add(GTK_CONTAINER(configure_win), vbox);
+	
+	notebook = gtk_notebook_new();
+	gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0);
+	
+	buffer_frame = gtk_frame_new(_("Buffering:"));
+	gtk_container_set_border_width(GTK_CONTAINER(buffer_frame), 5);
+	
+	buffer_vbox = gtk_vbox_new(FALSE, 0);
+	gtk_container_add(GTK_CONTAINER(buffer_frame), buffer_vbox);
+	
+	buffer_table = gtk_table_new(2, 1, TRUE);
+	gtk_container_set_border_width(GTK_CONTAINER(buffer_table), 5);
+	gtk_box_pack_start(GTK_BOX(buffer_vbox), buffer_table, FALSE, FALSE, 0);
+	
+	buffer_size_box = gtk_hbox_new(FALSE, 5);
+	gtk_table_attach_defaults(GTK_TABLE(buffer_table), buffer_size_box, 0, 1, 0, 1);
+	buffer_size_label = gtk_label_new(_("Buffer size (ms):"));
+	gtk_box_pack_start(GTK_BOX(buffer_size_box), buffer_size_label, FALSE, FALSE, 0);
+	gtk_widget_show(buffer_size_label);
+	buffer_size_adj = gtk_adjustment_new(artsxmms_cfg.buffer_size,
+					     200, 10000, 100, 100, 100);
+	buffer_size_spin = gtk_spin_button_new(GTK_ADJUSTMENT(buffer_size_adj), 8, 0);
+	gtk_widget_set_usize(buffer_size_spin, 60, -1);
+	gtk_box_pack_start(GTK_BOX(buffer_size_box), buffer_size_spin, FALSE, FALSE, 0);
+	
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buffer_frame,
+				 gtk_label_new(_("Buffering")));
+	
+	bbox = gtk_hbutton_box_new();
+	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
+	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
+	gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5);
+	
+	ok = gtk_button_new_with_label(_("Ok"));
+	cancel = gtk_button_new_with_label(_("Cancel"));
+	GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT);
+	GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT);
+	gtk_signal_connect(GTK_OBJECT(ok), "clicked",
+			   GTK_SIGNAL_FUNC(configure_win_ok_cb), NULL);
+	gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked",
+				  GTK_SIGNAL_FUNC(gtk_widget_destroy),
+				  GTK_OBJECT(configure_win));
+	gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
+	gtk_widget_grab_default(ok);
+	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
+	
+	gtk_widget_show_all(configure_win);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Output/arts/convert.c	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,112 @@
+/*
+ *  Copyright (C) 2001-2003  Haavard Kvaalen
+ *
+ *  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.
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include "audacious/plugin.h"
+#include <glib.h>
+
+#ifdef WORDS_BIGENDIAN
+# define IS_BIG_ENDIAN TRUE
+#else
+# define IS_BIG_ENDIAN FALSE
+#endif
+
+
+
+static int convert_swap_endian(void **data, int length)
+{
+	guint16 *ptr = *data;
+	int i;
+	for (i = 0; i < length; i += 2, ptr++)
+		*ptr = GUINT16_SWAP_LE_BE(*ptr);
+
+	return i;
+}
+
+static int convert_swap_sign_and_endian_to_native(void **data, int length)
+{
+	guint16 *ptr = *data;
+	int i;
+	for (i = 0; i < length; i += 2, ptr++)
+		*ptr = GUINT16_SWAP_LE_BE(*ptr) ^ 1 << 15;
+
+	return i;
+}
+
+static int convert_swap_sign_and_endian_to_alien(void **data, int length)
+{
+	guint16 *ptr = *data;
+	int i;
+	for (i = 0; i < length; i += 2, ptr++)
+		*ptr = GUINT16_SWAP_LE_BE(*ptr ^ 1 << 15);
+
+	return i;
+}
+
+static int convert_swap_sign16(void **data, int length)
+{
+	gint16 *ptr = *data;
+	int i;
+	for (i = 0; i < length; i += 2, ptr++)
+		*ptr ^= 1 << 15;
+
+	return i;
+}
+
+static int convert_swap_sign8(void **data, int length)
+{
+	gint8 *ptr = *data;
+	int i;
+	for (i = 0; i < length; i++)
+		*ptr++ ^= 1 << 7;
+
+	return i;
+}
+
+int (*arts_get_convert_func(int input))(void **, int)
+{
+	if (input == FMT_S16_NE)
+		input = IS_BIG_ENDIAN ? FMT_S16_BE : FMT_S16_LE;
+	else if (input == FMT_U16_NE)
+		input = IS_BIG_ENDIAN ? FMT_U16_BE : FMT_U16_LE;
+
+	if (input == FMT_S16_LE || input == FMT_U8)
+		return NULL;
+	
+	if (input == FMT_S16_BE)
+		return convert_swap_endian;
+
+	if (input == FMT_U16_LE)
+		return convert_swap_sign16;
+
+	if (!IS_BIG_ENDIAN && input == FMT_U16_BE)
+		return convert_swap_sign_and_endian_to_native;
+		
+	if (IS_BIG_ENDIAN && input == FMT_U16_BE)
+		return convert_swap_sign_and_endian_to_alien;
+
+	if (input == FMT_S8)
+		return convert_swap_sign8;
+
+	g_warning("Translation needed, but not available.\n"
+		  "Input: %d.", input);
+	return NULL;
+}
--- a/configure.ac	Wed Mar 08 11:16:59 2006 -0800
+++ b/configure.ac	Thu Mar 09 09:55:56 2006 -0800
@@ -429,6 +429,22 @@
 	OUTPUT_PLUGINS="$OUTPUT_PLUGINS jack"
 fi
 
+dnl *** arts output plugin
+AC_ARG_ENABLE( arts,
+[  --disable-arts          disable arts output plugin (default=enabled)],,
+                enable_arts="yes")
+
+if test "x$enable_arts" = xyes; then
+        AM_PATH_ARTSC(0.9.5, have_arts=yes, have_arts=no)
+else
+        AC_MSG_RESULT([*** arts plugin disabled per user request ***])
+        have_arts=no
+fi
+
+if test "$have_arts" = yes; then
+	OUTPUT_PLUGINS="$OUTPUT_PLUGINS arts"
+fi
+
 dnl *** sid
 AC_ARG_ENABLE( sid,
 [  --disable-sid           disable sid input plugin (default=enabled)],,
@@ -846,6 +862,8 @@
         Plugins/Output/esd/Makefile
         Plugins/Output/alsa/Makefile
 	Plugins/Output/jack/Makefile
+	Plugins/Output/arts/Makefile
+	Plugins/Output/arts/arts_helper/Makefile
 	Plugins/Output/disk_writer/Makefile
 	Plugins/Output/sun/Makefile
         Plugins/Input/Makefile
@@ -923,6 +941,7 @@
 echo "  Advanced Linux Sound Arch. (alsa):      $have_alsa"
 echo "  Enlightenment Sound Daemon (esd):       $have_esd"
 echo "  Jack Audio Connection Kit (jack):       $have_jack"
+echo "  Analog Realtime Synthesizer (arts):     $have_arts"
 echo "  BSD/SUN audio output (sun):             $have_sun"
 echo
 echo "  Input Plugins"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m4/arts.m4	Thu Mar 09 09:55:56 2006 -0800
@@ -0,0 +1,131 @@
+# CFLAGS and library paths for aRts
+# written 15 December 1999 by Ben Gertzfield <che@debian.org>
+# hacked for artsc by Haavard Kvaalen <havardk@xmms.org>
+
+dnl Usage:
+dnl AM_PATH_ARTSC([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+dnl
+dnl Example:
+dnl AM_PATH_ARTSC(0.9.5, , AC_MSG_ERROR([*** ARTSC >= 0.9.5 not installed - please install first ***]))
+dnl
+dnl Defines ARTSC_CFLAGS, ARTSC_LIBS and ARTSC_VERSION.
+dnl
+
+dnl ARTSC_TEST_VERSION(AVAILABLE-VERSION, NEEDED-VERSION [, ACTION-IF-OKAY [, ACTION-IF-NOT-OKAY]])
+AC_DEFUN(ARTSC_TEST_VERSION, [
+
+# Determine which version number is greater. Prints 2 to stdout if	
+# the second number is greater, 1 if the first number is greater,	
+# 0 if the numbers are equal.						
+									
+# Written 15 December 1999 by Ben Gertzfield <che@debian.org>		
+# Revised 15 December 1999 by Jim Monty <monty@primenet.com>		
+									
+    AC_PROG_AWK
+    artsc_got_version=[` $AWK '						\
+BEGIN {									\
+    print vercmp(ARGV[1], ARGV[2]);					\
+}									\
+									\
+function vercmp(ver1, ver2,    ver1arr, ver2arr,			\
+                               ver1len, ver2len,			\
+                               ver1int, ver2int, len, i, p) {		\
+									\
+    ver1len = split(ver1, ver1arr, /\./);				\
+    ver2len = split(ver2, ver2arr, /\./);				\
+									\
+    len = ver1len > ver2len ? ver1len : ver2len;			\
+									\
+    for (i = 1; i <= len; i++) {					\
+        p = 1000 ^ (len - i);						\
+        ver1int += ver1arr[i] * p;					\
+        ver2int += ver2arr[i] * p;					\
+    }									\
+									\
+    if (ver1int < ver2int)						\
+        return 2;							\
+    else if (ver1int > ver2int)						\
+        return 1;							\
+    else								\
+        return 0;							\
+}' $1 $2`]								
+
+    if test $artsc_got_version -eq 2; then 	# failure
+	ifelse([$4], , :, $4)			
+    else  					# success!
+	ifelse([$3], , :, $3)
+    fi
+])
+
+AC_DEFUN(AM_PATH_ARTSC,
+[
+AC_ARG_WITH(artsc-prefix,[  --with-artsc-prefix=PFX  Prefix where aRts is installed (optional)],
+	artsc_config_prefix="$withval", artsc_config_prefix="")
+AC_ARG_WITH(artsc-exec-prefix,[  --with-artsc-exec-prefix=PFX Exec prefix where aRts is installed (optional)],
+	artsc_config_exec_prefix="$withval", artsc_config_exec_prefix="")
+
+if test x$artsc_config_exec_prefix != x; then
+    artsc_config_args="$artsc_config_args --exec-prefix=$artsc_config_exec_prefix"
+    if test x${ARTSC_CONFIG+set} != xset; then
+	ARTSC_CONFIG=$artsc_config_exec_prefix/bin/artsc-config
+    fi
+fi
+
+if test x$artsc_config_prefix != x; then
+    artsc_config_args="$artsc_config_args --prefix=$artsc_config_prefix"
+    if test x${ARTSC_CONFIG+set} != xset; then
+  	ARTSC_CONFIG=$artsc_config_prefix/bin/artsc-config
+    fi
+fi
+
+AC_PATH_PROG(ARTSC_CONFIG, artsc-config, no)
+min_artsc_version=ifelse([$1], ,0.9.5.1, $1)
+
+if test "$ARTSC_CONFIG" = "no"; then
+    no_artsc=yes
+else
+    ARTSC_CFLAGS=`$ARTSC_CONFIG $artsc_config_args --cflags`
+    ARTSC_LIBS=`$ARTSC_CONFIG $artsc_config_args --libs`
+    ARTSC_VERSION=`$ARTSC_CONFIG $artsc_config_args --version`
+
+    ARTSC_TEST_VERSION($ARTSC_VERSION, $min_artsc_version, ,no_artsc=version)
+fi
+
+AC_MSG_CHECKING(for artsc - version >= $min_artsc_version)
+
+if test "x$no_artsc" = x; then
+    AC_MSG_RESULT(yes)
+    AC_SUBST(ARTSC_CFLAGS)
+    AC_SUBST(ARTSC_LIBS)
+    AC_SUBST(ARTSC_VERSION)
+    ifelse([$2], , :, [$2])
+else
+    AC_MSG_RESULT(no)
+
+    if test "$ARTSC_CONFIG" = "no" ; then
+	echo "*** The artsc-config script installed by aRts could not be found."
+      	echo "*** If aRts was installed in PREFIX, make sure PREFIX/bin is in"
+	echo "*** your path, or set the ARTSC_CONFIG environment variable to the"
+	echo "*** full path to artsc-config."
+    else
+	if test "$no_artsc" = "version"; then
+	    echo "*** An old version of aRts, $ARTSC_VERSION, was found."
+	    echo "*** You need a version of aRts newer than $min_artsc_version."
+	    echo "*** The latest version of aRts is available from"
+	    echo "*** http://www.arts-project.org/"
+	    echo "***"
+
+            echo "*** If you have already installed a sufficiently new version, this error"
+            echo "*** probably means that the wrong copy of the artsc-config shell script is"
+            echo "*** being found. The easiest way to fix this is to remove the old version"
+            echo "*** of aRts, but you can also set the ARTSC_CONFIG environment to point to the"
+            echo "*** correct copy of artsc-config. (In this case, you will have to"
+            echo "*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf"
+            echo "*** so that the correct libraries are found at run-time)"
+	fi
+    fi
+    ARTSC_CFLAGS=""
+    ARTSC_LIBS=""
+    ifelse([$3], , :, [$3])
+fi
+])
--- a/mk/rules.mk.in	Wed Mar 08 11:16:59 2006 -0800
+++ b/mk/rules.mk.in	Thu Mar 09 09:55:56 2006 -0800
@@ -67,6 +67,8 @@
 ARCH_DEFINES = @ARCH_DEFINES@
 ARCH_X86_FALSE = @ARCH_X86_FALSE@
 ARCH_X86_TRUE = @ARCH_X86_TRUE@
+ARTSC_CFLAGS = @ARTSC_CFLAGS@
+ARTSC_LIBS = @ARTSC_LIBS@
 AUTOCONF = @AUTOCONF@
 AUTOHEADER = @AUTOHEADER@
 AUTOMAKE = @AUTOMAKE@