/* 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; }
/* callback for "non-callback" case where we communicate with the main thread via FIFO. Here we first read the sudio 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)) fprintf(stderr, "warning: in and out rings unequal (%d, %d)\n", 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)) { if (outputBuffer) sys_ringbuf_Read(&pa_outring, outputBuffer, nframes*pa_outchans*sizeof(float)); else if (pa_outchans) fprintf(stderr, "no outputBuffer but output channels\n"); if (inputBuffer) sys_ringbuf_Write(&pa_inring, inputBuffer, nframes*pa_inchans*sizeof(float)); else if (pa_inchans) fprintf(stderr, "no inputBuffer but input channels\n"); } 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; } } } #ifdef THREADSIGNAL pthread_mutex_lock(&pa_mutex); pthread_cond_signal(&pa_sem); pthread_mutex_unlock(&pa_mutex); #endif return 0; }
/************************************************************ * 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; }
int pa_send_dacs(void) { t_sample *fp; float *fp2, *fp3; float *conversionbuf; int j, k; int rtnval = SENDDACS_YES; int timenow; int timeref = sys_getrealtime(); if (!sys_inchannels && !sys_outchannels) return (SENDDACS_NO); #if CHECKFIFOS if (sys_outchannels * sys_ringbuf_GetReadAvailable(&pa_inring) != sys_inchannels * sys_ringbuf_GetWriteAvailable(&pa_outring)) fprintf(stderr, "warning (2): in and out rings unequal (%d, %d)\n", sys_ringbuf_GetReadAvailable(&pa_inring), sys_ringbuf_GetWriteAvailable(&pa_outring)); #endif conversionbuf = (float *)alloca((sys_inchannels > sys_outchannels? sys_inchannels:sys_outchannels) * DEFDACBLKSIZE * sizeof(float)); if (pa_dio_error) { sys_log_error(ERR_RESYNC); pa_dio_error = 0; } if (!sys_inchannels) /* if no input channels sync on output */ { #ifdef THREADSIGNAL pthread_mutex_lock(&pa_mutex); #endif while (sys_ringbuf_GetWriteAvailable(&pa_outring) < (long)(sys_outchannels * DEFDACBLKSIZE * sizeof(float))) #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 } /* write output */ if (sys_outchannels) { 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))); } 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))) #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 } pa_started = 1; if (sys_inchannels) { sys_ringbuf_Read(&pa_inring, conversionbuf, sys_inchannels*(DEFDACBLKSIZE*sizeof(float))); 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 ((timenow = sys_getrealtime()) - timeref > 0.002) { rtnval = SENDDACS_SLEPT; } memset(sys_soundout, 0, DEFDACBLKSIZE*sizeof(t_sample)*sys_outchannels); return rtnval; }