# HG changeset patch # User giacomo # Date 1141926956 28800 # Node ID e9509e909193c19618c8e6100c028e1b5a6a9422 # Parent 79da0e6ed790d822deccadcff0def1a2f348d1cc [svn] ported xmms-arts 0.7.1 to audacious and integrated it in the build process diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/Makefile.in --- 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@ diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/Makefile.in --- /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} diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/arts.c --- /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 + * + * 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 \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; +} diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/arts.h --- /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 + * + * Licenced under GNU GPL version 2. + * + * Audacious port by Giacomo Lozito from develia.org + * + */ + +#ifndef XMMS_ARTS_H +#define XMMS_ARTS_H + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#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 diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/arts_helper/Makefile.in --- /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) diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/arts_helper/arts_helper.c --- /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 + * + * Licenced under GNU GPL version 2. + * + * Audacious port by Giacomo Lozito from develia.org + * + */ + +#include "arts_helper.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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; +} diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/arts_helper/arts_helper.h --- /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 + * + * 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, +}; + diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/audio.c --- /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 + * + * Licenced under GNU GPL version 2. + * + * Audacious port by Giacomo Lozito from develia.org + * + */ + +#include "arts.h" +#include "arts_helper/arts_helper.h" +#include +#include +#include + +#include +#include +#include +#include + +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)); +} diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/configure.c --- /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 + * + * Licenced under GNU GPL version 2. + * + * Audacious port by Giacomo Lozito from develia.org + * + */ + +#include "arts.h" +#define _(string) (string) + +#include + +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); +} diff -r 79da0e6ed790 -r e9509e909193 Plugins/Output/arts/convert.c --- /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 + +#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; +} diff -r 79da0e6ed790 -r e9509e909193 configure.ac --- 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" diff -r 79da0e6ed790 -r e9509e909193 m4/arts.m4 --- /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 +# hacked for artsc by Haavard Kvaalen + +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 +# Revised 15 December 1999 by Jim Monty + + 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 +]) diff -r 79da0e6ed790 -r e9509e909193 mk/rules.mk.in --- 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@