Update of /cvsroot/pure-data/pd/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24634
Modified Files: Tag: devel_0_38 s_audio_asio.cpp Log Message: callback-based scheduling
Index: s_audio_asio.cpp =================================================================== RCS file: /cvsroot/pure-data/pd/src/Attic/s_audio_asio.cpp,v retrieving revision 1.1.4.14 retrieving revision 1.1.4.15 diff -C2 -d -r1.1.4.14 -r1.1.4.15 *** s_audio_asio.cpp 18 Nov 2004 22:50:44 -0000 1.1.4.14 --- s_audio_asio.cpp 23 Nov 2004 23:08:53 -0000 1.1.4.15 *************** *** 65,69 **** extern "C" int asio_send_dacs(void);
! /* asio callback prototypes */ static void asio_bufferSwitch(long db_idx, ASIOBool directprocess); static void asio_sampleRateDidChange(ASIOSampleRate srate); --- 65,69 ---- extern "C" int asio_send_dacs(void);
! /* asio callback prototypes for traditional scheduling*/ static void asio_bufferSwitch(long db_idx, ASIOBool directprocess); static void asio_sampleRateDidChange(ASIOSampleRate srate); *************** *** 72,75 **** --- 72,83 ---- ASIOBool directprocess);
+ /* asio callback prototypes for callback-based scheduling*/ + static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess); + static void asio_sampleRateDidChange_cb(ASIOSampleRate srate); + static long asio_messages_cb(long selector, long value, void* message, double* opt); + static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, + ASIOBool directprocess); + + static void float32tofloat32(void* inbuffer, void* outbuffer, long frames); static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames); *************** *** 103,106 **** --- 111,116 ---- static int asio_samplewidth(ASIOSampleType format);
+ + /* that's the sample width in bytes (per output channel) - * it's only for silence when stopping the driver.... (please find a better solution) *************** *** 137,141 **** static long asio_outputlatency;
! static long asio_bufsize;
unsigned long sys_reftime; --- 147,151 ---- static long asio_outputlatency;
! static long asio_bufsize; /* hardware buffer size */
unsigned long sys_reftime; *************** *** 158,161 **** --- 168,189 ---- #define MAXNDEV 20
+ /* from m_sched.c: */ + extern "C" int sys_keepsched; + extern "C" int sys_callbackscheduler; + extern "C" double sys_time_per_dsp_tick; + extern "C" double sys_time; + + + /**************************************************************************/ + /* some function pointers for eventual fast copying when SIMD is possible */ + + static void (*copyblock)(t_sample *dst,t_sample *src,int n); + static void (*zeroblock)(t_sample *dst,int n); + static t_int *(*clipblock)(t_int *w); + + static void copyvec_nrm(t_sample *dst,t_sample *src,int n) { memcpy(dst,src,n*sizeof(t_sample)); } + static void zerovec_nrm(t_sample *dst,int n) { memset(dst,0,n*sizeof(t_sample)); } + + /*************************************************************************/
*************** *** 176,179 **** --- 204,208 ---- sprintf(asio_srate,"%d",srate); #endif + /* check, if the driver is still running */ *************** *** 269,272 **** --- 298,310 ---- asio_bufsize = asio_prefbufsize;
+ #ifdef CALLBACK_SCHEDULER + if (asio_bufsize % 2 == 0) + { + /* use callback scheduler */ + sys_keepsched = 0; + sys_callbackscheduler = 1; + } + #endif + /* set sample rate */ if(ASIOCanSampleRate( asio_srate ) != ASE_OK) *************** *** 292,300 ****
/* set callbacks */ ! asio_callbacks.bufferSwitch = &asio_bufferSwitch; ! asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange; ! asio_callbacks.asioMessage = &asio_messages; ! asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo; !
/* prepare, create and set up buffers */ --- 330,349 ----
/* set callbacks */ ! if(sys_callbackscheduler) ! { ! asio_callbacks.bufferSwitch = &asio_bufferSwitch_cb; ! asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange_cb; ! asio_callbacks.asioMessage = &asio_messages_cb; ! asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo_cb; ! } ! else ! { ! asio_callbacks.bufferSwitch = &asio_bufferSwitch; ! asio_callbacks.sampleRateDidChange = &asio_sampleRateDidChange; ! asio_callbacks.asioMessage = &asio_messages; ! asio_callbacks.bufferSwitchTimeInfo = &asio_bufferSwitchTimeInfo; ! } ! !
/* prepare, create and set up buffers */ *************** *** 321,330 **** asio_bufferinfo[i].isInput = ASIOTrue; asio_bufferinfo[i].channelNum = i - sys_outchannels; } } status = ASIOCreateBuffers(asio_bufferinfo, sys_inchannels + sys_outchannels, ! asio_bufsize, &asio_callbacks); ! if(status != ASE_OK) { --- 370,380 ---- asio_bufferinfo[i].isInput = ASIOTrue; asio_bufferinfo[i].channelNum = i - sys_outchannels; + asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0; } } status = ASIOCreateBuffers(asio_bufferinfo, sys_inchannels + sys_outchannels, ! asio_bufsize, &asio_callbacks); ! if(status != ASE_OK) { *************** *** 361,396 ****
! /* calculate ringbuffer length */ ! /* a strange way to find the least common multiple, ! * but works, since sys_dacblocksize (expt 2 x) */ ! ! asio_ringbuffer_length = asio_bufsize * sys_dacblocksize; ! while ( !(asio_ringbuffer_length % sys_dacblocksize) && ! !(asio_ringbuffer_length % asio_bufsize)) ! { ! asio_ringbuffer_length /= 2; ! } ! asio_ringbuffer_length *= 2; ! #ifdef ASIODEBUG ! post("ASIO: ringbuffer size: %d",asio_ringbuffer_length); #endif ! ! ! /* allocate ringbuffer */ ! asio_ringbuffer = (t_sample**) getbytes (channels * sizeof (t_sample*)); ! for (i = 0; i != channels; ++i) ! { ! asio_ringbuffer[i] = (t_sample*)getalignedbytes(asio_ringbuffer_length * sizeof (t_sample)); ! if (!asio_ringbuffer[i]) ! error("ASIO: couldn't allocate ASIO ringbuffer"); ! memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample)); } - /* initialize ringbuffer pointers */ - asio_ringbuffer_inoffset = asio_ringbuffer_outoffset = 0; - if(ASIOStart() != ASE_OK) goto bailout;
post("ASIO: started"); return; --- 411,463 ----
! /* we need a ringbuffer if we use the traditional scheduler */ ! if (!sys_callbackscheduler) ! { ! /* a strange way to find the least common multiple, ! * but works, since sys_dacblocksize (expt 2 x) */ ! asio_ringbuffer_length = asio_bufsize * sys_dacblocksize; ! while ( !(asio_ringbuffer_length % sys_dacblocksize) && ! !(asio_ringbuffer_length % asio_bufsize)) ! { ! asio_ringbuffer_length /= 2; ! } ! asio_ringbuffer_length *= 2; ! #ifdef ASIODEBUG ! post("ASIO: ringbuffer size: %d",asio_ringbuffer_length); #endif ! ! /* allocate ringbuffer */ ! asio_ringbuffer = (t_sample**) getbytes (channels * sizeof (t_sample*)); ! for (i = 0; i != channels; ++i) ! { ! asio_ringbuffer[i] = (t_sample*)getalignedbytes(asio_ringbuffer_length * sizeof (t_sample)); ! if (!asio_ringbuffer[i]) ! error("ASIO: couldn't allocate ASIO ringbuffer"); ! memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample)); ! } ! ! /* initialize ringbuffer pointers */ ! asio_ringbuffer_inoffset = asio_ringbuffer_outoffset = 0; } if(ASIOStart() != ASE_OK) goto bailout;
+ + /* set block copy/zero/clip functions */ + if(SIMD_CHKCNT(sys_dacblocksize) && simd_runtime_check()) + { + // urgh... ugly cast + copyblock = (void (*)(t_sample *,t_sample *,int))©vec_simd; + zeroblock = &zerovec_simd; + clipblock = &clip_perf_simd; + } + else + { + copyblock = ©vec_nrm; + zeroblock = &zerovec_nrm; + clipblock = &clip_perform; + } + post("ASIO: started"); return; *************** *** 495,498 **** --- 562,571 ---- freebytes(asio_driver, sizeof (ASIODriverInfo)); asio_driver = NULL; + + /* leave the scheduler and return to traditional mode */ + if (sys_callbackscheduler) + { + sys_callbackscheduler = sys_keepsched = 0; + } } } *************** *** 516,549 **** }
- /**************************************************************************/ - /* some function pointers for eventual fast copying when SIMD is possible */ - - static void copyvec_nrm(t_sample *dst,t_sample *src,int n) { memcpy(dst,src,n*sizeof(t_sample)); } - static void zerovec_nrm(t_sample *dst,int n) { memset(dst,0,n*sizeof(t_sample)); } - - /*************************************************************************/ - /* called on every dac~ send */ int asio_send_dacs(void) { - /* set block copy/zero/clip functions */ - void (*copyblock)(t_sample *dst,t_sample *src,int n); - void (*zeroblock)(t_sample *dst,int n); - t_int *(*clipblock)(t_int *w); - - if(SIMD_CHKCNT(sys_dacblocksize)) { - // urgh... ugly cast - copyblock = (void (*)(t_sample *,t_sample *,int))©vec_simd; - zeroblock = &zerovec_simd; - clipblock = &clip_perf_simd; - } - else { - copyblock = ©vec_nrm; - zeroblock = &zerovec_nrm; - clipblock = &clip_perform; - } - - /*************************************/ - t_sample * sp; /* sample pointer */ int i, j; --- 589,595 ---- *************** *** 564,569 **** for (i = 0; i < sys_outchannels; i++) { - /* clipping here, we are sure, we can use simd instructions */ - /* TG: are we? can sys_dacblocksize be < 16, with onset and size then not SIMD-able? */ t_float lo = -1.f; t_float hi = 1.f; --- 610,613 ---- *************** *** 710,715 **** ASIOBool directprocess) { - long i, j; - /* todo: i'm not sure if we'll have to synchronize with other media ... * probably yes ... */ --- 754,757 ---- *************** *** 719,723 **** /* perform the processing */
! for (i = 0; i < sys_outchannels + sys_inchannels; i++) { if(asio_converter[i]) --- 761,765 ---- /* perform the processing */
! for (long i = 0; i < sys_outchannels + sys_inchannels; i++) { if(asio_converter[i]) *************** *** 1014,1018 **** while (frames--) { ! float o = *(in++) * SCALE_INT24 + triangulardither() * DITHER_SCALE; #ifdef __GNUC__ __int32 intg = (__int32)lrintf(o); --- 1056,1060 ---- while (frames--) { ! float o = *(in++) * SCALE_INT24; #ifdef __GNUC__ __int32 intg = (__int32)lrintf(o); *************** *** 1101,1105 **** while (frames--) { ! float o = (float)*(in++) * SCALE_INT24 + triangulardither() * DITHER_SCALE; #ifdef __GNUC__ __int32 reverse = (__int32)lrintf(o); --- 1143,1147 ---- while (frames--) { ! float o = (float)*(in++) * SCALE_INT24; #ifdef __GNUC__ __int32 reverse = (__int32)lrintf(o); *************** *** 1179,1182 **** --- 1221,1313 ----
+ + /* callback-based scheduling callbacks: */ + + /* buffer switch callback */ + static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess) + { + ASIOTime time; + memset (&time, 0, sizeof (time)); + /* todo: do we need to syncronize with other media ??? */ + asio_bufferSwitchTimeInfo_cb(&time, db_idx, directprocess); + } + + /* sample rate change callback */ + static void asio_sampleRateDidChange_cb(ASIOSampleRate srate) + { + asio_sampleRateDidChange(srate); + } + + /* asio messaging callback */ + static long asio_messages_cb(long selector, long value, void* message, double* opt) + { + return asio_messages(selector, value, message, opt); + } + + static ASIOTime *asio_bufferSwitchTimeInfo_cb(ASIOTime *params, long db_idx, + ASIOBool directprocess) + { + /* todo: i'm not sure if we'll have to synchronize with other media ... + * probably yes ... */ + + /* perform the processing */ + + sys_lock(); + + for (int j = 0; j < asio_bufsize; j += sys_dacblocksize) + { + /* get sounds from input channels */ + for (long i = 0; i < sys_outchannels + sys_inchannels; i++) + { + t_sample * sp = sys_soundin; + + if(asio_converter[i]) + if (asio_bufferinfo[i].isInput == ASIOTrue) + { + asio_converter[i](asio_bufferinfo[i].buffers[db_idx], + sp, sys_dacblocksize); + sp += sys_dacblocksize; + } + + } + + /* run dsp */ + sched_tick(sys_time + sys_time_per_dsp_tick); + + /* send sound to hardware */ + for (long i = 0; i < sys_outchannels + sys_inchannels; i++) + { + t_sample * sp = sys_soundout; + + /* clip */ + t_float lo = -1.f; + t_float hi = 1.f; + t_int clipargs[6]; + clipargs[1] = clipargs[2] = (t_int)sp; + clipargs[3] = (t_int)&lo; + clipargs[4] = (t_int)&hi; + clipargs[5] = (t_int)sys_dacblocksize; + clipblock(clipargs); + + /* send */ + if(asio_converter[i]) + if (asio_bufferinfo[i].isInput != ASIOTrue) + { + asio_converter[i](sp, asio_bufferinfo[i].buffers[db_idx], + sys_dacblocksize); + sp += sys_dacblocksize; + } + } + } + sys_unlock(); + + if(asio_useoutputready) + ASIOOutputReady(); + + return 0L; /* time info!!! */ + } + + + #endif /* USEAPI_ASIO */