diff --git a/pd/src/dialog_audio.tcl b/pd/src/dialog_audio.tcl index b88b84681a844e8c97b18fb0f28af0c5f44a65ff..94f0ad5fce800d42aec7d3a7eda58bed3cae24fd 100644 --- a/pd/src/dialog_audio.tcl +++ b/pd/src/dialog_audio.tcl @@ -205,7 +205,7 @@ proc ::dialog_audio::pdtk_audio_dialog {id \ set audio_callback $callback set audio_blocksize $blocksize set audio_longform $longform - + set mytoplevel .prefs.nb.audio set apifr $mytoplevel.api if {![winfo exists $apifr]} { diff --git a/pd/src/pd.tk b/pd/src/pd.tk index 108326ad0c2f8792a44c0fa242f08fa3eeb9e7ec..b1b4bcb817494fd96788b9992acdb0bbfc0d828a 100644 --- a/pd/src/pd.tk +++ b/pd/src/pd.tk @@ -8493,8 +8493,7 @@ proc pdtk_audio_dialog {mytoplevel indev1 indev2 indev3 indev4 \ inchan1 inchan2 inchan3 inchan4 \ outdev1 outdev2 outdev3 outdev4 \ outchan1 outchan2 outchan3 outchan4 sr advance multi callback \ - longform} { - set blocksize 64 + longform blocksize} { ::dialog_audio::pdtk_audio_dialog \ $mytoplevel $indev1 $indev2 $indev3 $indev4 \ $inchan1 $inchan2 $inchan3 $inchan4 \ diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c index 33f8ef04fccb9460cf6118e59de155ec24fefd30..1d658800025f4d158c6c16ad1423cc4cc128ec54 100644 --- a/pd/src/s_audio.c +++ b/pd/src/s_audio.c @@ -90,6 +90,11 @@ int audio_isopen(void) || (audio_naudiooutdev > 0 && audio_audiochoutdev[0] > 0))); } +int sys_audio_get_blocksize(void) +{ + return (audio_blocksize); +} + void sys_get_audio_params( int *pnaudioindev, int *paudioindev, int *chindev, int *pnaudiooutdev, int *paudiooutdev, int *choutdev, @@ -146,7 +151,6 @@ void sys_save_audio_params( audio_advance = advance; audio_callback = callback; audio_blocksize = blocksize; - fprintf(stderr,"blocksize=%d\n", blocksize); } /* init routines for any API which needs to set stuff up before @@ -421,7 +425,7 @@ void sys_reopen_audio( void) #ifdef USEAPI_PORTAUDIO if (sys_audioapi == API_PORTAUDIO) { - int blksize = (sys_blocksize ? sys_blocksize : 64); + int blksize = (audio_blocksize ? audio_blocksize : 64); outcome = pa_open_audio((naudioindev > 0 ? chindev[0] : 0), (naudiooutdev > 0 ? choutdev[0] : 0), rate, sys_soundin, sys_soundout, blksize, sys_advance_samples/blksize, @@ -441,7 +445,8 @@ void sys_reopen_audio( void) #ifdef USEAPI_OSS if (sys_audioapi == API_OSS) outcome = oss_open_audio(naudioindev, audioindev, naudioindev, - chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate); + chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, + audio_blocksize); else #endif #ifdef USEAPI_ALSA @@ -456,7 +461,25 @@ void sys_reopen_audio( void) #ifdef USEAPI_MMIO if (sys_audioapi == API_MMIO) outcome = mmio_open_audio(naudioindev, audioindev, naudioindev, + chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, + audio_blocksize); + else +#endif +#ifdef USEAPI_AUDIOUNIT + if (sys_audioapi == API_AUDIOUNIT) + outcome = audiounit_open_audio((naudioindev > 0 ? chindev[0] : 0), + (naudioindev > 0 ? choutdev[0] : 0), rate); + else +#endif +#ifdef USEAPI_ESD + if (sys_audioapi == API_ALSA) + outcome = esd_open_audio(naudioindev, audioindev, naudioindev, chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate); + else +#endif +#ifdef USEAPI_DUMMY + if (sys_audioapi == API_DUMMY) + outcome = dummy_open_audio(naudioindev, naudiooutdev, rate); else #endif if (sys_audioapi == API_NONE) @@ -735,7 +758,7 @@ void glob_audio_properties(t_pd *dummy, t_floatarg flongform) "pdtk_audio_dialog %%s \ %d %d %d %d %d %d %d %d \ %d %d %d %d %d %d %d %d \ -%d %d %d %d %d\n", +%d %d %d %d %d %d\n", audioindev1, audioindev2, audioindev3, audioindev4, audioinchan1, audioinchan2, audioinchan3, audioinchan4, audiooutdev1, audiooutdev2, audiooutdev3, audiooutdev4, diff --git a/pd/src/s_audio_mmio.c b/pd/src/s_audio_mmio.c index fd17a1ce03d0ea39d6b9d559ea174c51cb500c94..6bb1f0877b304083aaf60f6d085463b7229b1b95 100644 --- a/pd/src/s_audio_mmio.c +++ b/pd/src/s_audio_mmio.c @@ -11,7 +11,7 @@ #include <windows.h> -#include <MMSYSTEM.H> +#include <mmsystem.h> /* ------------------------- audio -------------------------- */ @@ -696,11 +696,11 @@ idle: int mmio_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, - int nchoutdev, int *choutdev, int rate) + int nchoutdev, int *choutdev, int rate, int blocksize) { int nbuf; - nt_realdacblksize = (sys_blocksize ? sys_blocksize : DEFREALDACBLKSIZE); + nt_realdacblksize = (blocksize ? blocksize : DEFREALDACBLKSIZE); nbuf = sys_advance_samples/nt_realdacblksize; if (nbuf >= MAXBUFFER) { diff --git a/pd/src/s_audio_oss.c b/pd/src/s_audio_oss.c index 8c2da61d6681783e4ec134a28e3b553fc9a0888d..f7f7a1934ab80ec9ee8a23a883c6817b3357411f 100644 --- a/pd/src/s_audio_oss.c +++ b/pd/src/s_audio_oss.c @@ -5,7 +5,14 @@ /* this file inputs and outputs audio using the OSS API available on linux. */ -#include <linux/soundcard.h> +#include <sys/soundcard.h> + +#ifndef SNDCTL_DSP_GETISPACE +#define SNDCTL_DSP_GETISPACE SOUND_PCM_GETISPACE +#endif +#ifndef SNDCTL_DSP_GETOSPACE +#define SNDCTL_DSP_GETOSPACE SOUND_PCM_GETOSPACE +#endif #include "m_pd.h" #include "s_stuff.h" @@ -41,8 +48,11 @@ typedef int32_t t_oss_int32; #define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width)) /* GLOBALS */ +static int linux_meters; /* true if we're metering */ +static t_sample linux_inmax; /* max input amplitude */ +static t_sample linux_outmax; /* max output amplitude */ static int linux_fragsize = 0; /* for block mode; block size (sample frames) */ - +extern int audio_blocksize; /* stolen from s_audio.c */ /* our device handles */ typedef struct _oss_dev @@ -67,6 +77,7 @@ t_sample *sys_soundin; /* OSS-specific private variables */ static int oss_blockmode = 1; /* flag to use "blockmode" */ +static char ossdsp[] = "/dev/dsp%d"; /* don't assume we can turn all 31 bits when doing float-to-fix; otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */ @@ -117,10 +128,12 @@ int oss_reset(int fd) { return err; } -void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) +void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize, + int suggestedblocksize) { - int orig, param, fd = dev->d_fd, wantformat; + int orig, param, nblk, fd = dev->d_fd, wantformat; int nchannels = dev->d_nchannels; + int advwas = sys_schedadvance; audio_buf_info ainfo; @@ -148,7 +161,7 @@ void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) { int fragbytes, logfragsize, nfragment; /* setting fragment count and size. */ - linux_fragsize = sys_blocksize; + linux_fragsize = suggestedblocksize; if (!linux_fragsize) { linux_fragsize = OSS_DEFFRAGSIZE; @@ -192,7 +205,7 @@ void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize) out. */ int defect; - if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0) + if (ioctl(fd, SNDCTL_DSP_GETOSPACE,&ainfo) < 0) fprintf(stderr,"OSS: ioctl on output device failed"); dev->d_bufsize = ainfo.bytes; @@ -234,7 +247,7 @@ static int oss_setchannels(int fd, int wantchannels, char *devname) } } param = wantchannels; -//whynot: +whynot: while (param > 1) { int save = param; @@ -251,15 +264,19 @@ static int oss_setchannels(int fd, int wantchannels, char *devname) #define O_AUDIOFLAG O_NDELAY int oss_open_audio(int nindev, int *indev, int nchin, int *chin, - int noutdev, int *outdev, int nchout, int *chout, int rate) + int noutdev, int *outdev, int nchout, int *chout, int rate, + int blocksize) { int capabilities = 0; int inchannels = 0, outchannels = 0; char devname[20]; int n, i, fd, flags; char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; + int num_devs = 0; int wantmore=0; - + int spread = 0; + audio_buf_info ainfo; + linux_nindevs = linux_noutdevs = 0; /* mark devices unopened */ for (i = 0; i < OSS_MAXDEV; i++) @@ -350,7 +367,7 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, { linux_dacs[linux_noutdevs].d_nchannels = gotchans; linux_dacs[linux_noutdevs].d_fd = fd; - oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0); + oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0, blocksize); linux_noutdevs++; outchannels += gotchans; @@ -425,7 +442,8 @@ int oss_open_audio(int nindev, int *indev, int nchin, int *chin, linux_adcs[linux_nindevs].d_nchannels = gotchans; - oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened); + oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened, + blocksize); inchannels += gotchans; linux_nindevs++; @@ -499,14 +517,14 @@ static void oss_calcspace(void) audio_buf_info ainfo; for (dev=0; dev < linux_noutdevs; dev++) { - if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) + if (ioctl(linux_dacs[dev].d_fd, SNDCTL_DSP_GETOSPACE, &ainfo) < 0) fprintf(stderr,"OSS: ioctl on output device %d failed",dev); linux_dacs[dev].d_space = ainfo.bytes; } for (dev = 0; dev < linux_nindevs; dev++) { - if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0) + if (ioctl(linux_adcs[dev].d_fd, SNDCTL_DSP_GETISPACE,&ainfo) < 0) fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", dev, linux_adcs[dev].d_fd); linux_adcs[dev].d_space = ainfo.bytes; @@ -533,7 +551,7 @@ in audio output and/or input. */ static void oss_doresync( void) { - int dev, zeroed = 0; + int dev, zeroed = 0, wantsize; char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; audio_buf_info ainfo; @@ -554,7 +572,7 @@ static void oss_doresync( void) linux_adcs_read(linux_adcs[dev].d_fd, buf, OSS_XFERSIZE(linux_adcs[dev].d_nchannels, linux_adcs[dev].d_bytespersamp)); - if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0) + if (ioctl(linux_adcs[dev].d_fd, SNDCTL_DSP_GETISPACE, &ainfo) < 0) { fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed", dev, linux_adcs[dev].d_fd); @@ -583,7 +601,7 @@ static void oss_doresync( void) linux_dacs_write(linux_dacs[dev].d_fd, buf, OSS_XFERSIZE(linux_dacs[dev].d_nchannels, linux_dacs[dev].d_bytespersamp)); - if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0) + if (ioctl(linux_dacs[dev].d_fd, SNDCTL_DSP_GETOSPACE, &ainfo) < 0) { fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed", dev, linux_dacs[dev].d_fd); @@ -612,9 +630,11 @@ static void oss_doresync( void) int oss_send_dacs(void) { t_sample *fp1, *fp2; + long fill; int i, j, dev, rtnval = SENDDACS_YES; char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV]; t_oss_int16 *sp; + t_oss_int32 *lp; /* the maximum number of samples we should have in the ADC buffer */ int idle = 0; int thischan; @@ -655,6 +675,7 @@ int oss_send_dacs(void) for (dev = 0;dev < linux_nindevs; dev++) if (linux_adcs[dev].d_space == 0) { + audio_buf_info ainfo; sys_microsleep(2000); oss_calcspace(); if (linux_adcs[dev].d_space != 0) continue; diff --git a/pd/src/s_audio_pa.c b/pd/src/s_audio_pa.c index de5fe711b46e8f836a33d710529507b5d6af810f..d87770a1154526edb1a2aff1ee393ebeaef8558c 100644 --- a/pd/src/s_audio_pa.c +++ b/pd/src/s_audio_pa.c @@ -4,63 +4,114 @@ /* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's the main way in for Mac OS and, with Michael Casey's help, also into - ASIO in Windows. */ + ASIO in Windows. + + Both blocking and non-blocking call styles are supported. If non-blocking + is requested, either we call portaudio in non-blocking mode, or else we + call portaudio in callback mode and manage our own FIFO se we can offer + Pd "blocking" I/O calls. To do the latter we define FAKEBLOCKING; this + works better in MAXOSX (gets 40 msec lower latency!) and might also in + Windows. If FAKEBLOCKING is defined we can choose between two methods + for waiting on the (presumebly other-thread) I/O to complete, either + correct thread synchronization (by defining THREADSIGNAL) or just sleeping + and polling; the latter seems to work better so far. +*/ +/* dolist... + switch to usleep in s_inter.c +*/ #include "m_pd.h" #include "s_stuff.h" #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <portaudio.h> -#include "s_audio_pablio.h" -#ifdef MSW -#include <malloc.h> + +#ifdef _MSC_VER +#define snprintf sprintf_s +#endif + +#ifndef _WIN32 /* for the "dup2" workaround -- do we still need it? */ +#include <unistd.h> +#endif + +#ifdef HAVE_ALLOCA_H /* ifdef nonsense to find include for alloca() */ +# include <alloca.h> /* linux, mac, mingw, cygwin */ +#elif defined _MSC_VER +# include <malloc.h> /* MSVC */ #else -#include <alloca.h> +# include <stddef.h> /* BSDs for example */ +#endif /* end alloca() ifdef nonsense */ + +#if 1 +#define FAKEBLOCKING #endif +#if defined (FAKEBLOCKING) && defined(_WIN32) +#include <windows.h> /* for Sleep() */ +#endif + +/* define this to enable thread signaling instead of polling */ +/* #define THREADSIGNAL */ + /* LATER try to figure out how to handle default devices in portaudio; the way s_audio.c handles them isn't going to work here. */ /* public interface declared in m_imp.h */ /* implementation */ -static PABLIO_Stream *pa_stream; +static PaStream *pa_stream; static int pa_inchans, pa_outchans; static float *pa_soundin, *pa_soundout; static t_audiocallback pa_callback; -int pa_foo; +static int pa_started; +static int pa_nbuffers; +static int pa_dio_error; -#ifndef MSW -#include <unistd.h> -#endif -static void pa_init(void) +#ifdef FAKEBLOCKING +#include "s_audio_paring.h" +static PA_VOLATILE char *pa_outbuf; +static PA_VOLATILE sys_ringbuf pa_outring; +static PA_VOLATILE char *pa_inbuf; +static PA_VOLATILE sys_ringbuf pa_inring; +#ifdef THREADSIGNAL +#include <pthread.h> +pthread_mutex_t pa_mutex; +pthread_cond_t pa_sem; +#endif /* THREADSIGNAL */ +#endif /* FAKEBLOCKING */ + +static void pa_init(void) /* Initialize PortAudio */ { static int initialized; if (!initialized) { -#ifndef MSW - /* Initialize PortAudio */ - /* for some reason Pa_Initialize(0 closes file descriptor 1. - As a workaround, dup it to another number and dup2 it back - afterward. */ +#ifdef __APPLE__ + /* for some reason, on the Mac Pa_Initialize() closes file descriptor + 1 (standard output) As a workaround, dup it to another number and dup2 + it back afterward. */ int newfd = dup(1); + int another = open("/dev/null", 0); + dup2(another, 1); int err = Pa_Initialize(); + close(1); + close(another); if (newfd >= 0) { + fflush(stdout); dup2(newfd, 1); close(newfd); } #else int err = Pa_Initialize(); #endif + + if ( err != paNoError ) { - fprintf( stderr, - "Error number %d occured initializing portaudio\n", - err); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + post("Error opening audio: %s", err, Pa_GetErrorText(err)); return; } initialized = 1; @@ -68,120 +119,207 @@ static void pa_init(void) } static int pa_lowlevel_callback(const void *inputBuffer, - void *outputBuffer, unsigned long framesPerBuffer, + void *outputBuffer, unsigned long nframes, const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, void *userData) { int i; - unsigned int j; + unsigned int n, j; float *fbuf, *fp2, *fp3, *soundiop; - if (pa_foo) - fprintf(stderr, "pa_lowlevel_callback\n"); - if (framesPerBuffer != DEFDACBLKSIZE) + if (nframes % DEFDACBLKSIZE) { - fprintf(stderr, "ignoring buffer size %d\n", (int)framesPerBuffer); - return 0; + post("warning: audio nframes %ld not a multiple of blocksize %d", + nframes, (int)DEFDACBLKSIZE); + nframes -= (nframes % DEFDACBLKSIZE); } - if (inputBuffer != NULL) + for (n = 0; n < nframes; n += DEFDACBLKSIZE) { - fbuf = (float *)inputBuffer; - soundiop = pa_soundin; - for (i = 0, fp2 = fbuf; i < pa_inchans; i++, fp2++) - for (j = 0, fp3 = fp2; j < framesPerBuffer; j++, fp3 += pa_inchans) - *soundiop++ = *fp3; + if (inputBuffer != NULL) + { + fbuf = ((float *)inputBuffer) + n*pa_inchans; + soundiop = pa_soundin; + for (i = 0, fp2 = fbuf; i < pa_inchans; i++, fp2++) + for (j = 0, fp3 = fp2; j < DEFDACBLKSIZE; + j++, fp3 += pa_inchans) + *soundiop++ = *fp3; + } + else memset((void *)pa_soundin, 0, + DEFDACBLKSIZE * pa_inchans * sizeof(float)); + memset((void *)pa_soundout, 0, + DEFDACBLKSIZE * pa_outchans * sizeof(float)); + (*pa_callback)(); + if (outputBuffer != NULL) + { + fbuf = ((float *)outputBuffer) + n*pa_outchans; + soundiop = pa_soundout; + for (i = 0, fp2 = fbuf; i < pa_outchans; i++, fp2++) + for (j = 0, fp3 = fp2; j < DEFDACBLKSIZE; + j++, fp3 += pa_outchans) + *fp3 = *soundiop++; + } } - else memset((void *)pa_soundin, 0, - framesPerBuffer * pa_inchans * sizeof(float)); - memset((void *)pa_soundout, 0, - framesPerBuffer * pa_outchans * sizeof(float)); - (*pa_callback)(); - if (outputBuffer != NULL) + return 0; +} + +#ifdef FAKEBLOCKING + /* callback for "non-callback" case in which we actualy open portaudio + in callback mode but fake "blocking mode". We communicate with the + main thread via FIFO. First read the audio output FIFO (which + we sync on, not waiting for it but supplying zeros to the audio output if + there aren't enough samples in the FIFO when we are called), then write + to the audio input FIFO. The main thread will wait for the input fifo. + We can either throw it a pthreads condition or just allow the main thread + to poll for us; so far polling seems to work better. */ +static int pa_fifo_callback(const void *inputBuffer, + void *outputBuffer, unsigned long nframes, + const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags, + void *userData) +{ + /* callback routine for non-callback client... throw samples into + and read them out of a FIFO */ + int ch; + long fiforoom; + float *fbuf; + +#if CHECKFIFOS + if (pa_inchans * sys_ringbuf_getreadavailable(&pa_outring) != + pa_outchans * sys_ringbuf_getwriteavailable(&pa_inring)) + post("warning: in and out rings unequal (%d, %d)", + sys_ringbuf_getreadavailable(&pa_outring), + sys_ringbuf_getwriteavailable(&pa_inring)); +#endif + fiforoom = sys_ringbuf_getreadavailable(&pa_outring); + if ((unsigned)fiforoom >= nframes*pa_outchans*sizeof(float)) { - fbuf = (float *)outputBuffer; - soundiop = pa_soundout; - for (i = 0, fp2 = fbuf; i < pa_outchans; i++, fp2++) - for (j = 0, fp3 = fp2; j < framesPerBuffer; j++, fp3 += pa_outchans) - *fp3 = *soundiop++; + if (outputBuffer) + sys_ringbuf_read(&pa_outring, outputBuffer, + nframes*pa_outchans*sizeof(float), pa_outbuf); + else if (pa_outchans) + post("audio error: no outputBuffer but output channels"); + if (inputBuffer) + sys_ringbuf_write(&pa_inring, inputBuffer, + nframes*pa_inchans*sizeof(float), pa_inbuf); + else if (pa_inchans) + post("audio error: no inputBuffer but input channels"); + } + else + { /* PD could not keep up; generate zeros */ + if (pa_started) + pa_dio_error = 1; + if (outputBuffer) + { + for (ch = 0; ch < pa_outchans; ch++) + { + unsigned long frame; + fbuf = ((float *)outputBuffer) + ch; + for (frame = 0; frame < nframes; frame++, fbuf += pa_outchans) + *fbuf = 0; + } + } } - if (pa_foo) - fprintf(stderr, "done pa_lowlevel_callback\n"); +#ifdef THREADSIGNAL + pthread_mutex_lock(&pa_mutex); + pthread_cond_signal(&pa_sem); + pthread_mutex_unlock(&pa_mutex); +#endif return 0; } +#endif /* FAKEBLOCKING */ PaError pa_open_callback(double sampleRate, int inchannels, int outchannels, - int framesperbuf, int nbuffers, int indeviceno, int outdeviceno) + int framesperbuf, int nbuffers, int indeviceno, int outdeviceno, PaStreamCallback *callbackfn) { long bytesPerSample; PaError err; - PABLIO_Stream *pastream; - long numFrames; PaStreamParameters instreamparams, outstreamparams; + PaStreamParameters*p_instreamparams=0, *p_outstreamparams=0; - if (indeviceno < 0) - { - indeviceno = Pa_GetDefaultInputDevice(); - fprintf(stderr, "using default input device number: %d\n", indeviceno); - } - if (outdeviceno < 0) - { - outdeviceno = Pa_GetDefaultOutputDevice(); - fprintf(stderr, "using default output device number: %d\n", outdeviceno); - } /* fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n", nchannels, flags, nbuffers, framesperbuf); */ - /* Allocate PABLIO_Stream structure for caller. */ - pastream = (PABLIO_Stream *)malloc( sizeof(PABLIO_Stream)); - if (pastream == NULL) - return (1); - memset(pastream, 0, sizeof(PABLIO_Stream)); - - /* Determine size of a sample. */ - bytesPerSample = Pa_GetSampleSize(paFloat32); - if (bytesPerSample < 0) - { - err = (PaError) bytesPerSample; - goto error; - } - pastream->insamplesPerFrame = inchannels; - pastream->inbytesPerFrame = bytesPerSample * pastream->insamplesPerFrame; - pastream->outsamplesPerFrame = outchannels; - pastream->outbytesPerFrame = bytesPerSample * pastream->outsamplesPerFrame; - - numFrames = nbuffers * framesperbuf; - instreamparams.device = indeviceno; instreamparams.channelCount = inchannels; instreamparams.sampleFormat = paFloat32; - instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate; instreamparams.hostApiSpecificStreamInfo = 0; outstreamparams.device = outdeviceno; outstreamparams.channelCount = outchannels; outstreamparams.sampleFormat = paFloat32; - outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate; outstreamparams.hostApiSpecificStreamInfo = 0; +#ifdef FAKEBLOCKING + instreamparams.suggestedLatency = outstreamparams.suggestedLatency = 0; +#else + instreamparams.suggestedLatency = outstreamparams.suggestedLatency = + nbuffers*framesperbuf/sampleRate; +#endif /* FAKEBLOCKING */ + + if( inchannels>0 && indeviceno >= 0) + p_instreamparams=&instreamparams; + if( outchannels>0 && outdeviceno >= 0) + p_outstreamparams=&outstreamparams; + + err=Pa_IsFormatSupported(p_instreamparams, p_outstreamparams, sampleRate); + + if (paFormatIsSupported != err) + { + /* check whether we have to change the numbers of channel and/or samplerate */ + const PaDeviceInfo* info = 0; + double inRate=0, outRate=0; + + if (inchannels>0) + { + if (NULL != (info = Pa_GetDeviceInfo( instreamparams.device ))) + { + inRate=info->defaultSampleRate; + + if(info->maxInputChannels<inchannels) + instreamparams.channelCount=info->maxInputChannels; + } + } + + if (outchannels>0) + { + if (NULL != (info = Pa_GetDeviceInfo( outstreamparams.device ))) + { + outRate=info->defaultSampleRate; + + if(info->maxOutputChannels<outchannels) + outstreamparams.channelCount=info->maxOutputChannels; + } + } + + if (err == paInvalidSampleRate) + { + sampleRate=outRate; + } + + err=Pa_IsFormatSupported(p_instreamparams, p_outstreamparams, + sampleRate); + if (paFormatIsSupported != err) + goto error; + } err = Pa_OpenStream( - &pastream->stream, - (inchannels ? &instreamparams : 0), - (outchannels ? &outstreamparams : 0), + &pa_stream, + p_instreamparams, + p_outstreamparams, sampleRate, - DEFDACBLKSIZE, + framesperbuf, paNoFlag, /* portaudio will clip for us */ - pa_lowlevel_callback, - pastream); + callbackfn, + 0); if (err != paNoError) goto error; - err = Pa_StartStream(pastream->stream); + err = Pa_StartStream(pa_stream); if (err != paNoError) { - fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n"); - CloseAudioStream( pastream ); + post("error opening failed; closing audio stream: %s", + Pa_GetErrorText(err)); + pa_close_audio(); goto error; } - pa_stream = pastream; + sys_dacsr=sampleRate; return paNoError; error: pa_stream = NULL; @@ -193,13 +331,16 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, int indeviceno, int outdeviceno, t_audiocallback callbackfn) { PaError err; - int j, devno, pa_indev = 0, pa_outdev = 0; + int j, devno, pa_indev = -1, pa_outdev = -1; pa_callback = callbackfn; /* fprintf(stderr, "open callback %d\n", (callbackfn != 0)); */ pa_init(); /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ + if (pa_stream) + pa_close_audio(); + if (inchans > 0) { for (j = 0, devno = 0; j < Pa_GetDeviceCount(); j++) @@ -209,6 +350,9 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, { if (devno == indeviceno) { + if (inchans > info->maxInputChannels) + inchans = info->maxInputChannels; + pa_indev = j; break; } @@ -226,6 +370,9 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, { if (devno == outdeviceno) { + if (outchans > info->maxOutputChannels) + outchans = info->maxOutputChannels; + pa_outdev = j; break; } @@ -234,36 +381,68 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, } } + if (inchans > 0 && pa_indev == -1) + inchans = 0; + if (outchans > 0 && pa_outdev == -1) + outchans = 0; + if (sys_verbose) { post("input device %d, channels %d", pa_indev, inchans); post("output device %d, channels %d", pa_outdev, outchans); post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers); + post("rate %d", rate); } - pa_inchans = inchans; - pa_outchans = outchans; + pa_inchans = sys_inchannels = inchans; + pa_outchans = sys_outchannels = outchans; pa_soundin = soundin; pa_soundout = soundout; + +#ifdef FAKEBLOCKING + if (pa_inbuf) + free((char *)pa_inbuf), pa_inbuf = 0; + if (pa_outbuf) + free((char *)pa_outbuf), pa_outbuf = 0; +#endif + if (! inchans && !outchans) - return(0); + return (0); + if (callbackfn) { pa_callback = callbackfn; err = pa_open_callback(rate, inchans, outchans, - framesperbuf, nbuffers, pa_indev, pa_outdev); + framesperbuf, nbuffers, pa_indev, pa_outdev, pa_lowlevel_callback); } else { - err = OpenAudioStream( &pa_stream, rate, paFloat32, - inchans, outchans, framesperbuf, nbuffers, - pa_indev, pa_outdev); +#ifdef FAKEBLOCKING + if (pa_inchans) + { + pa_inbuf = malloc(nbuffers*framesperbuf*pa_inchans*sizeof(float)); + sys_ringbuf_init(&pa_inring, + nbuffers*framesperbuf*pa_inchans*sizeof(float), pa_inbuf, + nbuffers*framesperbuf*pa_inchans*sizeof(float)); + } + if (pa_outchans) + { + pa_outbuf = malloc(nbuffers*framesperbuf*pa_outchans*sizeof(float)); + sys_ringbuf_init(&pa_outring, + nbuffers*framesperbuf*pa_outchans*sizeof(float), pa_outbuf, 0); + } + err = pa_open_callback(rate, inchans, outchans, + framesperbuf, nbuffers, pa_indev, pa_outdev, pa_fifo_callback); +#else + err = pa_open_callback(rate, inchans, outchans, + framesperbuf, nbuffers, pa_indev, pa_outdev, 0); +#endif } + pa_started = 0; + pa_nbuffers = nbuffers; if ( err != paNoError ) { - fprintf(stderr, "Error number %d opening portaudio stream\n", - err); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - Pa_Terminate(); + post("Error opening audio: %s", Pa_GetErrorText(err)); + /* Pa_Terminate(); */ return (1); } else if (sys_verbose) @@ -273,132 +452,142 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, void pa_close_audio( void) { - /* fprintf(stderr, "close\n"); */ - if (pa_inchans || pa_outchans) - CloseAudioStream( pa_stream ); - pa_inchans = pa_outchans = 0; + if (pa_stream) + { + Pa_AbortStream(pa_stream); + Pa_CloseStream(pa_stream); + } + pa_stream = 0; +#ifdef FAKEBLOCKING + if (pa_inbuf) + free((char *)pa_inbuf), pa_inbuf = 0; + if (pa_outbuf) + free((char *)pa_outbuf), pa_outbuf = 0; +#endif } int pa_send_dacs(void) { - unsigned int framesize = (sizeof(float) * DEFDACBLKSIZE) * - (pa_inchans > pa_outchans ? pa_inchans:pa_outchans); - float *samples, *fp1, *fp2; - int i, j; + t_sample *fp; + float *fp2, *fp3; + float *conversionbuf; + int j, k; + int rtnval = SENDDACS_YES; +#ifndef FAKEBLOCKING double timebefore; - - - samples = alloca(framesize); - - timebefore = sys_getrealtime(); - if ((pa_inchans && GetAudioStreamReadable(pa_stream) < DEFDACBLKSIZE) || - (pa_outchans && GetAudioStreamWriteable(pa_stream) < DEFDACBLKSIZE)) +#endif /* FAKEBLOCKING */ + if (!sys_inchannels && !sys_outchannels || !pa_stream) + return (SENDDACS_NO); + conversionbuf = (float *)alloca((sys_inchannels > sys_outchannels? + sys_inchannels:sys_outchannels) * DEFDACBLKSIZE * sizeof(float)); + +#ifdef FAKEBLOCKING + if (!sys_inchannels) /* if no input channels sync on output */ { - if (pa_inchans && pa_outchans) +#ifdef THREADSIGNAL + pthread_mutex_lock(&pa_mutex); +#endif + while (sys_ringbuf_getwriteavailable(&pa_outring) < + (long)(sys_outchannels * DEFDACBLKSIZE * sizeof(float))) { - int synced = 0; - while (GetAudioStreamWriteable(pa_stream) > 2*DEFDACBLKSIZE) - { - for (j = 0; j < pa_outchans; j++) - for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++, - fp2 += pa_outchans) - { - *fp2 = 0; - } - synced = 1; - WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE); - } - while (GetAudioStreamReadable(pa_stream) > 2*DEFDACBLKSIZE) - { - synced = 1; - ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE); - } - /* if (synced) - post("sync"); */ + rtnval = SENDDACS_SLEPT; +#ifdef THREADSIGNAL + pthread_cond_wait(&pa_sem, &pa_mutex); +#else +#ifdef _WIN32 + Sleep(1); +#else + usleep(1000); +#endif /* _WIN32 */ +#endif /* THREADSIGNAL */ } - return (SENDDACS_NO); +#ifdef THREADSIGNAL + pthread_mutex_unlock(&pa_mutex); +#endif } - if (pa_inchans) + /* write output */ + if (sys_outchannels) { - ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE); - for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE) - for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++, - fp2 += pa_inchans) - { - fp1[i] = *fp2; - } + for (j = 0, fp = sys_soundout, fp2 = conversionbuf; + j < sys_outchannels; j++, fp2++) + for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; + k++, fp++, fp3 += sys_outchannels) + *fp3 = *fp; + sys_ringbuf_write(&pa_outring, conversionbuf, + sys_outchannels*(DEFDACBLKSIZE*sizeof(float)), pa_outbuf); } -#if 0 + if (sys_inchannels) /* if there is input sync on it */ + { +#ifdef THREADSIGNAL + pthread_mutex_lock(&pa_mutex); +#endif + while (sys_ringbuf_getreadavailable(&pa_inring) < + (long)(sys_inchannels * DEFDACBLKSIZE * sizeof(float))) { - static int nread; - if (nread == 0) - { - post("it's %f %f %f %f", - pa_soundin[0], pa_soundin[1], pa_soundin[2], pa_soundin[3]); - nread = 1000; - } - nread--; + rtnval = SENDDACS_SLEPT; +#ifdef THREADSIGNAL + pthread_cond_wait(&pa_sem, &pa_mutex); +#else +#ifdef _WIN32 + Sleep(1); +#else + usleep(1000); +#endif /* _WIN32 */ +#endif /* THREADSIGNAL */ } +#ifdef THREADSIGNAL + pthread_mutex_unlock(&pa_mutex); #endif - if (pa_outchans) + } + if (sys_inchannels) { - for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++, - fp1 += DEFDACBLKSIZE) - for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++, - fp2 += pa_outchans) - { - *fp2 = fp1[i]; - fp1[i] = 0; - } - WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE); + sys_ringbuf_read(&pa_inring, conversionbuf, + sys_inchannels*(DEFDACBLKSIZE*sizeof(float)), pa_inbuf); + for (j = 0, fp = sys_soundin, fp2 = conversionbuf; + j < sys_inchannels; j++, fp2++) + for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; + k++, fp++, fp3 += sys_inchannels) + *fp = *fp3; } - if (sys_getrealtime() > timebefore + 0.002) +#else /* FAKEBLOCKING */ + timebefore = sys_getrealtime(); + /* write output */ + if (sys_outchannels) { - /* post("slept"); */ - return (SENDDACS_SLEPT); + if (!pa_started) + { + memset(conversionbuf, 0, + sys_outchannels * DEFDACBLKSIZE * sizeof(float)); + for (j = 0; j < pa_nbuffers-1; j++) + Pa_WriteStream(pa_stream, conversionbuf, DEFDACBLKSIZE); + } + for (j = 0, fp = sys_soundout, fp2 = conversionbuf; + j < sys_outchannels; j++, fp2++) + for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; + k++, fp++, fp3 += sys_outchannels) + *fp3 = *fp; + Pa_WriteStream(pa_stream, conversionbuf, DEFDACBLKSIZE); } - else return (SENDDACS_YES); -} - -void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */ -{ - int i,j; - int numDevices; - const PaDeviceInfo *pdi; - PaError err; - pa_init(); - numDevices = Pa_GetDeviceCount(); - if( numDevices < 0 ) + if (sys_inchannels) { - fprintf(stderr, "ERROR: Pa_GetDeviceCount returned %d\n", numDevices ); - err = numDevices; - goto error; + Pa_ReadStream(pa_stream, conversionbuf, DEFDACBLKSIZE); + for (j = 0, fp = sys_soundin, fp2 = conversionbuf; + j < sys_inchannels; j++, fp2++) + for (k = 0, fp3 = fp2; k < DEFDACBLKSIZE; + k++, fp++, fp3 += sys_inchannels) + *fp = *fp3; } - fprintf(stderr, "Audio Devices:\n"); - for( i=0; i<numDevices; i++ ) + if (sys_getrealtime() - timebefore > 0.002) { - pdi = Pa_GetDeviceInfo( i ); - fprintf(stderr, "device %d:", i+1 ); - fprintf(stderr, " %s;", pdi->name ); - fprintf(stderr, "%d inputs, ", pdi->maxInputChannels ); - fprintf(stderr, "%d outputs", pdi->maxOutputChannels ); - if ( i == Pa_GetDefaultInputDevice() ) - fprintf(stderr, " (Default Input)"); - if ( i == Pa_GetDefaultOutputDevice() ) - fprintf(stderr, " (Default Output)"); - fprintf(stderr, "\n"); + rtnval = SENDDACS_SLEPT; } +#endif /* FAKEBLOCKING */ + pa_started = 1; - fprintf(stderr, "\n"); - return; - -error: - fprintf( stderr, "An error occured while using the portaudio stream\n" ); - fprintf( stderr, "Error number: %d\n", err ); - fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); - + memset(sys_soundout, 0, DEFDACBLKSIZE*sizeof(t_sample)*sys_outchannels); + return (rtnval); } /* scanning for devices */ @@ -416,16 +605,33 @@ void pa_getdevs(char *indevlist, int *nindevs, const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i); if (pdi->maxInputChannels > 0 && nin < maxndev) { - sprintf(indevlist + nin * devdescsize, "(%d)%s", - pdi->hostApi,pdi->name); - /* strcpy(indevlist + nin * devdescsize, pdi->name); */ + /* LATER figure out how to get API name correctly */ + snprintf(indevlist + nin * devdescsize, devdescsize, +#ifdef _WIN32 + "%s:%s", (pdi->hostApi == 0 ? "MMIO" : (pdi->hostApi == 1 ? "ASIO" : "?")), +#else +#ifdef __APPLE__ + "%s", +#else + "(%d) %s", pdi->hostApi, +#endif +#endif + pdi->name); nin++; } if (pdi->maxOutputChannels > 0 && nout < maxndev) { - sprintf(outdevlist + nout * devdescsize, "(%d)%s", - pdi->hostApi,pdi->name); - /* strcpy(outdevlist + nout * devdescsize, pdi->name); */ + snprintf(outdevlist + nout * devdescsize, devdescsize, +#ifdef _WIN32 + "%s:%s", (pdi->hostApi == 0 ? "MMIO" : (pdi->hostApi == 1 ? "ASIO" : "?")), +#else +#ifdef __APPLE__ + "%s", +#else + "(%d) %s", pdi->hostApi, +#endif +#endif + pdi->name); nout++; } } diff --git a/pd/src/s_audio_pablio.c b/pd/src/s_audio_pablio.c deleted file mode 100644 index 0873f269402d6a440f6ed65bf287f3caef79d1a4..0000000000000000000000000000000000000000 --- a/pd/src/s_audio_pablio.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - - * pablio.c - * Portable Audio Blocking Input/Output utility. - * - * Author: Phil Burk, http://www.softsynth.com - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: http://www.audiomulch.com/portaudio/ - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - - /* changes by Miller Puckette to support Pd: device selection, - settable audio buffer size, and settable number of channels. - LATER also fix it to poll for input and output fifo fill points. */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include "portaudio.h" -#include "s_audio_paring.h" -#include "s_audio_pablio.h" /* MSP */ -#include <string.h> - - /* MSP -- FRAMES_PER_BUFFER constant removed */ -static void NPa_Sleep(int n) /* MSP wrapper to check we never stall... */ -{ -#if 0 - fprintf(stderr, "sleep\n"); -#endif - Pa_Sleep(n); -} - -/************************************************************************/ -/******** Prototypes ****************************************************/ -/************************************************************************/ - -static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, /*MSP */ - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *outTime, - PaStreamCallbackFlags myflags, - void *userData ); -static PaError PABLIO_InitFIFO( sys_ringbuf *rbuf, long numFrames, long bytesPerFrame ); -static PaError PABLIO_TermFIFO( sys_ringbuf *rbuf ); - -/************************************************************************/ -/******** Functions *****************************************************/ -/************************************************************************/ - -/* Called from PortAudio. - * Read and write data only if there is room in FIFOs. - */ -static int blockingIOCallback( const void *inputBuffer, void *outputBuffer, /* MSP */ - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo *outTime, - PaStreamCallbackFlags myflags, - void *userData ) -{ - PABLIO_Stream *data = (PABLIO_Stream*)userData; - (void) outTime; - - /* This may get called with NULL inputBuffer during initial setup. */ - if( inputBuffer != NULL ) - { - sys_ringbuf_Write( &data->inFIFO, inputBuffer, - data->inbytesPerFrame * framesPerBuffer ); - } - if( outputBuffer != NULL ) - { - int i; - int numBytes = data->outbytesPerFrame * framesPerBuffer; - int numRead = sys_ringbuf_Read( &data->outFIFO, outputBuffer, - numBytes); - /* Zero out remainder of buffer if we run out of data. */ - for( i=numRead; i<numBytes; i++ ) - { - ((char *)outputBuffer)[i] = 0; - } - } - - return 0; -} - -/* Allocate buffer. */ -static PaError PABLIO_InitFIFO( sys_ringbuf *rbuf, long numFrames, long bytesPerFrame ) -{ - long numBytes = numFrames * bytesPerFrame; - char *buffer = (char *) malloc( numBytes ); - if( buffer == NULL ) return paInsufficientMemory; - memset( buffer, 0, numBytes ); - return (PaError) sys_ringbuf_Init( rbuf, numBytes, buffer ); -} - -/* Free buffer. */ -static PaError PABLIO_TermFIFO( sys_ringbuf *rbuf ) -{ - if( rbuf->buffer ) free( rbuf->buffer ); - rbuf->buffer = NULL; - return paNoError; -} - -/************************************************************ - * Write data to ring buffer. - * Will not return until all the data has been written. - */ -long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) -{ - long bytesWritten; - char *p = (char *) data; - long numBytes = aStream->outbytesPerFrame * numFrames; - while( numBytes > 0) - { - bytesWritten = sys_ringbuf_Write( &aStream->outFIFO, p, numBytes ); - numBytes -= bytesWritten; - p += bytesWritten; - if( numBytes > 0) NPa_Sleep(10); /* MSP */ - } - return numFrames; -} - -/************************************************************ - * Read data from ring buffer. - * Will not return until all the data has been read. - */ -long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ) -{ - long bytesRead; - char *p = (char *) data; - long numBytes = aStream->inbytesPerFrame * numFrames; - while( numBytes > 0) - { - bytesRead = sys_ringbuf_Read( &aStream->inFIFO, p, numBytes ); - numBytes -= bytesRead; - p += bytesRead; - if( numBytes > 0) NPa_Sleep(10); /* MSP */ - } - return numFrames; -} - -/************************************************************ - * Return the number of frames that could be written to the stream without - * having to wait. - */ -long GetAudioStreamWriteable( PABLIO_Stream *aStream ) -{ - int bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO ); - return bytesEmpty / aStream->outbytesPerFrame; -} - -/************************************************************ - * Return the number of frames that are available to be read from the - * stream without having to wait. - */ -long GetAudioStreamReadable( PABLIO_Stream *aStream ) -{ - int bytesFull = sys_ringbuf_GetReadAvailable( &aStream->inFIFO ); - return bytesFull / aStream->inbytesPerFrame; -} - -/************************************************************/ -static unsigned long RoundUpToNextPowerOf2( unsigned long n ) -{ - long numBits = 0; - if( ((n-1) & n) == 0) return n; /* Already Power of two. */ - while( n > 0 ) - { - n= n>>1; - numBits++; - } - return (1<<numBits); -} - -/************************************************************ - * Opens a PortAudio stream with default characteristics. - * Allocates PABLIO_Stream structure. - * - * flags parameter can be an ORed combination of: - * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE - */ -PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate, - PaSampleFormat format, int inchannels, - int outchannels, int framesperbuf, int nbuffers, - int indeviceno, int outdeviceno) /* MSP */ -{ - long bytesPerSample; - long doRead = 0; - long doWrite = 0; - PaError err; - PABLIO_Stream *aStream; - long numFrames; - PaStreamParameters instreamparams, outstreamparams; /* MSP */ - - /* fprintf(stderr, - "open %lf fmt %d flags %d ch: %d fperbuf: %d nbuf: %d devs: %d %d\n", - sampleRate, format, flags, nchannels, - framesperbuf, nbuffers, indeviceno, outdeviceno); */ - - if (indeviceno < 0) /* MSP... */ - { - indeviceno = Pa_GetDefaultInputDevice(); - fprintf(stderr, "using default input device number: %d\n", indeviceno); - } - if (outdeviceno < 0) - { - outdeviceno = Pa_GetDefaultOutputDevice(); - fprintf(stderr, "using default output device number: %d\n", outdeviceno); - } - /* fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n", - nchannels, flags, nbuffers, framesperbuf); */ - /* ...MSP */ - - /* Allocate PABLIO_Stream structure for caller. */ - aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) ); - if( aStream == NULL ) return paInsufficientMemory; - memset( aStream, 0, sizeof(PABLIO_Stream) ); - - /* Determine size of a sample. */ - bytesPerSample = Pa_GetSampleSize( format ); - if( bytesPerSample < 0 ) - { - err = (PaError) bytesPerSample; - goto error; - } - aStream->insamplesPerFrame = inchannels; /* MSP */ - aStream->inbytesPerFrame = bytesPerSample * aStream->insamplesPerFrame; - aStream->outsamplesPerFrame = outchannels; - aStream->outbytesPerFrame = bytesPerSample * aStream->outsamplesPerFrame; - - /* Initialize PortAudio */ - err = Pa_Initialize(); - if( err != paNoError ) goto error; - - numFrames = nbuffers * framesperbuf; /* ...MSP */ - - instreamparams.device = indeviceno; /* MSP... */ - instreamparams.channelCount = inchannels; - instreamparams.sampleFormat = format; - instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate; - instreamparams.hostApiSpecificStreamInfo = 0; - - outstreamparams.device = outdeviceno; - outstreamparams.channelCount = outchannels; - outstreamparams.sampleFormat = format; - outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate; - outstreamparams.hostApiSpecificStreamInfo = 0; /* ... MSP */ - - numFrames = nbuffers * framesperbuf; - /* fprintf(stderr, "numFrames %d\n", numFrames); */ - /* Initialize Ring Buffers */ - doRead = (inchannels != 0); - doWrite = (outchannels != 0); - if(doRead) - { - err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, - aStream->inbytesPerFrame ); - if( err != paNoError ) goto error; - } - if(doWrite) - { - long numBytes; - err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, - aStream->outbytesPerFrame ); - if( err != paNoError ) goto error; - /* Make Write FIFO appear full initially. */ - numBytes = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO ); - sys_ringbuf_AdvanceWriteIndex( &aStream->outFIFO, numBytes ); - } - - /* Open a PortAudio stream that we will use to communicate with the underlying - * audio drivers. */ - err = Pa_OpenStream( - &aStream->stream, - (doRead ? &instreamparams : 0), /* MSP */ - (doWrite ? &outstreamparams : 0), /* MSP */ - sampleRate, - framesperbuf, /* MSP */ - paNoFlag, /* MSP -- portaudio will clip for us */ - blockingIOCallback, - aStream ); - if( err != paNoError ) goto error; - - err = Pa_StartStream( aStream->stream ); - if( err != paNoError ) /* MSP */ - { - fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n"); - CloseAudioStream( aStream ); - goto error; - } - - *rwblPtr = aStream; - return paNoError; - -error: - *rwblPtr = NULL; - return err; -} - -/************************************************************/ -PaError CloseAudioStream( PABLIO_Stream *aStream ) -{ - PaError err; - int bytesEmpty; - int byteSize = aStream->outFIFO.bufferSize; - - /* If we are writing data, make sure we play everything written. */ - if( byteSize > 0 ) - { - bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO ); - while( bytesEmpty < byteSize ) - { - NPa_Sleep( 10 ); /* MSP */ - bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO ); - } - } - - err = Pa_StopStream( aStream->stream ); - if( err != paNoError ) goto error; - err = Pa_CloseStream( aStream->stream ); - if( err != paNoError ) goto error; - Pa_Terminate(); - -error: - PABLIO_TermFIFO( &aStream->inFIFO ); - PABLIO_TermFIFO( &aStream->outFIFO ); - free( aStream ); - return err; -} diff --git a/pd/src/s_audio_pablio.h b/pd/src/s_audio_pablio.h deleted file mode 100644 index f4d3261460a9562305ba9db4033445a99fc6abf9..0000000000000000000000000000000000000000 --- a/pd/src/s_audio_pablio.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _PABLIO_H -#define _PABLIO_H - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -/* - * PABLIO.h - * Portable Audio Blocking read/write utility. - * - * Author: Phil Burk, http://www.softsynth.com/portaudio/ - * - * Include file for PABLIO, the Portable Audio Blocking I/O Library. - * PABLIO is built on top of PortAudio, the Portable Audio Library. - * For more information see: http://www.audiomulch.com/portaudio/ - * Copyright (c) 1999-2000 Ross Bencina and Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include "portaudio.h" -#include "s_audio_paring.h" -#include <string.h> - -typedef struct -{ - sys_ringbuf inFIFO; - sys_ringbuf outFIFO; - PaStream *stream; - int inbytesPerFrame; - int insamplesPerFrame; - int outbytesPerFrame; - int outsamplesPerFrame; -} -PABLIO_Stream; - -/* Values for flags for OpenAudioStream(). */ -#define PABLIO_READ (1<<0) -#define PABLIO_WRITE (1<<1) -#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) -#define PABLIO_MONO (1<<2) -#define PABLIO_STEREO (1<<3) - -/************************************************************ - * Write data to ring buffer. - * Will not return until all the data has been written. - */ -long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); - -/************************************************************ - * Read data from ring buffer. - * Will not return until all the data has been read. - */ -long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); - -/************************************************************ - * Return the number of frames that could be written to the stream without - * having to wait. - */ -long GetAudioStreamWriteable( PABLIO_Stream *aStream ); - -/************************************************************ - * Return the number of frames that are available to be read from the - * stream without having to wait. - */ -long GetAudioStreamReadable( PABLIO_Stream *aStream ); - -/************************************************************ - * Opens a PortAudio stream with default characteristics. - * Allocates PABLIO_Stream structure. - * - * flags parameter can be an ORed combination of: - * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, - */ -PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate, - PaSampleFormat format, int inchannels, - int outchannels, int framesperbuf, int nbuffers, - int indeviceno, int outdeviceno); /* MSP */ - -PaError CloseAudioStream( PABLIO_Stream *aStream ); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* _PABLIO_H */ diff --git a/pd/src/s_audio_paring.c b/pd/src/s_audio_paring.c index 6e645e45b91fe15bb29d5e143a6da4149695514c..02f6d88de1216f63b6fb4882e48a582f3fa31dcf 100644 --- a/pd/src/s_audio_paring.c +++ b/pd/src/s_audio_paring.c @@ -31,10 +31,10 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - */ -/* * modified 2002/07/13 by olaf.matthes@gmx.de to allow any number if channels * + * extensively hacked by msp@ucsd.edu for various reasons + * */ #include <stdio.h> @@ -43,40 +43,73 @@ #include "s_audio_paring.h" #include <string.h> +/* Clear buffer. Should only be called when buffer is NOT being read. */ +static void sys_ringbuf_Flush(PA_VOLATILE sys_ringbuf *rbuf, + PA_VOLATILE void *dataPtr, long nfill); + +/* Get address of region(s) to which we can write data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be written or numBytes, whichever is smaller. +*/ +static long sys_ringbuf_GetWriteRegions(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, + PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer); +static long sys_ringbuf_AdvanceWriteIndex(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes); + +/* Get address of region(s) from which we can read data. +** If the region is contiguous, size2 will be zero. +** If non-contiguous, size2 will be the size of second region. +** Returns room available to be read or numBytes, whichever is smaller. +*/ +static long sys_ringbuf_GetReadRegions(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, + PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer); + +static long sys_ringbuf_AdvanceReadIndex(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes ); + /*************************************************************************** * Initialize FIFO. */ -long sys_ringbuf_Init( sys_ringbuf *rbuf, long numBytes, void *dataPtr ) +long sys_ringbuf_init(PA_VOLATILE sys_ringbuf *rbuf, long numBytes, + PA_VOLATILE char *dataPtr, long nfill) { rbuf->bufferSize = numBytes; - rbuf->buffer = (char *)dataPtr; - sys_ringbuf_Flush( rbuf ); + sys_ringbuf_Flush(rbuf, dataPtr, nfill); return 0; } /*************************************************************************** ** Return number of bytes available for reading. */ -long sys_ringbuf_GetReadAvailable( sys_ringbuf *rbuf ) +long sys_ringbuf_getreadavailable(PA_VOLATILE sys_ringbuf *rbuf) { long ret = rbuf->writeIndex - rbuf->readIndex; if (ret < 0) ret += 2 * rbuf->bufferSize; if (ret < 0 || ret > rbuf->bufferSize) fprintf(stderr, - "consistency check failed: sys_ringbuf_GetReadAvailable\n"); + "consistency check failed: sys_ringbuf_getreadavailable\n"); return ( ret ); } /*************************************************************************** ** Return number of bytes available for writing. */ -long sys_ringbuf_GetWriteAvailable( sys_ringbuf *rbuf ) +long sys_ringbuf_getwriteavailable(PA_VOLATILE sys_ringbuf *rbuf) { - return ( rbuf->bufferSize - sys_ringbuf_GetReadAvailable(rbuf)); + return ( rbuf->bufferSize - sys_ringbuf_getreadavailable(rbuf)); } /*************************************************************************** ** Clear buffer. Should only be called when buffer is NOT being read. */ -void sys_ringbuf_Flush( sys_ringbuf *rbuf ) +static void sys_ringbuf_Flush(PA_VOLATILE sys_ringbuf *rbuf, + PA_VOLATILE void *dataPtr, long nfill) { - rbuf->writeIndex = rbuf->readIndex = 0; + PA_VOLATILE char *s; + long n; + rbuf->readIndex = 0; + rbuf->writeIndex = nfill; + for (n = nfill, s = dataPtr; n--; s++) + *s = 0; } /*************************************************************************** @@ -85,12 +118,12 @@ void sys_ringbuf_Flush( sys_ringbuf *rbuf ) ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ -long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ) +static long sys_ringbuf_GetWriteRegions(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, + PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer) { long index; - long available = sys_ringbuf_GetWriteAvailable( rbuf ); + long available = sys_ringbuf_getwriteavailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if write is not contiguous. */ index = rbuf->writeIndex; @@ -100,14 +133,14 @@ long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes, { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; - *dataPtr1 = &rbuf->buffer[index]; + *dataPtr1 = &buffer[index]; *sizePtr1 = firstHalf; - *dataPtr2 = &rbuf->buffer[0]; + *dataPtr2 = &buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { - *dataPtr1 = &rbuf->buffer[index]; + *dataPtr1 = &buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; @@ -118,7 +151,8 @@ long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes, /*************************************************************************** */ -long sys_ringbuf_AdvanceWriteIndex( sys_ringbuf *rbuf, long numBytes ) +static long sys_ringbuf_AdvanceWriteIndex(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes) { long ret = (rbuf->writeIndex + numBytes); if ( ret >= 2 * rbuf->bufferSize) @@ -132,12 +166,12 @@ long sys_ringbuf_AdvanceWriteIndex( sys_ringbuf *rbuf, long numBytes ) ** If non-contiguous, size2 will be the size of second region. ** Returns room available to be written or numBytes, whichever is smaller. */ -long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ) +static long sys_ringbuf_GetReadRegions(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes, PA_VOLATILE void **dataPtr1, long *sizePtr1, + PA_VOLATILE void **dataPtr2, long *sizePtr2, PA_VOLATILE char *buffer) { long index; - long available = sys_ringbuf_GetReadAvailable( rbuf ); + long available = sys_ringbuf_getreadavailable( rbuf ); if( numBytes > available ) numBytes = available; /* Check to see if read is not contiguous. */ index = rbuf->readIndex; @@ -148,14 +182,14 @@ long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes, { /* Write data in two blocks that wrap the buffer. */ long firstHalf = rbuf->bufferSize - index; - *dataPtr1 = &rbuf->buffer[index]; + *dataPtr1 = &buffer[index]; *sizePtr1 = firstHalf; - *dataPtr2 = &rbuf->buffer[0]; + *dataPtr2 = &buffer[0]; *sizePtr2 = numBytes - firstHalf; } else { - *dataPtr1 = &rbuf->buffer[index]; + *dataPtr1 = &buffer[index]; *sizePtr1 = numBytes; *dataPtr2 = NULL; *sizePtr2 = 0; @@ -164,7 +198,8 @@ long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes, } /*************************************************************************** */ -long sys_ringbuf_AdvanceReadIndex( sys_ringbuf *rbuf, long numBytes ) +static long sys_ringbuf_AdvanceReadIndex(PA_VOLATILE sys_ringbuf *rbuf, + long numBytes) { long ret = (rbuf->readIndex + numBytes); if( ret >= 2 * rbuf->bufferSize) @@ -174,21 +209,23 @@ long sys_ringbuf_AdvanceReadIndex( sys_ringbuf *rbuf, long numBytes ) /*************************************************************************** ** Return bytes written. */ -long sys_ringbuf_Write( sys_ringbuf *rbuf, const void *data, long numBytes ) +long sys_ringbuf_write(PA_VOLATILE sys_ringbuf *rbuf, const void *data, + long numBytes, PA_VOLATILE char *buffer) { long size1, size2, numWritten; - void *data1, *data2; - numWritten = sys_ringbuf_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); + PA_VOLATILE void *data1, *data2; + numWritten = sys_ringbuf_GetWriteRegions( rbuf, numBytes, &data1, &size1, + &data2, &size2, buffer); if( size2 > 0 ) { - memcpy( data1, data, size1 ); + memcpy((void *)data1, data, size1 ); data = ((char *)data) + size1; - memcpy( data2, data, size2 ); + memcpy((void *)data2, data, size2 ); } else { - memcpy( data1, data, size1 ); + memcpy((void *)data1, data, size1 ); } sys_ringbuf_AdvanceWriteIndex( rbuf, numWritten ); return numWritten; @@ -196,20 +233,22 @@ long sys_ringbuf_Write( sys_ringbuf *rbuf, const void *data, long numBytes ) /*************************************************************************** ** Return bytes read. */ -long sys_ringbuf_Read( sys_ringbuf *rbuf, void *data, long numBytes ) +long sys_ringbuf_read(PA_VOLATILE sys_ringbuf *rbuf, void *data, long numBytes, + PA_VOLATILE char *buffer) { long size1, size2, numRead; - void *data1, *data2; - numRead = sys_ringbuf_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 ); + PA_VOLATILE void *data1, *data2; + numRead = sys_ringbuf_GetReadRegions( rbuf, numBytes, &data1, &size1, + &data2, &size2, buffer); if( size2 > 0 ) { - memcpy( data, data1, size1 ); + memcpy(data, (void *)data1, size1 ); data = ((char *)data) + size1; - memcpy( data, data2, size2 ); + memcpy(data, (void *)data2, size2 ); } else { - memcpy( data, data1, size1 ); + memcpy( data, (void *)data1, size1 ); } sys_ringbuf_AdvanceReadIndex( rbuf, numRead ); return numRead; diff --git a/pd/src/s_audio_paring.h b/pd/src/s_audio_paring.h index e5e5e6b294758d7c1d30a902721b3aa0d4f06a83..4154c22216dc23899e850570959a05132298241d 100644 --- a/pd/src/s_audio_paring.h +++ b/pd/src/s_audio_paring.h @@ -39,61 +39,35 @@ extern "C" * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include "s_audio_paring.h" -#include <string.h> + +/* If it's ever desired to use shared memory so that one process reads and +another one writes to the same ring buffer, define this as 'volatile' : */ +#define PA_VOLATILE typedef struct { - long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by sys_ringbuf_Init. */ -/* These are declared volatile because they are written by a different thread than the reader. */ - volatile long writeIndex; /* Index of next writable byte. Set by sys_ringbuf_AdvanceWriteIndex. */ - volatile long readIndex; /* Index of next readable byte. Set by sys_ringbuf_AdvanceReadIndex. */ - long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */ - long smallMask; /* Used for fitting indices to buffer. */ - char *buffer; -} -sys_ringbuf; -/* - * Initialize Ring Buffer. - * numBytes must be power of 2, returns -1 if not. - */ -long sys_ringbuf_Init( sys_ringbuf *rbuf, long numBytes, void *dataPtr ); + long bufferSize; /* Number of bytes in FIFO. + Set by sys_ringbuf_init */ + PA_VOLATILE long writeIndex; /* Index of next writable byte. + Set by sys_ringbuf_AdvanceWriteIndex */ + PA_VOLATILE long readIndex; /* Index of next readable byte. + Set by sys_ringbuf_AdvanceReadIndex */ +} sys_ringbuf; -/* Clear buffer. Should only be called when buffer is NOT being read. */ -void sys_ringbuf_Flush( sys_ringbuf *rbuf ); +/* Initialize Ring Buffer. */ +long sys_ringbuf_init(PA_VOLATILE sys_ringbuf *rbuf, long numBytes, + PA_VOLATILE char *dataPtr, long nfill); /* Return number of bytes available for writing. */ -long sys_ringbuf_GetWriteAvailable( sys_ringbuf *rbuf ); +long sys_ringbuf_getwriteavailable(PA_VOLATILE sys_ringbuf *rbuf); /* Return number of bytes available for read. */ -long sys_ringbuf_GetReadAvailable( sys_ringbuf *rbuf ); +long sys_ringbuf_getreadavailable(PA_VOLATILE sys_ringbuf *rbuf); /* Return bytes written. */ -long sys_ringbuf_Write( sys_ringbuf *rbuf, const void *data, long numBytes ); +long sys_ringbuf_write(PA_VOLATILE sys_ringbuf *rbuf, const void *data, + long numBytes, PA_VOLATILE char *buffer); /* Return bytes read. */ -long sys_ringbuf_Read( sys_ringbuf *rbuf, void *data, long numBytes ); - -/* Get address of region(s) to which we can write data. -** If the region is contiguous, size2 will be zero. -** If non-contiguous, size2 will be the size of second region. -** Returns room available to be written or numBytes, whichever is smaller. -*/ -long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ); -long sys_ringbuf_AdvanceWriteIndex( sys_ringbuf *rbuf, long numBytes ); - -/* Get address of region(s) from which we can read data. -** If the region is contiguous, size2 will be zero. -** If non-contiguous, size2 will be the size of second region. -** Returns room available to be read or numBytes, whichever is smaller. -*/ -long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes, - void **dataPtr1, long *sizePtr1, - void **dataPtr2, long *sizePtr2 ); - -long sys_ringbuf_AdvanceReadIndex( sys_ringbuf *rbuf, long numBytes ); +long sys_ringbuf_read(PA_VOLATILE sys_ringbuf *rbuf, void *data, long numBytes, + PA_VOLATILE char *buffer); #ifdef __cplusplus } diff --git a/pd/src/s_file.c b/pd/src/s_file.c index 7c12da3b22291d3b5a441b8bc6f75bc00e4a49c3..1d086e4f1bdd81de28a64c1f672a0886986ed60e 100644 --- a/pd/src/s_file.c +++ b/pd/src/s_file.c @@ -373,6 +373,8 @@ void sys_loadpreferences( void) sscanf(prefbuf, "%d", &advance); if (sys_getpreference("callback", prefbuf, MAXPDSTRING)) sscanf(prefbuf, "%d", &callback); + if (sys_getpreference("blocksize", prefbuf, MAXPDSTRING)) + sscanf(prefbuf, "%d", &blocksize); sys_set_audio_settings(naudioindev, audioindev, naudioindev, chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance, callback, blocksize); diff --git a/pd/src/s_stuff.h b/pd/src/s_stuff.h index 3af586934da524f7909961f8ee50459c08af2e85..5a9153cedd012de5d4d21fc094371ada26f29282 100644 --- a/pd/src/s_stuff.h +++ b/pd/src/s_stuff.h @@ -261,7 +261,7 @@ void pa_getdevs(char *indevlist, int *nindevs, int oss_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, - int *choutdev, int rate); + int *choutdev, int rate, int blocksize); void oss_close_audio(void); int oss_send_dacs(void); void oss_reportidle(void); @@ -290,7 +290,7 @@ void jack_listdevs(void); int mmio_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev, int naudiooutdev, int *audiooutdev, - int nchoutdev, int *choutdev, int rate); + int nchoutdev, int *choutdev, int rate, int blocksize); void mmio_close_audio( void); void mmio_reportidle(void); int mmio_send_dacs(void); @@ -309,6 +309,7 @@ void sys_set_audio_state(int onoff); void oss_set32bit( void); void linux_alsa_devname(char *devname); +EXTERN int sys_audio_get_blocksize(void); EXTERN void sys_get_audio_params( int *pnaudioindev, int *paudioindev, int *chindev, int *pnaudiooutdev, int *paudiooutdev, int *choutdev, diff --git a/pd/src/x_interface.c b/pd/src/x_interface.c index 90f568706c933970d2449f66f91ae844eb181ece..a10cd8b17f0a1028804b3888f68331744060cee0 100644 --- a/pd/src/x_interface.c +++ b/pd/src/x_interface.c @@ -817,7 +817,7 @@ void pdinfo_audio_samplerate(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv) void pdinfo_audio_blocksize(t_pdinfo *x, t_symbol *s, int argc, t_atom *argv) { t_atom at[1]; - SETFLOAT(at, (t_float)sys_getblksize()); + SETFLOAT(at, (t_float)sys_audio_get_blocksize()); info_out((t_text *)x, s, 1, at); }