Commit 6405adaa authored by Ivica Bukvic's avatar Ivica Bukvic
Browse files

*updated most of the audio API to the latest version (with the exception of...

*updated most of the audio API to the latest version (with the exception of ALSA and JACK which are partial until our improvements can be merged and/or new implementation of JACK thoroughly tested to ensure we like its default behavior)
parent 3da3a699
......@@ -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]} {
......
......@@ -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 \
......
......@@ -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,
......
......@@ -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)
{
......
......@@ -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;
......
......@@ -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;