/* 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 "desire.h" using namespace desire; #include "m_simd.h" #include #ifdef UNISTD #include #include #include #endif #include #include #include #include #define max std::max /* resolve "ambiguous" shit. */ #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 #define INTARG(i) atom_getintarg(i,argc,argv) 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_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 *idevlist, int *nidev, char *odevlist, int *nodev, 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 audi; static t_audiodevs audo; 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 && ((audi.ndev > 0 && audi.chdev[0] > 0) || (audo.ndev > 0 && audo.chdev[0] > 0));} extern "C" void sys_get_audio_params(t_audiodevs *ai, t_audiodevs *ao, int *prate, int *pdacblocksize, int *padvance, int *pscheduler) { ai->ndev=audi.ndev; for (int i=0; i< MAXAUDIOINDEV; i++) {ai->dev[i]=audi.dev[i]; ai->chdev[i]=audi.chdev[i];} ao->ndev=audo.ndev; for (int i=0; idev[i]=audo.dev[i]; ao->chdev[i]=audo.chdev[i];} *prate = audio_rate; *pdacblocksize = audio_dacblocksize; *padvance = audio_advance; *pscheduler = audio_scheduler; } void sys_save_audio_params( int nidev, int *idev, int *ichdev, int nodev, int *odev, int *ochdev, int rate, int dacblocksize, int advance, int scheduler) { audi.ndev = nidev; audo.ndev = nodev; for (int i=0; indev,ai->dev,ai->ndev,ai->chdev,ao->ndev,ao->dev,ao->ndev,ao->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<= 1) {nidev=nichdev=1; ichdev[0]=defaultchannels; idev[0]=DEFAULTAUDIODEV;} else nidev = nichdev=0; } else for (int i=0; i nidev) {for (int i=nidev; i= 1) {nodev=nochdev=1; ochdev[0]=defaultchannels; odev[0]=DEFAULTAUDIODEV;} else nodev = nochdev=0; } else for (int i=0; i nodev) {for (int i=nodev; i 0 ? ichdev[i] : 0)); for (int i=0; i 0 ? ochdev[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, (nodev>0?idev[0]:0), (nodev>0?odev[0]:0), schedmode); else #endif #ifdef USEAPI_JACK if (sys_audioapi == API_JACK) jack_open_audio((nidev>0?realich[0]:0), (nodev>0?realoch[0]:0), rate, schedmode); else #endif if (sys_audioapi == API_OSS || sys_audioapi == API_ALSA || sys_audioapi == API_MMIO) sys_audio()->open_audio(nidev, idev, nichdev, realich, nodev, odev, nochdev, realoch, rate, -42); else if (sys_audioapi == API_ASIO) sys_audio()->open_audio(nidev, idev, nichdev, ichdev, nodev, odev, nochdev, ochdev, rate, schedmode); else post("unknown audio API specified"); } sys_save_audio_params(nidev, idev, ichdev, nodev, odev, ochdev, 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 ai,ao; int rate, dacblocksize, advance, scheduler; sys_close_audio(); sys_get_audio_params(&ai,&ao,&rate,&dacblocksize,&advance,&scheduler); sys_open_audio2( &ai,&ao, 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 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 *idevlist, int *nidev, char *odevlist, int *nodev, int *canmulti, int maxndev, int devdescsize) { audio_init(); if (sys_audio()) sys_audio()->getdevs(idevlist, nidev, odevlist, nodev, canmulti, maxndev, devdescsize); else {*nidev = *nodev = 0;} } void sys_listdevs() { #ifdef USEAPI_JACK if (sys_audioapi == API_JACK) return jack_listdevs(); #endif char idevlist[MAXNDEV*DEVDESCSIZE], odevlist[MAXNDEV*DEVDESCSIZE]; int nidev = 0, nodev = 0, canmulti = 0; audio_getdevs(idevlist, &nidev, odevlist, &nodev, &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 (!nidev) post("no audio input devices found"); else post("audio input devices:"); for (int i=0; i 1 || ao.ndev > 1) flongform = 1; ostringstream idevs; for (int i=0; is_thing, selector, nidev, argv); } else if (f < nidev) { SETSTRING(argv, idevlist + f*DEVDESCSIZE); typedmess(pd->s_thing, selector, 1, argv); } } void glob_audio_getaudiooutdevices(t_pd *, t_symbol *s, int ac, t_atom *av) { t_audiodevs ai,ao; int rate, dacblocksize, advance, scheduler; int nidev=0, nodev=0, canmulti=0; t_atom argv[MAXNDEV]; int f = ac ? atom_getintarg(0,ac,av) : -1; t_symbol *selector = gensym("audiooutdev"), *pd = gensym("pd"); char idevlist[MAXNDEV*DEVDESCSIZE], odevlist[MAXNDEV*DEVDESCSIZE]; audio_getdevs(idevlist, &nidev, odevlist, &nodev, &canmulti, MAXNDEV, DEVDESCSIZE); sys_get_audio_params(&ai,&ao, &rate, &dacblocksize, &advance, &scheduler); if (f<0) { for (int i=0; is_thing, selector, nodev, argv); } else if (f < nodev) { SETSTRING(argv, odevlist + 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 *, t_float f) { #if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) if (sys_audioapi == API_PORTAUDIO) pa_getaudioininfo(f); #endif } void glob_audio_getaudiooutinfo(t_pd *, t_float f) { #if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) if (sys_audioapi == API_PORTAUDIO) pa_getaudiooutinfo(f); #endif } void glob_audio_testaudiosetting(t_pd *, 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 *, t_float f) { #if defined(USEAPI_PORTAUDIO) && !defined(PABLIO) if (sys_audioapi == API_PORTAUDIO) pa_get_asio_latencies(f); #endif } /* tb } */