diff options
Diffstat (limited to 'desiredata/src/s_audio.c')
-rw-r--r-- | desiredata/src/s_audio.c | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/desiredata/src/s_audio.c b/desiredata/src/s_audio.c new file mode 100644 index 00000000..0bcf85f4 --- /dev/null +++ b/desiredata/src/s_audio.c @@ -0,0 +1,724 @@ +/* Copyright (c) 2003, Miller Puckette and others. +* For information on usage and redistribution, and for a DISCLAIMER OF ALL +* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* machine-independent (well, mostly!) audio layer. Stores and recalls + audio settings from argparse routine and from dialog window. +*/ + +#define PD_PLUSPLUS_FACE +#include "m_pd.h" +#include "s_stuff.h" +#include "m_simd.h" +#include <stdio.h> +#ifdef UNISTD +#include <unistd.h> +#include <sys/time.h> +#include <sys/resource.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sstream> + +#define SYS_DEFAULTCH 2 +#define SYS_MAXCH 100 +typedef long t_pa_sample; +#define SYS_SAMPLEWIDTH sizeof(t_pa_sample) +#define SYS_BYTESPERCHAN (sys_dacblocksize * SYS_SAMPLEWIDTH) +#define SYS_XFERSAMPS (SYS_DEFAULTCH*sys_dacblocksize) +#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS) +#define MAXNDEV 100 +#define DEVDESCSIZE 80 + +extern t_audioapi pa_api, jack_api, oss_api, alsa_api, sgi_api, mmio_api, asio_api; + +t_sample *sys_soundin; +t_sample *sys_soundout; +float sys_dacsr; + +using namespace std; + +static t_audioapi *sys_audio() { +#ifdef USEAPI_PORTAUDIO + if (sys_audioapi == API_PORTAUDIO) return &pa_api; +#endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) return &jack_api; +#endif +#ifdef USEAPI_OSS + if (sys_audioapi == API_OSS) return &oss_api; +#endif +#ifdef USEAPI_ALSA + if (sys_audioapi == API_ALSA) return &alsa_api; +#endif +#ifdef USEAPI_SGI + if (sys_audioapi == API_SGI) return &sgi_api; +#endif +#ifdef USEAPI_MMIO + if (sys_audioapi == API_MMIO) return &mmio_api; +#endif +#ifdef USEAPI_ASIO + if (sys_audioapi == API_ASIO) return &asio_api; +#endif + post("sys_close_audio: unknown API %d", sys_audioapi); + sys_inchannels = sys_outchannels = 0; + sched_set_using_dacs(0); /* tb: dsp is switched off */ + return 0; +} + +static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize); + +/* these are set in this file when opening audio, but then may be reduced, + even to zero, in the system dependent open_audio routines. */ +int sys_inchannels; +int sys_outchannels; +int sys_advance_samples; /* scheduler advance in samples */ +int sys_blocksize = 0; /* audio I/O block size in sample frames */ +#ifndef API_DEFAULT +#define API_DEFAULT 0 +#endif +int sys_audioapi = API_DEFAULT; +int sys_dacblocksize; +int sys_schedblocksize; +int sys_meters; /* true if we're metering */ +static float sys_inmax; /* max input amplitude */ +static float sys_outmax; /* max output amplitude */ +int sys_schedadvance; /* scheduler advance in microseconds */ + +/* the "state" is normally one if we're open and zero otherwise; but if the state is one, + we still haven't necessarily opened the audio hardware; see audio_isopen() below. */ +static int audio_state; + +/* last requested parameters */ +static t_audiodevs audio_in; +static t_audiodevs audio_out; +static int audio_rate; +static int audio_dacblocksize; +static int audio_advance; +static int audio_scheduler; + +extern int sys_callbackscheduler; + +float peakvec(t_float* vec, t_int n, t_float cur_max); +static float (*peak_fp)(t_float*, t_int, t_float) = peakvec; + +static int audio_isopen() { + return audio_state && ((audio_in.ndev > 0 && audio_in.chdev[0] > 0) + || (audio_out.ndev > 0 && audio_out.chdev[0] > 0)); +} + +extern "C" void sys_get_audio_params(t_audiodevs *in, t_audiodevs *out, int *prate, int *pdacblocksize, int *padvance, int *pscheduler) { + in->ndev = audio_in.ndev; + out->ndev = audio_out.ndev; + for (int i=0; i<MAXAUDIOINDEV; i++) {in ->dev[i] = audio_in.dev[i]; in->chdev[i] = audio_in.chdev[i];} + for (int i=0; i<MAXAUDIOOUTDEV; i++) {out->dev[i] = audio_out.dev[i]; out->chdev[i] = audio_out.chdev[i];} + *prate = audio_rate; + *pdacblocksize = audio_dacblocksize; + *padvance = audio_advance; + *pscheduler = audio_scheduler; +} + +void sys_save_audio_params( +int nindev, int *indev, int *chindev, +int noutdev, int *outdev, int *choutdev, +int rate, int dacblocksize, int advance, int scheduler) { + audio_in.ndev = nindev; + audio_out.ndev = noutdev; + for (int i=0; i<MAXAUDIOINDEV; i++) {audio_in.dev[i] = indev[i]; audio_in.chdev[i] = chindev[i];} + for (int i=0; i<MAXAUDIOOUTDEV; i++) {audio_out.dev[i] = outdev[i]; audio_out.chdev[i] = choutdev[i];} + audio_rate = rate; + audio_dacblocksize = dacblocksize; + audio_advance = advance; + audio_scheduler = scheduler; +} + +extern "C" void sys_open_audio2(t_audiodevs *in, t_audiodevs *out, int rate, int dacblocksize, int advance, int scheduler) { + sys_open_audio(in->ndev, in->dev, in->ndev, in->chdev, + out->ndev, out->dev, out->ndev, out->chdev, rate, dacblocksize, advance, scheduler, 1); +} + +/* init routines for any API which needs to set stuff up before any other API gets used. This is only true of OSS so far. */ +#ifdef USEAPI_OSS +void oss_init(); +#endif + +static void audio_init() { + static int initted = 0; + if (initted) return; + initted = 1; +#ifdef USEAPI_OSS + oss_init(); +#endif +} + +/* set channels and sample rate. */ +void sys_setchsr(int chin, int chout, int sr, int dacblocksize) { + int inbytes = (chin ? chin : 2) * (sys_dacblocksize*sizeof(float)); + int outbytes = (chout ? chout : 2) * (sys_dacblocksize*sizeof(float)); + if (dacblocksize != (1<<ilog2(dacblocksize))) { + dacblocksize = 1<<ilog2(dacblocksize); + post("warning: adjusting dac~blocksize to power of 2: %d", dacblocksize); + } + sys_dacblocksize = dacblocksize; + sys_schedblocksize = dacblocksize; + sys_inchannels = chin; + sys_outchannels = chout; + sys_dacsr = double(sr); + sys_advance_samples = max(int(sys_schedadvance*sys_dacsr/1000000.),sys_dacblocksize); + if (sys_soundin) freealignedbytes(sys_soundin,inbytes); + sys_soundin = (t_float *)getalignedbytes(inbytes); + memset(sys_soundin, 0, inbytes); + if (sys_soundout) freealignedbytes(sys_soundout,outbytes); + sys_soundout = (t_float *)getalignedbytes(outbytes); + memset(sys_soundout, 0, outbytes); + /* tb: modification for simd-optimized peak finding */ + if (SIMD_CHKCNT(sys_inchannels * sys_dacblocksize) && + SIMD_CHKCNT(sys_outchannels * sys_dacblocksize)) + peak_fp = peakvec_simd; + else peak_fp = peakvec; + if (sys_verbose) post("input channels = %d, output channels = %d", sys_inchannels, sys_outchannels); + canvas_resume_dsp(canvas_suspend_dsp()); +} + +/* ----------------------- public routines ----------------------- */ + +/* open audio devices (after cleaning up the specified device and channel vectors). The audio devices are "zero based" + (i.e. "0" means the first one.) We also save the cleaned-up device specification so that we + can later re-open audio and/or show the settings on a dialog window. */ +void sys_open_audio(int nindev, int *indev, int nchindev, int *chindev, int noutdev, int *outdev, int nchoutdev, +int *choutdev, int rate, int dacblocksize, int advance, int schedmode, int enable) { + int defaultchannels = SYS_DEFAULTCH; + int realinchans[MAXAUDIOINDEV], realoutchans[MAXAUDIOOUTDEV]; + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int indevs = 0, outdevs = 0, canmulti = 0; + audio_getdevs(indevlist, &indevs, outdevlist, &outdevs, &canmulti, MAXNDEV, DEVDESCSIZE); + if (sys_externalschedlib) return; + if (sys_inchannels || sys_outchannels) sys_close_audio(); + if (rate < 1) rate = DEFAULTSRATE; + if (dacblocksize < 1) dacblocksize = DEFDACBLKSIZE; + if (advance <= 0) advance = DEFAULTADVANCE; + audio_init(); + /* Since the channel vector might be longer than the audio device vector, or vice versa, we fill the shorter one + in to match the longer one. Also, if both are empty, we fill in one device (the default) and two channels. */ + if (nindev == -1) { /* no input audio devices specified */ + if (nchindev == -1) { + if (indevs >= 1) { + nchindev=1; + chindev[0] = defaultchannels; + nindev = 1; + indev[0] = DEFAULTAUDIODEV; + } else nindev = nchindev = 0; + } else { + for (int i=0; i<MAXAUDIOINDEV; i++) indev[i] = i; + nindev = nchindev; + } + } else { + if (nchindev == -1) { + nchindev = nindev; + for (int i=0; i<nindev; i++) chindev[i] = defaultchannels; + } else if (nchindev > nindev) { + for (int i=nindev; i<nchindev; i++) { + if (i == 0) indev[0] = DEFAULTAUDIODEV; else indev[i] = indev[i-1] + 1; + } + nindev = nchindev; + } else if (nchindev < nindev) { + for (int i=nchindev; i<nindev; i++) { + if (i == 0) chindev[0] = defaultchannels; else chindev[i] = chindev[i-1]; + } + nindev = nchindev; + } + } + if (noutdev == -1) { /* not set */ + if (nchoutdev == -1) { + if (outdevs >= 1) { + nchoutdev=1; + choutdev[0]=defaultchannels; + noutdev=1; + outdev[0] = DEFAULTAUDIODEV; + } else nchoutdev = noutdev = 0; + } else { + for (int i=0; i<MAXAUDIOOUTDEV; i++) outdev[i] = i; + noutdev = nchoutdev; + } + } else { + if (nchoutdev == -1) { + nchoutdev = noutdev; + for (int i=0; i<noutdev; i++) choutdev[i] = defaultchannels; + } else if (nchoutdev > noutdev) { + for (int i=noutdev; i<nchoutdev; i++) { + if (i == 0) outdev[0] = DEFAULTAUDIODEV; else outdev[i] = outdev[i-1] + 1; + } + noutdev = nchoutdev; + } else if (nchoutdev < noutdev) { + for (int i=nchoutdev; i<noutdev; i++) { + if (i == 0) choutdev[0] = defaultchannels; else choutdev[i] = choutdev[i-1]; + } + noutdev = nchoutdev; + } + } + /* count total number of input and output channels */ + int inchans=0, outchans=0; + for (int i=0; i < nindev; i++) inchans += (realinchans[i] = (chindev[i] > 0 ? chindev[i] : 0)); + for (int i=0; i < noutdev; i++) outchans += (realoutchans[i] = (choutdev[i] > 0 ? choutdev[i] : 0)); + /* if no input or output devices seem to have been specified, this really means just disable audio, which we now do. */ + if (!inchans && !outchans) enable = 0; + sys_schedadvance = advance * 1000; + sys_setchsr(inchans, outchans, rate, dacblocksize); + sys_log_error(ERR_NOTHING); + if (enable) { + /* for alsa, only one device is supported; it may be open for both input and output. */ +#ifdef USEAPI_PORTAUDIO + if (sys_audioapi == API_PORTAUDIO) + pa_open_audio(inchans, outchans, rate, advance, + (noutdev > 0 ? indev[0] : 0), + (noutdev > 0 ? outdev[0] : 0), schedmode); + else +#endif +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) + jack_open_audio((nindev > 0 ? realinchans[0] : 0), + (noutdev > 0 ? realoutchans[0] : 0), rate, schedmode); + else +#endif + if (sys_audioapi == API_OSS || sys_audioapi == API_ALSA || sys_audioapi == API_MMIO) + sys_audio()->open_audio(nindev, indev, nchindev, realinchans, noutdev, outdev, nchoutdev, realoutchans, rate, -42); + else if (sys_audioapi == API_SGI) + sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, -42); + else if (sys_audioapi == API_ASIO) + sys_audio()->open_audio(nindev, indev, nchindev, chindev, noutdev, outdev, nchoutdev, choutdev, rate, schedmode); + else post("unknown audio API specified"); + } + sys_save_audio_params(nindev, indev, chindev, noutdev, outdev, choutdev, int(sys_dacsr), sys_dacblocksize, advance, schedmode); + if (sys_inchannels == 0 && sys_outchannels == 0) enable = 0; + audio_state = enable; + sys_vgui("set pd_whichapi %d\n", audio_isopen() ? sys_audioapi : 0); + sched_set_using_dacs(enable); + sys_update_sleepgrain(); + if (enable) { + t_atom argv[1]; + t_symbol *selector = gensym("audio_started"); + t_symbol *pd = gensym("pd"); + SETFLOAT(argv, 1.); + typedmess(pd->s_thing, selector, 1, argv); + } +} + +void sys_close_audio() { + /* jsarlo { (*/ + if (sys_externalschedlib) return; + /* } jsarlo */ + if (!audio_isopen()) return; + if (sys_audio()) sys_audio()->close_audio(); + else post("sys_close_audio: unknown API %d", sys_audioapi); + sys_inchannels = sys_outchannels = 0; + sched_set_using_dacs(0); /* tb: dsp is switched off */ +} + +/* open audio using whatever parameters were last used */ +void sys_reopen_audio() { + t_audiodevs in, out; + int rate, dacblocksize, advance, scheduler; + sys_close_audio(); + sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler); + sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler); +} + +/* tb: default value of peak_fp {*/ +float peakvec(t_float* vec, t_int n, t_float cur_max) { + for (int i=0; i<n; i++) { + float f = *vec++; + if (f > cur_max) cur_max = f; + else if (-f > cur_max) cur_max = -f; + } + return cur_max; +} +/* } */ + +void sys_peakmeters() { + if (sys_inchannels) sys_inmax = peak_fp(sys_soundin, sys_inchannels * sys_dacblocksize, sys_inmax); + if (sys_outchannels) sys_outmax = peak_fp(sys_soundout,sys_outchannels * sys_dacblocksize, sys_outmax); +} + +int sys_send_dacs() { + if (sys_meters) sys_peakmeters(); + if (sys_audio()) return sys_audio()->send_dacs(); + post("unknown API"); + return 0; +} + +float sys_getsr() {return sys_dacsr;} +int sys_get_outchannels() {return sys_outchannels;} +int sys_get_inchannels() {return sys_inchannels;} + +void sys_getmeters(float *inmax, float *outmax) { + if (inmax) { + sys_meters = 1; + *inmax = sys_inmax; + *outmax = sys_outmax; + } else sys_meters = 0; + sys_inmax = sys_outmax = 0; +} + +static void audio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) { + audio_init(); + if (sys_audio()) sys_audio()->getdevs(indevlist, nindevs, outdevlist, noutdevs, canmulti, maxndev, devdescsize); + else {*nindevs = *noutdevs = 0;} +} + +static void sys_listaudiodevs() { + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, canmulti = 0; + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE); + /* To agree with command line flags, normally start at 1; but microsoft "MMIO" device list starts at 0 (the "mapper"). */ + /* (see also sys_mmio variable in s_main.c) */ + if (!nindevs) post("no audio input devices found"); + else { + post("audio input devices:"); + for (int i=0; i<nindevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), indevlist + i * DEVDESCSIZE); + } + if (!noutdevs) post("no audio output devices found"); + else { + post("audio output devices:"); + for (int i=0; i<noutdevs; i++) post("%d. %s", i + (sys_audioapi != API_MMIO), outdevlist + i * DEVDESCSIZE); + } + post("API number %d", sys_audioapi); +} + +/* start an audio settings dialog window */ +void glob_audio_properties(t_pd *dummy, t_floatarg flongform) { + /* these are the devices you're using: */ + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + /* these are all the devices on your system: */ + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + int nindevs = 0, noutdevs = 0, canmulti = 0; + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE); + ostringstream indevliststring; for (int i=0; i<nindevs; i++) indevliststring << " {" << (indevlist + i*DEVDESCSIZE) << "}"; + ostringstream outdevliststring; for (int i=0; i<noutdevs; i++) outdevliststring << " {" << (outdevlist + i*DEVDESCSIZE) << "}"; + sys_get_audio_params(&in,&out,&rate,&dacblocksize,&advance,&scheduler); + if (in.ndev > 1 || out.ndev > 1) flongform = 1; + ostringstream indevs; for (int i=0; i< in.ndev; i++) indevs << " " << in.dev [i]; + ostringstream outdevs; for (int i=0; i<out.ndev; i++) outdevs << " " << out.dev[i]; + ostringstream inchans; for (int i=0; i< in.ndev; i++) inchans << " " << in.chdev[i]; + ostringstream outchans; for (int i=0; i<out.ndev; i++) outchans << " " << out.chdev[i]; + sys_vgui("pdtk_audio_dialog {%s} {%s} {%s} {%s} {%s} {%s} %d %d %d %d %d\n", + indevliststring .str().data()+1, indevs.str().data()+1, inchans.str().data()+1, + outdevliststring.str().data()+1, outdevs.str().data()+1, outchans.str().data()+1, + rate, dacblocksize, advance, canmulti, flongform!=0); +} + +/* new values from dialog window */ +void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { + int nindev=0, noutdev=0; + int newindev[4], newinchan[4], newoutdev[4], newoutchan[4]; + /* the new values the dialog came back with: */ + int newrate = atom_getintarg(16, argc, argv); + int newdacblocksize = atom_getintarg(17, argc, argv); + int newadvance = atom_getintarg(18, argc, argv); + int newschedmode = atom_getintarg(19, argc, argv); + for (int i=0; i<4; i++) { + newindev[i] = atom_getintarg(i, argc, argv); + newinchan[i] = atom_getintarg(i+4, argc, argv); + newoutdev[i] = atom_getintarg(i+8, argc, argv); + newoutchan[i] = atom_getintarg(i+12, argc, argv); + } + for (int i=0; i<4; i++) { + if (newinchan[i]) { + newindev[nindev] = newindev[i]; + newinchan[nindev] = newinchan[i]; + nindev++; + } + } + for (int i=0; i<4; i++) { + if (newoutchan[i]) { + newoutdev[noutdev] = newoutdev[i]; + newoutchan[noutdev] = newoutchan[i]; + noutdev++; + } + } + sys_close_audio(); + sys_open_audio(nindev, newindev, nindev, newinchan, + noutdev, newoutdev, noutdev, newoutchan, + newrate, newdacblocksize, newadvance, newschedmode, 1); +} + +extern void sgi_listaudiodevs(); +void sys_listdevs() { + if (sys_audioapi == API_PORTAUDIO) sys_listaudiodevs(); else +#ifdef USEAPI_JACK + if (sys_audioapi == API_JACK) jack_listdevs(); else +#endif + if (sys_audioapi == API_OSS) sys_listaudiodevs(); else + if (sys_audioapi == API_ALSA) sys_listaudiodevs(); else +#ifdef USEAPI_SGI + if (sys_audioapi == API_SGI) sgi_listaudiodevs(); else +#endif + if (sys_audioapi == API_MMIO) sys_listaudiodevs(); else + post("unknown API"); + sys_listmididevs(); +} + +void sys_setblocksize(int n) { + if (n < 1) n = 1; + if (n != (1 << ilog2(n))) post("warning: adjusting blocksize to power of 2: %d", (n = (1 << ilog2(n)))); + sys_blocksize = n; +} + +void sys_set_audio_api(int which) { + sys_audioapi = which; + if (sys_verbose) post("sys_audioapi %d", sys_audioapi); +} + +void glob_audio_setapi(t_pd *dummy, t_floatarg f) { + int newapi = int(f); + if (newapi != sys_audioapi) { + if (newapi != sys_audioapi) { + sys_close_audio(); + sys_audioapi = newapi; + /* bash device params back to default */ + audio_in.ndev = audio_out.ndev = 1; + audio_in.dev[0] = audio_out.dev[0] = DEFAULTAUDIODEV; + audio_in.chdev[0] = audio_out.chdev[0] = SYS_DEFAULTCH; + } + sched_set_using_dacs(0); +/* glob_audio_properties(0, 0); */ + } +} + +/* start or stop the audio hardware */ +void sys_set_audio_state(int onoff) { + if (onoff) { /* start */ + if (!audio_isopen()) sys_reopen_audio(); + } else { + if (audio_isopen()) sys_close_audio(); + } + sched_set_using_dacs(onoff); + sys_setscheduler(sys_getscheduler()); /* tb: reset scheduler */ + audio_state = onoff; +} + +void sys_get_audio_apis(char *buf) { + int n = 0; + strcpy(buf, "{ "); +#ifdef USEAPI_OSS + sprintf(buf + strlen(buf), "{OSS %d} ", API_OSS); n++; +#endif +#ifdef USEAPI_ASIO + sprintf(buf + strlen(buf), "{ASIO %d} ", API_ASIO); n++; +#endif +#ifdef USEAPI_MMIO + sprintf(buf + strlen(buf), "{\"standard (MMIO)\" %d} ", API_MMIO); n++; +#endif +#ifdef USEAPI_ALSA + sprintf(buf + strlen(buf), "{ALSA %d} ", API_ALSA); n++; +#endif +#ifdef USEAPI_PORTAUDIO +#ifdef __APPLE__ + sprintf(buf + strlen(buf), "{\"standard (portaudio)\" %d} ", API_PORTAUDIO); n++; +#else + sprintf(buf + strlen(buf), "{portaudio %d} ", API_PORTAUDIO); n++; +#endif +#endif +#ifdef USEAPI_SGI + sprintf(buf + strlen(buf), "{SGI %d} ", API_SGI); n++; +#endif +#ifdef USEAPI_JACK + sprintf(buf + strlen(buf), "{jack %d} ", API_JACK); n++; +#endif + strcat(buf, "}"); +} + +#ifdef USEAPI_ALSA +void alsa_putzeros(int iodev, int n); +void alsa_getzeros(int iodev, int n); +void alsa_printstate(); +#endif + +/* debugging */ +void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv) { + t_symbol *arg = atom_getsymbolarg(0, argc, argv); + if (arg == gensym("restart")) sys_reopen_audio(); +#ifdef USEAPI_ALSA + /* what's the matter here? what should be the value of iodev??? */ + else if (arg == gensym("alsawrite")) alsa_putzeros(0, atom_getintarg(1, argc, argv)); + else if (arg == gensym("alsaread")) alsa_getzeros(0, atom_getintarg(1, argc, argv)); + else if (arg == gensym("print")) alsa_printstate(); +#endif +} + +/* tb: message-based audio configuration + * supported by vibrez.net { */ +void glob_audio_samplerate(t_pd * dummy, t_float f) { + t_audiodevs in, out; + int rate, dacblocksize, advance, scheduler; + if (f == sys_getsr()) return; + sys_get_audio_params(&in,&out,&rate, &dacblocksize, &advance, &scheduler); + sys_close_audio(); + sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev, + (int)f, dacblocksize, advance, scheduler, 1); +} + +void glob_audio_api(t_pd *dummy, t_float f) { + int newapi = (int)f; + sys_close_audio(); + sys_audioapi = newapi; +} + +void glob_audio_delay(t_pd *dummy, t_float f) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + if ((int)f == audio_advance) return; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + sys_close_audio(); + sys_open_audio(in.ndev, in.dev, in.ndev, in.chdev, out.ndev, out.dev, out.ndev, out.chdev, + rate, dacblocksize, (int) f, scheduler, 1); +} + +void glob_audio_dacblocksize(t_pd * dummy, t_float f) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + if ((int)f == audio_dacblocksize) return; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + sys_close_audio(); + sys_open_audio2(&in,&out, rate, (int)f, advance, scheduler); +} + +void glob_audio_scheduler(t_pd * dummy, t_float f) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + if ((int)f == sys_callbackscheduler) return; + scheduler = f!=0; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + sys_close_audio(); + sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler); + if (scheduler != sys_callbackscheduler) { + if (scheduler == 1) { + post("switched to callback-based scheduler"); + } else { + post("switched to traditional scheduler"); + } + } else post("couldn't change scheduler"); +} + +void glob_audio_device(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + out.ndev = in.ndev = (int)atom_getfloatarg(0, argc, argv); + for (int i=0; i<MAXAUDIOINDEV; i++) { + out.dev [i] = in.dev [i] = int(atom_getfloatarg(i*2+1, argc, argv)); + out.chdev[i] = in.chdev[i] = int(atom_getfloatarg(i*2+2, argc, argv)); + } + sys_close_audio(); + sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler); +} + +void glob_audio_device_in(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + in.ndev = (int)atom_getfloatarg(0, argc, argv); + for (int i=0; i<MAXAUDIOINDEV; i=i+2) { + in.dev [i] = atom_getintarg(i+1, argc, argv); + in.chdev[i] = atom_getintarg(i+2, argc, argv); + } + sys_close_audio(); + sys_open_audio2(&in,&out,rate, dacblocksize, advance, scheduler); +} + +void glob_audio_device_out(t_pd *dummy, t_symbol *s, int argc, t_atom *argv) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + out.ndev = (int)atom_getfloatarg(0, argc, argv); + /* i+=2 ? isn't that a bug??? */ + for (int i=0; i<MAXAUDIOOUTDEV; i+=2) { + out.dev [i] = atom_getintarg(i+1, argc, argv); + out.chdev[i] = atom_getintarg(i+2, argc, argv); + } + sys_close_audio(); + sys_open_audio2(&in,&out, rate, dacblocksize, advance, scheduler); +} + +/* some general helper functions */ +void sys_update_sleepgrain() { + sys_sleepgrain = sys_schedadvance/4; + if (sys_sleepgrain < 1000) sys_sleepgrain = 1000; + else if (sys_sleepgrain > 5000) sys_sleepgrain = 5000; +} + +/* t_audiodevs are the ones you're using; char[] are all the devices available. */ +void glob_audio_getaudioindevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + int nindevs = 0, noutdevs = 0, canmulti = 0; + t_atom argv[MAXNDEV]; + int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1; + t_symbol *selector = gensym("audioindev"); + t_symbol *pd = gensym("pd"); + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE); + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + if (f < 0) { + for (int i=0; i<nindevs; i++) SETSTRING(argv+i,indevlist+i*DEVDESCSIZE); + typedmess(pd->s_thing, selector, nindevs, argv); + } else if (f < nindevs) { + SETSTRING(argv, indevlist + f * DEVDESCSIZE); + typedmess(pd->s_thing, selector, 1, argv); + } +} +void glob_audio_getaudiooutdevices(t_pd * dummy, t_symbol *s, int ac, t_atom *av) { + t_audiodevs in,out; + int rate, dacblocksize, advance, scheduler; + int nindevs = 0, noutdevs = 0, canmulti = 0; + t_atom argv[MAXNDEV]; + int f = ac ? (int)atom_getfloatarg(0,ac,av) : -1; + t_symbol *selector = gensym("audiooutdev"); + t_symbol *pd = gensym("pd"); + char indevlist[MAXNDEV*DEVDESCSIZE], outdevlist[MAXNDEV*DEVDESCSIZE]; + audio_getdevs(indevlist, &nindevs, outdevlist, &noutdevs, &canmulti, MAXNDEV, DEVDESCSIZE); + sys_get_audio_params(&in,&out, &rate, &dacblocksize, &advance, &scheduler); + if (f < 0) { + for (int i=0; i<noutdevs; i++) SETSYMBOL(argv+i, gensym(outdevlist+i*DEVDESCSIZE)); + typedmess(pd->s_thing, selector, noutdevs, argv); + } else if (f < noutdevs) { + SETSTRING(argv, outdevlist + f * DEVDESCSIZE); + typedmess(pd->s_thing, selector, 1, argv); + } +} + +/* some prototypes from s_audio_portaudio.c */ +extern void pa_getcurrent_devices(); +extern void pa_getaudioininfo(t_float f); +extern void pa_getaudiooutinfo(t_float f); +extern void pa_test_setting (int ac, t_atom *av); +extern void pa_get_asio_latencies(t_float f); + +void glob_audio_getaudioininfo(t_pd * dummy, t_float f) { +#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) + if (sys_audioapi == API_PORTAUDIO) pa_getaudioininfo(f); +#endif +} +void glob_audio_getaudiooutinfo(t_pd * dummy, t_float f) { +#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) + if (sys_audioapi == API_PORTAUDIO) pa_getaudiooutinfo(f); +#endif +} +void glob_audio_testaudiosetting(t_pd * dummy, t_symbol *s, int ac, t_atom *av) { +#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) + if (sys_audioapi == API_PORTAUDIO) pa_test_setting (ac, av); +#endif +} +void glob_audio_getcurrent_devices() { +#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) + if (sys_audioapi == API_PORTAUDIO) pa_getcurrent_devices(); +#endif +} +void glob_audio_asio_latencies(t_pd * dummy, t_float f) { +#if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) + if (sys_audioapi == API_PORTAUDIO) pa_get_asio_latencies(f); +#endif +} + +/* tb } */ |