/* Audio hardware handlers (SGI, OSS, ALSA, Sun, Windows, Mac OSX, Jack, ESD, HPUX, NetBSD) */
/*
* layout of this file:
* error handlers
* SGI new and old audio library
* OSS (with Sam 9407 support)
* ALSA
* Sun (has switches for OpenBSD, but they're untested)
* Windows 95/98
* OSX
* ESD
* JACK
* HPUX
* NetBSD
* audio describers
*/
/*
* void mus_audio_describe(void) describes the audio hardware state.
* char *mus_audio_report(void) returns the same information as a string.
*
* int mus_audio_open_output(int dev, int srate, int chans, int format, int size)
* int mus_audio_open_input(int dev, int srate, int chans, int format, int size)
* int mus_audio_write(int line, char *buf, int bytes)
* int mus_audio_close(int line)
* int mus_audio_read(int line, char *buf, int bytes)
*
* int mus_audio_mixer_read(int dev, int field, int chan, float *val)
* int mus_audio_mixer_write(int dev, int field, int chan, float *val)
* int mus_audio_initialize(void) does whatever is needed to get set up
* int mus_audio_systems(void) returns number of separate complete audio systems (soundcards essentially)
* AUDIO_SYSTEM(n) selects the nth card (counting from 0), AUDIO_SYSTEM(0) is always the default
* char *mus_audio_system_name(int system) returns some user-recognizable (?) name for the given card (don't free)
* char *mus_audio_moniker(void) returns some brief description of the overall audio setup (don't free return string).
*/
/* error handling is tricky here -- higher levels are using many calls as probes, so
* the "error" is a sign of non-existence, not a true error. So, for nearly all
* cases, I'll use mus_print, not mus_error.
*/
#include <config.h>
#if USE_SND && MUS_MAC_OSX && USE_MOTIF
#undef USE_MOTIF
#define USE_NO_GUI 1
/* Xt's Boolean collides with MacTypes.h Boolean, but we want snd.h for other stuff,
* so, if Motif is in use, don't load its headers at this time
*/
#endif
#if USE_SND && MUS_MAC_OSX && HAVE_RUBY
/* if using Ruby, OpenTransport.h T_* definitions collide with Ruby's -- it isn't needed here, so... */
#define REDEFINE_HAVE_RUBY 1
#undef HAVE_RUBY
#endif
#if USE_SND
#include "snd.h"
#else
#define PRINT_BUFFER_SIZE 512
#define LABEL_BUFFER_SIZE 64
#endif
#if USE_SND && MUS_MAC_OSX
#define USE_MOTIF 1
#undef USE_NO_GUI
#if REDEFINE_HAVE_RUBY
#define HAVE_RUBY 1
#endif
#endif
#include <math.h>
#include <stdio.h>
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <errno.h>
#include <stdlib.h>
#if (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H)))
#include <libc.h>
#else
#if (!(defined(_MSC_VER)))
#include <unistd.h>
#endif
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if (!HAVE_STRERROR)
char *strerror(int errnum)
{
char *strerrbuf;
strerrbuf = (char *)CALLOC(LABEL_BUFFER_SIZE, sizeof(char));
mus_snprintf(strerrbuf, LABEL_BUFFER_SIZE, "io err %d", errnum);
return(strerrbuf);
}
#endif
#if HAVE_SAM_9407
#include <sys/sam9407.h>
#endif
#ifdef MUS_MAC_OSX
#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudio.h>
/* these pull in stdbool.h apparently, so they have to precede sndlib.h */
#endif
#include "_sndlib.h"
#include "sndlib-strings.h"
#define MUS_STANDARD_ERROR(Error_Type, Error_Message) \
mus_print("%s\n [%s[%d] %s]", Error_Message, __FILE__, __LINE__, c__FUNCTION__)
#define MUS_STANDARD_IO_ERROR(Error_Type, IO_Func, IO_Name) \
mus_print("%s %s: %s\n [%s[%d] %s]", IO_Func, IO_Name, strerror(errno), __FILE__, __LINE__, c__FUNCTION__)
static char *version_name = NULL;
static bool audio_initialized = false;
static const char *mus_audio_device_names[] = {
S_mus_audio_default, S_mus_audio_duplex_default, S_mus_audio_adat_in, S_mus_audio_aes_in, S_mus_audio_line_out,
S_mus_audio_line_in, S_mus_audio_microphone, S_mus_audio_speakers, S_mus_audio_digital_in, S_mus_audio_digital_out,
S_mus_audio_dac_out, S_mus_audio_adat_out, S_mus_audio_aes_out, S_mus_audio_dac_filter, S_mus_audio_mixer,
S_mus_audio_line1, S_mus_audio_line2, S_mus_audio_line3, S_mus_audio_aux_input, S_mus_audio_cd,
S_mus_audio_aux_output, S_mus_audio_spdif_in, S_mus_audio_spdif_out, S_mus_audio_amp, S_mus_audio_srate,
S_mus_audio_channel, S_mus_audio_format, S_mus_audio_imix, S_mus_audio_igain, S_mus_audio_reclev,
S_mus_audio_pcm, S_mus_audio_pcm2, S_mus_audio_ogain, S_mus_audio_line, S_mus_audio_synth,
S_mus_audio_bass, S_mus_audio_treble, S_mus_audio_port, S_mus_audio_samples_per_channel,
S_mus_audio_direction
};
static const char *mus_audio_device_name(int dev)
{
if (MUS_AUDIO_DEVICE_OK(dev))
return(mus_audio_device_names[dev]);
return("invalid device");
}
#if (!HAVE_OSS) || (HAVE_ALSA)
static const char *mus_audio_format_names[] = {
"unknown", S_mus_bshort, S_mus_mulaw, S_mus_byte, S_mus_bfloat, S_mus_bint, S_mus_alaw, S_mus_ubyte, S_mus_b24int,
S_mus_bdouble, S_mus_lshort, S_mus_lint, S_mus_lfloat, S_mus_ldouble, S_mus_ubshort, S_mus_ulshort, S_mus_l24int,
S_mus_bintn, S_mus_lintn
};
static const char *mus_audio_format_name(int fr)
{
if (MUS_DATA_FORMAT_OK(fr))
return(mus_audio_format_names[fr]);
return("invalid format");
}
#endif
static char *audio_strbuf = NULL; /* previous name "strbuf" collides with Mac OSX global! */
static void pprint(char *str);
int device_channels(int dev);
int device_gains(int dev);
int device_channels(int dev)
{
float val[4];
#if USE_SND && DEBUGGING
XEN res;
res = XEN_EVAL_C_STRING("(if (defined? 'debugging-device-channels) debugging-device-channels 0)");
if (XEN_INTEGER_P(res))
{
int chans;
chans = XEN_TO_C_INT(res);
if (chans > 0) return(chans);
}
#endif
mus_audio_mixer_read(dev, MUS_AUDIO_CHANNEL, 0, val);
return((int)val[0]);
}
int device_gains(int ur_dev)
{
float val[4];
int err;
int dev;
dev = MUS_AUDIO_DEVICE(ur_dev);
/* to get hardware gains, read device amp_field and error = none */
if ((dev == MUS_AUDIO_DAC_FILTER) || (dev == MUS_AUDIO_MIXER))
{
err = mus_audio_mixer_read(ur_dev, MUS_AUDIO_CHANNEL, 0, val);
#ifdef HAVE_ALSA
if (err != MUS_NO_ERROR) return(0);
#endif
return((int)val[0]);
}
err = mus_audio_mixer_read(ur_dev, MUS_AUDIO_AMP, 0, val);
if (err != MUS_NO_ERROR) return(0);
return(device_channels(ur_dev));
}
/* ------------------------------- SGI ----------------------------------------- */
#ifdef MUS_SGI
#define AUDIO_OK
#include <audio.h>
int mus_audio_systems(void) {return(1);} /* I think more than 1 is possible, but don't have a case to test with */
char *mus_audio_system_name(int system) {return("SGI");}
char *mus_audio_moniker(void)
{
#ifdef AL_RESOURCE
return("New SGI audio");
#else
return("Old SGI audio");
#endif
}
#ifndef AL_RESOURCE
static char *alGetErrorString(int err)
{
switch (err)
{
case AL_BAD_NOT_IMPLEMENTED: return("not implemented yet"); break;
case AL_BAD_PORT: return("tried to use an invalid port"); break;
case AL_BAD_CONFIG: return("tried to use an invalid configuration"); break;
case AL_BAD_DEVICE: return("tried to use an invalid device"); break;
case AL_BAD_DEVICE_ACCESS: return("unable to access the device"); break;
case AL_BAD_DIRECTION: return("invalid direction given for port"); break;
case AL_BAD_OUT_OF_MEM: return("operation has run out of memory"); break;
case AL_BAD_NO_PORTS: return("not able to allocate a port"); break;
case AL_BAD_WIDTH: return("invalid sample width given"); break;
case AL_BAD_ILLEGAL_STATE: return("an invalid state has occurred"); break;
case AL_BAD_QSIZE: return("attempt to set an invalid queue size"); break;
case AL_BAD_FILLPOINT: return("attempt to set an invalid fillpoint"); break;
case AL_BAD_BUFFER_NULL: return("null buffer pointer"); break;
case AL_BAD_COUNT_NEG: return("negative count"); break;
case AL_BAD_PVBUFFER: return("param/val buffer doesn't make sense"); break;
case AL_BAD_BUFFERLENGTH_NEG: return("negative buffer length"); break;
case AL_BAD_BUFFERLENGTH_ODD: return("odd length parameter/value buffer"); break;
case AL_BAD_CHANNELS: return("invalid channel specifier"); break;
case AL_BAD_PARAM: return("invalid parameter"); break;
case AL_BAD_SAMPFMT: return("attempt to set invalid sample format"); break;
case AL_BAD_RATE: return("invalid sample rate token"); break;
case AL_BAD_TRANSFER_SIZE: return("invalid size for sample read/write"); break;
case AL_BAD_FLOATMAX: return("invalid size for floatmax"); break;
case AL_BAD_PORTSTYLE: return("invalid port style"); break;
default: return("");
}
}
#endif
static char *sgi_err_buf = NULL;
static mus_print_handler_t *old_handler = NULL;
static void sgi_mus_print(char *msg)
{
int oserr = oserror();
if (oserr)
{
if (sgi_err_buf == NULL) sgi_err_buf = (char *)CALLOC(PRINT_BUFFER_SIZE, sizeof(char));
mus_snprintf(sgi_err_buf, PRINT_BUFFER_SIZE, "%s [%s]", msg, alGetErrorString(oserr));
(*old_handler)(sgi_err_buf);
}
else (*old_handler)(msg);
}
static void start_sgi_print(void)
{
if (old_handler != sgi_mus_print)
old_handler = mus_print_set_handler(sgi_mus_print);
}
static void end_sgi_print(void)
{
if (old_handler != sgi_mus_print)
mus_print_set_handler(old_handler);
else mus_print_set_handler(NULL);
}
#if AL_RESOURCE
#define al_free(Line) alFreeConfig(config[Line])
#define al_newconfig() alNewConfig()
#define al_setsampfmt(Line, Format) alSetSampFmt(Line, Format)
#define al_setchannels(Line, Chans) alSetChannels(Line, Chans)
#define al_setwidth(Line, Width) alSetWidth(Line, Width)
#define al_setqueuesize(Line, Size) alSetQueueSize(Line, Size)
#define al_openport(Name, Flag, Line) alOpenPort(Name, Flag, Line)
#define al_getfilled(Port) alGetFilled(Port)
#define al_closeport(Port) alClosePort(Port)
#define al_freeconfig(Config) alFreeConfig(Config)
#else
#define al_free(Line) ALfreeconfig(config[Line]);
#define al_newconfig() ALnewconfig()
#define al_setsampfmt(Line, Format) ALsetsampfmt(Line, Format)
#define al_setchannels(Line, Chans) ALsetchannels(Line, Chans)
#define al_setwidth(Line, Width) ALsetwidth(Line, Width)
#define al_setqueuesize(Line, Size) ALsetqueuesize(Line, Size)
#define al_openport(Name, Flag, Line) ALopenport(Name, Flag, Line)
#define al_getfilled(Port) ALgetfilled(Port)
#define al_closeport(Port) ALcloseport(Port)
#define al_freeconfig(Config) ALfreeconfig(Config)
#endif
#define RETURN_ERROR_EXIT(Error_Type, Audio_Line, Ur_Error_Message) \
do { \
char *Error_Message; Error_Message = Ur_Error_Message; \
if (Audio_Line != -1) al_free(Audio_Line); \
if (Error_Message) \
{ \
MUS_STANDARD_ERROR(Error_Type, Error_Message); FREE(Error_Message); \
} \
else MUS_STANDARD_ERROR(Error_Type, mus_error_type_to_string(Error_Type)); \
end_sgi_print(); \
return(MUS_ERROR); \
} while (false)
#ifdef AL_RESOURCE
static int check_queue_size (int size, int chans)
{
if (size > chans * 1024)
return(size);
else return(chans * 1024);
}
#else
#define STEREO_QUEUE_MIN_SIZE 1024
#define STEREO_QUEUE_MIN_CHOICE 1024
/* docs say 510 or 512, but they die with "File size limit exceeded" %$@#!(& */
#define MONO_QUEUE_MIN_SIZE 1019
#define MONO_QUEUE_MIN_CHOICE 1024
#define STEREO_QUEUE_MAX_SIZE 131069
#define STEREO_QUEUE_MAX_CHOICE 65536
#define MONO_QUEUE_MAX_SIZE 262139
#define MONO_QUEUE_MAX_CHOICE 131072
/* if these limits are not followed, the damned thing dumps core and dies */
static int check_queue_size (int size, int chans)
{
if ((chans == 1) && (size > MONO_QUEUE_MAX_SIZE)) return(MONO_QUEUE_MAX_CHOICE);
if ((chans == 1) && (size < MONO_QUEUE_MIN_SIZE)) return(MONO_QUEUE_MIN_CHOICE);
if ((chans > 1) && (size > STEREO_QUEUE_MAX_SIZE)) return(STEREO_QUEUE_MAX_CHOICE);
if ((chans > 1) && (size < STEREO_QUEUE_MIN_SIZE)) return(STEREO_QUEUE_MIN_CHOICE);
return(size);
}
static void check_quad (int device, int channels)
{
long sr[2];
/* if quad, make sure we are set up for it, else make sure we aren't (perhaps the latter is unnecessary) */
/* in 4 channel mode, stereo mic and line-in are 4 inputs, headphones/speakers and stereo line-out are the 4 outputs */
sr[0] = AL_CHANNEL_MODE;
ALgetparams(device, sr, 2);
if ((channels == 4) && (sr[1] != AL_4CHANNEL))
{
sr[1] = AL_4CHANNEL;
ALsetparams(device, sr, 2);
}
else
{
if ((channels != 4) && (sr[1] != AL_STEREO))
{
sr[1] = AL_STEREO;
ALsetparams(device, sr, 2);
}
}
}
#endif
#define IO_LINES 8
static ALconfig *config = NULL;
static ALport *port = NULL;
static int *line_in_use = NULL;
static int *channels = NULL;
static long *device = NULL;
static int *datum_size = NULL;
static int *line_out = NULL;
int mus_audio_initialize(void)
{
if (!audio_initialized)
{
audio_initialized = true;
config = (ALconfig *)CALLOC(IO_LINES, sizeof(ALconfig));
port = (ALport *)CALLOC(IO_LINES, sizeof(ALport));
line_in_use = (int *)CALLOC(IO_LINES, sizeof(int));
channels = (int *)CALLOC(IO_LINES, sizeof(int));
device = (long *)CALLOC(IO_LINES, sizeof(long));
datum_size = (int *)CALLOC(IO_LINES, sizeof(int));
line_out = (int *)CALLOC(IO_LINES, sizeof(int));
}
return(MUS_NO_ERROR);
}
#ifdef AL_RESOURCE
static int to_al_interface_or_device(int dev, int which)
{
switch (dev)
{
case MUS_AUDIO_DEFAULT:
case MUS_AUDIO_DUPLEX_DEFAULT: return(AL_DEFAULT_OUTPUT); break;
case MUS_AUDIO_DAC_OUT:
case MUS_AUDIO_SPEAKERS: return(alGetResourceByName(AL_SYSTEM, "Analog Out", which)); break;
case MUS_AUDIO_MICROPHONE: return(alGetResourceByName(AL_SYSTEM, "Microphone", which)); break;
case MUS_AUDIO_ADAT_IN: return(alGetResourceByName(AL_SYSTEM, "ADAT In", which)); break;
case MUS_AUDIO_AES_IN: return(alGetResourceByName(AL_SYSTEM, "AES In", which)); break;
case MUS_AUDIO_ADAT_OUT: return(alGetResourceByName(AL_SYSTEM, "ADAT Out", which)); break;
case MUS_AUDIO_DIGITAL_OUT:
case MUS_AUDIO_AES_OUT: return(alGetResourceByName(AL_SYSTEM, "AES Out", which)); break;
case MUS_AUDIO_LINE_IN: return(alGetResourceByName(AL_SYSTEM, "Line In", which)); break;
case MUS_AUDIO_LINE_OUT: return(alGetResourceByName(AL_SYSTEM, "Line Out2", which)); break; /* ?? */
/* case MUS_AUDIO_DIGITAL_IN: return(alGetResourceByName(AL_SYSTEM, "DAC2 In", which)); break; */ /* this is analog in ?? */
}
return(MUS_ERROR);
}
static int to_al_device(int dev)
{
return(to_al_interface_or_device(dev, AL_DEVICE_TYPE));
}
static int to_al_interface(int dev)
{
return(to_al_interface_or_device(dev, AL_INTERFACE_TYPE));
}
#endif
#include <stdio.h>
/* just a placeholder for now */
int find_audio_output(int chans)
{
#ifdef AL_RESOURCE
ALvalue x[32];
ALpv y;
int n, i;
y.param = AL_INTERFACE;
y.value.i = AL_DIGITAL_IF_TYPE;
n = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, x, 32, &y, 1);
for (i = 0; i < n; i++)
{
y.param = AL_CHANNELS;
alGetParams(x[i].i, &y, 1);
if (chans <= y.value.i) return(x[i].i);
}
#endif
return(MUS_ERROR);
}
static int to_sgi_format(int frm)
{
switch (frm)
{
case MUS_BYTE:
case MUS_BSHORT:
case MUS_B24INT: return(AL_SAMPFMT_TWOSCOMP); break;
case MUS_BFLOAT: return(AL_SAMPFMT_FLOAT); break;
case MUS_BDOUBLE: return(AL_SAMPFMT_DOUBLE); break;
}
return(MUS_ERROR);
}
int mus_audio_open_output(int ur_dev, int srate, int chans, int format, int requested_size)
{
#ifdef AL_RESOURCE
ALpv z[2];
#endif
long sr[2];
int i, line, size, width, sgi_format, dev;
start_sgi_print();
dev = MUS_AUDIO_DEVICE(ur_dev);
line = -1;
for (i = 0; i < IO_LINES; i++)
if (line_in_use[i] == 0)
{
line = i;
break;
}
if (line == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_NO_LINES_AVAILABLE, line,
"no free audio lines?");
channels[line] = chans;
line_out[line] = 1;
if (requested_size == 0)
size = 1024 * chans;
else size = check_queue_size(requested_size, chans);
/* if (chans > 2) size = 65536; */ /* for temp adat code */
datum_size[line] = mus_bytes_per_sample(format);
if (datum_size[line] == 3)
width = AL_SAMPLE_24;
else
{
if (datum_size[line] == 1)
width = AL_SAMPLE_8;
else width = AL_SAMPLE_16;
}
sgi_format = to_sgi_format(format);
if (sgi_format == MUS_ERROR)
RETURN_ERROR_EXIT(MUS_AUDIO_FORMAT_NOT_AVAILABLE, -1,
mus_format("format %d (%s) not supported by SGI",
format,
mus_audio_format_name(format)));
#ifdef AL_RESOURCE
if (dev == MUS_AUDIO_DEFAULT)
device[line] = AL_DEFAULT_OUTPUT;
else device[line] = to_al_device(dev);
if (!(device[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_DEVICE_NOT_AVAILABLE, -1,
mus_format("device %d (%s) not available",
dev,
mus_audio_device_name(dev)));
#if 0
if (device_channels(dev) < chans) /* look for some device that can play this file */
device[line] = find_audio_output(chans);
if (device[line] == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, -1,
mus_format("can't find %d channel device",
chans));
#endif
if ((chans == 4) && (dev == MUS_AUDIO_DAC_OUT))
{ /* kludge around a bug in the new audio library */
sr[0] = AL_CHANNEL_MODE;
sr[1] = AL_4CHANNEL;
ALsetparams(AL_DEFAULT_DEVICE, sr, 2);
}
z[0].param = AL_RATE;
z[0].value.ll = alDoubleToFixed((double)srate);
z[1].param = AL_MASTER_CLOCK;
/* z[1].value.i = AL_CRYSTAL_MCLK_TYPE; */
z[1].value.i = AL_MCLK_TYPE; /* was AL_CRYSTAL_MCLK_TYPE -- digital I/O perhaps needs AL_VARIABLE_MCLK_TYPE */
if (alSetParams(device[line], z, 2) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_SRATE_NOT_AVAILABLE, -1,
mus_format("can't set srate of %s to %d",
mus_audio_device_name(dev),
srate));
#else
device[line] = AL_DEFAULT_DEVICE;
check_quad(device[line], chans);
sr[0] = AL_OUTPUT_RATE;
sr[1] = srate;
if (ALsetparams(device[line], sr, 2) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_SRATE_NOT_AVAILABLE, -1,
mus_format("can't set srate of %s to %d",
mus_audio_device_name(dev),
srate));
#endif
config[line] = al_newconfig();
if (!(config[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
"can't allocate audio configuration?");
if ((al_setsampfmt(config[line], sgi_format) == -1) ||
(al_setwidth(config[line], width) == -1)) /* this is a no-op in the float and double cases */
RETURN_ERROR_EXIT(MUS_AUDIO_FORMAT_NOT_AVAILABLE, line,
mus_format("audio format %d (%s, SGI: %d) not available on device %d (%s)",
format, mus_audio_format_name(format), sgi_format,
dev,
mus_audio_device_name(dev)));
if (al_setchannels(config[line], chans) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, line,
mus_format("can't get %d channels on device %d (%s)",
chans, dev, mus_audio_device_name(dev)));
/* set queue size probably needs a check first for legal queue sizes given the current desired device */
/* in new AL, I'm assuming above (check_queue_size) that it needs at least 1024 per chan */
if (al_setqueuesize(config[line], size) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_SIZE_NOT_AVAILABLE, line,
mus_format("can't get queue size %d on device %d (%s) (chans: %d, requested_size: %d)",
size, dev,
mus_audio_device_name(dev),
chans, requested_size));
#ifdef AL_RESOURCE
if (alSetDevice(config[line], device[line]) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_DEVICE_NOT_AVAILABLE, line,
mus_format("can't get device %d (%s)",
dev,
mus_audio_device_name(dev)));
#endif
port[line] = al_openport("dac", "w", config[line]);
if (!(port[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, line,
mus_format("can't open output port on device %d (%s)",
dev,
mus_audio_device_name(dev)));
line_in_use[line] = 1;
end_sgi_print();
return(line);
}
int mus_audio_write(int line, char *buf, int bytes)
{
start_sgi_print();
#ifdef AL_RESOURCE
if (alWriteFrames(port[line], (short *)buf, bytes / (channels[line] * datum_size[line])))
#else
if (ALwritesamps(port[line], (short *)buf, bytes / datum_size[line]))
#endif
RETURN_ERROR_EXIT(MUS_AUDIO_WRITE_ERROR, -1,
"write error");
end_sgi_print();
return(MUS_NO_ERROR);
}
int mus_audio_close(int line)
{
int err;
start_sgi_print();
if (line_in_use[line])
{
if (line_out[line])
while (al_getfilled(port[line]) > 0)
sginap(1);
err = ((al_closeport(port[line])) ||
(al_freeconfig(config[line])));
line_in_use[line] = 0;
if (err)
RETURN_ERROR_EXIT(MUS_AUDIO_CANT_CLOSE, -1,
mus_format("can't close audio port %p (line %d)",
port[line], line));
}
end_sgi_print();
return(MUS_NO_ERROR);
}
int mus_audio_open_input(int ur_dev, int srate, int chans, int format, int requested_size)
{
int dev;
#ifdef AL_RESOURCE
ALpv pv;
ALpv x[2];
#else
long sr[2];
int resind;
#endif
int i, line, sgi_format;
start_sgi_print();
dev = MUS_AUDIO_DEVICE(ur_dev);
line = -1;
for (i = 0; i < IO_LINES; i++)
if (line_in_use[i] == 0)
{
line = i;
break;
}
if (line == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_NO_LINES_AVAILABLE, -1,
"no free audio lines?");
channels[line] = chans;
line_out[line] = 0;
datum_size[line] = mus_bytes_per_sample(format);
#ifdef AL_RESOURCE
if (dev == MUS_AUDIO_DEFAULT)
device[line] = AL_DEFAULT_INPUT;
else
{
int itf;
device[line] = to_al_device(dev);
itf = to_al_interface(dev);
if (itf)
{
pv.param = AL_INTERFACE;
pv.value.i = itf;
if (alSetParams(device[line], &pv, 1) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
mus_format("can't set up device %d (%s)",
dev,
mus_audio_device_name(dev)));
}
}
if (!(device[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_DEVICE_NOT_AVAILABLE, -1,
mus_format("can't get input device %d (%s)",
dev, mus_audio_device_name(dev)));
x[0].param = AL_RATE;
x[0].value.ll = alDoubleToFixed((double)srate);
x[1].param = AL_MASTER_CLOCK;
x[1].value.i = AL_MCLK_TYPE; /* AL_CRYSTAL_MCLK_TYPE; */
if (alSetParams(device[line], x, 2) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_SRATE_NOT_AVAILABLE, -1,
mus_format("can't set srate of %s to %d",
mus_audio_device_name(dev),
srate));
#else
switch (dev)
{
case MUS_AUDIO_DEFAULT:
case MUS_AUDIO_DUPLEX_DEFAULT:
case MUS_AUDIO_MICROPHONE: resind = AL_INPUT_MIC; break;
case MUS_AUDIO_LINE_IN: resind = AL_INPUT_LINE; break;
case MUS_AUDIO_DIGITAL_IN: resind = AL_INPUT_DIGITAL; break;
default:
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
mus_format("audio input device %d (%s) not available",
dev,
mus_audio_device_name(dev)));
break;
}
device[line] = AL_DEFAULT_DEVICE;
sr[0] = AL_INPUT_SOURCE;
sr[1] = resind;
if (ALsetparams(device[line], sr, 2) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
mus_format("can't set up input device %d (%s)",
dev,
mus_audio_device_name(dev)));
check_quad(device[line], chans);
sr[0] = AL_INPUT_RATE;
sr[1] = srate;
if (ALsetparams(device[line], sr, 2) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_SRATE_NOT_AVAILABLE, -1,
mus_format("can't set srate of %s to %d",
mus_audio_device_name(dev),
srate));
#endif
config[line] = al_newconfig();
if (!(config[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, -1,
"can't allocate audio configuration?");
sgi_format = to_sgi_format(format);
if (sgi_format == MUS_ERROR)
RETURN_ERROR_EXIT(MUS_AUDIO_FORMAT_NOT_AVAILABLE, -1,
mus_format("format %d (%s) not supported by SGI",
format,
mus_audio_format_name(format)));
if ((al_setsampfmt(config[line], sgi_format) == -1) ||
(al_setwidth(config[line], (datum_size[line] == 2) ? AL_SAMPLE_16 : AL_SAMPLE_8) == -1))
RETURN_ERROR_EXIT(MUS_AUDIO_FORMAT_NOT_AVAILABLE, line,
mus_format("audio format %d (%s, SGI: %d) not available on device %d (%s)",
format,
mus_audio_format_name(format), sgi_format,
dev,
mus_audio_device_name(dev)));
if (al_setchannels(config[line], chans) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_CHANNELS_NOT_AVAILABLE, line,
mus_format("can't get %d channels on device %d (%s)",
chans, dev,
mus_audio_device_name(dev)));
#ifdef AL_RESOURCE
if (alSetDevice(config[line], device[line]) == -1)
RETURN_ERROR_EXIT(MUS_AUDIO_DEVICE_NOT_AVAILABLE, line,
mus_format("can't get device %d (%s)",
dev,
mus_audio_device_name(dev)));
#endif
port[line] = al_openport("adc", "r", config[line]);
if (!(port[line]))
RETURN_ERROR_EXIT(MUS_AUDIO_CONFIGURATION_NOT_AVAILABLE, line,
mus_format("can't open input port on device %d (%s)",