Mercurial > audlegacy
changeset 758:f9e8807ea6e5 trunk
[svn] - Initial port of the bsd/sun audio output plugin from XMMS. Needs testing.
author | nenolod |
---|---|
date | Tue, 28 Feb 2006 11:32:33 -0800 |
parents | 30fe36d312c8 |
children | 9b1126434a72 |
files | Plugins/Output/sun/Makefile.in Plugins/Output/sun/about.c Plugins/Output/sun/audio.c Plugins/Output/sun/audioio.h Plugins/Output/sun/configure.c Plugins/Output/sun/convert.c Plugins/Output/sun/mixer.c Plugins/Output/sun/mixer.h Plugins/Output/sun/resample.h Plugins/Output/sun/sun.c Plugins/Output/sun/sun.h configure.ac |
diffstat | 12 files changed, 2454 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/Makefile.in Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,17 @@ +include ../../../mk/rules.mk +include ../../../mk/objective.mk + +sunsources = sun.c \ + audio.c \ + convert.c \ + mixer.c \ + configure.c \ + about.c + +LIBDIR = $(plugindir)/$(OUTPUT_PLUGIN_DIR) +OBJECTIVE_LIBS = libsun.so + +CFLAGS += -fPIC -DPIC $(GTK_CFLAGS) -I../../../intl -I../../.. +LIBADD = $(GTK_LIBS) +SOURCES= $(sunsources) +OBJECTS= ${SOURCES:.c=.o}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/about.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "sun.h" +#include "libaudacious/util.h" + +#include <glib.h> +#include <glib/gi18n.h> + +void sun_about(void) +{ + static GtkWidget *dialog; + + if (dialog != NULL) + return; + + dialog = xmms_show_message( + _("About the Sun Driver"), + _("XMMS BSD Sun Driver\n\n" + "Copyright (c) 2001 CubeSoft Communications, Inc.\n" + "Maintainer: <vedge at csoft.org>.\n"), + _("Ok"), FALSE, NULL, NULL); + + gtk_signal_connect(GTK_OBJECT(dialog), "destroy", + GTK_SIGNAL_FUNC(gtk_widget_destroyed), + &dialog); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/audio.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,586 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* FIXME: g_error() is used several places, it will exit xmms */ + +#include <errno.h> +#include "libaudacious/util.h" +#include "sun.h" +#include "resample.h" + +static int sun_bps(int, int, int); +static int sun_format(AFormat); + +static void sun_setformat(AFormat, int, int); +static void sun_setparams(void); +static void *sun_loop(void *); +static int sun_downsample(gpointer, guint, guint, guint); + +static gboolean prebuffer, remove_prebuffer; +static pthread_t buffer_thread; +static int (*sun_convert)(void **, int); +static int realtime; +static int rd_index, wr_index; +static int buffer_size; +static int prebuffer_size; +static int output_time_offset; +static int device_buffer_used; +static int blocksize; +static char *buffer; +static guint64 output_bytes; +static guint64 written; + +/* + * The format of the data from the input plugin + * This will never change during a song. + */ +struct sun_format input; + +/* + * The format we get from the effect plugin. + * This will be different from input if the effect plugin does + * some kind of format conversion. + */ +struct sun_format effect; + +/* + * The format of the data we actually send to the soundcard. + * This might be different from effect if we need to resample or do + * some other format conversion. + */ +struct sun_format output; + +static int sun_bps(int sunfmt, int rate, int nch) +{ + int bitrate; + + bitrate = rate * nch; + + switch (sunfmt) + { + case AUDIO_ENCODING_ULINEAR_BE: + case AUDIO_ENCODING_ULINEAR_LE: + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_SLINEAR_LE: + bitrate *= 2; + break; + } + + return (bitrate); +} + +static int sun_format(AFormat fmt) +{ + switch (fmt) + { + case FMT_U8: + return (AUDIO_ENCODING_PCM8); + case FMT_S8: + return (AUDIO_ENCODING_SLINEAR); + case FMT_U16_LE: + return (AUDIO_ENCODING_ULINEAR_LE); + case FMT_U16_BE: + return (AUDIO_ENCODING_ULINEAR_BE); + case FMT_U16_NE: +#ifdef WORDS_BIGENDIAN + return (AUDIO_ENCODING_ULINEAR_BE); +#else + return (AUDIO_ENCODING_ULINEAR_LE); +#endif + case FMT_S16_LE: + return (AUDIO_ENCODING_SLINEAR_LE); + case FMT_S16_BE: + return (AUDIO_ENCODING_SLINEAR_BE); + case FMT_S16_NE: +#ifdef WORDS_BIGENDIAN + return (AUDIO_ENCODING_SLINEAR_BE); +#else + return (AUDIO_ENCODING_SLINEAR_LE); +#endif + } + return -1; +} + +static void sun_setformat(AFormat fmt, int rate, int nch) +{ + int sun; + + sun = sun_format(fmt); + + effect.format.sun = sun; + effect.format.xmms = fmt; + effect.frequency = rate; + effect.channels = nch; + effect.bps = sun_bps(sun, rate, nch); + + output.format.sun = sun; + output.format.xmms = fmt; + output.frequency = rate; + output.channels = nch; + sun_setparams(); + + output.bps = sun_bps(output.format.sun, output.frequency, + output.channels); + + audio.input = &input; + audio.output = &output; + audio.effect = &effect; +} + +void sun_setparams(void) +{ + audio_info_t info; + audio_encoding_t enc; + + AUDIO_INITINFO(&info); + + info.mode = AUMODE_PLAY; + if (ioctl(audio.fd, AUDIO_SETINFO, &info) != 0) + { + g_error("%s: cannot play (%s)", audio.devaudio, + strerror(errno)); + return; + } + + /* + * Pass 1: try the preferred encoding, if it is supported. + */ + enc.index = 0; + while (ioctl(audio.fd, AUDIO_GETENC, &enc) == 0 && + enc.encoding != output.format.sun) + enc.index++; + + info.play.encoding = enc.encoding; + info.play.precision = enc.precision; + strcpy(output.name, enc.name); + if (ioctl(audio.fd, AUDIO_SETINFO, &info) != 0) + { + g_error("%s: unsupported encoding: %s (%s)", audio.devaudio, + output.name, strerror(errno)); + return; + } + + info.play.channels = output.channels; + ioctl(audio.fd, AUDIO_SETINFO, &info); + + info.play.sample_rate = output.frequency; + if (ioctl(audio.fd, AUDIO_SETINFO, &info) < 0) + { + g_error("%s: cannot handle %i Hz (%s)", audio.devaudio, + output.frequency, strerror(errno)); + return; + } + + if (ioctl(audio.fd, AUDIO_GETINFO, &info) != 0) + { + blocksize = SUN_DEFAULT_BLOCKSIZE; + output.channels = info.play.channels; + } + else + { + blocksize = blocksize; + } + + sun_convert = sun_get_convert_func(output.format.sun, + sun_format(effect.format.xmms)); +#if 0 + if (sun_convert != NULL) + { + g_warning("audio conversion (output=0x%x effect=0x%x)", + output.format.sun, sun_format(effect.format.xmms)); + } +#endif +} + +static inline void sun_bufused(void) +{ + audio_offset_t ooffs; + + if (audio.paused) + device_buffer_used = 0; + else if (ioctl(audio.fd, AUDIO_GETOOFFS, &ooffs) == 0) + device_buffer_used = ooffs.offset; +} + +int sun_written_time(void) +{ + if (!audio.going) + return 0; + + return ((written * 1000) / effect.bps); +} + +int sun_output_time(void) +{ + guint64 bytes; + + if (!audio.fd || !audio.going) + return 0; + + if (realtime) + sun_bufused(); + + bytes = output_bytes < device_buffer_used ? + 0 : output_bytes - device_buffer_used; + return (output_time_offset + ((bytes * 1000) / output.bps)); +} + +static inline int sun_used(void) +{ + if (realtime) + return 0; + + if (wr_index >= rd_index) + return (wr_index - rd_index); + + return (buffer_size - (rd_index - wr_index)); +} + +int sun_playing(void) +{ + if (!audio.going) + return 0; + + if (realtime) + sun_bufused(); + + if (!sun_used() && (device_buffer_used - (3 * blocksize)) <= 0) + return (FALSE); + + return (TRUE); +} + +int sun_free(void) +{ + if (realtime) + return (audio.paused ? 0 : 1000000); + + if (remove_prebuffer && prebuffer) + { + prebuffer = FALSE; + remove_prebuffer = FALSE; + } + if (prebuffer) + remove_prebuffer = TRUE; + + if (rd_index > wr_index) + return ((rd_index - wr_index) - blocksize - 1); + + return ((buffer_size - (wr_index - rd_index)) - blocksize - 1); +} + +static inline ssize_t write_all(int fd, const void *buf, size_t count) +{ + static ssize_t done; + + for (done = 0; count > done; ) + { + static ssize_t n; + + n = write(fd, buf, count - done); + if (n == -1) + { + if (errno == EINTR) + continue; + else + break; + } + done += n; + } + + return (done); +} + +static inline void sun_write_audio(gpointer data, int length) +{ + AFormat new_format; + EffectPlugin *ep; + int new_frequency, new_channels; + + new_format = input.format.xmms; + new_frequency = input.frequency; + new_channels = input.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 != effect.format.xmms || + new_frequency != effect.frequency || + new_channels != effect.channels) + { + output_time_offset += (output_bytes * 1000) / output.bps; + output_bytes = 0; + close(audio.fd); + audio.fd = open(audio.devaudio, O_RDWR); + sun_setformat(new_format, new_frequency, new_channels); + } + if (effects_enabled() && ep && ep->mod_samples) + { + length = ep->mod_samples(&data, length, input.format.xmms, + input.frequency, input.channels); + } + + if (sun_convert != NULL) + length = sun_convert(&data, length); + + if (effect.frequency == output.frequency) + { + output_bytes += write_all(audio.fd, data, length); + } + else + { + output_bytes += sun_downsample(data, length, + effect.frequency, output.frequency); + } +} + +static void sun_bswap16(guint16 *data, int len) +{ + int i; + + for (i = 0; i < len; i += 2, data++) + *data = GUINT16_SWAP_LE_BE(*data); +} + +static int sun_downsample(gpointer ob, guint length, guint speed, guint espeed) +{ + guint w = 0; + static gpointer nbuffer = NULL; + static int nbuffer_size = 0; + + switch (output.format.sun) { + case AUDIO_ENCODING_SLINEAR_BE: + case AUDIO_ENCODING_SLINEAR_LE: + if (output.channels == 2) + RESAMPLE_STEREO(gint16); + else + RESAMPLE_MONO(gint16); + break; + case AUDIO_ENCODING_ULINEAR_BE: + case AUDIO_ENCODING_ULINEAR_LE: + if (output.channels == 2) + RESAMPLE_STEREO(guint16); + else + RESAMPLE_MONO(guint16); + break; + case AUDIO_ENCODING_SLINEAR: + if (output.channels == 2) + RESAMPLE_STEREO(gint8); + else + RESAMPLE_MONO(gint8); + break; + case AUDIO_ENCODING_ULINEAR: + if (output.channels == 2) + RESAMPLE_STEREO(guint8); + else + RESAMPLE_MONO(guint8); + break; + } + return (w); +} + +void sun_write(gpointer ptr, int length) +{ + int cnt, off = 0; + + if (realtime) + { + if (audio.paused) + return; + sun_write_audio(ptr, length); + written += length; + return; + } + + remove_prebuffer = FALSE; + written += length; + while (length > 0) + { + cnt = MIN(length, buffer_size - wr_index); + memcpy(buffer + wr_index, (char *) ptr + off, cnt); + wr_index = (wr_index + cnt) % buffer_size; + length -= cnt; + off += cnt; + } +} + +void sun_close(void) +{ + if (!audio.going) + return; + + audio.going = 0; + + if (realtime) + { + ioctl(audio.fd, AUDIO_FLUSH, NULL); + close(audio.fd); + } + else + { + pthread_join(buffer_thread, NULL); + } + + sun_get_convert_buffer(0); + wr_index = 0; + rd_index = 0; +} + +void sun_flush(int time) +{ + ioctl(audio.fd, AUDIO_FLUSH, NULL); + + output_time_offset = time; + written = (guint16)(time / 10) * (guint64)(input.bps / 100); + output_bytes = 0; +} + +void sun_pause(short p) +{ + if (!realtime) + { + if (p == TRUE) + audio.do_pause = TRUE; + else + audio.unpause = TRUE; + } + else + audio.paused = p; +} + +static void* sun_loop(void *arg) +{ + struct timeval tv; + int length, cnt; + fd_set set; + + while (audio.going) + { + if (sun_used() > prebuffer_size) + prebuffer = FALSE; + + if (sun_used() > 0 && !audio.paused && !prebuffer) + { + tv.tv_sec = 0; + tv.tv_usec = 10000; + FD_ZERO(&set); + FD_SET(audio.fd, &set); + + if (select(audio.fd + 1, NULL, &set, NULL, &tv) > 0) + { + length = MIN(blocksize, sun_used()); + while (length > 0) + { + cnt = MIN(length, + buffer_size - rd_index); + sun_write_audio( + buffer + rd_index, cnt); + rd_index = (rd_index + cnt) % + buffer_size; + length -= cnt; + } + } + } + else + xmms_usleep(10000); + + sun_bufused(); + + if (audio.do_pause && !audio.paused) + { + audio.do_pause = FALSE; + audio.paused = TRUE; + + rd_index -= device_buffer_used; + output_bytes -= device_buffer_used; + if (rd_index < 0) + rd_index += buffer_size; + ioctl(audio.fd, AUDIO_FLUSH, NULL); + } + else if (audio.unpause && audio.paused) + { + audio.unpause = FALSE; + close(audio.fd); + audio.fd = open(audio.devaudio, O_RDWR); + sun_setparams(); + audio.paused = FALSE; + } + } + + close(audio.fd); + g_free(buffer); + pthread_exit(NULL); +} + +int sun_open(AFormat fmt, int rate, int nch) +{ + audio_info_t info; + + AUDIO_INITINFO(&info); + + if ((audio.fd = open(audio.devaudio, O_RDWR)) < 0) + { + g_error("%s: %s", audio.devaudio, strerror(errno)); + return 0; + } + + input.format.xmms = fmt; + input.frequency = rate; + input.channels = nch; + input.bps = sun_bps(sun_format(fmt), rate, nch); + sun_setformat(fmt, rate, nch); + + realtime = xmms_check_realtime_priority(); + + if (ioctl(audio.fd, AUDIO_GETINFO, &info) != 0) + blocksize = SUN_DEFAULT_BLOCKSIZE; + else + blocksize = info.blocksize; + + if (!realtime) + { + buffer_size = audio.req_buffer_size; + + if (buffer_size < SUN_MIN_BUFFER_SIZE) + buffer_size = SUN_MIN_BUFFER_SIZE; + + prebuffer_size = (buffer_size * audio.req_prebuffer_size) / 100; + + buffer_size += blocksize; + buffer = g_malloc0(buffer_size); + } + prebuffer = TRUE; + wr_index = 0; + rd_index = 0; + output_time_offset = 0; + written = 0; + output_bytes = 0; + + audio.paused = FALSE; + audio.do_pause = FALSE; + audio.unpause = FALSE; + remove_prebuffer = FALSE; + + audio.going++; + if (!realtime) + pthread_create(&buffer_thread, NULL, sun_loop, NULL); + + return 1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/audioio.h Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,326 @@ +/* $NetBSD: audioio.h,v 1.29 2005/12/11 12:25:20 christos Exp $ */ + +/* + * Copyright (c) 1991-1993 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Computer Systems + * Engineering Group at Lawrence Berkeley Laboratory. + * 4. Neither the name of the University nor of the Laboratory may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#ifndef _SYS_AUDIOIO_H_ +#define _SYS_AUDIOIO_H_ + +/* + * Audio device + */ +struct audio_prinfo { + u_int sample_rate; /* sample rate in bit/s */ + u_int channels; /* number of channels, usually 1 or 2 */ + u_int precision; /* number of bits/sample */ + u_int encoding; /* data encoding (AUDIO_ENCODING_* below) */ + u_int gain; /* volume level */ + u_int port; /* selected I/O port */ + u_int seek; /* BSD extension */ + u_int avail_ports; /* available I/O ports */ + u_int buffer_size; /* total size audio buffer */ + u_int _ispare[1]; + /* Current state of device: */ + u_int samples; /* number of samples */ + u_int eof; /* End Of File (zero-size writes) counter */ + u_char pause; /* non-zero if paused, zero to resume */ + u_char error; /* non-zero if underflow/overflow ocurred */ + u_char waiting; /* non-zero if another process hangs in open */ + u_char balance; /* stereo channel balance */ + u_char cspare[2]; + u_char open; /* non-zero if currently open */ + u_char active; /* non-zero if I/O is currently active */ +}; +typedef struct audio_prinfo audio_prinfo_t; + +struct audio_info { + struct audio_prinfo play; /* Info for play (output) side */ + struct audio_prinfo record; /* Info for record (input) side */ + + u_int monitor_gain; /* input to output mix */ + /* BSD extensions */ + u_int blocksize; /* H/W read/write block size */ + u_int hiwat; /* output high water mark */ + u_int lowat; /* output low water mark */ + u_int _ispare1; + u_int mode; /* current device mode */ +#define AUMODE_PLAY 0x01 +#define AUMODE_RECORD 0x02 +#define AUMODE_PLAY_ALL 0x04 /* don't do real-time correction */ +}; +typedef struct audio_info audio_info_t; + +#define AUDIO_INITINFO(p) \ + (void)memset((void *)(p), 0xff, sizeof(struct audio_info)) + +/* + * Parameter for the AUDIO_GETDEV ioctl to determine current + * audio devices. + */ +#define MAX_AUDIO_DEV_LEN 16 +typedef struct audio_device { + char name[MAX_AUDIO_DEV_LEN]; + char version[MAX_AUDIO_DEV_LEN]; + char config[MAX_AUDIO_DEV_LEN]; +} audio_device_t; + +typedef struct audio_offset { + u_int samples; /* Total number of bytes transferred */ + u_int deltablks; /* Blocks transferred since last checked */ + u_int offset; /* Physical transfer offset in buffer */ +} audio_offset_t; + +/* + * Supported audio encodings + */ +/* Encoding ID's */ +#define AUDIO_ENCODING_NONE 0 /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW 1 /* ITU G.711 mu-law */ +#define AUDIO_ENCODING_ALAW 2 /* ITU G.711 A-law */ +#define AUDIO_ENCODING_PCM16 3 /* signed linear PCM, obsolete */ +#define AUDIO_ENCODING_LINEAR AUDIO_ENCODING_PCM16 /* SunOS compat */ +#define AUDIO_ENCODING_PCM8 4 /* unsigned linear PCM, obsolete */ +#define AUDIO_ENCODING_LINEAR8 AUDIO_ENCODING_PCM8 /* SunOS compat */ +#define AUDIO_ENCODING_ADPCM 5 /* adaptive differential PCM */ +#define AUDIO_ENCODING_SLINEAR_LE 6 +#define AUDIO_ENCODING_SLINEAR_BE 7 +#define AUDIO_ENCODING_ULINEAR_LE 8 +#define AUDIO_ENCODING_ULINEAR_BE 9 +#define AUDIO_ENCODING_SLINEAR 10 +#define AUDIO_ENCODING_ULINEAR 11 +#define AUDIO_ENCODING_MPEG_L1_STREAM 12 +#define AUDIO_ENCODING_MPEG_L1_PACKETS 13 +#define AUDIO_ENCODING_MPEG_L1_SYSTEM 14 +#define AUDIO_ENCODING_MPEG_L2_STREAM 15 +#define AUDIO_ENCODING_MPEG_L2_PACKETS 16 +#define AUDIO_ENCODING_MPEG_L2_SYSTEM 17 + +typedef struct audio_encoding { + int index; + char name[MAX_AUDIO_DEV_LEN]; + int encoding; + int precision; + int flags; +#define AUDIO_ENCODINGFLAG_EMULATED 1 /* software emulation mode */ +} audio_encoding_t; + +/* + * Balance settings. + */ +#define AUDIO_LEFT_BALANCE 0 /* left channel only */ +#define AUDIO_MID_BALANCE 32 /* equal left/right channel */ +#define AUDIO_RIGHT_BALANCE 64 /* right channel only */ +#define AUDIO_BALANCE_SHIFT 3 + +/* + * Output ports + */ +#define AUDIO_SPEAKER 0x01 /* built-in speaker */ +#define AUDIO_HEADPHONE 0x02 /* headphone jack */ +#define AUDIO_LINE_OUT 0x04 /* line out */ + +/* + * Input ports + */ +#define AUDIO_MICROPHONE 0x01 /* microphone */ +#define AUDIO_LINE_IN 0x02 /* line in */ +#define AUDIO_CD 0x04 /* on-board CD inputs */ +#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* internal CDROM */ + +/* + * Audio device operations + */ +#define AUDIO_GETINFO _IOR('A', 21, struct audio_info) +#define AUDIO_SETINFO _IOWR('A', 22, struct audio_info) +#define AUDIO_DRAIN _IO('A', 23) +#define AUDIO_FLUSH _IO('A', 24) +#define AUDIO_WSEEK _IOR('A', 25, u_long) +#define AUDIO_RERROR _IOR('A', 26, int) +#define AUDIO_GETDEV _IOR('A', 27, struct audio_device) +#define AUDIO_GETENC _IOWR('A', 28, struct audio_encoding) +#define AUDIO_GETFD _IOR('A', 29, int) +#define AUDIO_SETFD _IOWR('A', 30, int) +#define AUDIO_PERROR _IOR('A', 31, int) +#define AUDIO_GETIOFFS _IOR('A', 32, struct audio_offset) +#define AUDIO_GETOOFFS _IOR('A', 33, struct audio_offset) +#define AUDIO_GETPROPS _IOR('A', 34, int) +#define AUDIO_PROP_FULLDUPLEX 0x01 +#define AUDIO_PROP_MMAP 0x02 +#define AUDIO_PROP_INDEPENDENT 0x04 + +/* + * Mixer device + */ +#define AUDIO_MIN_GAIN 0 +#define AUDIO_MAX_GAIN 255 + +typedef struct mixer_level { + int num_channels; + u_char level[8]; /* [num_channels] */ +} mixer_level_t; +#define AUDIO_MIXER_LEVEL_MONO 0 +#define AUDIO_MIXER_LEVEL_LEFT 0 +#define AUDIO_MIXER_LEVEL_RIGHT 1 + +/* + * Device operations + */ + +typedef struct audio_mixer_name { + char name[MAX_AUDIO_DEV_LEN]; + int msg_id; +} audio_mixer_name_t; + +typedef struct mixer_devinfo { + int index; + audio_mixer_name_t label; + int type; +#define AUDIO_MIXER_CLASS 0 +#define AUDIO_MIXER_ENUM 1 +#define AUDIO_MIXER_SET 2 +#define AUDIO_MIXER_VALUE 3 + int mixer_class; + int next, prev; +#define AUDIO_MIXER_LAST -1 + union { + struct audio_mixer_enum { + int num_mem; + struct { + audio_mixer_name_t label; + int ord; + } member[32]; + } e; + struct audio_mixer_set { + int num_mem; + struct { + audio_mixer_name_t label; + int mask; + } member[32]; + } s; + struct audio_mixer_value { + audio_mixer_name_t units; + int num_channels; + int delta; + } v; + } un; +} mixer_devinfo_t; + + +typedef struct mixer_ctrl { + int dev; + int type; + union { + int ord; /* enum */ + int mask; /* set */ + mixer_level_t value; /* value */ + } un; +} mixer_ctrl_t; + +/* + * Mixer operations + */ +#define AUDIO_MIXER_READ _IOWR('M', 0, mixer_ctrl_t) +#define AUDIO_MIXER_WRITE _IOWR('M', 1, mixer_ctrl_t) +#define AUDIO_MIXER_DEVINFO _IOWR('M', 2, mixer_devinfo_t) + +/* + * Well known device names + */ +#define AudioNmicrophone "mic" +#define AudioNline "line" +#define AudioNcd "cd" +#define AudioNdac "dac" +#define AudioNaux "aux" +#define AudioNrecord "record" +#define AudioNvolume "volume" +#define AudioNmonitor "monitor" +#define AudioNtreble "treble" +#define AudioNmid "mid" +#define AudioNbass "bass" +#define AudioNbassboost "bassboost" +#define AudioNspeaker "speaker" +#define AudioNheadphone "headphones" +#define AudioNoutput "output" +#define AudioNinput "input" +#define AudioNmaster "master" +#define AudioNstereo "stereo" +#define AudioNmono "mono" +#define AudioNloudness "loudness" +#define AudioNspatial "spatial" +#define AudioNsurround "surround" +#define AudioNpseudo "pseudo" +#define AudioNmute "mute" +#define AudioNenhanced "enhanced" +#define AudioNpreamp "preamp" +#define AudioNon "on" +#define AudioNoff "off" +#define AudioNmode "mode" +#define AudioNsource "source" +#define AudioNfmsynth "fmsynth" +#define AudioNwave "wave" +#define AudioNmidi "midi" +#define AudioNmixerout "mixerout" +#define AudioNswap "swap" /* swap left and right channels */ +#define AudioNagc "agc" +#define AudioNdelay "delay" +#define AudioNselect "select" /* select destination */ +#define AudioNvideo "video" +#define AudioNcenter "center" +#define AudioNdepth "depth" +#define AudioNlfe "lfe" + +#define AudioEmulaw "mulaw" +#define AudioEalaw "alaw" +#define AudioEadpcm "adpcm" +#define AudioEslinear "slinear" +#define AudioEslinear_le "slinear_le" +#define AudioEslinear_be "slinear_be" +#define AudioEulinear "ulinear" +#define AudioEulinear_le "ulinear_le" +#define AudioEulinear_be "ulinear_be" +#define AudioEmpeg_l1_stream "mpeg_l1_stream" +#define AudioEmpeg_l1_packets "mpeg_l1_packets" +#define AudioEmpeg_l1_system "mpeg_l1_system" +#define AudioEmpeg_l2_stream "mpeg_l2_stream" +#define AudioEmpeg_l2_packets "mpeg_l2_packets" +#define AudioEmpeg_l2_system "mpeg_l2_system" + +#define AudioCinputs "inputs" +#define AudioCoutputs "outputs" +#define AudioCrecord "record" +#define AudioCmonitor "monitor" +#define AudioCequalization "equalization" +#define AudioCmodem "modem" + +#endif /* !_SYS_AUDIOIO_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/configure.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,577 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <errno.h> +#include "sun.h" +#include "libaudacious/util.h" +#include "libaudacious/configdb.h" + +#include <glib.h> +#include <glib/gi18n.h> + +#include "mixer.h" + +struct sun_statsframe stats_frame; + +static GtkWidget *configure_win; +static GtkWidget *buffer_size_spin, *buffer_pre_spin; +static GtkWidget *adevice_entry, *actldevice_entry, *mdevice_entry; +static GtkWidget *keepopen_cbutton; +static char devaudio[64], devaudioctl[64], devmixer[64], mixer_toggle[64]; + +static void configure_win_destroy(); + +static void configure_win_ok_cb(GtkWidget *w, gpointer data) +{ + ConfigFile *cfgfile; + + strcpy(audio.devaudio, gtk_entry_get_text(GTK_ENTRY(adevice_entry))); + strcpy(audio.devmixer, gtk_entry_get_text(GTK_ENTRY(mdevice_entry))); + + audio.req_buffer_size = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(buffer_size_spin)); + audio.req_prebuffer_size = gtk_spin_button_get_value_as_int( + GTK_SPIN_BUTTON(buffer_pre_spin)); + + if (sun_mixer_open() == 0) + { + audio.mixer_keepopen = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(keepopen_cbutton)); + sun_mixer_close(); + } + + cfgfile = xmms_cfg_open_default_file(); + + xmms_cfg_write_string(cfgfile, "sun", + "audio_devaudio", audio.devaudio); + xmms_cfg_write_string(cfgfile, "sun", + "audio_devaudioctl", audio.devaudioctl); + xmms_cfg_write_string(cfgfile, "sun", + "audio_devmixer", audio.devmixer); + + xmms_cfg_write_string(cfgfile, "sun", + "mixer_voldev", audio.mixer_voldev); + xmms_cfg_write_boolean(cfgfile, "sun", + "mixer_keepopen", audio.mixer_keepopen); + + xmms_cfg_write_int(cfgfile, "sun", + "buffer_size", audio.req_buffer_size); + xmms_cfg_write_int(cfgfile, "sun", + "prebuffer_size", audio.req_prebuffer_size); + + xmms_cfg_write_default_file(cfgfile); + xmms_cfg_free(cfgfile); + + configure_win_destroy(); +} + +static void configure_win_cancel_cb(GtkWidget *w, gpointer data) +{ + configure_win_destroy(); +} + +static void mixer_cbutton_toggled_cb(GtkWidget *w, int id) +{ + mixer_ctrl_t mixer; + + if (sun_mixer_open() == 0) + { + mixer.type = AUDIO_MIXER_ENUM; + mixer.dev = id; + mixer_toggle[id] = !mixer_toggle[id]; + mixer.un.ord = mixer_toggle[id]; + + if (ioctl(audio.mixerfd, AUDIO_MIXER_WRITE, &mixer) != 0) + g_warning("Could not toggle mixer setting %i", id); + sun_mixer_close(); + } +} + +static void configure_win_mixer_volume_dev_cb(GtkWidget *w, gint voldev_index) +{ + mixer_devinfo_t info; + + if (sun_mixer_open() == 0) + { + info.index = voldev_index; + if (!ioctl(audio.mixerfd, AUDIO_MIXER_DEVINFO, &info)) + strcpy(audio.mixer_voldev, info.label.name); + sun_mixer_close(); + } +} + +static void configure_win_destroy(void) +{ + stats_frame.active = 0; + + if (!pthread_mutex_lock(&stats_frame.active_mutex)) + { + if (!pthread_mutex_lock(&stats_frame.audioctl_mutex)) + { + if (stats_frame.fd) + { + close(stats_frame.fd); + stats_frame.fd = 0; + } + pthread_mutex_unlock(&stats_frame.audioctl_mutex); + pthread_mutex_destroy(&stats_frame.audioctl_mutex); + } + pthread_mutex_unlock(&stats_frame.active_mutex); + pthread_mutex_destroy(&stats_frame.active_mutex); + } + gtk_widget_destroy(configure_win); + configure_win = NULL; +} + +static void configure_mixer_volumedev_scan(gchar *type, GtkWidget *option_menu) +{ + mixer_devinfo_t info; + GtkWidget *menu; + + if (sun_mixer_open() < 0) + return; + + menu = gtk_menu_new(); + + /* FIXME: info is used while undefined here */ + for (info.index = 0; + ioctl(audio.mixerfd, AUDIO_MIXER_DEVINFO, &info) == 0; + info.index++) + { + GtkWidget *item; + + if (info.type == AUDIO_MIXER_VALUE) + { + item = gtk_menu_item_new_with_label(info.label.name); + gtk_signal_connect(GTK_OBJECT(item), "activate", + (GCallback) configure_win_mixer_volume_dev_cb, + (gpointer) info.index); + + gtk_widget_show(item); + gtk_menu_append(GTK_MENU(menu), item); + + if (!strcmp(info.label.name, audio.mixer_voldev)) + gtk_menu_reorder_child(GTK_MENU(menu), item, 0); + } + } + + gtk_option_menu_set_menu(GTK_OPTION_MENU(option_menu), menu); + + sun_mixer_close(); +} + +static void configure_adevice_box(GtkWidget *dev_vbox) +{ + GtkWidget *adevice_frame, *adevice_vbox; + + adevice_frame = gtk_frame_new(_("Audio device:")); + gtk_box_pack_start(GTK_BOX(dev_vbox), adevice_frame, FALSE, FALSE, 0); + + adevice_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5); + gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox); + + strcpy(devaudio, audio.devaudio); + + adevice_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(adevice_entry), devaudio); + gtk_box_pack_start_defaults(GTK_BOX(adevice_vbox), adevice_entry); +} + +static void configure_actldevice_box(GtkWidget *dev_vbox) +{ + GtkWidget *actldevice_frame, *actldevice_vbox; + + actldevice_frame = gtk_frame_new(_("Audio control device:")); + gtk_box_pack_start(GTK_BOX(dev_vbox), actldevice_frame, + FALSE, FALSE, 0); + + actldevice_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(actldevice_vbox), 5); + gtk_container_add(GTK_CONTAINER(actldevice_frame), actldevice_vbox); + + strcpy(devaudioctl, audio.devaudioctl); + + actldevice_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(actldevice_entry), devaudioctl); + gtk_box_pack_start_defaults(GTK_BOX(actldevice_vbox), actldevice_entry); +} + +static void configure_mdevice_box(GtkWidget *dev_vbox) +{ + GtkWidget *mdevice_frame, *mdevice_vbox; + + mdevice_frame = gtk_frame_new(_("Mixer device:")); + gtk_box_pack_start(GTK_BOX(dev_vbox), mdevice_frame, FALSE, FALSE, 0); + + mdevice_vbox = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(mdevice_vbox), 5); + gtk_container_add(GTK_CONTAINER(mdevice_frame), mdevice_vbox); + + strcpy(devmixer, audio.devmixer); + + mdevice_entry = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(mdevice_entry), devmixer); + gtk_box_pack_start_defaults(GTK_BOX(mdevice_vbox), mdevice_entry); + +} + + +static void configure_devices_frame(GtkWidget *vbox, GtkWidget * notebook) +{ + GtkWidget *dev_vbox; + + dev_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(dev_vbox), 5); + + configure_adevice_box(dev_vbox); + configure_actldevice_box(dev_vbox); + configure_mdevice_box(dev_vbox); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dev_vbox, + gtk_label_new(_("Devices"))); +} + + +static void configure_buffering_frame(GtkWidget *vbox, GtkWidget * notebook) +{ + GtkWidget *buffer_frame, *buffer_vbox, *buffer_table; + GtkWidget *buffer_size_box, *buffer_size_label; + GtkObject *buffer_size_adj, *buffer_pre_adj; + GtkWidget *buffer_pre_box, *buffer_pre_label; + + 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); + + buffer_size_adj = gtk_adjustment_new(audio.req_buffer_size, + 200, 131072, 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); + + buffer_pre_box = gtk_hbox_new(FALSE, 5); + gtk_table_attach_defaults(GTK_TABLE(buffer_table), + buffer_pre_box, 1, 2, 0, 1); + buffer_pre_label = gtk_label_new(_("Pre-buffer (percent):")); + gtk_box_pack_start(GTK_BOX(buffer_pre_box), buffer_pre_label, + FALSE, FALSE, 0); + + buffer_pre_adj = gtk_adjustment_new(audio.req_prebuffer_size, + 0, 90, 1, 1, 1); + buffer_pre_spin = gtk_spin_button_new(GTK_ADJUSTMENT(buffer_pre_adj), + 1, 0); + + gtk_widget_set_usize(buffer_pre_spin, 60, -1); + gtk_box_pack_start(GTK_BOX(buffer_pre_box), buffer_pre_spin, + FALSE, FALSE, 0); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), buffer_frame, + gtk_label_new(_("Buffering"))); +} + +static void configure_mixer_toggle_button(GtkWidget *vbox, gchar *devname, gchar *label) +{ + GtkWidget *toggle_cbutton; + gint devid; + mixer_ctrl_t mixer; + + if (!sun_mixer_get_dev(audio.mixerfd, &devid, devname)) + { + mixer.type = AUDIO_MIXER_ENUM; + mixer.dev = devid; + + if (!ioctl(audio.mixerfd, AUDIO_MIXER_READ, &mixer)) + { + toggle_cbutton = + gtk_check_button_new_with_label(_(label)); + gtk_box_pack_start_defaults(GTK_BOX(vbox), + toggle_cbutton); + + if (mixer.un.ord) + { + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(toggle_cbutton), TRUE); + mixer_toggle[mixer.dev]++; + } + else + { + mixer_toggle[mixer.dev] = 0; + } + + gtk_signal_connect(GTK_OBJECT(toggle_cbutton), + "toggled", + GTK_SIGNAL_FUNC(mixer_cbutton_toggled_cb), + (gpointer) mixer.dev); + } + } +} + + +static void configure_mixer_box(GtkWidget *vbox, GtkWidget *notebook) +{ + GtkWidget *mixervol_frame, *mixervol_box; + GtkWidget *mixervol_menu; + + mixervol_frame = gtk_frame_new(_("Volume controls device:")); + gtk_box_pack_start(GTK_BOX(vbox), mixervol_frame, FALSE, FALSE, 0); + + mixervol_box = gtk_vbox_new(FALSE, 0); + gtk_container_set_border_width(GTK_CONTAINER(mixervol_box), 5); + gtk_container_add(GTK_CONTAINER(mixervol_frame), mixervol_box); + + mixervol_menu = gtk_option_menu_new(); + gtk_box_pack_start(GTK_BOX(mixervol_box), mixervol_menu, TRUE, TRUE, 0); + + configure_mixer_volumedev_scan("Volume devices:", mixervol_menu); + + keepopen_cbutton = gtk_check_button_new_with_label( + _("XMMS uses mixer exclusively.")); + if (audio.mixer_keepopen) + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(keepopen_cbutton), TRUE); + + gtk_box_pack_start_defaults(GTK_BOX(vbox), keepopen_cbutton); + + if (sun_mixer_open() == 0) + { + configure_mixer_toggle_button(vbox, "bassboost", "Bass boost"); + configure_mixer_toggle_button(vbox, "loudness", "Loudness"); + configure_mixer_toggle_button(vbox, "spatial", "Spatial"); + configure_mixer_toggle_button(vbox, "surround", "Surround"); + configure_mixer_toggle_button(vbox, "enhanced", "Enhanced"); + configure_mixer_toggle_button(vbox, "preamp", "Preamp"); + configure_mixer_toggle_button(vbox, "swap", "Swap channels"); + sun_mixer_close(); + } +} + + +static void configure_mixer_frame(GtkWidget *vbox, GtkWidget *notebook) +{ + GtkWidget *mixervol_vbox; + + mixervol_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(mixervol_vbox), 5); + + configure_mixer_box(mixervol_vbox, notebook); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), + mixervol_vbox, gtk_label_new(_("Mixer"))); +} + + +static void configure_stats_loop(void) +{ + if (pthread_mutex_lock(&stats_frame.active_mutex) != 0) + { + perror("active_mutex"); + return; + } + + while (stats_frame.active && stats_frame.fd) + { + audio_info_t info; + char sl[32]; + + pthread_mutex_lock(&stats_frame.audioctl_mutex); + + sl[0] = '\0'; + + if (!ioctl(stats_frame.fd, AUDIO_GETINFO, &info)) + { + char s[128]; + + sprintf(s, "Currently %s", + (info.mode == AUMODE_PLAY) ? "playing" : + (info.mode == AUMODE_RECORD) ? "recording" : + (info.mode == AUMODE_PLAY_ALL) ? "playing" : + "not playing"); + + if (info.mode == AUMODE_PLAY) + { + sprintf(s, "%s at %i Hz (%i-bit %s)", s, + info.play.sample_rate, info.play.precision, + audio.output->name); + sprintf(sl,"%i samples, %i error(s). %s", + info.play.samples, info.play.error, + info.play.active ? + "I/O in progress." : ""); + } + gtk_label_set_text(GTK_LABEL(stats_frame.mode_label), + s); + + sprintf(s, "H/W block: %i bytes. Buffer: %i bytes", + info.blocksize, info.play.buffer_size); + gtk_label_set_text( + GTK_LABEL(stats_frame.blocksize_label), s); + } + gtk_label_set_text(GTK_LABEL(stats_frame.ooffs_label), sl); + + pthread_mutex_unlock(&stats_frame.audioctl_mutex); + xmms_usleep(400000); + } + pthread_mutex_unlock(&stats_frame.active_mutex); + + pthread_exit(NULL); +} + +static void configure_status_frame(GtkWidget *vbox, GtkWidget *notebook) +{ + GtkWidget *status_vbox; + GtkWidget *name_label, *props_label; + pthread_t loop_thread; + + memset(&stats_frame, 0, sizeof(struct sun_statsframe)); + + if (pthread_mutex_init(&stats_frame.audioctl_mutex, NULL) != 0) + { + perror("audioctl_mutex"); + return; + } + if (pthread_mutex_init(&stats_frame.active_mutex, NULL) != 0) + { + perror("active_mutex"); + return; + } + status_vbox = gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(status_vbox), 5); + + name_label = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(status_vbox), name_label); + props_label = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(status_vbox), props_label); + + stats_frame.mode_label = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(status_vbox), stats_frame.mode_label); + stats_frame.blocksize_label = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(status_vbox), + stats_frame.blocksize_label); + stats_frame.ooffs_label = gtk_label_new(NULL); + gtk_container_add(GTK_CONTAINER(status_vbox), stats_frame.ooffs_label); + + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), status_vbox, + gtk_label_new(_("Status"))); + + if ((stats_frame.fd = open(audio.devaudioctl, O_RDWR)) >= 0) + { + audio_device_t device; + int props; + + if (ioctl(stats_frame.fd, AUDIO_GETDEV, &device) >= 0) + { + char *s = g_strdup_printf("%s - %s(4) %s", + device.name, device.config, device.version); + gtk_label_set_text(GTK_LABEL(name_label), s); + g_free(s); + } + if (ioctl(stats_frame.fd, AUDIO_GETPROPS, &props) >= 0) + { + char s[32]; + s[0] = '\0'; + + if ((props & AUDIO_PROP_FULLDUPLEX) == + AUDIO_PROP_FULLDUPLEX) + sprintf(s, "FULLDUPLEX "); + if ((props & AUDIO_PROP_MMAP) == AUDIO_PROP_MMAP) + sprintf(s, "%s MMAP ", s); + if ((props & AUDIO_PROP_INDEPENDENT) == + AUDIO_PROP_INDEPENDENT) + sprintf(s, "%s INDEPENDENT ", s); + + gtk_label_set_text(GTK_LABEL(props_label), s); + } + } + stats_frame.active++; + pthread_create(&loop_thread, NULL, (void *) configure_stats_loop, NULL); +} + +void sun_configure(void) +{ + GtkWidget *vbox, *notebook; + GtkWidget *bbox, *ok, *cancel; + + if (configure_win) + { + gdk_window_raise(configure_win->window); + return; + } + configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_signal_connect(GTK_OBJECT(configure_win), "destroy", + GTK_SIGNAL_FUNC(configure_win_destroy), NULL); + + gtk_window_set_title(GTK_WINDOW(configure_win), + _("Sun 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); + + configure_devices_frame(vbox, notebook); + configure_buffering_frame(vbox, notebook); + configure_mixer_frame(vbox, notebook); + configure_status_frame(vbox, notebook); + + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); + gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); + + ok = gtk_button_new_with_label(_("Ok")); + gtk_signal_connect(GTK_OBJECT(ok), "clicked", + GTK_SIGNAL_FUNC(configure_win_ok_cb), NULL); + + GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); + gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); + gtk_widget_grab_default(ok); + + cancel = gtk_button_new_with_label(_("Cancel")); + gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", + GTK_SIGNAL_FUNC(configure_win_cancel_cb), + GTK_OBJECT(configure_win)); + + GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); + 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/sun/convert.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2001 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. + */ + +#include "sun.h" + +void * sun_get_convert_buffer(size_t size) +{ + static size_t length; + static void *buffer; + + if (size > 0 && size <= length) + return buffer; + + length = size; + buffer = g_realloc(buffer, size); + return buffer; +} + +static int convert_swap_endian(void **data, int length) +{ + int i; + guint16 *ptr = *data; + + 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) +{ + int i; + guint16 *ptr = *data; + + 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) +{ + int i; + guint16 *ptr = *data; + + 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) +{ + int i; + gint16 *ptr = *data; + + for (i = 0; i < length; i += 2, ptr++) + *ptr ^= 1 << 15; + + return i; +} + +static int convert_swap_sign8(void **data, int length) +{ + int i; + gint8 *ptr = *data; + + for (i = 0; i < length; i++) + *ptr++ ^= 1 << 7; + + return i; +} + +static int convert_to_8_native_endian(void **data, int length) +{ + int i; + gint16 *input = *data; + gint8 *output = *data; + + for (i = 0; i < length / 2; i++) + *output++ = *input++ >> 8; + + return i; +} + +static int convert_to_8_native_endian_swap_sign(void **data, int length) +{ + int i; + gint16 *input = *data; + gint8 *output = *data; + + for (i = 0; i < length / 2; i++) + *output++ = (*input++ >> 8) ^ (1 << 7); + + return i; +} + + +static int convert_to_8_alien_endian(void **data, int length) +{ + int i; + gint16 *input = *data; + gint8 *output = *data; + + for (i = 0; i < length / 2; i++) + *output++ = *input++ & 0xff; + + return i; +} + +static int convert_to_8_alien_endian_swap_sign(void **data, int length) +{ + int i; + gint16 *input = *data; + gint8 *output = *data; + + for (i = 0; i < length / 2; i++) + *output++ = (*input++ & 0xff) ^ (1 << 7); + + return i; +} + +static int convert_to_16_native_endian(void **data, int length) +{ + int i; + guint16 *output; + guint8 *input = *data; + + *data = sun_get_convert_buffer(length * 2); + output = *data; + + for (i = 0; i < length; i++) + *output++ = *input++ << 8; + + return (i * 2); +} + +static int convert_to_16_native_endian_swap_sign(void **data, int length) +{ + int i; + guint16 *output; + guint8 *input = *data; + + *data = sun_get_convert_buffer(length * 2); + output = *data; + for (i = 0; i < length; i++) + *output++ = (*input++ << 8) ^ (1 << 15); + + return (i * 2); +} + + +static int convert_to_16_alien_endian(void **data, int length) +{ + int i; + guint16 *output; + guint8 *input = *data; + + *data = sun_get_convert_buffer(length * 2); + output = *data; + for (i = 0; i < length; i++) + *output++ = *input++; + + return (i * 2); +} + +static int convert_to_16_alien_endian_swap_sign(void **data, int length) +{ + int i; + guint16 *output; + guint8 *input = *data; + + *data = sun_get_convert_buffer(length * 2); + output = *data; + for (i = 0; i < length; i++) + *output++ = *input++ ^ (1 << 7); + + return (i * 2); +} + +int (*sun_get_convert_func(int output, int input))(void **, int) +{ + if (output == input) + return NULL; + + if ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_ULINEAR_LE) || + (output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_ULINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_SLINEAR_BE)) + return convert_swap_endian; + + if ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_SLINEAR_BE) || + (output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_ULINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_ULINEAR_LE)) + return convert_swap_sign16; + + if ((IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_ULINEAR_LE))) || + (!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_SLINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_ULINEAR_BE)))) + return convert_swap_sign_and_endian_to_native; + + if ((!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_ULINEAR_LE))) || + (IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_SLINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_ULINEAR_BE)))) + return convert_swap_sign_and_endian_to_alien; + + if ((IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_ULINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_SLINEAR_BE))) || + (!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_ULINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_SLINEAR_LE)))) + return convert_to_8_native_endian; + + if ((IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_SLINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_ULINEAR_BE))) || + (!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_ULINEAR_LE)))) + return convert_to_8_native_endian_swap_sign; + + if ((!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_ULINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_SLINEAR_BE))) || + (IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_ULINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_SLINEAR_LE)))) + return convert_to_8_alien_endian; + + if ((!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_SLINEAR_BE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_ULINEAR_BE))) || + (IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_SLINEAR_LE) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_ULINEAR_LE)))) + return convert_to_8_alien_endian_swap_sign; + + if ((output == AUDIO_ENCODING_PCM8 && + input == AUDIO_ENCODING_SLINEAR) || + (output == AUDIO_ENCODING_SLINEAR && + input == AUDIO_ENCODING_PCM8)) + return convert_swap_sign8; + + if ((IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_PCM8) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_SLINEAR))) || + (!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_PCM8) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_SLINEAR)))) + return convert_to_16_native_endian; + + if ((IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_SLINEAR) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_PCM8))) || + (!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_SLINEAR) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_PCM8)))) + return convert_to_16_native_endian_swap_sign; + + if ((!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_PCM8) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_SLINEAR))) || + (IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_PCM8) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_SLINEAR)))) + return convert_to_16_alien_endian; + + if ((!IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_BE && + input == AUDIO_ENCODING_SLINEAR) || + (output == AUDIO_ENCODING_SLINEAR_BE && + input == AUDIO_ENCODING_PCM8))) || + (IS_BIG_ENDIAN && + ((output == AUDIO_ENCODING_ULINEAR_LE && + input == AUDIO_ENCODING_SLINEAR) || + (output == AUDIO_ENCODING_SLINEAR_LE && + input == AUDIO_ENCODING_PCM8)))) + return convert_to_16_alien_endian_swap_sign; + + return NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/mixer.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "sun.h" +#include "mixer.h" + +int sun_mixer_open(void) +{ + if (pthread_mutex_lock(&audio.mixer_mutex) != 0) + return -1; + + if (!audio.mixer_keepopen || audio.mixerfd < 1) + { + audio.mixerfd = open(audio.devmixer, O_RDWR); + if (audio.mixerfd < 0) + perror(audio.devmixer); + } + return 0; +} + +void sun_mixer_close(void) +{ + if (!audio.mixer_keepopen) + { + close(audio.mixerfd); + audio.mixerfd = 0; + } + pthread_mutex_unlock(&audio.mixer_mutex); +} + +int sun_mixer_get_dev(int fd, int *dev, char *id) +{ + mixer_devinfo_t info; + + for (info.index = 0; ioctl(fd, AUDIO_MIXER_DEVINFO, &info) >= 0; + info.index++) + { + if (!strcmp(id, info.label.name)) + { + *dev = info.index; + return 0; + } + } + return -1; +} + +void sun_get_volume(int *l, int *r) +{ + mixer_ctrl_t mixer; + + if (sun_mixer_open() < 0) + { + *l = 0; + *r = 0; + return; + } + + if ((sun_mixer_get_dev(audio.mixerfd, &mixer.dev, + audio.mixer_voldev) < 0)) + goto closemixer; + + mixer.type = AUDIO_MIXER_VALUE; + if (audio.output != NULL) + mixer.un.value.num_channels = audio.output->channels; + else + mixer.un.value.num_channels = 2; + + if (ioctl(audio.mixerfd, AUDIO_MIXER_READ, &mixer) < 0) + goto closemixer; + *l = (mixer.un.value.level[AUDIO_MIXER_LEVEL_LEFT] * 100) / 255; + if (mixer.un.value.num_channels > 1) + *r = (mixer.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] * 100) / 255; + else + *r = *l; + + closemixer: + sun_mixer_close(); +} + +void sun_set_volume(int l, int r) +{ + mixer_ctrl_t mixer; + + if (sun_mixer_open() < 0) + return; + + if ((sun_mixer_get_dev(audio.mixerfd, &mixer.dev, + audio.mixer_voldev) < 0)) + { + if (!audio.mixer_keepopen) + close(audio.mixerfd); + return; + } + mixer.type = AUDIO_MIXER_VALUE; + if (audio.output != NULL) + mixer.un.value.num_channels = audio.output->channels; + else + mixer.un.value.num_channels = 2; + mixer.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = (l * 255) / 100; + if (mixer.un.value.num_channels > 1) + mixer.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = (r * 255) / 100; + + if (ioctl(audio.mixerfd, AUDIO_MIXER_WRITE, &mixer) < 0) + { + if (!audio.mixer_keepopen) + close(audio.mixerfd); + return; + } + sun_mixer_close(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/mixer.h Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +int sun_mixer_open(void); +void sun_mixer_close(void); +int sun_mixer_get_dev(int, int *, char *); +void sun_get_volume(int *, int *); +void sun_set_volume(int, int); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/resample.h Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,110 @@ +/* XMMS - Cross-platform multimedia player + * Copyright (C) 1998-2001 Peter Alm, Mikael Alm, Olle Hallnas, + * Thomas Nilsson and 4Front Technologies + * Copyright (C) 1999-2001 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. + */ + +#define NOT_NATIVE_ENDIAN \ + ((IS_BIG_ENDIAN && \ + (output.format.sun == AUDIO_ENCODING_SLINEAR_LE || \ + output.format.sun == AUDIO_ENCODING_ULINEAR_LE))|| \ + (!IS_BIG_ENDIAN && \ + (output.format.sun == AUDIO_ENCODING_SLINEAR_BE || \ + output.format.sun == AUDIO_ENCODING_ULINEAR_BE))) + +#define RESAMPLE_STEREO(sample_type) \ +do { \ + const int shift = sizeof (sample_type); \ + int i, in_samples, out_samples, x, delta; \ + sample_type *inptr = (sample_type *)ob, *outptr; \ + guint nlen = (((length >> shift) * espeed) / speed); \ + \ + if (nlen == 0) \ + break; \ + nlen <<= shift; \ + if (NOT_NATIVE_ENDIAN) \ + sun_bswap16(ob, length); \ + if (nlen > nbuffer_size) \ + { \ + nbuffer = g_realloc(nbuffer, nlen); \ + nbuffer_size = nlen; \ + } \ + outptr = (sample_type *)nbuffer; \ + in_samples = length >> shift; \ + out_samples = nlen >> shift; \ + delta = (in_samples << 12) / out_samples; \ + for (x = 0, i = 0; i < out_samples; i++) \ + { \ + int x1, frac; \ + x1 = (x >> 12) << 12; \ + frac = x - x1; \ + *outptr++ = \ + (sample_type) \ + ((inptr[(x1 >> 12) << 1] * \ + ((1<<12) - frac) + \ + inptr[((x1 >> 12) + 1) << 1] * \ + frac) >> 12); \ + *outptr++ = \ + (sample_type) \ + ((inptr[((x1 >> 12) << 1) + 1] * \ + ((1<<12) - frac) + \ + inptr[(((x1 >> 12) + 1) << 1) + 1] * \ + frac) >> 12); \ + x += delta; \ + } \ + if (NOT_NATIVE_ENDIAN) \ + sun_bswap16(nbuffer, nlen); \ + w = write_all(audio.fd, nbuffer, nlen); \ +} while (0) + +#define RESAMPLE_MONO(sample_type) \ +do { \ + const int shift = sizeof (sample_type) - 1; \ + int i, x, delta, in_samples, out_samples; \ + sample_type *inptr = (sample_type *)ob, *outptr; \ + guint nlen = (((length >> shift) * espeed) / speed); \ + \ + if (nlen == 0) \ + break; \ + nlen <<= shift; \ + if (NOT_NATIVE_ENDIAN) \ + sun_bswap16(ob, length); \ + if (nlen > nbuffer_size) \ + { \ + nbuffer = g_realloc(nbuffer, nlen); \ + nbuffer_size = nlen; \ + } \ + outptr = (sample_type *)nbuffer; \ + in_samples = length >> shift; \ + out_samples = nlen >> shift; \ + delta = ((length >> shift) << 12) / out_samples; \ + for (x = 0, i = 0; i < out_samples; i++) \ + { \ + int x1, frac; \ + x1 = (x >> 12) << 12; \ + frac = x - x1; \ + *outptr++ = \ + (sample_type) \ + ((inptr[x1 >> 12] * ((1<<12) - frac) + \ + inptr[(x1 >> 12) + 1] * frac) >> 12); \ + x += delta; \ + } \ + if (NOT_NATIVE_ENDIAN) \ + sun_bswap16(nbuffer, nlen); \ + w = write_all(audio.fd, nbuffer, nlen); \ +} while (0) +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/sun.c Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "sun.h" +#include "libaudacious/configfile.h" + +#include <glib.h> +#include <glib/gi18n.h> +#include <errno.h> + +struct sun_audio audio; + +OutputPlugin sun_op = +{ + NULL, + NULL, + NULL, /* Description */ + sun_init, + sun_about, + sun_cleanup, + sun_configure, + sun_get_volume, + sun_set_volume, + sun_open, + sun_write, + sun_close, + sun_flush, + sun_pause, + sun_free, + sun_playing, + sun_output_time, + sun_written_time +}; + + +OutputPlugin * get_oplugin_info(void) +{ + sun_op.description = g_strdup_printf(_("BSD Sun Driver %s"), + SUN_VERSION); + return (&sun_op); +} + +void sun_init(void) +{ + ConfigFile *cfgfile; + char *s; + + memset(&audio, 0, sizeof(struct sun_audio)); + + cfgfile = xmms_cfg_open_default_file(); + /* Devices */ + xmms_cfg_read_string(cfgfile, "sun", "audio_devaudio", &audio.devaudio); + xmms_cfg_read_string(cfgfile, "sun", + "audio_devaudioctl", &audio.devaudioctl); + xmms_cfg_read_string(cfgfile, "sun", "audio_devmixer", &audio.devmixer); + + /* Buffering */ + xmms_cfg_read_int(cfgfile, "sun", + "buffer_size", &audio.req_buffer_size); + xmms_cfg_read_int(cfgfile, "sun", + "prebuffer_size", &audio.req_prebuffer_size); + + /* Mixer */ + xmms_cfg_read_string(cfgfile, "sun", "mixer_voldev", &audio.mixer_voldev); + xmms_cfg_read_boolean(cfgfile, "sun", + "mixer_keepopen", &audio.mixer_keepopen); + + xmms_cfg_free(cfgfile); + + /* Audio device path */ + if ((s = getenv("AUDIODEVICE"))) + audio.devaudio = g_strdup(s); + else if (!audio.devaudio || !strcmp("", audio.devaudio)) + audio.devaudio = g_strdup(SUN_DEV_AUDIO); + + /* Audio control device path */ + if (!audio.devaudioctl || !strcmp("", audio.devaudioctl)) + audio.devaudioctl = g_strdup(SUN_DEV_AUDIOCTL); + + /* Mixer device path */ + if ((s = getenv("MIXERDEVICE"))) + audio.devmixer = g_strdup(s); + else if (!audio.devmixer || !strcmp("", audio.devmixer)) + audio.devmixer = g_strdup(SUN_DEV_MIXER); + + if (!audio.mixer_voldev || !strcmp("", audio.mixer_voldev)) + audio.mixer_voldev = g_strdup(SUN_DEFAULT_VOLUME_DEV); + + /* Default buffering settings */ + if (!audio.req_buffer_size) + audio.req_buffer_size = SUN_DEFAULT_BUFFER_SIZE; + if (!audio.req_prebuffer_size) + audio.req_prebuffer_size = SUN_DEFAULT_PREBUFFER_SIZE; + + audio.input = NULL; + audio.output = NULL; + audio.effect = NULL; + + if (pthread_mutex_init(&audio.mixer_mutex, NULL) != 0) + perror("mixer_mutex"); +} + +void sun_cleanup(void) +{ + g_free(audio.devaudio); + g_free(audio.devaudioctl); + g_free(audio.devmixer); + g_free(audio.mixer_voldev); + + if (!pthread_mutex_lock(&audio.mixer_mutex)) + { + if (audio.mixerfd) + close(audio.mixerfd); + pthread_mutex_unlock(&audio.mixer_mutex); + pthread_mutex_destroy(&audio.mixer_mutex); + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Output/sun/sun.h Tue Feb 28 11:32:33 2006 -0800 @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2001 CubeSoft Communications, Inc. + * <http://www.csoft.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include <gtk/gtk.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 <pthread.h> + +#include "audioio.h" + +#include "audacious/plugin.h" +#include "libaudacious/configfile.h" + +/* Default path to audio device. */ +#ifndef SUN_DEV_AUDIO +#define SUN_DEV_AUDIO "/dev/audio" +#endif + +/* Default path to audioctl device */ +#ifndef SUN_DEV_AUDIOCTL +#define SUN_DEV_AUDIOCTL "/dev/audioctl" +#endif + +/* Default path to mixer device */ +#ifndef SUN_DEV_MIXER +#define SUN_DEV_MIXER "/dev/mixer" +#endif + +/* Default mixer device to control */ +#ifndef SUN_DEFAULT_VOLUME_DEV +#define SUN_DEFAULT_VOLUME_DEV "dac" +#endif + +/* Default hardware block size */ +#ifndef SUN_DEFAULT_BLOCKSIZE +#define SUN_DEFAULT_BLOCKSIZE 8800 +#endif + +/* Default `requested' buffer size */ +#ifndef SUN_DEFAULT_BUFFER_SIZE +#define SUN_DEFAULT_BUFFER_SIZE 8800 +#endif + +/* Minimum total buffer size */ +#ifndef SUN_MIN_BUFFER_SIZE +#define SUN_MIN_BUFFER_SIZE 14336 +#endif + +/* Default prebuffering (%) */ +#ifndef SUN_DEFAULT_PREBUFFER_SIZE +#define SUN_DEFAULT_PREBUFFER_SIZE 25 +#endif + +#define SUN_VERSION "0.6" + +struct sun_format { + char name[16]; + union { + AFormat xmms; + gint sun; + } format; + int frequency; + int channels; + int bps; +}; + +struct sun_audio { + struct sun_format *input; + struct sun_format *output; + struct sun_format *effect; + + gchar *devaudio; + gchar *devaudioctl; + gchar *devmixer; + gchar *mixer_voldev; + + gint fd; + gint mixerfd; + + gboolean mixer_keepopen; + + gboolean going; + gboolean paused; + gboolean unpause, do_pause; + + gint req_prebuffer_size; + gint req_buffer_size; + + pthread_mutex_t mixer_mutex; +}; + +struct sun_statsframe { + int fd; + int active; + + GtkWidget *mode_label; + GtkWidget *blocksize_label; + GtkWidget *ooffs_label; + pthread_mutex_t audioctl_mutex; + pthread_mutex_t active_mutex; +}; + +extern OutputPlugin op; + +extern struct sun_audio audio; +extern struct sun_statsframe stats_frame; + +void sun_init(void); +void sun_about(void); +void sun_configure(void); +void sun_cleanup(void); + +gint sun_open(AFormat, int, int); +void sun_write(void *, int); +void sun_close(void); +void sun_flush(int); +void sun_pause(short); +gint sun_free(void); +gint sun_playing(void); +gint sun_output_time(void); +gint sun_written_time(void); +void sun_get_volume(int *, int *); +void sun_set_volume(int, int); +void *sun_get_convert_buffer(size_t); +int (*sun_get_convert_func(int, int))(void **, int); + +#ifdef WORDS_BIGENDIAN +#define IS_BIG_ENDIAN TRUE +#else +#define IS_BIG_ENDIAN FALSE +#endif +
--- a/configure.ac Mon Feb 27 22:12:32 2006 -0800 +++ b/configure.ac Tue Feb 28 11:32:33 2006 -0800 @@ -702,6 +702,7 @@ then AC_DEFINE(SYMBOL_PREFIX, "_", [Define to symbol prefix, if any]) fi + OUTPUT_PLUGINS="$OUTPUT_PLUGINS sun" ;; *-*-darwin*) AC_DEFINE(SYMBOL_PREFIX, "_", [Define to symbol prefix, if any]) @@ -921,6 +922,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 " BSD/SUN audio output (sun): $have_sun" echo echo " Input Plugins" echo " -------------"