From 8dbec761cf858ea65900c8a094599857208d8c3a Mon Sep 17 00:00:00 2001 From: "N.N." Date: Tue, 5 Jan 2010 22:49:36 +0000 Subject: svn path=/trunk/; revision=12907 --- desiredata/src/s_audio_asio.cpp | 1014 --------------------------------------- 1 file changed, 1014 deletions(-) delete mode 100644 desiredata/src/s_audio_asio.cpp (limited to 'desiredata/src/s_audio_asio.cpp') diff --git a/desiredata/src/s_audio_asio.cpp b/desiredata/src/s_audio_asio.cpp deleted file mode 100644 index fde2891d..00000000 --- a/desiredata/src/s_audio_asio.cpp +++ /dev/null @@ -1,1014 +0,0 @@ -/* Copyright (c) 2004, Tim Blechmann and others - * supported by vibrez.net - * For information on usage and redistribution, and for a DISCLAIMER OF ALL - * WARRANTIES, see the file, "LICENSE.txt" in this distribution. */ - -/* native ASIO interface for windows - * adapted from hostsample.cpp (ASIO SDK) - */ - -#ifdef MSW -#include "windows.h" /* for application window handle */ -#define IEEE754_64FLOAT 1 -#else -#error This is for MS Windows (Intel CPU architecture) only!! -#endif - -#ifdef _MSC_VER -#pragma warning( disable : 4091 ) -#endif - -#include "m_pd.h" -extern "C" { -#include "s_stuff.h" -#include "m_simd.h" -} - -#include "asio.h" /* steinberg's header file */ -#include "asiodrivers.h" /* ASIODrivers class */ -#include "asiosys.h" -#include "pthread.h" -#include "stdio.h" /* for sprintf */ - -#include -#include - -#include "assert.h" -#define ASSERT assert - - -/* fast float to integer conversion adapted from Erik de Castro Lopo */ -#define _ISOC9X_SOURCE 1 -#define _ISOC99_SOURCE 1 -#define __USE_ISOC9X 1 -#define __USE_ISOC99 1 -#include "math.h" - -// seconds to wait for driver to respond -#define DRIVERWAIT 1 - -#define ASIODEBUG - -/* public function prototypes */ -// extern "C" void asio_open_audio(int naudioindev, int *audioindev, int nchindev, -// int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler); -extern "C" void asio_close_audio(); -extern "C" void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize); -extern "C" int asio_send_dacs(); - -/* asio callback prototypes for traditional scheduling*/ -static void asio_bufferSwitch(long db_idx, ASIOBool directprocess); -static void asio_sampleRateDidChange(ASIOSampleRate srate); -static long asio_messages(long selector, long value, void* message, double* opt); -static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, 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); -static void float32tofloat64(void* inbuffer, void* outbuffer, long frames); -static void float64tofloat32(void* inbuffer, void* outbuffer, long frames); -static void float32toInt16(void* inbuffer, void* outbuffer, long frames); -static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames); -static void float32toInt24(void* inbuffer, void* outbuffer, long frames); -static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames); -static void float32toInt32(void* inbuffer, void* outbuffer, long frames); -static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames); -static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames); -static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames); -static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames); -static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames); -static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames); -static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames); -void asio_close_audio(void); - -typedef void converter_t(void* inbuffer, void* outbuffer, long frames); - -/* sample converting helper functions: - * - global send / receive functions - * - sample conversion functions (adapted from ASIOConvertSamples.cpp */ -static converter_t *asio_converter_send (ASIOSampleType format); -static converter_t *asio_converter_receive (ASIOSampleType format); - -/* pointers to the converter functions of each channel are stored here */ -static converter_t **asio_converter = NULL; - -/* function to get sample width of data according to ASIOSampleType */ -static int asio_get_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) */ -static int *asio_samplewidth = NULL; - - -/* some local helper functions */ -static void prepare_asio_drivernames(); - -/* system dependent helper functions */ -static unsigned long get_sys_reference_time(); - -/* global storage */ -static ASIODriverInfo * asio_driver = NULL; -static ASIOBufferInfo * asio_bufferinfo = NULL; -static ASIOChannelInfo* asio_channelinfo = NULL; -static AsioTimeInfo * asio_timerinfo = NULL; -static ASIOCallbacks asio_callbacks; -extern AsioDrivers * asioDrivers; /* declared in asiodrivers.cpp */ - -static char ** asio_drivernames = NULL; - -static ASIOSampleRate asio_srate; -static long asio_inchannels; -static long asio_outchannels; - -static long asio_minbufsize; -static long asio_maxbufsize; -static long asio_prefbufsize; -static long asio_granularity; -static unsigned char asio_useoutputready; -static long asio_inputlatency; -static long asio_outputlatency; - -static long asio_bufsize; /* hardware buffer size */ -static long asio_ticks_per_callback; - -unsigned long sys_reftime; - -/* ringbuffer stuff */ -static t_sample ** asio_ringbuffer = NULL; /* ringbuffers */ -static int asio_ringbuffer_inoffset; /* ringbuffer(in) pointer offset for dac */ -static int asio_ringbuffer_outoffset; /* ringbuffer(out) pointer offset */ -static int asio_ringbuffer_length; /* latency - hardware latency in samples*/ - -/* i hope we can remove this to use callback based dsp scheduling */ -static pthread_mutex_t asio_ringbuf_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t asio_ringbuf_cond = PTHREAD_COND_INITIALIZER; - -/* some global definitions: */ -#define ASIOVERSION 2 /* i hope we are compatible with asio 2 */ - -/* definitions from s_audio.c ... it should be save to use them */ -#define DEVDESCSIZE 80 -#define MAXNDEV 20 - -/* from m_sched.c: */ -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)); } - -/*************************************************************************/ - - -/* open asio interface */ -/* todo: some more error messages */ -void asio_open_audio(int naudioindev, int *audioindev, int nchindev, -int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev, int srate, int scheduler) { - ASIOError status = ASE_OK; - ASIOBufferInfo * buffers = NULL; - int i; - int channels; - -#ifdef IEEE754_64FLOAT - asio_srate=(ASIOSampleRate)srate; -#else - sprintf(asio_srate,"%8d",srate); -#endif - /* check, if the driver is still running */ - if(asio_driver) asio_close_audio(); - /* check, if we use the first asio device */ - prepare_asio_drivernames(); - asioDrivers->getDriverNames(asio_drivernames,MAXNDEV); - - try { - asioDrivers->loadDriver(asio_drivernames[*audioindev]); - } - catch(...) { - error("ASIO: Error loading driver"); - goto bailout; - } - /* initialize ASIO */ - asio_driver = (ASIODriverInfo*) getbytes (sizeof(ASIODriverInfo)); - asio_driver->asioVersion = ASIOVERSION; - asio_driver->sysRef = GetDesktopWindow(); - status = ASIOInit(asio_driver); -#ifdef ASIODEBUG - post("sysRef: %x", asio_driver->sysRef); - post("asioversion: %d", asio_driver->asioVersion); - post("driverversion: %d", asio_driver->driverVersion); - post("name: %s", asio_driver->name); -#endif - - switch (status) { - if(status) post("error: %s", asio_driver->errorMessage); - case ASE_NotPresent: error("ASIO: ASE_NotPresent"); goto bailout; - case ASE_NoMemory: error("ASIO: ASE_NoMemory"); goto bailout; - case ASE_HWMalfunction: error("ASIO: ASE_HWMalfunction"); goto bailout; - } -#ifdef ASIODEBUG - post("ASIO initialized successfully"); -#endif - - - /* query driver */ - status = ASIOGetChannels(&asio_inchannels, &asio_outchannels); - if(status != ASE_OK) { - error("ASIO: Couldn't get channel count"); - goto bailout; - } - -#ifdef ASIODEBUG - post ("ASIOGetChannels\tinputs: %d, outputs: %d", asio_inchannels, - asio_outchannels); -#endif - - sys_inchannels = *chindev <= asio_inchannels ? *chindev : asio_inchannels; - sys_outchannels = *choutdev <= asio_outchannels ? *choutdev : asio_outchannels; - channels = sys_inchannels + sys_outchannels; - status = ASIOGetBufferSize(&asio_minbufsize, &asio_maxbufsize, &asio_prefbufsize, &asio_granularity); - if(status != ASE_OK) { - error("ASIO: Couldn't get buffer size"); - goto bailout; - } -#ifdef ASIODEBUG - post ("ASIOGetBufferSize\tmin: %d, max: %d, preferred: %d, granularity: " - "%d", asio_minbufsize, asio_maxbufsize, asio_prefbufsize, - asio_granularity); -#endif - - /* todo: buffer size hardcoded to asio hardware */ - asio_bufsize = asio_prefbufsize; - if (scheduler) { - if ( asio_bufsize % sys_dacblocksize == 0 ) { - /* use callback scheduler */ - sys_setscheduler(1); - asio_ticks_per_callback = asio_bufsize / sys_dacblocksize; - post("ASIO: using callback-based scheduler"); - } - } else post("ASIO: using traditional scheduler"); - /* try to set sample rate */ - if(ASIOCanSampleRate( asio_srate ) != ASE_OK) { - error ("Samplerate not supported, using default"); -#ifdef IEEE754_64FLOAT - asio_srate = (ASIOSampleRate)44100.0; -#else - sprintf(&asio_srate,"%8d",44100); -#endif - srate=44100; - } - - status = ASIOSetSampleRate( asio_srate ); - if(status != ASE_OK) -#ifdef IEEE754_64FLOAT - post("Setting ASIO sample rate to %lg failed... is the device in slave sync mode?", (double)asio_srate); -#else - post("Setting ASIO sample rate to %s failed... is the device in slave sync mode?", asio_srate); -#endif - - if(ASIOOutputReady() == ASE_OK) - asio_useoutputready = 1; - else - asio_useoutputready = 0; - - - /* 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 */ - asio_bufferinfo = (ASIOBufferInfo*) getbytes (channels*sizeof(ASIOBufferInfo)); - asio_channelinfo = (ASIOChannelInfo*) getbytes(channels*sizeof(ASIOChannelInfo)); - if (!(asio_bufferinfo && asio_channelinfo)) { - error("ASIO: couldn't allocate buffer or channel info"); - goto bailout; - } - - for (i = 0; i != sys_inchannels + sys_outchannels; ++i) { - if (i < sys_outchannels) { - asio_bufferinfo[i].isInput = ASIOFalse; - asio_bufferinfo[i].channelNum = i; - asio_bufferinfo[i].buffers[0] = asio_bufferinfo[i].buffers[1] = 0; - } else { - 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) { - error("ASIO: couldn't allocate buffers"); - goto bailout; - } -#ifdef ASIODEBUG - post("ASIO: buffers allocated"); -#endif - - asio_converter = (converter_t **)getbytes(channels * sizeof (converter_t *)); - asio_samplewidth = (int *)getbytes((sys_outchannels + sys_inchannels) * sizeof (int)); - for (i = 0; i != sys_outchannels + sys_inchannels; ++i) { - asio_channelinfo[i].channel = asio_bufferinfo[i].channelNum; - asio_channelinfo[i].isInput = asio_bufferinfo[i].isInput; - ASIOGetChannelInfo(&asio_channelinfo[i]); - -#ifdef ASIODEBUG - post("ASIO: channel %d type %d", i, asio_channelinfo[i].type); -#endif - asio_samplewidth[i] = asio_get_samplewidth(asio_channelinfo[i].type); - if (i < sys_outchannels) asio_converter[i] = asio_converter_send( asio_channelinfo[i].type); - else asio_converter[i] = asio_converter_receive(asio_channelinfo[i].type); - } - - /* get latencies */ - ASIOGetLatencies(&asio_inputlatency, &asio_outputlatency); -#ifdef ASIODEBUG - post("ASIO: input latency: %d, output latency: %d",asio_inputlatency, asio_outputlatency); -#endif - - - /* 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; - -bailout: - if(status) post("error: %s", asio_driver->errorMessage); - post("ASIO: couldn't start"); - asio_close_audio(); - return; -} - - - -/* stop asio, free buffers and close asio interface */ -void asio_close_audio() { - if (asio_driver) { - pthread_cond_broadcast(&asio_ringbuf_cond); - - ASIOError status; - int channels = sys_inchannels + sys_outchannels; - int i; - - if(asio_useoutputready) { - // the DMA buffers would be played past ASIOStop - // -> clear output buffers and notify driver -#if 0 - if(asio_ringbuffer) { - // slow, blocking method - for(i = 0; i != sys_outchannels; ++i) - zerovec_simd(asio_ringbuffer[i], asio_ringbuffer_length); - // wait for bufferswitch to process silence (twice) - pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex); - for(i = 0; i != sys_outchannels; ++i) memset(asio_ringbuffer[i], 0, asio_ringbuffer_length * sizeof (t_sample)); - pthread_cond_wait(&asio_ringbuf_cond, &asio_ringbuf_mutex); - } -#else - // direct method - clear both hardware buffers - if(asio_bufferinfo && asio_samplewidth) { - for(i = 0; i < sys_outchannels; ++i) { - long bytes = asio_bufsize*asio_samplewidth[i]; - memset(asio_bufferinfo[i].buffers[0],0,bytes); - memset(asio_bufferinfo[i].buffers[1],0,bytes); - } - } - // notify driver - status = ASIOOutputReady(); -#endif - } - - status = ASIOStop(); - if(status == ASE_OK) post("ASIO: stopped"); - status = ASIODisposeBuffers(); - try { - // ASIOExit can crash if driver not really running - status = ASIOExit(); - } catch(...) {} - // deallocate all memory - if(asio_ringbuffer) { - for(i = 0; i < channels; i++) - if(asio_ringbuffer[i]) freealignedbytes(asio_ringbuffer[i],asio_ringbuffer_length * sizeof (t_sample)); - freebytes(asio_ringbuffer, channels * sizeof (t_sample *)); - asio_ringbuffer = NULL; - } - - if(asio_bufferinfo) { - freebytes(asio_bufferinfo, channels * sizeof (ASIOBufferInfo)); - asio_bufferinfo = NULL; - } - if(asio_channelinfo) { - freebytes(asio_channelinfo, channels * sizeof (ASIOChannelInfo)); - asio_channelinfo = NULL; - } - if(asio_converter) { - freebytes(asio_converter, channels * sizeof (converter_t *)); - asio_converter = NULL; - } - if(asio_samplewidth) { - freebytes(asio_samplewidth, (sys_outchannels + sys_inchannels) * sizeof (int)); - asio_samplewidth = NULL; - } - freebytes(asio_driver, sizeof (ASIODriverInfo)); - asio_driver = NULL; - /* leave the scheduler and return to traditional mode */ - if (sys_callbackscheduler) sys_setscheduler(0); - } -} - -void asio_getdevs(char *indevlist, int *nindevs, char *outdevlist, int *noutdevs, int *canmulti, int maxndev, int devdescsize) { - prepare_asio_drivernames(); - *canmulti = 0; /* we will only support one asio device */ - *nindevs = *noutdevs = (int)asioDrivers->getDriverNames(asio_drivernames, maxndev); - for(int i = 0; i!= *nindevs; ++i) { - sprintf(indevlist + i * devdescsize, "%s", asio_drivernames[i]); - sprintf(outdevlist + i * devdescsize, "%s", asio_drivernames[i]); - } -} - -/* called on every dac~ send */ -int asio_send_dacs() { - t_sample * sp; /* sample pointer */ - int i, j; - double timenow; - double timeref = sys_getrealtime(); -#ifdef ASIODEBUG - if (!asio_driver) { - static int written = 0; - if(written%100 == 0) error("ASIO not running"); - written++; - return SENDDACS_NO; - } - -#endif - - /* send sound to ringbuffer */ - sp = sys_soundout; - for (i = 0; i < sys_outchannels; i++) { - t_float lo = -1.f; - t_float hi = 1.f; - t_int clipargs[6]; - clipargs[1] = (t_int)sp; - clipargs[2] = (t_int)(asio_ringbuffer[i] + asio_ringbuffer_inoffset); - clipargs[3] = (t_int)&lo; - clipargs[4] = (t_int)&hi; - clipargs[5] = (t_int)sys_dacblocksize; - clipblock(clipargs); - zeroblock(sp,sys_dacblocksize); - sp+=sys_dacblocksize; - } - /* get sound from ringbuffer */ - sp = sys_soundin; - for (j = 0; j < sys_inchannels; j++) { -#if 0 - /* we should be able to read from the ringbuffer on a different position - * to reduce latency for asio buffer sizes that aren't multiples of 64... */ - int offset = asio_bufsize + sys_dacblocksize; - offset += sys_dacblocksize - offset % sys_dacblocksize; - if (asio_ringbuffer_inoffset < offset) { - memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_length + - asio_ringbuffer_inoffset - offset, 64 *sizeof(t_sample)); - } else memcpy(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset - offset, 64*sizeof(t_sample)); -#else - /* working but higher latency */ - copyblock(sp, asio_ringbuffer[i+j] + asio_ringbuffer_inoffset,sys_dacblocksize); -#endif - sp+=sys_dacblocksize; - } - asio_ringbuffer_inoffset += sys_dacblocksize; -#if 1 - // blocking method - if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) { - struct timespec tm; - _timeb tmb; - _ftime(&tmb); - tm.tv_nsec = tmb.millitm*1000000; - tm.tv_sec = tmb.time+DRIVERWAIT; // delay - if(pthread_cond_timedwait(&asio_ringbuf_cond, &asio_ringbuf_mutex, &tm) == ETIMEDOUT) { - error("ASIO: ASIO driver non-responsive! - closing"); - asio_close_audio(); - return SENDDACS_SLEPT; - } - if (asio_ringbuffer_inoffset == asio_ringbuffer_length) { - asio_ringbuffer_outoffset = 0; - asio_ringbuffer_inoffset = 0; - } else asio_ringbuffer_outoffset += asio_bufsize; - } - if ((timenow = sys_getrealtime()) - timeref > 0.002) { - return SENDDACS_SLEPT; - } -#else - // non-blocking... let PD wait -> doesn't work! - if (asio_ringbuffer_inoffset >= asio_ringbuffer_outoffset + asio_bufsize) return SENDDACS_NO; - if (asio_ringbuffer_inoffset == asio_ringbuffer_length) { - asio_ringbuffer_outoffset = 0; - asio_ringbuffer_inoffset = 0; - } else asio_ringbuffer_outoffset += asio_bufsize; -#endif - return SENDDACS_YES; -} - -/* buffer switch callback */ -static void asio_bufferSwitch(long db_idx, ASIOBool directprocess) { - ASIOTime time; -#ifdef ASIODEBUG - static int written = 0; - if(written == 0) { - post("ASIO: asio_bufferSwitch_cb"); - written = 1; - } -#endif - memset (&time, 0, sizeof (time)); - /* todo: do we need to syncronize with other media ??? */ - asio_bufferSwitchTimeInfo(&time, db_idx, directprocess); -} - -/* sample rate change callback */ -static void asio_sampleRateDidChange(ASIOSampleRate srate) { - asio_srate = srate; -#ifdef ASIODEBUG - post("sample rate changed"); -#endif -} - -/* asio messaging callback */ -static long asio_messages(long selector, long value, void* message, double* opt) { - switch (selector) { - case kAsioSelectorSupported: - if (value == kAsioResetRequest || value == kAsioSupportsTimeInfo) return 1L; - return 0L; - case kAsioEngineVersion: - return ASIOVERSION; - case kAsioResetRequest: - /* how to handle this without changing the dsp scheduler? */ - post("ASIO: Reset request"); - return 1L; - case kAsioBufferSizeChange: - /* todo */ - post("ASIO: Buffer size changed"); - sys_reopen_audio(); - return 1L; - case kAsioResyncRequest: - post("ASIO: Resync request"); - return 0L; - case kAsioLatenciesChanged: - /* we are not handling the latencies atm */ - return 0L; - case kAsioSupportsTimeInfo: - return 1L; - case kAsioSupportsTimeCode: - /* we don't support that atm */ - return 0L; - } - return 0L; -} - -static ASIOTime *asio_bufferSwitchTimeInfo(ASIOTime *params, long db_idx, ASIOBool directprocess) { - /* todo: i'm not sure if we'll have to synchronize with other media ... probably yes ... */ - /* sys_reftime = get_sys_reference_time(); */ - /* perform the processing */ - int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6; - if (sys_timedlock(timeout) == ETIMEDOUT) /* we're late */ { - post("timeout %d", timeout); - sys_log_error(ERR_SYSLOCK); - return 0; - } - for (long i = 0; i < sys_outchannels + sys_inchannels; i++) { - if(asio_converter[i]) - if (asio_bufferinfo[i].isInput != ASIOTrue) { - asio_converter[i](asio_ringbuffer[i]+asio_ringbuffer_outoffset, - asio_bufferinfo[i].buffers[db_idx], asio_bufsize); - } - else /* these are the input channels */ { - asio_converter[i](asio_bufferinfo[i].buffers[db_idx], - asio_ringbuffer[i]+asio_ringbuffer_outoffset, asio_bufsize); - } - } - pthread_cond_broadcast(&asio_ringbuf_cond); - sys_unlock(); - if(asio_useoutputready) ASIOOutputReady(); - return 0L; /* time info!!! */ -} - -/* get system reference time on both platforms */ -static unsigned long get_sys_reference_time() { -#if WINDOWS - return timeGetTime(); -#elif MAC - static const double twoRaisedTo32 = 4294967296.; - UnsignedWide ys; - Microseconds(&ys); - double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo); - return (unsigned long)(r / 1000.); -#endif -} - -/* sample converting helper functions */ -static converter_t *asio_converter_send(ASIOSampleType format) { -#ifdef ASIODEBUG - /* post("ASIO: Sample Type %d", format); */ -#endif - switch (format) { - case ASIOSTInt16LSB: return float32toInt16; - case ASIOSTInt24LSB: return float32toInt24; // used for 20 bits as well - case ASIOSTInt32LSB: return float32toInt32; - case ASIOSTInt16MSB: return float32toInt16_S; - case ASIOSTInt24MSB: return float32toInt24_S; // used for 20 bits as well - case ASIOSTInt32MSB: return float32toInt32_S; - case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture - case ASIOSTFloat32MSB:return float32tofloat32_S; - case ASIOSTFloat64LSB:return float32tofloat64; // IEEE 754 64 bit double float, as found on Intel x86 architecture - case ASIOSTFloat64MSB: - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment - case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment - case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment - case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment - case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment - case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment - case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment - default: - post("Output sample Type %d not supported, yet!!!",format); - return NULL; - } -} - -static converter_t *asio_converter_receive (ASIOSampleType format) { -#ifdef ASIODEBUG - /* post("ASIO: Sample Type %d", format); */ -#endif - switch (format) { - case ASIOSTInt16LSB: return Int16tofloat32; - case ASIOSTInt24LSB: return Int24tofloat32; // used for 20 bits as well - case ASIOSTInt32LSB: return Int32tofloat32; - case ASIOSTInt16MSB: return Int16tofloat32_S; - case ASIOSTInt24MSB: return Int24tofloat32_S; // used for 20 bits as well - case ASIOSTInt32MSB: return Int32tofloat32_S; - case ASIOSTFloat32MSB:return float32tofloat32_S; // IEEE 754 32 bit float, as found on Intel x86 architecture - case ASIOSTFloat32LSB:return float32tofloat32; // IEEE 754 32 bit float, as found on Intel x86 architecture - case ASIOSTFloat64LSB:return float64tofloat32; // IEEE 754 64 bit double float, as found on Intel x86 architecture - case ASIOSTFloat64MSB: - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment - case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment - case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment - case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment - case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment - case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment - case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment - default: - post("Input sample Type %d not supported, yet!!!",format); - return NULL; - } -} - -static int asio_get_samplewidth(ASIOSampleType format) { - switch (format) { - case ASIOSTInt16LSB: case ASIOSTInt16MSB: return 2; - case ASIOSTInt24LSB: case ASIOSTInt24MSB: return 3; - case ASIOSTFloat32LSB:case ASIOSTFloat32MSB: - case ASIOSTInt32LSB: case ASIOSTInt32MSB: - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32LSB16: - case ASIOSTInt32LSB18: - case ASIOSTInt32LSB20: - case ASIOSTInt32LSB24: - // these are used for 32 bit data buffer, with different alignment of the data inside - // 32 bit PCI bus systems can more easily used with these - case ASIOSTInt32MSB16: - case ASIOSTInt32MSB18: - case ASIOSTInt32MSB20: - case ASIOSTInt32MSB24: - return 4; - case ASIOSTFloat64MSB: - case ASIOSTFloat64LSB: - return 8; - default: - post("Input sample Type %d not supported, yet!!!",format); - return 0; - } -} - -/* dithering algo taken from Portaudio ASIO implementation */ -/************************************************************* -** Calculate 2 LSB dither signal with a triangular distribution. -** Ranged properly for adding to a 32 bit integer prior to >>15. -*/ -#define DITHER_BITS (15) -#define DITHER_SCALE (1.0f / ((1<>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS)); - /* High pass filter to reduce audibility. */ - highPass = current - previous; - previous = current; - return highPass; -} - -/* sample conversion functions */ - -#define SCALE_INT16 32767.f /* (- (expt 2 15) 1) */ -#define SCALE_INT24 8388607.f /* (- (expt 2 23) 1) */ -#define SCALE_INT32 2147483647.f /* (- (expt 2 31) 1) */ - -/* Swap LSB to MSB and vice versa */ -inline __int32 swaplong(__int32 v) { - return ((v>>24)&0xFF)|((v>>8)&0xFF00)|((v&0xFF00)<<8)|((v&0xFF)<<24); -} - -inline __int16 swapshort(__int16 v) { - return ((v>>8)&0xFF)|((v&0xFF)<<8); -} - -/* todo: check dithering */ - -static void float32tofloat32(void* inbuffer, void* outbuffer, long frames) { - if(SIMD_CHECK2(frames,inbuffer,outbuffer)) copyvec_simd((float *)outbuffer,(float *)inbuffer,frames); - else memcpy (outbuffer, inbuffer, frames* sizeof (float)); -} - -static void float32tofloat32_S(void* inbuffer, void* outbuffer, long frames) { - __int32 *in = (__int32 *)inbuffer; - __int32* out = (__int32*)outbuffer; - while (frames--) *out++ = swaplong(*(in++)); -} - -static void float32tofloat64(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - double* out = (double*)outbuffer; - while (frames--) *(out++) = *(in++); -} - -static void float64tofloat32(void* inbuffer, void* outbuffer, long frames) { - const double *in = (const double *)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = *(in++); -} - -static void float32toInt16(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - __int16* out = (__int16*)outbuffer; - while (frames--) { - float o = *(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE; - __int16 lng = lrintf(o); - *out++ = lng ; - } -} - -static void Int16tofloat32(void* inbuffer, void* outbuffer, long frames) { - const __int16* in = (const __int16*)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT16); -} - -static void float32toInt24(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - __int32* out = (__int32*)outbuffer; - while (frames--) { - float o = *(in++) * SCALE_INT24; - __int32 intg = (__int32)lrintf(o); - *(out++) = intg; - } -} - -static void Int24tofloat32(void* inbuffer, void* outbuffer, long frames) { - const __int32* in = (const __int32*)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT24); -} - -static void float32toInt32(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - __int32* out = (__int32*)outbuffer; - while (frames--) { - float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE; - *out++ = lrintf(o); - } -} - -static void Int32tofloat32(void* inbuffer, void* outbuffer, long frames) { - const __int32* in = (const __int32*)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = (float)*(in++) * (1.f / SCALE_INT32); -} - -static void float32toInt16_S(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - __int16* out = (__int16*)outbuffer; - while (frames--) { - float o = (float)*(in++) * SCALE_INT16 + triangulardither() * DITHER_SCALE; - __int16 reverse = (__int16)lrintf(o); - *out++ = swapshort(reverse); - } -} - -static void Int16tofloat32_S(void* inbuffer, void* outbuffer, long frames) { - const __int16* in = (const __int16*)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = (float)swapshort(*(in++)) * (1.f / SCALE_INT16); -} - -static void float32toInt24_S(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - char* out = (char*)outbuffer; - while (frames--) { - float o = (float)*(in++) * SCALE_INT24; - __int32 reverse = (__int32)lrintf(o); - out[2] = ((char *)&reverse)[0]; - out[1] = ((char *)&reverse)[1]; - out[0] = ((char *)&reverse)[2]; - out += 3; - } -} - -static void Int24tofloat32_S(void* inbuffer, void* outbuffer, long frames) { - const char* in = (const char*)inbuffer; - float *out = (float *)outbuffer; - __int32 d = 0; - while (frames--) { - ((char *)&d)[1] = in[2]; - ((char *)&d)[2] = in[1]; - ((char *)&d)[3] = in[0]; - *(out++) = (float)d * (1.f / SCALE_INT24); - in += 3; - } -} - -static void float32toInt32_S(void* inbuffer, void* outbuffer, long frames) { - const float *in = (const float *)inbuffer; - __int32* out = (__int32*)outbuffer; - while (frames--) { - float o = (float)*(in++) * SCALE_INT32 + triangulardither() * DITHER_SCALE; - __int32 reverse = (__int32)lrintf(o); - *out++ = swaplong(reverse); - } -} - -static void Int32tofloat32_S(void* inbuffer, void* outbuffer, long frames) { - const __int32* in = (const __int32*)inbuffer; - float *out = (float *)outbuffer; - while (frames--) *(out++) = (float)swaplong(*(in++)) * (1.f / SCALE_INT32); -} - - -/* some local helper functions */ -static void prepare_asio_drivernames() { - if (!asio_drivernames) { - asio_drivernames = (char**)getbytes(MAXNDEV * sizeof(char*)); - for (int i = 0; i!= MAXNDEV; ++i) { - asio_drivernames[i] = (char*)getbytes (32 * sizeof(char)); - } - } - /* load the driver */ - if (!asioDrivers) asioDrivers = new AsioDrivers(); - return; -} - -/* callback-based scheduling callbacks: */ - -/* buffer switch callback */ -static void asio_bufferSwitch_cb(long db_idx, ASIOBool directprocess) { - ASIOTime time; -#ifdef ASIODEBUG - static int written = 0; - if(written == 0) { - post("ASIO: asio_bufferSwitch_cb"); - written = 1; - } -#endif - 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 */ - int timeout = sys_dacblocksize * (float)asio_ticks_per_callback / (float) sys_dacsr * 1e6; - if (sys_timedlock(timeout) == ETIMEDOUT) - /* we're late ... lets hope that jack doesn't kick us out */ - return 0; - - for (int j = 0; j != asio_ticks_per_callback; j++) { - t_sample * sp = sys_soundin; - /* get sounds from input channels */ - for (long i = 0; i < sys_outchannels + sys_inchannels; i++) { - if(asio_converter[i]) - if (asio_bufferinfo[i].isInput == ASIOTrue) { - asio_converter[i]((char*)asio_bufferinfo[i].buffers[db_idx] + - asio_samplewidth[i] * j *sys_dacblocksize, sp, sys_dacblocksize); - sp += sys_dacblocksize; - } - } - /* run dsp */ - sched_tick(sys_time + sys_time_per_dsp_tick); - sp = sys_soundout; - /* send sound to hardware */ - for (long i = 0; i < sys_outchannels + sys_inchannels; i++) { - if (asio_bufferinfo[i].isInput != ASIOTrue) { - /* 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]) - asio_converter[i](sp, (char*)asio_bufferinfo[i].buffers[db_idx] - + asio_samplewidth[i] * j *sys_dacblocksize, sys_dacblocksize); - zeroblock(sp,sys_dacblocksize); - sp += sys_dacblocksize; - } - } - } - if(asio_useoutputready) ASIOOutputReady(); - sys_unlock(); - return 0L; /* time info!!! */ -} - -t_audioapi asio_api = { - asio_open_audio, - asio_close_audio, - asio_send_dacs, - asio_getdevs, -}; -- cgit v1.2.1