Update of /cvsroot/pure-data/pd/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30038
Modified Files: Tag: devel_0_38 s_audio_pa.c s_audio.c s_stuff.h Log Message: callback based scheduling for portaudio v19
Index: s_audio_pa.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/s_audio_pa.c,v retrieving revision 1.4.4.2 retrieving revision 1.4.4.3 diff -C2 -d -r1.4.4.2 -r1.4.4.3 *** s_audio_pa.c 26 Nov 2004 10:03:41 -0000 1.4.4.2 --- s_audio_pa.c 11 May 2005 14:32:07 -0000 1.4.4.3 *************** *** 4,10 ****
/* 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. */
#include "m_pd.h" --- 4,11 ----
/* 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. */
+ /* tb: requires portaudio >= V19 */
#include "m_pd.h" *************** *** 13,66 **** #include <stdlib.h> #include <portaudio.h> ! #include "s_audio_pablio.h"
#ifdef MSW ! /* jmz thinks that we have to include: ! * on Windows: <malloc.h> (probably this is already included?) ! * on linux: <alloca.h> (might be true for osX too, no way to check right now...) ! */ ! # include <malloc.h> ! #else ! # include <alloca.h> #endif
! /* 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 int pa_inchans, pa_outchans; ! static float *pa_soundin, *pa_soundout;
! #define MAX_PA_CHANS 32
! #ifndef PA19 ! #define Pa_GetDeviceCount Pa_CountDevices ! #endif
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, ! t_sample *soundout, int framesperbuf, int nbuffers, ! int indeviceno, int outdeviceno) { PaError err; - static int initialized; int j, devno, pa_indev = 0, pa_outdev = 0;
! if (!initialized) ! { ! /* Initialize PortAudio */ ! int err = Pa_Initialize(); ! if ( err != paNoError ) ! { ! fprintf( stderr, ! "Error number %d occured initializing portaudio\n", ! err); ! fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); ! return (1); ! } ! initialized = 1; ! } /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ if (inchans > MAX_PA_CHANS) --- 14,69 ---- #include <stdlib.h> #include <portaudio.h> ! #include <errno.h>
#ifdef MSW ! #include "pthread.h" /* for ETIMEDOUT */ #endif
! #define MAX_PA_CHANS 32
! #define PA19 ! /* portaudio's blocking api is not working, yet: */ ! /* #define PABLOCKING */
static int pa_inchans, pa_outchans; ! static float *pa_soundin[MAX_PA_CHANS], *pa_soundout[MAX_PA_CHANS];
! static PaStream *pa_stream; ! static PaStreamCallback *pa_callback = NULL;
! int process (const void *input, void *output, unsigned long frameCount, ! const PaStreamCallbackTimeInfo* timeInfo, ! PaStreamCallbackFlags statusFlags, void *userData);
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, ! t_sample *soundout, int advance, ! int indeviceno, int outdeviceno, int schedmode) { PaError err; int j, devno, pa_indev = 0, pa_outdev = 0;
! #ifndef PABLOCKING ! schedmode = 1; ! #endif ! ! if (schedmode == 1) ! pa_callback = process; ! else ! pa_callback = NULL; ! ! sys_keepsched = 0; ! sys_callbackscheduler = schedmode; ! ! /* Initialize PortAudio */ ! err = Pa_Initialize(); ! if ( err != paNoError ) ! { ! fprintf( stderr, ! "Error number %d occured initializing portaudio\n", ! err); ! fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); ! return (1); ! } ! /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */ if (inchans > MAX_PA_CHANS) *************** *** 90,94 **** } } ! }
if (outchans > 0) --- 93,97 ---- } } ! }
if (outchans > 0) *************** *** 107,111 **** } } ! }
if (sys_verbose) --- 110,114 ---- } } ! }
if (sys_verbose) *************** *** 113,128 **** 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); } if (inchans || outchans) ! err = OpenAudioStream( &pa_stream, rate, paFloat32, ! inchans, outchans, framesperbuf, nbuffers, ! pa_indev, pa_outdev); ! else err = 0; ! if ( err != paNoError ) { ! fprintf( stderr, "Error number %d occured opening portaudio stream\n", ! err); ! fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); Pa_Terminate(); sys_inchannels = sys_outchannels = 0; --- 116,155 ---- post("input device %d, channels %d", pa_indev, inchans); post("output device %d, channels %d", pa_outdev, outchans); ! post("latency advance %d", advance); } if (inchans || outchans) ! { ! PaStreamParameters inputParameters, outputParameters; ! ! /* initialize input */ ! inputParameters.device = pa_indev ; ! inputParameters.channelCount = inchans; ! inputParameters.sampleFormat = paFloat32 | paNonInterleaved; ! inputParameters.suggestedLatency = advance * 0.001; ! inputParameters.hostApiSpecificStreamInfo = NULL; ! ! /* initialize output */ ! outputParameters.device = pa_outdev; ! outputParameters.channelCount = outchans; ! outputParameters.sampleFormat = paFloat32 | paNonInterleaved; ! outputParameters.suggestedLatency = advance * 0.001; ! outputParameters.hostApiSpecificStreamInfo = NULL; ! ! /* report to portaudio */ ! err = Pa_OpenStream(&pa_stream, (inchans ? &inputParameters : 0), ! (outchans ? &outputParameters : 0), ! rate, ! sys_dacblocksize, ! paClipOff, /* tb: we should be faster ;-) */ ! pa_callback, NULL); ! } ! else ! err = 0; ! ! if ( err != paNoError ) { ! post("Error number %d occured opening portaudio stream\n", ! err); ! post("Error message: %s\n", Pa_GetErrorText( err ) ); Pa_Terminate(); sys_inchannels = sys_outchannels = 0; *************** *** 133,228 **** pa_inchans = inchans; pa_outchans = outchans; ! pa_soundin = soundin; ! pa_soundout = soundout; return (0); }
void pa_close_audio( void) { if (pa_inchans || pa_outchans) ! CloseAudioStream( pa_stream ); pa_inchans = pa_outchans = 0; }
int pa_send_dacs(void) { ! float *samples, *fp1, *fp2; ! int i, j; ! double timebefore;
! samples=(float*)alloca(sizeof(float) * MAX_PA_CHANS * sys_dacblocksize); ! ! timebefore = sys_getrealtime(); ! if ((pa_inchans && GetAudioStreamReadable(pa_stream) < sys_dacblocksize) || ! (pa_outchans && GetAudioStreamWriteable(pa_stream) < sys_dacblocksize)) ! { ! if (pa_inchans && pa_outchans) ! { ! int synced = 0; ! while (GetAudioStreamWriteable(pa_stream) > 2*sys_dacblocksize) ! { ! for (j = 0; j < pa_outchans; j++) ! for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, ! fp2 += pa_outchans) ! { ! *fp2 = 0; ! } ! synced = 1; ! WriteAudioStream(pa_stream, samples, sys_dacblocksize); ! } ! while (GetAudioStreamReadable(pa_stream) > 2*sys_dacblocksize) ! { ! synced = 1; ! ReadAudioStream(pa_stream, samples, sys_dacblocksize); ! } ! /* if (synced) ! post("sync"); */ ! } ! return (SENDDACS_NO); ! } ! if (pa_inchans) ! { ! ReadAudioStream(pa_stream, samples, sys_dacblocksize); ! for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += sys_dacblocksize) ! for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, ! fp2 += pa_inchans) ! { ! fp1[i] = *fp2; ! } ! } ! #if 0 ! { ! 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--; ! } ! #endif ! if (pa_outchans) ! { ! for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++, ! fp1 += sys_dacblocksize) ! for (i = 0, fp2 = samples + j; i < sys_dacblocksize; i++, ! fp2 += pa_outchans) ! { ! *fp2 = fp1[i]; ! fp1[i] = 0; ! } ! WriteAudioStream(pa_stream, samples, sys_dacblocksize); ! }
! if (sys_getrealtime() > timebefore + 0.002) ! { ! /* post("slept"); */ ! return (SENDDACS_SLEPT); ! } ! else return (SENDDACS_YES); }
void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */ { --- 160,331 ---- pa_inchans = inchans; pa_outchans = outchans; ! ! err = Pa_StartStream(pa_stream); ! if ( err != paNoError ) ! { ! post("Error number %d occured starting portaudio stream\n", ! err); ! post("Error message: %s\n", Pa_GetErrorText(err)); ! Pa_Terminate(); ! sys_inchannels = sys_outchannels = 0; ! return (1); ! } ! ! post("successfully started"); ! ! for (j = 0; j != MAX_PA_CHANS; ++j) ! { ! if (j < inchans) ! pa_soundin[j] = sys_soundin + j * sys_dacblocksize; ! else ! pa_soundin[j] = 0; ! ! if (j < outchans) ! pa_soundout[j] = sys_soundout + j * sys_dacblocksize; ! else ! pa_soundout[j] = 0; ! } ! return (0); }
+ + void sys_peakmeters(void); + extern int sys_meters; /* true if we're metering */ + + int process (const void *input, void *output, unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, void *userData) + { + int i,j; + int timeout = (float)frameCount / (float) sys_dacsr * 1e6; + + if (sys_timedlock(timeout) == ETIMEDOUT) + /* we're late */ + return 0; + + #if 0 + for (i = 0; i < frameCount / sys_dacblocksize; ++i) + { + for (j = 0; j < sys_inchannels; j++) + { + t_sample * in = ((t_sample**)input)[j]; + copyvec(sys_soundin + j * sys_dacblocksize, + in + i * sys_dacblocksize, + sys_dacblocksize); + } + + sched_tick(sys_time + sys_time_per_dsp_tick); + + for (j = 0; j < sys_outchannels; j++) + { + t_sample * out = ((t_sample**)output)[j]; + copyvec(out + i * sys_dacblocksize, + sys_soundout + j * sys_dacblocksize, + sys_dacblocksize); + } + /* update peak meters */ + if (sys_meters) + sys_peakmeters(); + + /* clear the output buffer */ + zerovec_simd(sys_soundout, pa_outchans * sys_dacblocksize); + } + #else + for (j = 0; j < sys_inchannels; j++) + { + t_sample * in = ((t_sample**)input)[j]; + copyvec(sys_soundin + j * sys_dacblocksize, + in, + sys_dacblocksize); + } + + sched_tick(sys_time + sys_time_per_dsp_tick); + + for (j = 0; j < sys_outchannels; j++) + { + t_sample * out = ((t_sample**)output)[j]; + copyvec(out, + sys_soundout + j * sys_dacblocksize, + sys_dacblocksize); + } + /* update peak meters */ + if (sys_meters) + sys_peakmeters(); + + /* clear the output buffer */ + zerovec_simd(sys_soundout, pa_outchans * sys_dacblocksize); + + #endif + sys_unlock(); + + return 0; + + } + void pa_close_audio( void) { + post("closing portaudio"); if (pa_inchans || pa_outchans) ! { ! Pa_StopStream(pa_stream); ! Pa_CloseStream(pa_stream); ! } ! post("portaudio closed"); pa_inchans = pa_outchans = 0; }
+ + /* for blocked IO */ int pa_send_dacs(void) { ! #ifdef PABLOCKING /* tb: blocking IO isn't really working for v19 yet */ ! double timenow, timebefore; ! ! if ( (pa_inchans && Pa_GetStreamReadAvailable(pa_stream) ! < sys_dacblocksize*0.8) && ! (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) ! < sys_dacblocksize*0.8)) ! { ! /* we can't transfer data ... wait in the scheduler */ ! return SENDDACS_NO; ! } ! ! timebefore = sys_getrealtime();
! if (pa_outchans) ! Pa_WriteStream(pa_stream, pa_soundout, sys_dacblocksize); ! if (pa_inchans) ! Pa_ReadStream(pa_stream, pa_soundin, sys_dacblocksize); ! zerovec(sys_soundout, pa_inchans * sys_dacblocksize);
! while ( (pa_inchans && Pa_GetStreamReadAvailable(pa_stream) ! < sys_dacblocksize*0.8) && ! (pa_outchans && Pa_GetStreamWriteAvailable(pa_stream) ! < sys_dacblocksize*0.8)) ! { ! if (pa_outchans) ! Pa_WriteStream(pa_stream, pa_soundout, sys_dacblocksize); ! if (pa_inchans) ! Pa_ReadStream(pa_stream, pa_soundin, sys_dacblocksize); ! zerovec(sys_soundout, pa_inchans * sys_dacblocksize); ! ! sched_tick(sys_time + sys_time_per_dsp_tick); ! } ! ! if ((timenow = sys_getrealtime()) - timebefore > sys_sleepgrain * 1e-6) ! { ! return SENDDACS_SLEPT; ! } ! else ! return SENDDACS_YES; ! #else ! /* we should never reach this point */ ! return 0; ! #endif }
+ void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */ { *************** *** 242,247 **** for( i=0; i<numDevices; i++ ) { ! pdi = Pa_GetDeviceInfo( i ); ! fprintf(stderr, "device %d:", i+1 ); fprintf(stderr, " %s;", pdi->name ); fprintf(stderr, "%d inputs, ", pdi->maxInputChannels ); --- 345,351 ---- for( i=0; i<numDevices; i++ ) { ! PaDeviceInfo * pdi = Pa_GetDeviceInfo( i ); ! post ("device %s", pdi->name); ! fprintf(stderr, "device %d:", i+1 ); fprintf(stderr, " %s;", pdi->name ); fprintf(stderr, "%d inputs, ", pdi->maxInputChannels ); *************** *** 265,269 ****
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 ) ); --- 369,373 ----
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 ) ); *************** *** 271,275 **** }
! /* scanning for devices */ void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, --- 375,380 ---- }
! ! /* scanning for devices */ void pa_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti,
Index: s_audio.c =================================================================== RCS file: /cvsroot/pure-data/pd/src/s_audio.c,v retrieving revision 1.5.4.12 retrieving revision 1.5.4.13 diff -C2 -d -r1.5.4.12 -r1.5.4.13 *** s_audio.c 10 May 2005 11:16:03 -0000 1.5.4.12 --- s_audio.c 11 May 2005 14:32:08 -0000 1.5.4.13 *************** *** 332,338 **** int blksize = (sys_blocksize ? sys_blocksize : 64); pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, ! blksize, sys_advance_samples/blksize, ! (naudiooutdev > 0 ? audioindev[0] : 0), ! (naudiooutdev > 0 ? audiooutdev[0] : 0)); } else --- 332,339 ---- int blksize = (sys_blocksize ? sys_blocksize : 64); pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout, ! advance, ! (naudiooutdev > 0 ? audioindev[0] : 0), ! (naudiooutdev > 0 ? audiooutdev[0] : 0), ! schedmode); } else
Index: s_stuff.h =================================================================== RCS file: /cvsroot/pure-data/pd/src/s_stuff.h,v retrieving revision 1.5.4.5 retrieving revision 1.5.4.6 diff -C2 -d -r1.5.4.5 -r1.5.4.6 *** s_stuff.h 8 Apr 2005 12:45:25 -0000 1.5.4.5 --- s_stuff.h 11 May 2005 14:32:09 -0000 1.5.4.6 *************** *** 202,207 ****
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, ! t_sample *soundout, int framesperbuf, int nbuffers, ! int indeviceno, int outdeviceno); void pa_close_audio(void); int pa_send_dacs(void); --- 202,207 ----
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin, ! t_sample *soundout, int advance, ! int indeviceno, int outdeviceno, int schedmode) void pa_close_audio(void); int pa_send_dacs(void);