📄 audio.c
字号:
/* 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 <mus-config.h>#if USE_SND && MUS_MAC_OSX && USE_MOTIF #undef USE_MOTIF #define USE_NO_GUI 1 /* Xt's Boolean (/usr/include/X11/Intrinsic.h = char) collides with MacTypes.h Boolean, (actually, * unsigned char in /Developer/SDKs/MacOSX10.4u.sdk/System/Library/Frameworks/CoreFoundation.framework/Versions/A/Headers/CFBase.h) * but we want snd.h for other stuff, so, if Motif is in use, don't load its headers at this time * perhaps we could use the -funsigned-char switch in gcc */#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_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"#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#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");}#endifstatic 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 && MUS_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_RESOURCEstatic 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(""); }}#endifstatic 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_RESOURCEstatic 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 8static 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -