From: DaShun Date: Tue, 17 Apr 2018 03:36:55 +0000 (+0800) Subject: Add asio lib. X-Git-Tag: v19.7.0~141 X-Git-Url: https://andrewgundersen.net/repos?a=commitdiff_plain;h=c5e8f1dca7f2d1b9c3d5c92a3f6f174870c303d8;p=portaudio Add asio lib. --- diff --git a/src/hostapi/asio/ASIOSDK/ASIO SDK 2.3.pdf b/src/hostapi/asio/ASIOSDK/ASIO SDK 2.3.pdf new file mode 100644 index 0000000..378553c Binary files /dev/null and b/src/hostapi/asio/ASIOSDK/ASIO SDK 2.3.pdf differ diff --git a/src/hostapi/asio/ASIOSDK/Steinberg ASIO Licensing Agreement.pdf b/src/hostapi/asio/ASIOSDK/Steinberg ASIO Licensing Agreement.pdf new file mode 100644 index 0000000..492db70 Binary files /dev/null and b/src/hostapi/asio/ASIOSDK/Steinberg ASIO Licensing Agreement.pdf differ diff --git a/src/hostapi/asio/ASIOSDK/asio/asio.dsw b/src/hostapi/asio/ASIOSDK/asio/asio.dsw new file mode 100644 index 0000000..14bc965 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/asio/asio.dsw @@ -0,0 +1,41 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "asiosample"="..\driver\asiosample\asiosample\asiosample.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "hostsample"="..\host\sample\hostsample.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/hostapi/asio/ASIOSDK/asio/asio.opt b/src/hostapi/asio/ASIOSDK/asio/asio.opt new file mode 100644 index 0000000..ef444d6 Binary files /dev/null and b/src/hostapi/asio/ASIOSDK/asio/asio.opt differ diff --git a/src/hostapi/asio/ASIOSDK/changes.txt b/src/hostapi/asio/ASIOSDK/changes.txt new file mode 100644 index 0000000..22c4428 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/changes.txt @@ -0,0 +1,12 @@ +Changes in ASIO 2.3 since ASIO 2.2 +- added host queries to detect the driver's buffering and drop-out detection capabilities +- some additional documentation on MMCSS; see page 46 of 'ASIO SDK 2.3.pdf' +- dropped support for Mac OS 8 and 9 + +Changes in ASIO 2.2 since ASIO 2.1 +- added support for Windows 64 bit + +Changes in ASIO 2.1 since ASIO 2.0 +- Sony DSD support added +- fixed Windows registry sample to HKEY_LOCAL_MACHINE +- fixed a definition problem for input monitoring diff --git a/src/hostapi/asio/ASIOSDK/common/asio.cpp b/src/hostapi/asio/ASIOSDK/common/asio.cpp new file mode 100644 index 0000000..747b9e8 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/asio.cpp @@ -0,0 +1,257 @@ +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + + asio.cpp + + asio functions entries which translate the + asio interface to the asiodrvr class methods +*/ + +#include +#include "asiosys.h" // platform definition +#include "asio.h" + +#if MAC +#include "asiodrvr.h" + +#pragma export on + +AsioDriver *theAsioDriver = 0; + +extern "C" +{ + +long main() +{ + return 'ASIO'; +} + +#elif WINDOWS + +#include "windows.h" +#include "iasiodrv.h" +#include "asiodrivers.h" + +IASIO *theAsioDriver = 0; +extern AsioDrivers *asioDrivers; + +#elif SGI || SUN || BEOS || LINUX +#include "asiodrvr.h" +static AsioDriver *theAsioDriver = 0; +#endif + +//----------------------------------------------------------------------------------------------------- +ASIOError ASIOInit(ASIODriverInfo *info) +{ +#if MAC || SGI || SUN || BEOS || LINUX + if(theAsioDriver) + { + delete theAsioDriver; + theAsioDriver = 0; + } + info->driverVersion = 0; + strcpy(info->name, "No ASIO Driver"); + theAsioDriver = getDriver(); + if(!theAsioDriver) + { + strcpy(info->errorMessage, "Not enough memory for the ASIO driver!"); + return ASE_NotPresent; + } + if(!theAsioDriver->init(info->sysRef)) + { + theAsioDriver->getErrorMessage(info->errorMessage); + delete theAsioDriver; + theAsioDriver = 0; + return ASE_NotPresent; + } + strcpy(info->errorMessage, "No ASIO Driver Error"); + theAsioDriver->getDriverName(info->name); + info->driverVersion = theAsioDriver->getDriverVersion(); + return ASE_OK; + +#else + + info->driverVersion = 0; + strcpy(info->name, "No ASIO Driver"); + if(theAsioDriver) // must be loaded! + { + if(!theAsioDriver->init(info->sysRef)) + { + theAsioDriver->getErrorMessage(info->errorMessage); + theAsioDriver = 0; + return ASE_NotPresent; + } + + strcpy(info->errorMessage, "No ASIO Driver Error"); + theAsioDriver->getDriverName(info->name); + info->driverVersion = theAsioDriver->getDriverVersion(); + return ASE_OK; + } + return ASE_NotPresent; + +#endif // !MAC +} + +ASIOError ASIOExit(void) +{ + if(theAsioDriver) + { +#if WINDOWS + asioDrivers->removeCurrentDriver(); +#else + delete theAsioDriver; +#endif + } + theAsioDriver = 0; + return ASE_OK; +} + +ASIOError ASIOStart(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->start(); +} + +ASIOError ASIOStop(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->stop(); +} + +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) +{ + if(!theAsioDriver) + { + *numInputChannels = *numOutputChannels = 0; + return ASE_NotPresent; + } + return theAsioDriver->getChannels(numInputChannels, numOutputChannels); +} + +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) +{ + if(!theAsioDriver) + { + *inputLatency = *outputLatency = 0; + return ASE_NotPresent; + } + return theAsioDriver->getLatencies(inputLatency, outputLatency); +} + +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) +{ + if(!theAsioDriver) + { + *minSize = *maxSize = *preferredSize = *granularity = 0; + return ASE_NotPresent; + } + return theAsioDriver->getBufferSize(minSize, maxSize, preferredSize, granularity); +} + +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->canSampleRate(sampleRate); +} + +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->getSampleRate(currentRate); +} + +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->setSampleRate(sampleRate); +} + +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) +{ + if(!theAsioDriver) + { + *numSources = 0; + return ASE_NotPresent; + } + return theAsioDriver->getClockSources(clocks, numSources); +} + +ASIOError ASIOSetClockSource(long reference) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->setClockSource(reference); +} + +ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->getSamplePosition(sPos, tStamp); +} + +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) +{ + if(!theAsioDriver) + { + info->channelGroup = -1; + info->type = ASIOSTInt16MSB; + strcpy(info->name, "None"); + return ASE_NotPresent; + } + return theAsioDriver->getChannelInfo(info); +} + +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) +{ + if(!theAsioDriver) + { + ASIOBufferInfo *info = bufferInfos; + for(long i = 0; i < numChannels; i++, info++) + info->buffers[0] = info->buffers[1] = 0; + return ASE_NotPresent; + } + return theAsioDriver->createBuffers(bufferInfos, numChannels, bufferSize, callbacks); +} + +ASIOError ASIODisposeBuffers(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->disposeBuffers(); +} + +ASIOError ASIOControlPanel(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->controlPanel(); +} + +ASIOError ASIOFuture(long selector, void *opt) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->future(selector, opt); +} + +ASIOError ASIOOutputReady(void) +{ + if(!theAsioDriver) + return ASE_NotPresent; + return theAsioDriver->outputReady(); +} + +#if MAC +} // extern "C" +#pragma export off +#endif + + diff --git a/src/hostapi/asio/ASIOSDK/common/asio.h b/src/hostapi/asio/ASIOSDK/common/asio.h new file mode 100644 index 0000000..341e755 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/asio.h @@ -0,0 +1,1070 @@ +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +/* + Steinberg Audio Stream I/O API + (c) 1997 - 2013, Steinberg Media Technologies GmbH + + ASIO Interface Specification v 2.3 + + 2005 - Added support for DSD sample data (in cooperation with Sony) + 2012 - Added support for drop out detection + + + + basic concept is an i/o synchronous double-buffer scheme: + + on bufferSwitch(index == 0), host will read/write: + + after ASIOStart(), the + read first input buffer A (index 0) + | will be invalid (empty) + * ------------------------ + |------------------------|-----------------------| + | | | + | Input Buffer A (0) | Input Buffer B (1) | + | | | + |------------------------|-----------------------| + | | | + | Output Buffer A (0) | Output Buffer B (1) | + | | | + |------------------------|-----------------------| + * ------------------------- + | before calling ASIOStart(), + write host will have filled output + buffer B (index 1) already + + *please* take special care of proper statement of input + and output latencies (see ASIOGetLatencies()), these + control sequencer sync accuracy + +*/ + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +/* + +prototypes summary: + +ASIOError ASIOInit(ASIODriverInfo *info); +ASIOError ASIOExit(void); +ASIOError ASIOStart(void); +ASIOError ASIOStop(void); +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); +ASIOError ASIOSetClockSource(long reference); +ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); +ASIOError ASIODisposeBuffers(void); +ASIOError ASIOControlPanel(void); +void *ASIOFuture(long selector, void *params); +ASIOError ASIOOutputReady(void); + +*/ + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +#ifndef __ASIO_H +#define __ASIO_H + +// force 4 byte alignment +#if defined(_MSC_VER) && !defined(__MWERKS__) +#pragma pack(push,4) +#elif PRAGMA_ALIGN_SUPPORTED +#pragma options align = native +#endif + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Type definitions +//- - - - - - - - - - - - - - - - - - - - - - - - - + +// number of samples data type is 64 bit integer +#if NATIVE_INT64 + typedef long long int ASIOSamples; +#else + typedef struct ASIOSamples { + unsigned long hi; + unsigned long lo; + } ASIOSamples; +#endif + +// Timestamp data type is 64 bit integer, +// Time format is Nanoseconds. +#if NATIVE_INT64 + typedef long long int ASIOTimeStamp ; +#else + typedef struct ASIOTimeStamp { + unsigned long hi; + unsigned long lo; + } ASIOTimeStamp; +#endif + +// Samplerates are expressed in IEEE 754 64 bit double float, +// native format as host computer +#if IEEE754_64FLOAT + typedef double ASIOSampleRate; +#else + typedef struct ASIOSampleRate { + char ieee[8]; + } ASIOSampleRate; +#endif + +// Boolean values are expressed as long +typedef long ASIOBool; +enum { + ASIOFalse = 0, + ASIOTrue = 1 +}; + +// Sample Types are expressed as long +typedef long ASIOSampleType; +enum { + ASIOSTInt16MSB = 0, + ASIOSTInt24MSB = 1, // used for 20 bits as well + ASIOSTInt32MSB = 2, + ASIOSTFloat32MSB = 3, // IEEE 754 32 bit float + ASIOSTFloat64MSB = 4, // IEEE 754 64 bit double float + + // these are used for 32 bit data buffer, with different alignment of the data inside + // 32 bit PCI bus systems can be more easily used with these + ASIOSTInt32MSB16 = 8, // 32 bit data with 16 bit alignment + ASIOSTInt32MSB18 = 9, // 32 bit data with 18 bit alignment + ASIOSTInt32MSB20 = 10, // 32 bit data with 20 bit alignment + ASIOSTInt32MSB24 = 11, // 32 bit data with 24 bit alignment + + ASIOSTInt16LSB = 16, + ASIOSTInt24LSB = 17, // used for 20 bits as well + ASIOSTInt32LSB = 18, + ASIOSTFloat32LSB = 19, // IEEE 754 32 bit float, as found on Intel x86 architecture + ASIOSTFloat64LSB = 20, // IEEE 754 64 bit double float, as found on Intel x86 architecture + + // 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 + ASIOSTInt32LSB16 = 24, // 32 bit data with 18 bit alignment + ASIOSTInt32LSB18 = 25, // 32 bit data with 18 bit alignment + ASIOSTInt32LSB20 = 26, // 32 bit data with 20 bit alignment + ASIOSTInt32LSB24 = 27, // 32 bit data with 24 bit alignment + + // ASIO DSD format. + ASIOSTDSDInt8LSB1 = 32, // DSD 1 bit data, 8 samples per byte. First sample in Least significant bit. + ASIOSTDSDInt8MSB1 = 33, // DSD 1 bit data, 8 samples per byte. First sample in Most significant bit. + ASIOSTDSDInt8NER8 = 40, // DSD 8 bit data, 1 sample per byte. No Endianness required. + + ASIOSTLastEntry +}; + +/*----------------------------------------------------------------------------- +// DSD operation and buffer layout +// Definition by Steinberg/Sony Oxford. +// +// We have tried to treat DSD as PCM and so keep a consistant structure across +// the ASIO interface. +// +// DSD's sample rate is normally referenced as a multiple of 44.1Khz, so +// the standard sample rate is refered to as 64Fs (or 2.8224Mhz). We looked +// at making a special case for DSD and adding a field to the ASIOFuture that +// would allow the user to select the Over Sampleing Rate (OSR) as a seperate +// entity but decided in the end just to treat it as a simple value of +// 2.8224Mhz and use the standard interface to set it. +// +// The second problem was the "word" size, in PCM the word size is always a +// greater than or equal to 8 bits (a byte). This makes life easy as we can +// then pack the samples into the "natural" size for the machine. +// In DSD the "word" size is 1 bit. This is not a major problem and can easily +// be dealt with if we ensure that we always deal with a multiple of 8 samples. +// +// DSD brings with it another twist to the Endianness religion. How are the +// samples packed into the byte. It would be nice to just say the most significant +// bit is always the first sample, however there would then be a performance hit +// on little endian machines. Looking at how some of the processing goes... +// Little endian machines like the first sample to be in the Least Significant Bit, +// this is because when you write it to memory the data is in the correct format +// to be shifted in and out of the words. +// Big endian machine prefer the first sample to be in the Most Significant Bit, +// again for the same reasion. +// +// And just when things were looking really muddy there is a proposed extension to +// DSD that uses 8 bit word sizes. It does not care what endianness you use. +// +// Switching the driver between DSD and PCM mode +// ASIOFuture allows for extending the ASIO API quite transparently. +// See kAsioSetIoFormat, kAsioGetIoFormat, kAsioCanDoIoFormat +// +//-----------------------------------------------------------------------------*/ + + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Error codes +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef long ASIOError; +enum { + ASE_OK = 0, // This value will be returned whenever the call succeeded + ASE_SUCCESS = 0x3f4847a0, // unique success return value for ASIOFuture calls + ASE_NotPresent = -1000, // hardware input or output is not present or available + ASE_HWMalfunction, // hardware is malfunctioning (can be returned by any ASIO function) + ASE_InvalidParameter, // input parameter invalid + ASE_InvalidMode, // hardware is in a bad mode or used in a bad mode + ASE_SPNotAdvancing, // hardware is not running when sample position is inquired + ASE_NoClock, // sample clock or rate cannot be determined or is not present + ASE_NoMemory // not enough memory for completing the request +}; + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Time Info support +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOTimeCode +{ + double speed; // speed relation (fraction of nominal speed) + // optional; set to 0. or 1. if not supported + ASIOSamples timeCodeSamples; // time in samples + unsigned long flags; // some information flags (see below) + char future[64]; +} ASIOTimeCode; + +typedef enum ASIOTimeCodeFlags +{ + kTcValid = 1, + kTcRunning = 1 << 1, + kTcReverse = 1 << 2, + kTcOnspeed = 1 << 3, + kTcStill = 1 << 4, + + kTcSpeedValid = 1 << 8 +} ASIOTimeCodeFlags; + +typedef struct AsioTimeInfo +{ + double speed; // absolute speed (1. = nominal) + ASIOTimeStamp systemTime; // system time related to samplePosition, in nanoseconds + // on mac, must be derived from Microseconds() (not UpTime()!) + // on windows, must be derived from timeGetTime() + ASIOSamples samplePosition; + ASIOSampleRate sampleRate; // current rate + unsigned long flags; // (see below) + char reserved[12]; +} AsioTimeInfo; + +typedef enum AsioTimeInfoFlags +{ + kSystemTimeValid = 1, // must always be valid + kSamplePositionValid = 1 << 1, // must always be valid + kSampleRateValid = 1 << 2, + kSpeedValid = 1 << 3, + + kSampleRateChanged = 1 << 4, + kClockSourceChanged = 1 << 5 +} AsioTimeInfoFlags; + +typedef struct ASIOTime // both input/output +{ + long reserved[4]; // must be 0 + struct AsioTimeInfo timeInfo; // required + struct ASIOTimeCode timeCode; // optional, evaluated if (timeCode.flags & kTcValid) +} ASIOTime; + +/* + +using time info: +it is recommended to use the new method with time info even if the asio +device does not support timecode; continuous calls to ASIOGetSamplePosition +and ASIOGetSampleRate are avoided, and there is a more defined relationship +between callback time and the time info. + +see the example below. +to initiate time info mode, after you have received the callbacks pointer in +ASIOCreateBuffers, you will call the asioMessage callback with kAsioSupportsTimeInfo +as the argument. if this returns 1, host has accepted time info mode. +now host expects the new callback bufferSwitchTimeInfo to be used instead +of the old bufferSwitch method. the ASIOTime structure is assumed to be valid +and accessible until the callback returns. + +using time code: +if the device supports reading time code, it will call host's asioMessage callback +with kAsioSupportsTimeCode as the selector. it may then fill the according +fields and set the kTcValid flag. +host will call the future method with the kAsioEnableTimeCodeRead selector when +it wants to enable or disable tc reading by the device. you should also support +the kAsioCanTimeInfo and kAsioCanTimeCode selectors in ASIOFuture (see example). + +note: +the AsioTimeInfo/ASIOTimeCode pair is supposed to work in both directions. +as a matter of convention, the relationship between the sample +position counter and the time code at buffer switch time is +(ignoring offset between tc and sample pos when tc is running): + +on input: sample 0 -> input buffer sample 0 -> time code 0 +on output: sample 0 -> output buffer sample 0 -> time code 0 + +this means that for 'real' calculations, one has to take into account +the according latencies. + +example: + +ASIOTime asioTime; + +in createBuffers() +{ + memset(&asioTime, 0, sizeof(ASIOTime)); + AsioTimeInfo* ti = &asioTime.timeInfo; + ti->sampleRate = theSampleRate; + ASIOTimeCode* tc = &asioTime.timeCode; + tc->speed = 1.; + timeInfoMode = false; + canTimeCode = false; + if(callbacks->asioMessage(kAsioSupportsTimeInfo, 0, 0, 0) == 1) + { + timeInfoMode = true; +#if kCanTimeCode + if(callbacks->asioMessage(kAsioSupportsTimeCode, 0, 0, 0) == 1) + canTimeCode = true; +#endif + } +} + +void switchBuffers(long doubleBufferIndex, bool processNow) +{ + if(timeInfoMode) + { + AsioTimeInfo* ti = &asioTime.timeInfo; + ti->flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; + ti->systemTime = theNanoSeconds; + ti->samplePosition = theSamplePosition; + if(ti->sampleRate != theSampleRate) + ti->flags |= kSampleRateChanged; + ti->sampleRate = theSampleRate; + +#if kCanTimeCode + if(canTimeCode && timeCodeEnabled) + { + ASIOTimeCode* tc = &asioTime.timeCode; + tc->timeCodeSamples = tcSamples; // tc in samples + tc->flags = kTcValid | kTcRunning | kTcOnspeed; // if so... + } + ASIOTime* bb = callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); +#else + callbacks->bufferSwitchTimeInfo(&asioTime, doubleBufferIndex, processNow ? ASIOTrue : ASIOFalse); +#endif + } + else + callbacks->bufferSwitch(doubleBufferIndex, ASIOFalse); +} + +ASIOError ASIOFuture(long selector, void *params) +{ + switch(selector) + { + case kAsioEnableTimeCodeRead: + timeCodeEnabled = true; + return ASE_SUCCESS; + case kAsioDisableTimeCodeRead: + timeCodeEnabled = false; + return ASE_SUCCESS; + case kAsioCanTimeInfo: + return ASE_SUCCESS; + #if kCanTimeCode + case kAsioCanTimeCode: + return ASE_SUCCESS; + #endif + } + return ASE_NotPresent; +}; + +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// application's audio stream handler callbacks +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOCallbacks +{ + void (*bufferSwitch) (long doubleBufferIndex, ASIOBool directProcess); + // bufferSwitch indicates that both input and output are to be processed. + // the current buffer half index (0 for A, 1 for B) determines + // - the output buffer that the host should start to fill. the other buffer + // will be passed to output hardware regardless of whether it got filled + // in time or not. + // - the input buffer that is now filled with incoming data. Note that + // because of the synchronicity of i/o, the input always has at + // least one buffer latency in relation to the output. + // directProcess suggests to the host whether it should immedeately + // start processing (directProcess == ASIOTrue), or whether its process + // should be deferred because the call comes from a very low level + // (for instance, a high level priority interrupt), and direct processing + // would cause timing instabilities for the rest of the system. If in doubt, + // directProcess should be set to ASIOFalse. + // Note: bufferSwitch may be called at interrupt time for highest efficiency. + + void (*sampleRateDidChange) (ASIOSampleRate sRate); + // gets called when the AudioStreamIO detects a sample rate change + // If sample rate is unknown, 0 is passed (for instance, clock loss + // when externally synchronized). + + long (*asioMessage) (long selector, long value, void* message, double* opt); + // generic callback for various purposes, see selectors below. + // note this is only present if the asio version is 2 or higher + + ASIOTime* (*bufferSwitchTimeInfo) (ASIOTime* params, long doubleBufferIndex, ASIOBool directProcess); + // new callback with time info. makes ASIOGetSamplePosition() and various + // calls to ASIOGetSampleRate obsolete, + // and allows for timecode sync etc. to be preferred; will be used if + // the driver calls asioMessage with selector kAsioSupportsTimeInfo. +} ASIOCallbacks; + +// asioMessage selectors +enum +{ + kAsioSelectorSupported = 1, // selector in , returns 1L if supported, + // 0 otherwise + kAsioEngineVersion, // returns engine (host) asio implementation version, + // 2 or higher + kAsioResetRequest, // request driver reset. if accepted, this + // will close the driver (ASIO_Exit() ) and + // re-open it again (ASIO_Init() etc). some + // drivers need to reconfigure for instance + // when the sample rate changes, or some basic + // changes have been made in ASIO_ControlPanel(). + // returns 1L; note the request is merely passed + // to the application, there is no way to determine + // if it gets accepted at this time (but it usually + // will be). + kAsioBufferSizeChange, // not yet supported, will currently always return 0L. + // for now, use kAsioResetRequest instead. + // once implemented, the new buffer size is expected + // in , and on success returns 1L + kAsioResyncRequest, // the driver went out of sync, such that + // the timestamp is no longer valid. this + // is a request to re-start the engine and + // slave devices (sequencer). returns 1 for ok, + // 0 if not supported. + kAsioLatenciesChanged, // the drivers latencies have changed. The engine + // will refetch the latencies. + kAsioSupportsTimeInfo, // if host returns true here, it will expect the + // callback bufferSwitchTimeInfo to be called instead + // of bufferSwitch + kAsioSupportsTimeCode, // + kAsioMMCCommand, // unused - value: number of commands, message points to mmc commands + kAsioSupportsInputMonitor, // kAsioSupportsXXX return 1 if host supports this + kAsioSupportsInputGain, // unused and undefined + kAsioSupportsInputMeter, // unused and undefined + kAsioSupportsOutputGain, // unused and undefined + kAsioSupportsOutputMeter, // unused and undefined + kAsioOverload, // driver detected an overload + + kAsioNumMessageSelectors +}; + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// (De-)Construction +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIODriverInfo +{ + long asioVersion; // currently, 2 + long driverVersion; // driver specific + char name[32]; + char errorMessage[124]; + void *sysRef; // on input: system reference + // (Windows: application main window handle, Mac & SGI: 0) +} ASIODriverInfo; + +ASIOError ASIOInit(ASIODriverInfo *info); +/* Purpose: + Initialize the AudioStreamIO. + Parameter: + info: pointer to an ASIODriver structure: + - asioVersion: + - on input, the host version. *** Note *** this is 0 for earlier asio + implementations, and the asioMessage callback is implemeted + only if asioVersion is 2 or greater. sorry but due to a design fault + the driver doesn't have access to the host version in ASIOInit :-( + added selector for host (engine) version in the asioMessage callback + so we're ok from now on. + - on return, asio implementation version. + older versions are 1 + if you support this version (namely, ASIO_outputReady() ) + this should be 2 or higher. also see the note in + ASIO_getTimeStamp() ! + - version: on return, the driver version (format is driver specific) + - name: on return, a null-terminated string containing the driver's name + - error message: on return, should contain a user message describing + the type of error that occured during ASIOInit(), if any. + - sysRef: platform specific + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + ASE_NoMemory, ASE_HWMalfunction are other possible error conditions +*/ + +ASIOError ASIOExit(void); +/* Purpose: + Terminates the AudioStreamIO. + Parameter: + None. + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + Notes: this implies ASIOStop() and ASIODisposeBuffers(), + meaning that no host callbacks must be accessed after ASIOExit(). +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Start/Stop +//- - - - - - - - - - - - - - - - - - - - - - - - - + +ASIOError ASIOStart(void); +/* Purpose: + Start input and output processing synchronously. + This will + - reset the sample counter to zero + - start the hardware (both input and output) + The first call to the hosts' bufferSwitch(index == 0) then tells + the host to read from input buffer A (index 0), and start + processing to output buffer A while output buffer B (which + has been filled by the host prior to calling ASIOStart()) + is possibly sounding (see also ASIOGetLatencies()) + Parameter: + None. + Returns: + If neither input nor output is present, ASE_NotPresent + will be returned. + If the hardware fails to start, ASE_HWMalfunction will be returned. + Notes: + There is no restriction on the time that ASIOStart() takes + to perform (that is, it is not considered a realtime trigger). +*/ + +ASIOError ASIOStop(void); +/* Purpose: + Stops input and output processing altogether. + Parameter: + None. + Returns: + If neither input nor output is present ASE_NotPresent + will be returned. + Notes: + On return from ASIOStop(), the driver must in no + case call the hosts' bufferSwitch() routine. +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Inquiry methods and sample rate +//- - - - - - - - - - - - - - - - - - - - - - - - - + +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels); +/* Purpose: + Returns number of individual input/output channels. + Parameter: + numInputChannels will hold the number of available input channels + numOutputChannels will hold the number of available output channels + Returns: + If no input/output is present ASE_NotPresent will be returned. + If only inputs, or only outputs are available, the according + other parameter will be zero, and ASE_OK is returned. +*/ + +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency); +/* Purpose: + Returns the input and output latencies. This includes + device specific delays, like FIFOs etc. + Parameter: + inputLatency will hold the 'age' of the first sample frame + in the input buffer when the hosts reads it in bufferSwitch() + (this is theoretical, meaning it does not include the overhead + and delay between the actual physical switch, and the time + when bufferSitch() enters). + This will usually be the size of one block in sample frames, plus + device specific latencies. + + outputLatency will specify the time between the buffer switch, + and the time when the next play buffer will start to sound. + The next play buffer is defined as the one the host starts + processing after (or at) bufferSwitch(), indicated by the + index parameter (0 for buffer A, 1 for buffer B). + It will usually be either one block, if the host writes directly + to a dma buffer, or two or more blocks if the buffer is 'latched' by + the driver. As an example, on ASIOStart(), the host will have filled + the play buffer at index 1 already; when it gets the callback (with + the parameter index == 0), this tells it to read from the input + buffer 0, and start to fill the play buffer 0 (assuming that now + play buffer 1 is already sounding). In this case, the output + latency is one block. If the driver decides to copy buffer 1 + at that time, and pass it to the hardware at the next slot (which + is most commonly done, but should be avoided), the output latency + becomes two blocks instead, resulting in a total i/o latency of at least + 3 blocks. As memory access is the main bottleneck in native dsp processing, + and to acheive less latency, it is highly recommended to try to avoid + copying (this is also why the driver is the owner of the buffers). To + summarize, the minimum i/o latency can be acheived if the input buffer + is processed by the host into the output buffer which will physically + start to sound on the next time slice. Also note that the host expects + the bufferSwitch() callback to be accessed for each time slice in order + to retain sync, possibly recursively; if it fails to process a block in + time, it will suspend its operation for some time in order to recover. + Returns: + If no input/output is present ASE_NotPresent will be returned. +*/ + +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); +/* Purpose: + Returns min, max, and preferred buffer sizes for input/output + Parameter: + minSize will hold the minimum buffer size + maxSize will hold the maxium possible buffer size + preferredSize will hold the preferred buffer size (a size which + best fits performance and hardware requirements) + granularity will hold the granularity at which buffer sizes + may differ. Usually, the buffer size will be a power of 2; + in this case, granularity will hold -1 on return, signalling + possible buffer sizes starting from minSize, increased in + powers of 2 up to maxSize. + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: + When minimum and maximum buffer size are equal, + the preferred buffer size has to be the same value as well; granularity + should be 0 in this case. +*/ + +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate); +/* Purpose: + Inquires the hardware for the available sample rates. + Parameter: + sampleRate is the rate in question. + Returns: + If the inquired sample rate is not supported, ASE_NoClock will be returned. + If no input/output is present ASE_NotPresent will be returned. +*/ +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate); +/* Purpose: + Get the current sample Rate. + Parameter: + currentRate will hold the current sample rate on return. + Returns: + If sample rate is unknown, sampleRate will be 0 and ASE_NoClock will be returned. + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate); +/* Purpose: + Set the hardware to the requested sample Rate. If sampleRate == 0, + enable external sync. + Parameter: + sampleRate: on input, the requested rate + Returns: + If sampleRate is unknown ASE_NoClock will be returned. + If the current clock is external, and sampleRate is != 0, + ASE_InvalidMode will be returned + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +typedef struct ASIOClockSource +{ + long index; // as used for ASIOSetClockSource() + long associatedChannel; // for instance, S/PDIF or AES/EBU + long associatedGroup; // see channel groups (ASIOGetChannelInfo()) + ASIOBool isCurrentSource; // ASIOTrue if this is the current clock source + char name[32]; // for user selection +} ASIOClockSource; + +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources); +/* Purpose: + Get the available external audio clock sources + Parameter: + clocks points to an array of ASIOClockSource structures: + - index: this is used to identify the clock source + when ASIOSetClockSource() is accessed, should be + an index counting from zero + - associatedInputChannel: the first channel of an associated + input group, if any. + - associatedGroup: the group index of that channel. + groups of channels are defined to seperate for + instance analog, S/PDIF, AES/EBU, ADAT connectors etc, + when present simultaniously. Note that associated channel + is enumerated according to numInputs/numOutputs, means it + is independant from a group (see also ASIOGetChannelInfo()) + inputs are associated to a clock if the physical connection + transfers both data and clock (like S/PDIF, AES/EBU, or + ADAT inputs). if there is no input channel associated with + the clock source (like Word Clock, or internal oscillator), both + associatedChannel and associatedGroup should be set to -1. + - isCurrentSource: on exit, ASIOTrue if this is the current clock + source, ASIOFalse else + - name: a null-terminated string for user selection of the available sources. + numSources: + on input: the number of allocated array members + on output: the number of available clock sources, at least + 1 (internal clock generator). + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: +*/ + +ASIOError ASIOSetClockSource(long index); +/* Purpose: + Set the audio clock source + Parameter: + index as obtained from an inquiry to ASIOGetClockSources() + Returns: + If no input/output is present ASE_NotPresent will be returned. + If the clock can not be selected because an input channel which + carries the current clock source is active, ASE_InvalidMode + *may* be returned (this depends on the properties of the driver + and/or hardware). + Notes: + Should *not* return ASE_NoClock if there is no clock signal present + at the selected source; this will be inquired via ASIOGetSampleRate(). + It should call the host callback procedure sampleRateHasChanged(), + if the switch causes a sample rate change, or if no external clock + is present at the selected source. +*/ + +ASIOError ASIOGetSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); +/* Purpose: + Inquires the sample position/time stamp pair. + Parameter: + sPos will hold the sample position on return. The sample + position is reset to zero when ASIOStart() gets called. + tStamp will hold the system time when the sample position + was latched. + Returns: + If no input/output is present, ASE_NotPresent will be returned. + If there is no clock, ASE_SPNotAdvancing will be returned. + Notes: + + in order to be able to synchronise properly, + the sample position / time stamp pair must refer to the current block, + that is, the engine will call ASIOGetSamplePosition() in its bufferSwitch() + callback and expect the time for the current block. thus, when requested + in the very first bufferSwitch after ASIO_Start(), the sample position + should be zero, and the time stamp should refer to the very time where + the stream was started. it also means that the sample position must be + block aligned. the driver must ensure proper interpolation if the system + time can not be determined for the block position. the driver is responsible + for precise time stamps as it usually has most direct access to lower + level resources. proper behaviour of ASIO_GetSamplePosition() and ASIO_GetLatencies() + are essential for precise media synchronization! +*/ + +typedef struct ASIOChannelInfo +{ + long channel; // on input, channel index + ASIOBool isInput; // on input + ASIOBool isActive; // on exit + long channelGroup; // dto + ASIOSampleType type; // dto + char name[32]; // dto +} ASIOChannelInfo; + +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info); +/* Purpose: + retreive information about the nature of a channel + Parameter: + info: pointer to a ASIOChannelInfo structure with + - channel: on input, the channel index of the channel in question. + - isInput: on input, ASIOTrue if info for an input channel is + requested, else output + - channelGroup: on return, the channel group that the channel + belongs to. For drivers which support different types of + channels, like analog, S/PDIF, AES/EBU, ADAT etc interfaces, + there should be a reasonable grouping of these types. Groups + are always independant form a channel index, that is, a channel + index always counts from 0 to numInputs/numOutputs regardless + of the group it may belong to. + There will always be at least one group (group 0). Please + also note that by default, the host may decide to activate + channels 0 and 1; thus, these should belong to the most + useful type (analog i/o, if present). + - type: on return, contains the sample type of the channel + - isActive: on return, ASIOTrue if channel is active as it was + installed by ASIOCreateBuffers(), ASIOFalse else + - name: describing the type of channel in question. Used to allow + for user selection, and enabling of specific channels. examples: + "Analog In", "SPDIF Out" etc + Returns: + If no input/output is present ASE_NotPresent will be returned. + Notes: + If possible, the string should be organised such that the first + characters are most significantly describing the nature of the + port, to allow for identification even if the view showing the + port name is too small to display more than 8 characters, for + instance. +*/ + +//- - - - - - - - - - - - - - - - - - - - - - - - - +// Buffer preparation +//- - - - - - - - - - - - - - - - - - - - - - - - - + +typedef struct ASIOBufferInfo +{ + ASIOBool isInput; // on input: ASIOTrue: input, else output + long channelNum; // on input: channel index + void *buffers[2]; // on output: double buffer addresses +} ASIOBufferInfo; + +ASIOError ASIOCreateBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); + +/* Purpose: + Allocates input/output buffers for all input and output channels to be activated. + Parameter: + bufferInfos is a pointer to an array of ASIOBufferInfo structures: + - isInput: on input, ASIOTrue if the buffer is to be allocated + for an input, output buffer else + - channelNum: on input, the index of the channel in question + (counting from 0) + - buffers: on exit, 2 pointers to the halves of the channels' double-buffer. + the size of the buffer(s) of course depend on both the ASIOSampleType + as obtained from ASIOGetChannelInfo(), and bufferSize + numChannels is the sum of all input and output channels to be created; + thus bufferInfos is a pointer to an array of numChannels ASIOBufferInfo + structures. + bufferSize selects one of the possible buffer sizes as obtained from + ASIOGetBufferSizes(). + callbacks is a pointer to an ASIOCallbacks structure. + Returns: + If not enough memory is available ASE_NoMemory will be returned. + If no input/output is present ASE_NotPresent will be returned. + If bufferSize is not supported, or one or more of the bufferInfos elements + contain invalid settings, ASE_InvalidMode will be returned. + Notes: + If individual channel selection is not possible but requested, + the driver has to handle this. namely, bufferSwitch() will only + have filled buffers of enabled outputs. If possible, processing + and buss activities overhead should be avoided for channels which + were not enabled here. +*/ + +ASIOError ASIODisposeBuffers(void); +/* Purpose: + Releases all buffers for the device. + Parameter: + None. + Returns: + If no buffer were ever prepared, ASE_InvalidMode will be returned. + If no input/output is present ASE_NotPresent will be returned. + Notes: + This implies ASIOStop(). +*/ + +ASIOError ASIOControlPanel(void); +/* Purpose: + request the driver to start a control panel component + for device specific user settings. This will not be + accessed on some platforms (where the component is accessed + instead). + Parameter: + None. + Returns: + If no panel is available ASE_NotPresent will be returned. + Actually, the return code is ignored. + Notes: + if the user applied settings which require a re-configuration + of parts or all of the enigine and/or driver (such as a change of + the block size), the asioMessage callback can be used (see + ASIO_Callbacks). +*/ + +ASIOError ASIOFuture(long selector, void *params); +/* Purpose: + various + Parameter: + selector: operation Code as to be defined. zero is reserved for + testing purposes. + params: depends on the selector; usually pointer to a structure + for passing and retreiving any type and amount of parameters. + Returns: + the return value is also selector dependant. if the selector + is unknown, ASE_InvalidParameter should be returned to prevent + further calls with this selector. on success, ASE_SUCCESS + must be returned (note: ASE_OK is *not* sufficient!) + Notes: + see selectors defined below. +*/ + +enum +{ + kAsioEnableTimeCodeRead = 1, // no arguments + kAsioDisableTimeCodeRead, // no arguments + kAsioSetInputMonitor, // ASIOInputMonitor* in params + kAsioTransport, // ASIOTransportParameters* in params + kAsioSetInputGain, // ASIOChannelControls* in params, apply gain + kAsioGetInputMeter, // ASIOChannelControls* in params, fill meter + kAsioSetOutputGain, // ASIOChannelControls* in params, apply gain + kAsioGetOutputMeter, // ASIOChannelControls* in params, fill meter + kAsioCanInputMonitor, // no arguments for kAsioCanXXX selectors + kAsioCanTimeInfo, + kAsioCanTimeCode, + kAsioCanTransport, + kAsioCanInputGain, + kAsioCanInputMeter, + kAsioCanOutputGain, + kAsioCanOutputMeter, + kAsioOptionalOne, + + // DSD support + // The following extensions are required to allow switching + // and control of the DSD subsystem. + kAsioSetIoFormat = 0x23111961, /* ASIOIoFormat * in params. */ + kAsioGetIoFormat = 0x23111983, /* ASIOIoFormat * in params. */ + kAsioCanDoIoFormat = 0x23112004, /* ASIOIoFormat * in params. */ + + // Extension for drop out detection + kAsioCanReportOverload = 0x24042012, /* return ASE_SUCCESS if driver can detect and report overloads */ + + kAsioGetInternalBufferSamples = 0x25042012 /* ASIOInternalBufferInfo * in params. Deliver size of driver internal buffering, return ASE_SUCCESS if supported */ +}; + +typedef struct ASIOInputMonitor +{ + long input; // this input was set to monitor (or off), -1: all + long output; // suggested output for monitoring the input (if so) + long gain; // suggested gain, ranging 0 - 0x7fffffffL (-inf to +12 dB) + ASIOBool state; // ASIOTrue => on, ASIOFalse => off + long pan; // suggested pan, 0 => all left, 0x7fffffff => right +} ASIOInputMonitor; + +typedef struct ASIOChannelControls +{ + long channel; // on input, channel index + ASIOBool isInput; // on input + long gain; // on input, ranges 0 thru 0x7fffffff + long meter; // on return, ranges 0 thru 0x7fffffff + char future[32]; +} ASIOChannelControls; + +typedef struct ASIOTransportParameters +{ + long command; // see enum below + ASIOSamples samplePosition; + long track; + long trackSwitches[16]; // 512 tracks on/off + char future[64]; +} ASIOTransportParameters; + +enum +{ + kTransStart = 1, + kTransStop, + kTransLocate, // to samplePosition + kTransPunchIn, + kTransPunchOut, + kTransArmOn, // track + kTransArmOff, // track + kTransMonitorOn, // track + kTransMonitorOff, // track + kTransArm, // trackSwitches + kTransMonitor // trackSwitches +}; + +/* +// DSD support +// Some notes on how to use ASIOIoFormatType. +// +// The caller will fill the format with the request types. +// If the board can do the request then it will leave the +// values unchanged. If the board does not support the +// request then it will change that entry to Invalid (-1) +// +// So to request DSD then +// +// ASIOIoFormat NeedThis={kASIODSDFormat}; +// +// if(ASE_SUCCESS != ASIOFuture(kAsioSetIoFormat,&NeedThis) ){ +// // If the board did not accept one of the parameters then the +// // whole call will fail and the failing parameter will +// // have had its value changes to -1. +// } +// +// Note: Switching between the formats need to be done before the "prepared" +// state (see ASIO 2 documentation) is entered. +*/ +typedef long int ASIOIoFormatType; +enum ASIOIoFormatType_e +{ + kASIOFormatInvalid = -1, + kASIOPCMFormat = 0, + kASIODSDFormat = 1, +}; + +typedef struct ASIOIoFormat_s +{ + ASIOIoFormatType FormatType; + char future[512-sizeof(ASIOIoFormatType)]; +} ASIOIoFormat; + +// Extension for drop detection +// Note: Refers to buffering that goes beyond the double buffer e.g. used by USB driver designs +typedef struct ASIOInternalBufferInfo +{ + long inputSamples; // size of driver's internal input buffering which is included in getLatencies + long outputSamples; // size of driver's internal output buffering which is included in getLatencies +} ASIOInternalBufferInfo; + + +ASIOError ASIOOutputReady(void); +/* Purpose: + this tells the driver that the host has completed processing + the output buffers. if the data format required by the hardware + differs from the supported asio formats, but the hardware + buffers are DMA buffers, the driver will have to convert + the audio stream data; as the bufferSwitch callback is + usually issued at dma block switch time, the driver will + have to convert the *previous* host buffer, which increases + the output latency by one block. + when the host finds out that ASIOOutputReady() returns + true, it will issue this call whenever it completed + output processing. then the driver can convert the + host data directly to the dma buffer to be played next, + reducing output latency by one block. + another way to look at it is, that the buffer switch is called + in order to pass the *input* stream to the host, so that it can + process the input into the output, and the output stream is passed + to the driver when the host has completed its process. + Parameter: + None + Returns: + only if the above mentioned scenario is given, and a reduction + of output latency can be acheived by this mechanism, should + ASE_OK be returned. otherwise (and usually), ASE_NotPresent + should be returned in order to prevent further calls to this + function. note that the host may want to determine if it is + to use this when the system is not yet fully initialized, so + ASE_OK should always be returned if the mechanism makes sense. + Notes: + please remeber to adjust ASIOGetLatencies() according to + whether ASIOOutputReady() was ever called or not, if your + driver supports this scenario. + also note that the engine may fail to call ASIO_OutputReady() + in time in overload cases. as already mentioned, bufferSwitch + should be called for every block regardless of whether a block + could be processed in time. +*/ + +// restore old alignment +#if defined(_MSC_VER) && !defined(__MWERKS__) +#pragma pack(pop) +#elif PRAGMA_ALIGN_SUPPORTED +#pragma options align = reset +#endif + +#endif + diff --git a/src/hostapi/asio/ASIOSDK/common/asiodrvr.cpp b/src/hostapi/asio/ASIOSDK/common/asiodrvr.cpp new file mode 100644 index 0000000..6ada6f6 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/asiodrvr.cpp @@ -0,0 +1,139 @@ +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + charlie (May 1996) + + asiodrvr.cpp + c++ superclass to implement asio functionality. from this, + you can derive whatever required +*/ + +#include +#include "asiosys.h" +#include "asiodrvr.h" + +#if WINDOWS +#error do not use this +AsioDriver::AsioDriver (LPUNKNOWN pUnk, HRESULT *phr) : CUnknown("My AsioDriver", pUnk, phr) +{ +} + +#else + +AsioDriver::AsioDriver() +{ +} + +#endif + +AsioDriver::~AsioDriver() +{ +} + +ASIOBool AsioDriver::init(void *sysRef) +{ + return ASE_NotPresent; +} + +void AsioDriver::getDriverName(char *name) +{ + strcpy(name, "No Driver"); +} + +long AsioDriver::getDriverVersion() +{ + return 0; +} + +void AsioDriver::getErrorMessage(char *string) +{ + strcpy(string, "ASIO Driver Implementation Error!"); +} + +ASIOError AsioDriver::start() +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::stop() +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getChannels(long *numInputChannels, long *numOutputChannels) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getLatencies(long *inputLatency, long *outputLatency) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::canSampleRate(ASIOSampleRate sampleRate) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getSampleRate(ASIOSampleRate *sampleRate) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::setSampleRate(ASIOSampleRate sampleRate) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getClockSources(ASIOClockSource *clocks, long *numSources) +{ + *numSources = 0; + return ASE_NotPresent; +} + +ASIOError AsioDriver::setClockSource(long reference) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::getChannelInfo(ASIOChannelInfo *info) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::createBuffers(ASIOBufferInfo *channelInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::disposeBuffers() +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::controlPanel() +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::future(long selector, void *opt) +{ + return ASE_NotPresent; +} + +ASIOError AsioDriver::outputReady() +{ + return ASE_NotPresent; +} \ No newline at end of file diff --git a/src/hostapi/asio/ASIOSDK/common/asiodrvr.h b/src/hostapi/asio/ASIOSDK/common/asiodrvr.h new file mode 100644 index 0000000..1670dfa --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/asiodrvr.h @@ -0,0 +1,76 @@ +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + charlie (May 1996) + + asiodrvr.h + c++ superclass to implement asio functionality. from this, + you can derive whatever required +*/ + +#ifndef _asiodrvr_ +#define _asiodrvr_ + +// cpu and os system we are running on +#include "asiosys.h" +// basic "C" interface +#include "asio.h" + +class AsioDriver; +extern AsioDriver *getDriver(); // for generic constructor + +#if WINDOWS +#include +#include "combase.h" +#include "iasiodrv.h" +class AsioDriver : public IASIO ,public CUnknown +{ +public: + AsioDriver(LPUNKNOWN pUnk, HRESULT *phr); + + DECLARE_IUNKNOWN + // Factory method + static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + // IUnknown + virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); + +#else + +class AsioDriver +{ +public: + AsioDriver(); +#endif + virtual ~AsioDriver(); + + virtual ASIOBool init(void* sysRef); + virtual void getDriverName(char *name); // max 32 bytes incl. terminating zero + virtual long getDriverVersion(); + virtual void getErrorMessage(char *string); // max 124 bytes incl. + + virtual ASIOError start(); + virtual ASIOError stop(); + + virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); + virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); + virtual ASIOError getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity); + + virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); + virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); + virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); + virtual ASIOError setClockSource(long reference); + + virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); + virtual ASIOError getChannelInfo(ASIOChannelInfo *info); + + virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); + virtual ASIOError disposeBuffers(); + + virtual ASIOError controlPanel(); + virtual ASIOError future(long selector, void *opt); + virtual ASIOError outputReady(); +}; +#endif diff --git a/src/hostapi/asio/ASIOSDK/common/asiosys.h b/src/hostapi/asio/ASIOSDK/common/asiosys.h new file mode 100644 index 0000000..b4c7a8b --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/asiosys.h @@ -0,0 +1,82 @@ +#ifndef __asiosys__ + #define __asiosys__ + + #if defined(_WIN32) || defined(_WIN64) + #undef MAC + #define PPC 0 + #define WINDOWS 1 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #elif BEOS + #define MAC 0 + #define PPC 0 + #define WINDOWS 0 + #define PC 0 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + + #elif SGI + #define MAC 0 + #define PPC 0 + #define WINDOWS 0 + #define PC 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + + #else // MAC + + #define MAC 1 + #define PPC 1 + #define WINDOWS 0 + #define PC 0 + #define SGI 0 + #define SUN 0 + #define LINUX 0 + #define BEOS 0 + + #define NATIVE_INT64 0 + #define IEEE754_64FLOAT 1 + + #ifndef DEBUG + #define DEBUG 0 + #if DEBUG + void DEBUGGERMESSAGE(char *string); + #else + #define DEBUGGERMESSAGE(a) + #endif + #endif + #endif + +#endif diff --git a/src/hostapi/asio/ASIOSDK/common/combase.cpp b/src/hostapi/asio/ASIOSDK/common/combase.cpp new file mode 100644 index 0000000..84b64f8 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/combase.cpp @@ -0,0 +1,202 @@ +//==========================================================================; +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. +// +// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved. +// +//--------------------------------------------------------------------------; + +// Base class hierachy for creating COM objects, December 1994 + +#include +#include "wxdebug.h" +#include "combase.h" +#pragma warning( disable : 4514 ) // Disable warnings re unused inline functions + + +/* Define the static member variable */ + +LONG CBaseObject::m_cObjects = 0; + + +/* Constructor */ + +CBaseObject::CBaseObject(TCHAR *pName) +{ + /* Increment the number of active objects */ + InterlockedIncrement(&m_cObjects); + +#ifdef DEBUG + m_dwCookie = DbgRegisterObjectCreation(pName); +#endif +} + + +/* Destructor */ + +CBaseObject::~CBaseObject() +{ + /* Decrement the number of objects active */ + InterlockedDecrement(&m_cObjects); + +#ifdef DEBUG + DbgRegisterObjectDestruction(m_dwCookie); +#endif +} + + +/* Constructor */ + +// We know we use "this" in the initialization list, we also know we don't modify *phr. +#pragma warning( disable : 4355 4100 ) +CUnknown::CUnknown(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr) +: CBaseObject(pName) +/* Start the object with a reference count of zero - when the */ +/* object is queried for it's first interface this may be */ +/* incremented depending on whether or not this object is */ +/* currently being aggregated upon */ +, m_cRef(0) +/* Set our pointer to our IUnknown interface. */ +/* If we have an outer, use its, otherwise use ours. */ +/* This pointer effectivly points to the owner of */ +/* this object and can be accessed by the GetOwner() method. */ +, m_pUnknown( pUnk != 0 ? pUnk : reinterpret_cast( static_cast(this) ) ) + /* Why the double cast? Well, the inner cast is a type-safe cast */ + /* to pointer to a type from which we inherit. The second is */ + /* type-unsafe but works because INonDelegatingUnknown "behaves */ + /* like" IUnknown. (Only the names on the methods change.) */ +{ + // Everything we need to do has been done in the initializer list +} +#pragma warning( default : 4355 4100 ) + +/* QueryInterface */ + +STDMETHODIMP CUnknown::NonDelegatingQueryInterface(REFIID riid, void ** ppv) +{ + CheckPointer(ppv,E_POINTER); + ValidateReadWritePtr(ppv,sizeof(PVOID)); + + /* We know only about IUnknown */ + + if (riid == IID_IUnknown) { + GetInterface((LPUNKNOWN) (PNDUNKNOWN) this, ppv); + return NOERROR; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } +} + +/* We have to ensure that we DON'T use a max macro, since these will typically */ +/* lead to one of the parameters being evaluated twice. Since we are worried */ +/* about concurrency, we can't afford to access the m_cRef twice since we can't */ +/* afford to run the risk that its value having changed between accesses. */ +#ifdef max + #undef max +#endif + +template inline static T max( const T & a, const T & b ) +{ + return a > b ? a : b; +} + +/* AddRef */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingAddRef() +{ + LONG lRef = InterlockedIncrement( &m_cRef ); + ASSERT(lRef > 0); + DbgLog((LOG_MEMORY,3,TEXT(" Obj %d ref++ = %d"), + m_dwCookie, m_cRef)); + return max(ULONG(m_cRef), 1ul); +} + + + +/* Release */ + +STDMETHODIMP_(ULONG) CUnknown::NonDelegatingRelease() +{ + /* If the reference count drops to zero delete ourselves */ + + LONG lRef = InterlockedDecrement( &m_cRef ); + ASSERT(lRef >= 0); + + DbgLog((LOG_MEMORY,3,TEXT(" Object %d ref-- = %d"), + m_dwCookie, m_cRef)); + if (lRef == 0) { + + // COM rules say we must protect against re-entrancy. + // If we are an aggregator and we hold our own interfaces + // on the aggregatee, the QI for these interfaces will + // addref ourselves. So after doing the QI we must release + // a ref count on ourselves. Then, before releasing the + // private interface, we must addref ourselves. When we do + // this from the destructor here it will result in the ref + // count going to 1 and then back to 0 causing us to + // re-enter the destructor. Hence we add an extra refcount here + // once we know we will delete the object. + // for an example aggregator see filgraph\distrib.cpp. + + m_cRef++; + + delete this; + return ULONG(0); + } else { + return max(ULONG(m_cRef), 1ul); + } +} + + +/* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + +HRESULT CUnknown::GetInterface(LPUNKNOWN pUnk, void **ppv) +{ + CheckPointer(ppv, E_POINTER); + *ppv = pUnk; + pUnk->AddRef(); + return NOERROR; +} + + +/* Compares two interfaces and returns TRUE if they are on the same object */ + +BOOL IsEqualObject(IUnknown *pFirst, IUnknown *pSecond) +{ + /* Different objects can't have the same interface pointer for + any interface + */ + if (pFirst == pSecond) { + return TRUE; + } + /* OK - do it the hard way - check if they have the same + IUnknown pointers - a single object can only have one of these + */ + LPUNKNOWN pUnknown1; // Retrieve the IUnknown interface + LPUNKNOWN pUnknown2; // Retrieve the other IUnknown interface + HRESULT hr; // General OLE return code + + ASSERT(pFirst); + ASSERT(pSecond); + + /* See if the IUnknown pointers match */ + + hr = pFirst->QueryInterface(IID_IUnknown,(void **) &pUnknown1); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown1); + + hr = pSecond->QueryInterface(IID_IUnknown,(void **) &pUnknown2); + ASSERT(SUCCEEDED(hr)); + ASSERT(pUnknown2); + + /* Release the extra interfaces we hold */ + + pUnknown1->Release(); + pUnknown2->Release(); + return (pUnknown1 == pUnknown2); +} diff --git a/src/hostapi/asio/ASIOSDK/common/combase.h b/src/hostapi/asio/ASIOSDK/common/combase.h new file mode 100644 index 0000000..6141803 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/combase.h @@ -0,0 +1,284 @@ +//==========================================================================; +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. +// +// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved. +// +//--------------------------------------------------------------------------; + +// Base class hierachy for creating COM objects, December 1994 + +/* + +a. Derive your COM object from CUnknown + +b. Make a static CreateInstance function that takes an LPUNKNOWN, an HRESULT * + and a TCHAR *. The LPUNKNOWN defines the object to delegate IUnknown calls + to. The HRESULT * allows error codes to be passed around constructors and + the TCHAR * is a descriptive name that can be printed on the debugger. + + It is important that constructors only change the HRESULT * if they have + to set an ERROR code, if it was successful then leave it alone or you may + overwrite an error code from an object previously created. + + When you call a constructor the descriptive name should be in static store + as we do not copy the string. To stop large amounts of memory being used + in retail builds by all these static strings use the NAME macro, + + CMyFilter = new CImplFilter(NAME("My filter"),pUnknown,phr); + if (FAILED(hr)) { + return hr; + } + + In retail builds NAME(_x_) compiles to NULL, the base CBaseObject class + knows not to do anything with objects that don't have a name. + +c. Have a constructor for your object that passes the LPUNKNOWN, HRESULT * and + TCHAR * to the CUnknown constructor. You can set the HRESULT if you have an + error, or just simply pass it through to the constructor. + + The object creation will fail in the class factory if the HRESULT indicates + an error (ie FAILED(HRESULT) == TRUE) + +d. Create a FactoryTemplate with your object's class id and CreateInstance + function. + +Then (for each interface) either + +Multiple inheritance + +1. Also derive it from ISomeInterface +2. Include DECLARE_IUNKNOWN in your class definition to declare + implementations of QueryInterface, AddRef and Release that + call the outer unknown +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Declare and implement the member functions of ISomeInterface. + +or: Nested interfaces + +1. Declare a class derived from CUnknown +2. Include DECLARE_IUNKNOWN in your class definition +3. Override NonDelegatingQueryInterface to expose ISomeInterface by + code something like + + if (riid == IID_ISomeInterface) { + return GetInterface((ISomeInterface *) this, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +4. Implement the member functions of ISomeInterface. Use GetOwner() to + access the COM object class. + +And in your COM object class: + +5. Make the nested class a friend of the COM object class, and declare + an instance of the nested class as a member of the COM object class. + + NOTE that because you must always pass the outer unknown and an hResult + to the CUnknown constructor you cannot use a default constructor, in + other words you will have to make the member variable a pointer to the + class and make a NEW call in your constructor to actually create it. + +6. override the NonDelegatingQueryInterface with code like this: + + if (riid == IID_ISomeInterface) { + return m_pImplFilter-> + NonDelegatingQueryInterface(IID_ISomeInterface, ppv); + } else { + return CUnknown::NonDelegatingQueryInterface(riid, ppv); + } + +You can have mixed classes which support some interfaces via multiple +inheritance and some via nested classes + +*/ + +#ifndef __COMBASE__ +#define __COMBASE__ + +/* The DLLENTRY module initialises the module handle on loading */ + +extern HINSTANCE g_hInst; + +/* On DLL load remember which platform we are running on */ + +extern DWORD g_amPlatform; +extern OSVERSIONINFO g_osInfo; // Filled in by GetVersionEx + +/* Version of IUnknown that is renamed to allow a class to support both + non delegating and delegating IUnknowns in the same COM object */ + +DECLARE_INTERFACE(INonDelegatingUnknown) +{ + STDMETHOD(NonDelegatingQueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG, NonDelegatingAddRef)(THIS) PURE; + STDMETHOD_(ULONG, NonDelegatingRelease)(THIS) PURE; +}; + +typedef INonDelegatingUnknown *PNDUNKNOWN; + + +/* This is the base object class that supports active object counting. As + part of the debug facilities we trace every time a C++ object is created + or destroyed. The name of the object has to be passed up through the class + derivation list during construction as you cannot call virtual functions + in the constructor. The downside of all this is that every single object + constructor has to take an object name parameter that describes it */ + +class CBaseObject +{ + +private: + + // Disable the copy constructor and assignment by default so you will get + // compiler errors instead of unexpected behaviour if you pass objects + // by value or assign objects. + CBaseObject(const CBaseObject& objectSrc); // no implementation + void operator=(const CBaseObject& objectSrc); // no implementation + +private: + static LONG m_cObjects; /* Total number of objects active */ + +protected: +#ifdef DEBUG + DWORD m_dwCookie; /* Cookie identifying this object */ +#endif + + +public: + + /* These increment and decrement the number of active objects */ + + CBaseObject(TCHAR *pName); + ~CBaseObject(); + + /* Call this to find if there are any CUnknown derived objects active */ + + static LONG ObjectsActive() { + return m_cObjects; + }; +}; + + +/* An object that supports one or more COM interfaces will be based on + this class. It supports counting of total objects for DLLCanUnloadNow + support, and an implementation of the core non delegating IUnknown */ + +class CUnknown : public INonDelegatingUnknown, + public CBaseObject +{ + +private: + const LPUNKNOWN m_pUnknown; /* Owner of this object */ + +protected: /* So we can override NonDelegatingRelease() */ + volatile LONG m_cRef; /* Number of reference counts */ + +public: + + CUnknown(TCHAR *pName, LPUNKNOWN pUnk, HRESULT *phr); + virtual ~CUnknown() {}; + + /* Return the owner of this object */ + + LPUNKNOWN GetOwner() const { + return m_pUnknown; + }; + + /* Called from the class factory to create a new instance, it is + pure virtual so it must be overriden in your derived class */ + + /* static CUnknown *CreateInstance(LPUNKNOWN, HRESULT *) */ + + /* Non delegating unknown implementation */ + + STDMETHODIMP NonDelegatingQueryInterface(REFIID, void **); + STDMETHODIMP_(ULONG) NonDelegatingAddRef(); + STDMETHODIMP_(ULONG) NonDelegatingRelease(); + + /* Return an interface pointer to a requesting client + performing a thread safe AddRef as necessary */ + + HRESULT GetInterface(LPUNKNOWN pUnk, void **ppv); + + +}; + +#if WINVER < 0x0501 + +/* The standard InterlockedXXX functions won't take volatiles */ +static inline LONG InterlockedIncrement( volatile LONG * plong ) +{ return InterlockedIncrement( const_cast( plong ) ); } + +static inline LONG InterlockedDecrement( volatile LONG * plong ) +{ return InterlockedDecrement( const_cast( plong ) ); } + +static inline LONG InterlockedExchange( volatile LONG * plong, LONG new_value ) +{ return InterlockedExchange( const_cast( plong ), new_value ); } + +#endif + +/* A function that can create a new COM object */ + +typedef CUnknown *(*LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr); + +/* A function (can be NULL) which is called from the DLL entrypoint + routine for each factory template: + + bLoading - TRUE on DLL load, FALSE on DLL unload + rclsid - the m_ClsID of the entry +*/ +typedef void (*LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid); + +/* Create one of these per object class in an array so that + the default class factory code can create new instances */ + +class CFactoryTemplate { + +public: + + const WCHAR *m_Name; + const CLSID *m_ClsID; + LPFNNewCOMObject m_lpfnNew; + LPFNInitRoutine m_lpfnInit; + + BOOL IsClassID(REFCLSID rclsid) const { + return (IsEqualCLSID(*m_ClsID,rclsid)); + }; + + CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const { + return m_lpfnNew(pUnk, phr); + }; +}; + + +/* You must override the (pure virtual) NonDelegatingQueryInterface to return + interface pointers (using GetInterface) to the interfaces your derived + class supports (the default implementation only supports IUnknown) */ + +#define DECLARE_IUNKNOWN \ + STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ + return GetOwner()->QueryInterface(riid,ppv); \ + }; \ + STDMETHODIMP_(ULONG) AddRef() { \ + return GetOwner()->AddRef(); \ + }; \ + STDMETHODIMP_(ULONG) Release() { \ + return GetOwner()->Release(); \ + }; + +#endif /* __COMBASE__ */ + + diff --git a/src/hostapi/asio/ASIOSDK/common/debugmessage.cpp b/src/hostapi/asio/ASIOSDK/common/debugmessage.cpp new file mode 100644 index 0000000..2f47926 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/debugmessage.cpp @@ -0,0 +1,14 @@ +#include "asiosys.h" + +#if DEBUG +#if MAC +#include +void DEBUGGERMESSAGE(char *string) +{ + c2pstr(string); + DebugStr((unsigned char *)string); +} +#else +#error debugmessage +#endif +#endif diff --git a/src/hostapi/asio/ASIOSDK/common/dllentry.cpp b/src/hostapi/asio/ASIOSDK/common/dllentry.cpp new file mode 100644 index 0000000..be717d4 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/dllentry.cpp @@ -0,0 +1,323 @@ +//==========================================================================; +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. +// +// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved. +// +//--------------------------------------------------------------------------; + +// +// classes used to support dll entrypoints for COM objects. +// +// #include "switches.h" + +#include +#include "wxdebug.h" +#include "combase.h" +#ifdef DEBUG +#include +#endif + +#include + +extern CFactoryTemplate g_Templates[]; +extern int g_cTemplates; + +HINSTANCE hinstance = 0; +DWORD g_amPlatform; // VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx) +OSVERSIONINFO g_osInfo; + +// +// an instance of this is created by the DLLGetClassObject entrypoint +// it uses the CFactoryTemplate object it is given to support the +// IClassFactory interface + +class CClassFactory : public IClassFactory +{ + +private: + const CFactoryTemplate * m_pTemplate; + + ULONG m_cRef; + + static int m_cLocked; +public: + CClassFactory(const CFactoryTemplate *); + + // IUnknown + STDMETHODIMP QueryInterface(REFIID riid, void ** ppv); + STDMETHODIMP_(ULONG)AddRef(); + STDMETHODIMP_(ULONG)Release(); + + // IClassFactory + STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv); + STDMETHODIMP LockServer(BOOL fLock); + + // allow DLLGetClassObject to know about global server lock status + static BOOL IsLocked() { + return (m_cLocked > 0); + }; +}; + +// process-wide dll locked state +int CClassFactory::m_cLocked = 0; + +CClassFactory::CClassFactory(const CFactoryTemplate *pTemplate) +{ + m_cRef = 0; + m_pTemplate = pTemplate; +} + + +STDMETHODIMP CClassFactory::QueryInterface(REFIID riid,void **ppv) +{ + CheckPointer(ppv,E_POINTER) + ValidateReadWritePtr(ppv,sizeof(PVOID)); + *ppv = NULL; + + // any interface on this object is the object pointer. + if ((riid == IID_IUnknown) || (riid == IID_IClassFactory)) { + *ppv = (LPVOID) this; + // AddRef returned interface pointer + ((LPUNKNOWN) *ppv)->AddRef(); + return NOERROR; + } + + return ResultFromScode(E_NOINTERFACE); +} + + +STDMETHODIMP_(ULONG) CClassFactory::AddRef() +{ + return ++m_cRef; +} + +STDMETHODIMP_(ULONG) CClassFactory::Release() +{ + LONG rc; + + if (--m_cRef == 0) { + delete this; + rc = 0; + } else rc = m_cRef; + + return rc; +} + +STDMETHODIMP CClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,REFIID riid,void **pv) +{ + CheckPointer(pv,E_POINTER) + ValidateReadWritePtr(pv,sizeof(void *)); + + /* Enforce the normal OLE rules regarding interfaces and delegation */ + + if (pUnkOuter != NULL) { + if (IsEqualIID(riid,IID_IUnknown) == FALSE) { + return ResultFromScode(E_NOINTERFACE); + } + } + + /* Create the new object through the derived class's create function */ + + HRESULT hr = NOERROR; + CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr); + + if (pObj == NULL) { + return E_OUTOFMEMORY; + } + + /* Delete the object if we got a construction error */ + + if (FAILED(hr)) { + delete pObj; + return hr; + } + + /* Get a reference counted interface on the object */ + + /* We wrap the non-delegating QI with NDAddRef & NDRelease. */ + /* This protects any outer object from being prematurely */ + /* released by an inner object that may have to be created */ + /* in order to supply the requested interface. */ + pObj->NonDelegatingAddRef(); + hr = pObj->NonDelegatingQueryInterface(riid, pv); + pObj->NonDelegatingRelease(); + /* Note that if NonDelegatingQueryInterface fails, it will */ + /* not increment the ref count, so the NonDelegatingRelease */ + /* will drop the ref back to zero and the object will "self-*/ + /* destruct". Hence we don't need additional tidy-up code */ + /* to cope with NonDelegatingQueryInterface failing. */ + + if (SUCCEEDED(hr)) { + ASSERT(*pv); + } + + return hr; +} + +STDMETHODIMP CClassFactory::LockServer(BOOL fLock) +{ + if (fLock) { + m_cLocked++; + } else { + m_cLocked--; + } + return NOERROR; +} + + +// --- COM entrypoints ----------------------------------------- +// DllRegisterServer + +//called by COM to get the class factory object for a given class +STDAPI DllGetClassObject(REFCLSID rClsID,REFIID riid,void **pv) +{ + // DebugBreak(); + + if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) { + return E_NOINTERFACE; + } + + // traverse the array of templates looking for one with this + // class id + for (int i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->IsClassID(rClsID)) { + + // found a template - make a class factory based on this + // template + + *pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT); + if (*pv == NULL) { + return E_OUTOFMEMORY; + } + ((LPUNKNOWN)*pv)->AddRef(); + return NOERROR; + } + } + return CLASS_E_CLASSNOTAVAILABLE; +} + +// +// Call any initialization routines +// +void DllInitClasses(BOOL bLoading) +{ + int i; + + // DebugBreak(); + + // traverse the array of templates calling the init routine + // if they have one + for (i = 0; i < g_cTemplates; i++) { + const CFactoryTemplate * pT = &g_Templates[i]; + if (pT->m_lpfnInit != NULL) { + (*pT->m_lpfnInit)(bLoading, pT->m_ClsID); + } + } + +} + +// called by COM to determine if this dll can be unloaded +// return ok unless there are outstanding objects or a lock requested +// by IClassFactory::LockServer +// +// CClassFactory has a static function that can tell us about the locks, +// and CCOMObject has a static function that can tell us about the active +// object count +STDAPI DllCanUnloadNow() +{ + // DebugBreak(); + + DbgLog((LOG_MEMORY,2,TEXT("DLLCanUnloadNow called - IsLocked = %d, Active objects = %d"), + CClassFactory::IsLocked(), + CBaseObject::ObjectsActive())); + + if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive()) { + + return S_FALSE; + } + else { + return S_OK; + } +} + + +// --- standard WIN32 entrypoints -------------------------------------- + + +//extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); +//BOOL WINAPI DllEntryPoint(HINSTANCE hInstance,ULONG ulReason,LPVOID pv) +//BOOL WINAPI DllMain (HINSTANCE hInstance,ULONG ulReason,LPVOID pv) +BOOL WINAPI DllEntryPoint (HINSTANCE hInstance,ULONG ulReason,LPVOID pv) +{ + + // DebugBreak(); + + switch (ulReason) { + + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInstance); + DbgInitialise(hInstance); + { + // The platform identifier is used to work out whether + // full unicode support is available or not. Hence the + // default will be the lowest common denominator - i.e. N/A + g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails + + g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo); + if (GetVersionEx(&g_osInfo)) { + g_amPlatform = g_osInfo.dwPlatformId; + } + else { + DbgLog((LOG_ERROR, 1, "Failed to get the OS platform, assuming Win95")); + } + } + hinstance = hInstance; + DllInitClasses(TRUE); + + break; + + case DLL_PROCESS_DETACH: + DllInitClasses(FALSE); + +#ifdef DEBUG + if (CBaseObject::ObjectsActive()) { + DbgSetModuleLevel(LOG_MEMORY, 2); + TCHAR szInfo[512]; + extern TCHAR m_ModuleName[]; // Cut down module name + + TCHAR FullName[_MAX_PATH]; // Load the full path and module name + TCHAR *pName; // Searches from the end for a backslash + + GetModuleFileName(NULL,FullName,_MAX_PATH); + pName = _tcsrchr(FullName,'\\'); + if (pName == NULL) { + pName = FullName; + } + else { + pName++; + } + + DWORD cch = wsprintf(szInfo, TEXT("Executable: %s Pid %x Tid %x. "), + pName, GetCurrentProcessId(), GetCurrentThreadId()); + + wsprintf(szInfo+cch, TEXT("Module %s, %d objects left active!"), + m_ModuleName, CBaseObject::ObjectsActive()); + DbgAssert(szInfo, TEXT(__FILE__),__LINE__); + + // If running remotely wait for the Assert to be acknowledged + // before dumping out the object register + DbgDumpObjectRegister(); + } + DbgTerminate(); +#endif + break; + } + return TRUE; +} + + diff --git a/src/hostapi/asio/ASIOSDK/common/iasiodrv.h b/src/hostapi/asio/ASIOSDK/common/iasiodrv.h new file mode 100644 index 0000000..1496f0f --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/iasiodrv.h @@ -0,0 +1,37 @@ +#include "asiosys.h" +#include "asio.h" + +/* Forward Declarations */ + +#ifndef __ASIODRIVER_FWD_DEFINED__ +#define __ASIODRIVER_FWD_DEFINED__ +typedef interface IASIO IASIO; +#endif /* __ASIODRIVER_FWD_DEFINED__ */ + +interface IASIO : public IUnknown +{ + + virtual ASIOBool init(void *sysHandle) = 0; + virtual void getDriverName(char *name) = 0; + virtual long getDriverVersion() = 0; + virtual void getErrorMessage(char *string) = 0; + virtual ASIOError start() = 0; + virtual ASIOError stop() = 0; + virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels) = 0; + virtual ASIOError getLatencies(long *inputLatency, long *outputLatency) = 0; + virtual ASIOError getBufferSize(long *minSize, long *maxSize, + long *preferredSize, long *granularity) = 0; + virtual ASIOError canSampleRate(ASIOSampleRate sampleRate) = 0; + virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate) = 0; + virtual ASIOError setSampleRate(ASIOSampleRate sampleRate) = 0; + virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources) = 0; + virtual ASIOError setClockSource(long reference) = 0; + virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0; + virtual ASIOError getChannelInfo(ASIOChannelInfo *info) = 0; + virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) = 0; + virtual ASIOError disposeBuffers() = 0; + virtual ASIOError controlPanel() = 0; + virtual ASIOError future(long selector,void *opt) = 0; + virtual ASIOError outputReady() = 0; +}; diff --git a/src/hostapi/asio/ASIOSDK/common/register.cpp b/src/hostapi/asio/ASIOSDK/common/register.cpp new file mode 100644 index 0000000..8c6cbea --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/register.cpp @@ -0,0 +1,332 @@ +#include +#include + +typedef struct keylist +{ + HKEY mainKey; + HKEY subKey; + char *keyname; + struct keylist *next; +} KEYLIST, *LPKEYLIST; + +#define CLSID_STRING_LEN 100 +#define MAX_PATH_LEN 360 + +#define DEV_ERR_SELFREG -100 +#define ERRSREG_MODULE_NOT_FOUND DEV_ERR_SELFREG-1 +#define ERRSREG_MODPATH_NOT_FOUND DEV_ERR_SELFREG-2 +#define ERRSREG_STRING_FROM_CLSID DEV_ERR_SELFREG-3 +#define ERRSREG_CHAR_TO_MULTIBYTE DEV_ERR_SELFREG-4 + +#define SZREGSTR_DESCRIPTION "Description" +#define SZREGSTR_CLSID "CLSID" +#define SZREGSTR_INPROCSERVER32 "InprocServer32" +#define SZREGSTR_THREADINGMODEL "ThreadingModel" +#define SZREGSTR_SOFTWARE "SOFTWARE" +#define SZREGSTR_ASIO "ASIO" + +LONG RegisterAsioDriver (CLSID,char *,char *,char *,char *); +LONG UnregisterAsioDriver (CLSID,char *,char *); + +static LONG findRegPath (HKEY,char *); +static LONG createRegPath (HKEY,char *,char *); +static LONG createRegStringValue (HKEY,char *,char *,char *); +static LONG getRegString (HKEY,char *,char *,LPVOID,DWORD); +static LPKEYLIST findAllSubKeys (HKEY,HKEY,DWORD,char *,LPKEYLIST); +static LONG deleteRegPath (HKEY,char *,char *); + +static char subkeybuf[MAX_PATH_LEN]; + + +// ------------------------------------------ +// Global Functions +// ------------------------------------------ +LONG RegisterAsioDriver (CLSID clsid,char *szdllname,char *szregname,char *szasiodesc,char *szthreadmodel) +{ + HMODULE hMod; + char szDLLPath[MAX_PATH_LEN]; + char szModuleName[MAX_PATH_LEN]; + char szregpath[MAX_PATH_LEN]; + char szclsid[CLSID_STRING_LEN]; + LPOLESTR wszCLSID = NULL; + BOOL newregentry = FALSE; + LONG rc; + + hMod = GetModuleHandle(szdllname); + if (!hMod) return ERRSREG_MODULE_NOT_FOUND; + szModuleName[0] = 0; + GetModuleFileName(hMod,szModuleName,MAX_PATH_LEN); + if (!szModuleName[0]) return ERRSREG_MODPATH_NOT_FOUND; + CharLower((LPTSTR)szModuleName); + + rc = (LONG)StringFromCLSID(clsid,&wszCLSID); + if (rc != S_OK) return ERRSREG_STRING_FROM_CLSID; + rc = (LONG)WideCharToMultiByte(CP_ACP,0,(LPWSTR)wszCLSID,-1,szclsid,CLSID_STRING_LEN,0,0); + if (!rc) return ERRSREG_CHAR_TO_MULTIBYTE; + + sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid); + rc = findRegPath(HKEY_CLASSES_ROOT,szregpath); + if (rc) { + sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_CLSID,szclsid,SZREGSTR_INPROCSERVER32); + getRegString (HKEY_CLASSES_ROOT,szregpath,0,(LPVOID)szDLLPath,MAX_PATH_LEN); + CharLower((LPTSTR)szDLLPath); + rc = (LONG)strcmp(szDLLPath,szModuleName); + if (rc) { + // delete old regentry + sprintf(szregpath,"%s",SZREGSTR_CLSID); + deleteRegPath(HKEY_CLASSES_ROOT,szregpath,szclsid); + newregentry = TRUE; + } + } + else newregentry = TRUE; + + if (newregentry) { + // HKEY_CLASSES_ROOT\CLSID\{...} + sprintf(szregpath,"%s",SZREGSTR_CLSID); + createRegPath (HKEY_CLASSES_ROOT,szregpath,szclsid); + // HKEY_CLASSES_ROOT\CLSID\{...} -> Description + sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid); + createRegStringValue(HKEY_CLASSES_ROOT,szregpath,0,szasiodesc); + // HKEY_CLASSES_ROOT\CLSID\InProcServer32 + sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid); + createRegPath (HKEY_CLASSES_ROOT,szregpath,SZREGSTR_INPROCSERVER32); + // HKEY_CLASSES_ROOT\CLSID\InProcServer32 -> DLL path + sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_CLSID,szclsid,SZREGSTR_INPROCSERVER32); + createRegStringValue(HKEY_CLASSES_ROOT,szregpath,0,szModuleName); + // HKEY_CLASSES_ROOT\CLSID\InProcServer32 -> ThreadingModel + createRegStringValue(HKEY_CLASSES_ROOT,szregpath,SZREGSTR_THREADINGMODEL,szthreadmodel); + } + + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO + sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO); + rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath); + if (rc) { + sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname); + rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath); + if (rc) { + sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO); + deleteRegPath(HKEY_LOCAL_MACHINE,szregpath,szregname); + } + } + else { + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO + sprintf(szregpath,"%s",SZREGSTR_SOFTWARE); + createRegPath (HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_ASIO); + } + + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\ + sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO); + createRegPath (HKEY_LOCAL_MACHINE,szregpath,szregname); + + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\ -> CLSID + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\ -> Description + sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname); + createRegStringValue(HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_CLSID,szclsid); + createRegStringValue(HKEY_LOCAL_MACHINE,szregpath,SZREGSTR_DESCRIPTION,szasiodesc); + + return 0; +} + + +LONG UnregisterAsioDriver (CLSID clsid,char *szdllname,char *szregname) +{ + LONG rc; + HMODULE hMod; + char szregpath[MAX_PATH_LEN]; + char szModuleName[MAX_PATH_LEN]; + char szclsid[CLSID_STRING_LEN]; + LPOLESTR wszCLSID = NULL; + + + hMod = GetModuleHandle(szdllname); + if (!hMod) return ERRSREG_MODULE_NOT_FOUND; + szModuleName[0] = 0; + GetModuleFileName(hMod,szModuleName,MAX_PATH_LEN); + if (!szModuleName[0]) return ERRSREG_MODPATH_NOT_FOUND; + CharLower((LPTSTR)szModuleName); + + rc = (LONG)StringFromCLSID(clsid,&wszCLSID) ; + if (rc != S_OK) return ERRSREG_STRING_FROM_CLSID; + rc = (LONG)WideCharToMultiByte(CP_ACP,0,(LPWSTR)wszCLSID,-1,szclsid,CLSID_STRING_LEN,0,0); + if (!rc) return ERRSREG_CHAR_TO_MULTIBYTE; + + + sprintf(szregpath,"%s\\%s",SZREGSTR_CLSID,szclsid); + rc = findRegPath(HKEY_CLASSES_ROOT,szregpath); + if (rc) { + // delete old regentry + sprintf(szregpath,"%s",SZREGSTR_CLSID); + deleteRegPath(HKEY_CLASSES_ROOT,szregpath,szclsid); + } + + + // HKEY_LOCAL_MACHINE\SOFTWARE\ASIO + sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO); + rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath); + if (rc) { + sprintf(szregpath,"%s\\%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO,szregname); + rc = findRegPath(HKEY_LOCAL_MACHINE,szregpath); + if (rc) { + sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO); + deleteRegPath(HKEY_LOCAL_MACHINE,szregpath,szregname); + } + } + + return 0; +} + + +// ------------------------------------------ +// Local Functions +// ------------------------------------------ +static LONG findRegPath (HKEY mainkey,char *szregpath) +{ + HKEY hkey; + LONG cr,rc = -1; + + if (szregpath) { + if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) { + RegCloseKey(hkey); + rc = 1; + } + else rc = 0; + } + + return rc; +} + +static LONG createRegPath (HKEY mainkey,char *szregpath,char *sznewpath) +{ + HKEY hkey,hksub; + LONG cr,rc = -1; + char newregpath[MAX_PATH_LEN]; + + sprintf(newregpath,"%s\\%s",szregpath,sznewpath); + if (!(cr = findRegPath(mainkey,newregpath))) { + if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) { + if ((cr = RegCreateKey(hkey,sznewpath,&hksub)) == ERROR_SUCCESS) { + RegCloseKey(hksub); + rc = 0; + } + RegCloseKey(hkey); + } + } + else if (cr > 0) rc = 0; + + return rc; +} + +static LONG createRegStringValue (HKEY mainkey,char *szregpath,char *valname,char *szvalstr) +{ + LONG cr,rc = -1; + HKEY hkey; + + if (szregpath) { + if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) { + cr = RegSetValueEx(hkey,(LPCTSTR)valname,0,REG_SZ,(const BYTE *)szvalstr,(DWORD)strlen(szvalstr)); + RegCloseKey(hkey); + if (cr == ERROR_SUCCESS) rc = 0; + } + } + + return rc; +} + + +static LONG getRegString (HKEY mainkey,char *szregpath,char *valname,LPVOID pval,DWORD vsize) +{ + HKEY hkey; + LONG cr,rc = -1; + DWORD hsize,htype; + + if (szregpath) { + if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) { + cr = RegQueryValueEx(hkey,valname,0,&htype,0,&hsize); + if (cr == ERROR_SUCCESS) { + if (hsize <= vsize) { + cr = RegQueryValueEx(hkey,valname,0,&htype,(LPBYTE)pval,&hsize); + rc = 0; + } + } + RegCloseKey(hkey); + } + } + return rc; +} + +static LPKEYLIST findAllSubKeys (HKEY hkey,HKEY hksub,DWORD index,char *keyname,LPKEYLIST kl) +{ + HKEY hknew = 0; + char *newkey; + LONG cr; + + if (!hksub) { + cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_ALL_ACCESS,&hknew); + if (cr != ERROR_SUCCESS) return kl; + } + else hknew = hksub; + + cr = RegEnumKey(hknew,index,(LPTSTR)subkeybuf,MAX_PATH_LEN); + if (cr == ERROR_SUCCESS) { + newkey = new char[strlen(subkeybuf)+1]; + strcpy(newkey,subkeybuf); + + kl = findAllSubKeys(hknew,0,0,newkey,kl); + kl = findAllSubKeys(hkey,hknew,index+1,keyname,kl); + + return kl; + + } + + if (!kl->next) { + kl->next = new KEYLIST[1]; + kl = kl->next; + kl->mainKey = hkey; + kl->subKey = hknew; + kl->keyname = keyname; + kl->next = 0; + } + + return kl; +} + +static LONG deleteRegPath (HKEY mainkey,char *szregpath,char *szdelpath) +{ + HKEY hkey; + LONG cr,rc = -1; + KEYLIST klist; + LPKEYLIST pkl,k; + char *keyname = 0; + + if ((cr = RegOpenKey(mainkey,szregpath,&hkey)) == ERROR_SUCCESS) { + + keyname = new char[strlen(szdelpath)+1]; + if (!keyname) { + RegCloseKey(hkey); + return rc; + } + strcpy(keyname,szdelpath); + klist.next = 0; + + findAllSubKeys(hkey,0,0,keyname,&klist); + + if (klist.next) { + pkl = klist.next; + + while (pkl) { + RegCloseKey(pkl->subKey); + cr = RegDeleteKey(pkl->mainKey,pkl->keyname); + delete pkl->keyname; + k = pkl; + pkl = pkl->next; + delete k; + } + rc = 0; + } + + RegCloseKey(hkey); + } + + return rc; +} + diff --git a/src/hostapi/asio/ASIOSDK/common/wxdebug.h b/src/hostapi/asio/ASIOSDK/common/wxdebug.h new file mode 100644 index 0000000..9273eeb --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/common/wxdebug.h @@ -0,0 +1,326 @@ +//==========================================================================; +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY +// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR +// PURPOSE. +// +// Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved. +// +//--------------------------------------------------------------------------; + +// Debugging facilities, January 1995 + +#ifndef __WXDEBUG__ +#define __WXDEBUG__ + +// Avoid conflict with MFC +#undef ASSERT + +// This library provides fairly straight forward debugging functionality, this +// is split into two main sections. The first is assertion handling, there are +// three types of assertions provided here. The most commonly used one is the +// ASSERT(condition) macro which will pop up a message box including the file +// and line number if the condition evaluates to FALSE. Then there is the +// EXECUTE_ASSERT macro which is the same as ASSERT except the condition will +// still be executed in NON debug builds. The final type of assertion is the +// KASSERT macro which is more suitable for pure (perhaps kernel) filters as +// the condition is printed onto the debugger rather than in a message box. +// +// The other part of the debug module facilties is general purpose logging. +// This is accessed by calling DbgLog(). The function takes a type and level +// field which define the type of informational string you are presenting and +// it's relative importance. The type field can be a combination (one or more) +// of LOG_TIMING, LOG_TRACE, LOG_MEMORY, LOG_LOCKING and LOG_ERROR. The level +// is a DWORD value where zero defines highest important. Use of zero as the +// debug logging level is to be encouraged ONLY for major errors or events as +// they will ALWAYS be displayed on the debugger. Other debug output has it's +// level matched against the current debug output level stored in the registry +// for this module and if less than the current setting it will be displayed. +// +// Each module or executable has it's own debug output level for each of the +// five types. These are read in when the DbgInitialise function is called +// for DLLs linking to STRMBASE.LIB this is done automatically when the DLL +// is loaded, executables must call it explicitely with the module instance +// handle given to them through the WINMAIN entry point. An executable must +// also call DbgTerminate when they have finished to clean up the resources +// the debug library uses, once again this is done automatically for DLLs + +// These are the five different categories of logging information + +enum { LOG_TIMING = 0x01, // Timing and performance measurements + LOG_TRACE = 0x02, // General step point call tracing + LOG_MEMORY = 0x04, // Memory and object allocation/destruction + LOG_LOCKING = 0x08, // Locking/unlocking of critical sections + LOG_ERROR = 0x10 }; // Debug error notification + +enum { CDISP_HEX = 0x01, + CDISP_DEC = 0x02}; + +// For each object created derived from CBaseObject (in debug builds) we +// create a descriptor that holds it's name (statically allocated memory) +// and a cookie we assign it. We keep a list of all the active objects +// we have registered so that we can dump a list of remaining objects + +typedef struct tag_ObjectDesc { + TCHAR *m_pName; + DWORD m_dwCookie; + tag_ObjectDesc *m_pNext; +} ObjectDesc; + +#define DLLIMPORT __declspec(dllimport) +#define DLLEXPORT __declspec(dllexport) + +#ifdef DEBUG + + #define NAME(x) TEXT(x) + + // These are used internally by the debug library (PRIVATE) + + void DbgInitKeyLevels(HKEY hKey); + void DbgInitGlobalSettings(); + void DbgInitModuleSettings(); + void DbgInitModuleName(); + DWORD DbgRegisterObjectCreation(TCHAR *pObjectName); + BOOL DbgRegisterObjectDestruction(DWORD dwCookie); + + // These are the PUBLIC entry points + + BOOL DbgCheckModuleLevel(DWORD Type,DWORD Level); + void DbgSetModuleLevel(DWORD Type,DWORD Level); + + // Initialise the library with the module handle + + void DbgInitialise(HINSTANCE hInst); + void DbgTerminate(); + + void DbgDumpObjectRegister(); + + // Display error and logging to the user + + void DbgAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void DbgBreakPoint(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void DbgKernelAssert(const TCHAR *pCondition,const TCHAR *pFileName,INT iLine); + void DbgLogInfo(DWORD Type,DWORD Level,const TCHAR *pFormat,...); + void DbgOutString(LPCTSTR psz); + + // Debug infinite wait stuff + DWORD DbgWaitForSingleObject(HANDLE h); + DWORD DbgWaitForMultipleObjects(DWORD nCount, + CONST HANDLE *lpHandles, + BOOL bWaitAll); + void DbgSetWaitTimeout(DWORD dwTimeout); + +#ifdef __strmif_h__ + void DisplayType(LPSTR label, const AM_MEDIA_TYPE *pmtIn); +#endif + + #define KASSERT(_x_) if (!(_x_)) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Break on the debugger without putting up a message box + // message goes to debugger instead + + #define KDbgBreak(_x_) \ + DbgKernelAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define ASSERT(_x_) if (!(_x_)) \ + DbgAssert(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + // Put up a message box informing the user of a halt + // condition in the program + + #define DbgBreak(_x_) \ + DbgBreakPoint(TEXT(#_x_),TEXT(__FILE__),__LINE__) + + #define EXECUTE_ASSERT(_x_) ASSERT(_x_) + #define DbgLog(_x_) DbgLogInfo _x_ + + // MFC style trace macros + + #define NOTE(_x_) DbgLog((LOG_TRACE,5,TEXT(_x_))); + #define NOTE1(_x_,a) DbgLog((LOG_TRACE,5,TEXT(_x_),a)); + #define NOTE2(_x_,a,b) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b)); + #define NOTE3(_x_,a,b,c) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c)); + #define NOTE4(_x_,a,b,c,d) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d)); + #define NOTE5(_x_,a,b,c,d,e) DbgLog((LOG_TRACE,5,TEXT(_x_),a,b,c,d,e)); + +#else + + // Retail builds make public debug functions inert - WARNING the source + // files do not define or build any of the entry points in debug builds + // (public entry points compile to nothing) so if you go trying to call + // any of the private entry points in your source they won't compile + + #define NAME(_x_) NULL + + #define DbgInitialise(hInst) + #define DbgTerminate() + #define DbgLog(_x_) + #define DbgOutString(psz) + + #define DbgRegisterObjectCreation(pObjectName) + #define DbgRegisterObjectDestruction(dwCookie) + #define DbgDumpObjectRegister() + + #define DbgCheckModuleLevel(Type,Level) + #define DbgSetModuleLevel(Type,Level) + + #define DbgWaitForSingleObject(h) WaitForSingleObject(h, INFINITE) + #define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll) \ + WaitForMultipleObjects(nCount, lpHandles, bWaitAll, INFINITE) + #define DbgSetWaitTimeout(dwTimeout) + + #define KDbgBreak(_x_) + #define DbgBreak(_x_) + + #define KASSERT(_x_) + #define ASSERT(_x_) + #define EXECUTE_ASSERT(_x_) _x_ + + // MFC style trace macros + + #define NOTE(_x_) + #define NOTE1(_x_,a) + #define NOTE2(_x_,a,b) + #define NOTE3(_x_,a,b,c) + #define NOTE4(_x_,a,b,c,d) + #define NOTE5(_x_,a,b,c,d,e) + + #define DisplayType(label, pmtIn) + +#endif + + +// Checks a pointer which should be non NULL - can be used as follows. + +#define CheckPointer(p,ret) {if((p)==NULL) return (ret);} + +// HRESULT Foo(VOID *pBar) +// { +// CheckPointer(pBar,E_INVALIDARG) +// } +// +// Or if the function returns a boolean +// +// BOOL Foo(VOID *pBar) +// { +// CheckPointer(pBar,FALSE) +// } + +// These validate pointers when symbol VFWROBUST is defined +// This will normally be defined in debug not retail builds + +#ifdef DEBUG + #define VFWROBUST +#endif + +#ifdef VFWROBUST + + #define ValidateReadPtr(p,cb) \ + {if(IsBadReadPtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid read pointer");} + + #define ValidateWritePtr(p,cb) \ + {if(IsBadWritePtr((PVOID)p,cb) == TRUE) \ + DbgBreak("Invalid write pointer");} + + #define ValidateReadWritePtr(p,cb) \ + {ValidateReadPtr(p,cb) ValidateWritePtr(p,cb)} + + #define ValidateStringPtr(p) \ + {if(IsBadStringPtr((LPCTSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid string pointer");} + + #define ValidateStringPtrA(p) \ + {if(IsBadStringPtrA((LPCSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid ANSII string pointer");} + + #define ValidateStringPtrW(p) \ + {if(IsBadStringPtrW((LPCWSTR)p,INFINITE) == TRUE) \ + DbgBreak("Invalid UNICODE string pointer");} + +#else + #define ValidateReadPtr(p,cb) + #define ValidateWritePtr(p,cb) + #define ValidateReadWritePtr(p,cb) + #define ValidateStringPtr(p) + #define ValidateStringPtrA(p) + #define ValidateStringPtrW(p) +#endif + + +#ifdef _OBJBASE_H_ + + // Outputting GUID names. If you want to include the name + // associated with a GUID (eg CLSID_...) then + // + // GuidNames[yourGUID] + // + // Returns the name defined in uuids.h as a string + + typedef struct { + TCHAR *szName; + GUID guid; + } GUID_STRING_ENTRY; + + class CGuidNameList { + public: + TCHAR *operator [] (const GUID& guid); + }; + + extern CGuidNameList GuidNames; + +#endif + + +// REMIND macro - generates warning as reminder to complete coding +// (eg) usage: +// +// #pragma message (REMIND("Add automation support")) + + +#define QUOTE(x) #x +#define QQUOTE(y) QUOTE(y) +#define REMIND(str) __FILE__ "(" QQUOTE(__LINE__) ") : " str + + +// Hack to display objects in a useful format +// +// eg If you want to display a LONGLONG ll in a debug string do (eg) +// +// DbgLog((LOG_TRACE, n, TEXT("Value is %s"), (LPCTSTR)CDisp(ll, CDISP_HEX))); + + +class CDispBasic +{ +public: + CDispBasic() { m_pString = m_String; }; + ~CDispBasic(); +protected: + PTCHAR m_pString; // normally points to m_String... unless too much data + TCHAR m_String[50]; +}; +class CDisp : public CDispBasic +{ +public: + CDisp(LONGLONG ll, int Format = CDISP_HEX); // Display a LONGLONG in CDISP_HEX or CDISP_DEC form + CDisp(REFCLSID clsid); // Display a GUID + CDisp(double d); // Display a floating point number +#ifdef __strmif_h__ +#ifdef __STREAMS__ + CDisp(CRefTime t); // Display a Reference Time +#endif + CDisp(IPin *pPin); // Display a pin as {filter clsid}(pin name) +#endif // __strmif_h__ + ~CDisp(); + + // Implement cast to (LPCTSTR) as parameter to logger + operator LPCTSTR() + { + return (LPCTSTR)m_pString; + }; +}; + +#endif // __WXDEBUG__ + diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.def b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.def new file mode 100644 index 0000000..963b98c --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.def @@ -0,0 +1,9 @@ +LIBRARY ASIOSample +DESCRIPTION 'ASIO Sample Driver' +PROTMODE +EXPORTS + DllMain + DllGetClassObject + DllCanUnloadNow + DllRegisterServer + DllUnregisterServer diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.txt b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.txt new file mode 100644 index 0000000..8f28b9b --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample.txt @@ -0,0 +1,23 @@ +Asiosample + +This sample driver illustrates the implementation of an ASIO driver. + + + +Windows notes: + +For Windows a COM implementation is provided. The final driver can be +installed in the system by dragging the asiosample.dll onto the +regsvr32.exe in the windows\system directory. + +It is normal that the LNK4104 warning is issued for the following 4 +exported symbols: + +DllGetClassObject +DllCanUnloadNow +DllRegisterServer +DllUnregisterServer + + +Macintosh notes: +The supplied project is created with CodeWarrior Pro 5. diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.dsp b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.dsp new file mode 100644 index 0000000..f0a0b01 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.dsp @@ -0,0 +1,151 @@ +# Microsoft Developer Studio Project File - Name="asiosample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=asiosample - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "asiosample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "asiosample.mak" CFG="asiosample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "asiosample - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "asiosample - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "asiosample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\..\Common" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /machine:I386 + +!ELSEIF "$(CFG)" == "asiosample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GX /Zi /Od /I "..\..\..\Common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "asiosample - Win32 Release" +# Name "asiosample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\asiosample.def +# End Source File +# Begin Source File + +SOURCE=..\asiosmpl.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\combase.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\dllentry.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\register.cpp +# End Source File +# Begin Source File + +SOURCE=..\wintimer.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\..\common\asio.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\Asiodrvr.h +# End Source File +# Begin Source File + +SOURCE=..\asiosmpl.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\asiosys.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\combase.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\common\iasiodrv.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.vcproj b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.vcproj new file mode 100644 index 0000000..9f49594 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosample/asiosample.vcproj @@ -0,0 +1,629 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.cpp b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.cpp new file mode 100644 index 0000000..ca72be7 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.cpp @@ -0,0 +1,660 @@ +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + charlie (May 1996) + + asiosmpl.cpp + + sample implementation of asio. can be set to simulate input with some + stupid oscillators. + this driver doesn't output sound at all... + timing is done via the extended time manager on the mac, and + a simple thread on pc. + you may test various configurations by changing the kNumInputs/Outputs, + and kBlockFrames. note that when using wave generation, as i/o is not optimized + at all, it moves quite a bit of memory, too many i/o channels may make it + pretty slow. + + if you use this file as a template, make sure to resolve places where the + search string !!! can be found... +*/ + +#include +#include +#include "asiosmpl.h" +//#include "virtape.h" + +//------------------------------------------------------------------------------------------ + +// extern +void getNanoSeconds(ASIOTimeStamp *time); + +// local + +double AsioSamples2double (ASIOSamples* samples); + +static const double twoRaisedTo32 = 4294967296.; +static const double twoRaisedTo32Reciprocal = 1. / twoRaisedTo32; + +//------------------------------------------------------------------------------------------ +// on windows, we do the COM stuff. + +#if WINDOWS +#include "windows.h" +#include "mmsystem.h" + +// class id. !!! NOTE: !!! you will obviously have to create your own class id! +// {188135E1-D565-11d2-854F-00A0C99F5D19} +CLSID IID_ASIO_DRIVER = { 0x188135e1, 0xd565, 0x11d2, { 0x85, 0x4f, 0x0, 0xa0, 0xc9, 0x9f, 0x5d, 0x19 } }; + +CFactoryTemplate g_Templates[1] = { + {L"ASIOSAMPLE", &IID_ASIO_DRIVER, AsioSample::CreateInstance} +}; +int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]); + +CUnknown* AsioSample::CreateInstance (LPUNKNOWN pUnk, HRESULT *phr) +{ + return (CUnknown*)new AsioSample (pUnk,phr); +}; + +STDMETHODIMP AsioSample::NonDelegatingQueryInterface (REFIID riid, void ** ppv) +{ + if (riid == IID_ASIO_DRIVER) + { + return GetInterface (this, ppv); + } + return CUnknown::NonDelegatingQueryInterface (riid, ppv); +} + +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// Register ASIO Driver +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +extern LONG RegisterAsioDriver (CLSID,char *,char *,char *,char *); +extern LONG UnregisterAsioDriver (CLSID,char *,char *); + +// +// Server registration, called on REGSVR32.EXE "the dllname.dll" +// +HRESULT _stdcall DllRegisterServer() +{ + LONG rc; + char errstr[128]; + + rc = RegisterAsioDriver (IID_ASIO_DRIVER,"ASIOSample.dll","ASIO Sample Driver","ASIO Sample","Apartment"); + + if (rc) { + memset(errstr,0,128); + sprintf(errstr,"Register Server failed ! (%d)",rc); + MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"ASIO sample Driver",MB_OK); + return -1; + } + + return S_OK; +} + +// +// Server unregistration +// +HRESULT _stdcall DllUnregisterServer() +{ + LONG rc; + char errstr[128]; + + rc = UnregisterAsioDriver (IID_ASIO_DRIVER,"ASIOSample.dll","ASIO Sample Driver"); + + if (rc) { + memset(errstr,0,128); + sprintf(errstr,"Unregister Server failed ! (%d)",rc); + MessageBox(0,(LPCTSTR)errstr,(LPCTSTR)"ASIO Korg1212 I/O Driver",MB_OK); + return -1; + } + + return S_OK; +} + +//------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------ +AsioSample::AsioSample (LPUNKNOWN pUnk, HRESULT *phr) + : CUnknown("ASIOSAMPLE", pUnk, phr) + +//------------------------------------------------------------------------------------------ + +#else + +// when not on windows, we derive from AsioDriver +AsioSample::AsioSample () : AsioDriver () + +#endif +{ + long i; + + blockFrames = kBlockFrames; + inputLatency = blockFrames; // typically + outputLatency = blockFrames * 2; + // typically blockFrames * 2; try to get 1 by offering direct buffer + // access, and using asioPostOutput for lower latency + samplePosition = 0; + sampleRate = 44100.; + milliSeconds = (long)((double)(kBlockFrames * 1000) / sampleRate); + active = false; + started = false; + timeInfoMode = false; + tcRead = false; + for (i = 0; i < kNumInputs; i++) + { + inputBuffers[i] = 0; + inMap[i] = 0; + } +#if TESTWAVES + sawTooth = sineWave = 0; +#endif + for (i = 0; i < kNumOutputs; i++) + { + outputBuffers[i] = 0; + outMap[i] = 0; + } + callbacks = 0; + activeInputs = activeOutputs = 0; + toggle = 0; +} + +//------------------------------------------------------------------------------------------ +AsioSample::~AsioSample () +{ + stop (); + outputClose (); + inputClose (); + disposeBuffers (); +} + +//------------------------------------------------------------------------------------------ +void AsioSample::getDriverName (char *name) +{ + strcpy (name, "Sample ASIO"); +} + +//------------------------------------------------------------------------------------------ +long AsioSample::getDriverVersion () +{ + return 0x00000001L; +} + +//------------------------------------------------------------------------------------------ +void AsioSample::getErrorMessage (char *string) +{ + strcpy (string, errorMessage); +} + +//------------------------------------------------------------------------------------------ +ASIOBool AsioSample::init (void* sysRef) +{ + sysRef = sysRef; + if (active) + return true; + strcpy (errorMessage, "ASIO Driver open Failure!"); + if (inputOpen ()) + { + if (outputOpen ()) + { + active = true; + return true; + } + } + timerOff (); // de-activate 'hardware' + + outputClose (); + inputClose (); + return false; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::start () +{ + if (callbacks) + { + started = false; + samplePosition = 0; + theSystemTime.lo = theSystemTime.hi = 0; + toggle = 0; + + timerOn (); // activate 'hardware' + started = true; + + return ASE_OK; + } + return ASE_NotPresent; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::stop () +{ + started = false; + timerOff (); // de-activate 'hardware' + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getChannels (long *numInputChannels, long *numOutputChannels) +{ + *numInputChannels = kNumInputs; + *numOutputChannels = kNumOutputs; + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getLatencies (long *_inputLatency, long *_outputLatency) +{ + *_inputLatency = inputLatency; + *_outputLatency = outputLatency; + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getBufferSize (long *minSize, long *maxSize, + long *preferredSize, long *granularity) +{ + *minSize = *maxSize = *preferredSize = blockFrames; // allow this size only + *granularity = 0; + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::canSampleRate (ASIOSampleRate sampleRate) +{ + if (sampleRate == 44100. || sampleRate == 48000.) // allow these rates only + return ASE_OK; + return ASE_NoClock; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getSampleRate (ASIOSampleRate *sampleRate) +{ + *sampleRate = this->sampleRate; + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::setSampleRate (ASIOSampleRate sampleRate) +{ + if (sampleRate != 44100. && sampleRate != 48000.) + return ASE_NoClock; + if (sampleRate != this->sampleRate) + { + this->sampleRate = sampleRate; + asioTime.timeInfo.sampleRate = sampleRate; + asioTime.timeInfo.flags |= kSampleRateChanged; + milliSeconds = (long)((double)(kBlockFrames * 1000) / this->sampleRate); + if (callbacks && callbacks->sampleRateDidChange) + callbacks->sampleRateDidChange (this->sampleRate); + } + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getClockSources (ASIOClockSource *clocks, long *numSources) +{ + // internal + clocks->index = 0; + clocks->associatedChannel = -1; + clocks->associatedGroup = -1; + clocks->isCurrentSource = ASIOTrue; + strcpy(clocks->name, "Internal"); + *numSources = 1; + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::setClockSource (long index) +{ + if (!index) + { + asioTime.timeInfo.flags |= kClockSourceChanged; + return ASE_OK; + } + return ASE_NotPresent; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + tStamp->lo = theSystemTime.lo; + tStamp->hi = theSystemTime.hi; + if (samplePosition >= twoRaisedTo32) + { + sPos->hi = (unsigned long)(samplePosition * twoRaisedTo32Reciprocal); + sPos->lo = (unsigned long)(samplePosition - (sPos->hi * twoRaisedTo32)); + } + else + { + sPos->hi = 0; + sPos->lo = (unsigned long)samplePosition; + } + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::getChannelInfo (ASIOChannelInfo *info) +{ + if (info->channel < 0 || (info->isInput ? info->channel >= kNumInputs : info->channel >= kNumOutputs)) + return ASE_InvalidParameter; +#if WINDOWS + info->type = ASIOSTInt16LSB; +#else + info->type = ASIOSTInt16MSB; +#endif + info->channelGroup = 0; + info->isActive = ASIOFalse; + long i; + if (info->isInput) + { + for (i = 0; i < activeInputs; i++) + { + if (inMap[i] == info->channel) + { + info->isActive = ASIOTrue; + break; + } + } + } + else + { + for (i = 0; i < activeOutputs; i++) + { + if (outMap[i] == info->channel) + { + info->isActive = ASIOTrue; + break; + } + } + } + strcpy(info->name, "Sample "); + return ASE_OK; +} + +//------------------------------------------------------------------------------------------ +ASIOError AsioSample::createBuffers (ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks) +{ + ASIOBufferInfo *info = bufferInfos; + long i; + bool notEnoughMem = false; + + activeInputs = 0; + activeOutputs = 0; + blockFrames = bufferSize; + for (i = 0; i < numChannels; i++, info++) + { + if (info->isInput) + { + if (info->channelNum < 0 || info->channelNum >= kNumInputs) + goto error; + inMap[activeInputs] = info->channelNum; + inputBuffers[activeInputs] = new short[blockFrames * 2]; // double buffer + if (inputBuffers[activeInputs]) + { + info->buffers[0] = inputBuffers[activeInputs]; + info->buffers[1] = inputBuffers[activeInputs] + blockFrames; + } + else + { + info->buffers[0] = info->buffers[1] = 0; + notEnoughMem = true; + } + activeInputs++; + if (activeInputs > kNumInputs) + { +error: + disposeBuffers(); + return ASE_InvalidParameter; + } + } + else // output + { + if (info->channelNum < 0 || info->channelNum >= kNumOutputs) + goto error; + outMap[activeOutputs] = info->channelNum; + outputBuffers[activeOutputs] = new short[blockFrames * 2]; // double buffer + if (outputBuffers[activeOutputs]) + { + info->buffers[0] = outputBuffers[activeOutputs]; + info->buffers[1] = outputBuffers[activeOutputs] + blockFrames; + } + else + { + info->buffers[0] = info->buffers[1] = 0; + notEnoughMem = true; + } + activeOutputs++; + if (activeOutputs > kNumOutputs) + { + activeOutputs--; + disposeBuffers(); + return ASE_InvalidParameter; + } + } + } + if (notEnoughMem) + { + disposeBuffers(); + return ASE_NoMemory; + } + + this->callbacks = callbacks; + if (callbacks->asioMessage (kAsioSupportsTimeInfo, 0, 0, 0)) + { + timeInfoMode = true; + asioTime.timeInfo.speed = 1.; + asioTime.timeInfo.systemTime.hi = asioTime.timeInfo.systemTime.lo = 0; + asioTime.timeInfo.samplePosition.hi = asioTime.timeInfo.samplePosition.lo = 0; + asioTime.timeInfo.sampleRate = sampleRate; + asioTime.timeInfo.flags = kSystemTimeValid | kSamplePositionValid | kSampleRateValid; + + asioTime.timeCode.speed = 1.; + asioTime.timeCode.timeCodeSamples.lo = asioTime.timeCode.timeCodeSamples.hi = 0; + asioTime.timeCode.flags = kTcValid | kTcRunning ; + } + else + timeInfoMode = false; + return ASE_OK; +} + +//--------------------------------------------------------------------------------------------- +ASIOError AsioSample::disposeBuffers() +{ + long i; + + callbacks = 0; + stop(); + for (i = 0; i < activeInputs; i++) + delete inputBuffers[i]; + activeInputs = 0; + for (i = 0; i < activeOutputs; i++) + delete outputBuffers[i]; + activeOutputs = 0; + return ASE_OK; +} + +//--------------------------------------------------------------------------------------------- +ASIOError AsioSample::controlPanel() +{ + return ASE_NotPresent; +} + +//--------------------------------------------------------------------------------------------- +ASIOError AsioSample::future (long selector, void* opt) // !!! check properties +{ + ASIOTransportParameters* tp = (ASIOTransportParameters*)opt; + switch (selector) + { + case kAsioEnableTimeCodeRead: tcRead = true; return ASE_SUCCESS; + case kAsioDisableTimeCodeRead: tcRead = false; return ASE_SUCCESS; + case kAsioSetInputMonitor: return ASE_SUCCESS; // for testing!!! + case kAsioCanInputMonitor: return ASE_SUCCESS; // for testing!!! + case kAsioCanTimeInfo: return ASE_SUCCESS; + case kAsioCanTimeCode: return ASE_SUCCESS; + } + return ASE_NotPresent; +} + +//-------------------------------------------------------------------------------------------------------- +// private methods +//-------------------------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------------------------- +// input +//-------------------------------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------------------- +bool AsioSample::inputOpen () +{ +#if TESTWAVES + sineWave = new short[blockFrames]; + if (!sineWave) + { + strcpy (errorMessage, "ASIO Sample Driver: Out of Memory!"); + return false; + } + makeSine (sineWave); + + sawTooth = new short[blockFrames]; + if (!sawTooth) + { + strcpy(errorMessage, "ASIO Sample Driver: Out of Memory!"); + return false; + } + makeSaw(sawTooth); +#endif + return true; +} + +#if TESTWAVES + +#include + +const double pi = 0.3141592654; + +//--------------------------------------------------------------------------------------------- +void AsioSample::makeSine (short *wave) +{ + double frames = (double)blockFrames; + double i, f = (pi * 2.) / frames; + + for (i = 0; i < frames; i++) + *wave++ = (short)((double)0x7fff * sin(f * i)); +} + +//--------------------------------------------------------------------------------------------- +void AsioSample::makeSaw(short *wave) +{ + double frames = (double)blockFrames; + double i, f = 2. / frames; + + for (i = 0; i < frames; i++) + *wave++ = (short)((double)0x7fff * (-1. + f * i)); +} +#endif + +//--------------------------------------------------------------------------------------------- +void AsioSample::inputClose () +{ +#if TESTWAVES + if (sineWave) + delete sineWave; + sineWave = 0; + if (sawTooth) + delete sawTooth; + sawTooth = 0; +#endif +} + +//--------------------------------------------------------------------------------------------- +void AsioSample::input() +{ +#if TESTWAVES + long i; + short *in = 0; + + for (i = 0; i < activeInputs; i++) + { + in = inputBuffers[i]; + if (in) + { + if (toggle) + in += blockFrames; + if ((i & 1) && sawTooth) + memcpy(in, sawTooth, (unsigned long)(blockFrames * 2)); + else if (sineWave) + memcpy(in, sineWave, (unsigned long)(blockFrames * 2)); + } + } +#endif +} + +//------------------------------------------------------------------------------------------------------------------ +// output +//------------------------------------------------------------------------------------------------------------------ + +//--------------------------------------------------------------------------------------------- +bool AsioSample::outputOpen() +{ + return true; +} + +//--------------------------------------------------------------------------------------------- +void AsioSample::outputClose () +{ +} + +//--------------------------------------------------------------------------------------------- +void AsioSample::output () +{ +} + +//--------------------------------------------------------------------------------------------- +void AsioSample::bufferSwitch () +{ + if (started && callbacks) + { + getNanoSeconds(&theSystemTime); // latch system time + input(); + output(); + samplePosition += blockFrames; + if (timeInfoMode) + bufferSwitchX (); + else + callbacks->bufferSwitch (toggle, ASIOFalse); + toggle = toggle ? 0 : 1; + } +} + +//--------------------------------------------------------------------------------------------- +// asio2 buffer switch +void AsioSample::bufferSwitchX () +{ + getSamplePosition (&asioTime.timeInfo.samplePosition, &asioTime.timeInfo.systemTime); + long offset = toggle ? blockFrames : 0; + if (tcRead) + { // Create a fake time code, which is 10 minutes ahead of the card's sample position + // Please note that for simplicity here time code will wrap after 32 bit are reached + asioTime.timeCode.timeCodeSamples.lo = asioTime.timeInfo.samplePosition.lo + 600.0 * sampleRate; + asioTime.timeCode.timeCodeSamples.hi = 0; + } + callbacks->bufferSwitchTimeInfo (&asioTime, toggle, ASIOFalse); + asioTime.timeInfo.flags &= ~(kSampleRateChanged | kClockSourceChanged); +} + +//--------------------------------------------------------------------------------------------- +ASIOError AsioSample::outputReady () +{ + return ASE_NotPresent; +} + +//--------------------------------------------------------------------------------------------- +double AsioSamples2double (ASIOSamples* samples) +{ + double a = (double)(samples->lo); + if (samples->hi) + a += (double)(samples->hi) * twoRaisedTo32; + return a; +} + diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.h b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.h new file mode 100644 index 0000000..8316f12 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/asiosmpl.h @@ -0,0 +1,148 @@ +/* + Steinberg Audio Stream I/O API + (c) 1999, Steinberg Soft- und Hardware GmbH + + asiosmpl.h + + test implementation of asio +*/ + +#ifndef _asiosmpl_ +#define _asiosmpl_ + +#include "asiosys.h" + +#define TESTWAVES 1 +// when true, will feed the left input (to host) with +// a sine wave, and the right one with a sawtooth + +enum +{ + kBlockFrames = 256, + kNumInputs = 16, + kNumOutputs = 16 +}; + +#if WINDOWS + +#include "rpc.h" +#include "rpcndr.h" +#ifndef COM_NO_WINDOWS_H +#include +#include "ole2.h" +#endif + +#include "combase.h" +#include "iasiodrv.h" + +class AsioSample : public IASIO, public CUnknown +{ +public: + AsioSample(LPUNKNOWN pUnk, HRESULT *phr); + ~AsioSample(); + + DECLARE_IUNKNOWN + //STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { \ + // return GetOwner()->QueryInterface(riid,ppv); \ + //}; \ + //STDMETHODIMP_(ULONG) AddRef() { \ + // return GetOwner()->AddRef(); \ + //}; \ + //STDMETHODIMP_(ULONG) Release() { \ + // return GetOwner()->Release(); \ + //}; + + // Factory method + static CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr); + // IUnknown + virtual HRESULT STDMETHODCALLTYPE NonDelegatingQueryInterface(REFIID riid,void **ppvObject); +#else + +#include "asiodrvr.h" + +//--------------------------------------------------------------------------------------------- +class AsioSample : public AsioDriver +{ +public: + AsioSample (); + ~AsioSample (); +#endif + + ASIOBool init (void* sysRef); + void getDriverName (char *name); // max 32 bytes incl. terminating zero + long getDriverVersion (); + void getErrorMessage (char *string); // max 128 bytes incl. + + ASIOError start (); + ASIOError stop (); + + ASIOError getChannels (long *numInputChannels, long *numOutputChannels); + ASIOError getLatencies (long *inputLatency, long *outputLatency); + ASIOError getBufferSize (long *minSize, long *maxSize, + long *preferredSize, long *granularity); + + ASIOError canSampleRate (ASIOSampleRate sampleRate); + ASIOError getSampleRate (ASIOSampleRate *sampleRate); + ASIOError setSampleRate (ASIOSampleRate sampleRate); + ASIOError getClockSources (ASIOClockSource *clocks, long *numSources); + ASIOError setClockSource (long index); + + ASIOError getSamplePosition (ASIOSamples *sPos, ASIOTimeStamp *tStamp); + ASIOError getChannelInfo (ASIOChannelInfo *info); + + ASIOError createBuffers (ASIOBufferInfo *bufferInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); + ASIOError disposeBuffers (); + + ASIOError controlPanel (); + ASIOError future (long selector, void *opt); + ASIOError outputReady (); + + void bufferSwitch (); + long getMilliSeconds () {return milliSeconds;} + +private: +friend void myTimer(); + + bool inputOpen (); +#if TESTWAVES + void makeSine (short *wave); + void makeSaw (short *wave); +#endif + void inputClose (); + void input (); + + bool outputOpen (); + void outputClose (); + void output (); + + void timerOn (); + void timerOff (); + void bufferSwitchX (); + + double samplePosition; + double sampleRate; + ASIOCallbacks *callbacks; + ASIOTime asioTime; + ASIOTimeStamp theSystemTime; + short *inputBuffers[kNumInputs * 2]; + short *outputBuffers[kNumOutputs * 2]; +#if TESTWAVES + short *sineWave, *sawTooth; +#endif + long inMap[kNumInputs]; + long outMap[kNumOutputs]; + long blockFrames; + long inputLatency; + long outputLatency; + long activeInputs; + long activeOutputs; + long toggle; + long milliSeconds; + bool active, started; + bool timeInfoMode, tcRead; + char errorMessage[128]; +}; + +#endif + diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/macnanosecs.cpp b/src/hostapi/asio/ASIOSDK/driver/asiosample/macnanosecs.cpp new file mode 100644 index 0000000..3a46fb2 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/macnanosecs.cpp @@ -0,0 +1,15 @@ +#include "asio.h" +#include + +void getNanoSeconds(ASIOTimeStamp *time); + +static const double twoRaisedTo32 = 4294967296.; + +void getNanoSeconds(ASIOTimeStamp *time) +{ + UnsignedWide ys; + Microseconds(&ys); + double r = 1000. * ((double)ys.hi * twoRaisedTo32 + (double)ys.lo); + time->hi = (unsigned long)(r / twoRaisedTo32); + time->lo = (unsigned long)(r - (double)time->hi * twoRaisedTo32); +} diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/mactimer.cpp b/src/hostapi/asio/ASIOSDK/driver/asiosample/mactimer.cpp new file mode 100644 index 0000000..1f0008b --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/mactimer.cpp @@ -0,0 +1,52 @@ +/* + Steinberg Audio Stream I/O API + (c) 1996, Steinberg Soft- und Hardware GmbH + charlie (May 1996) + + asiosmpl.cpp + + sample implementation of asio. + time manager irq + **** mac os specific **** +*/ + +#include +#include +#include +#include "asiosmpl.h" + +static TMTask myTmTask; +static bool tmTaskOn = false; +static AsioSample *theSound = 0; + +void myTimer(); +void myTimer() +{ + if(theSound) + theSound->bufferSwitch(); + PrimeTime((QElemPtr)&myTmTask, theSound->milliSeconds); +} + +void AsioSample::timerOn() +{ + theSound = this; // for irq + if(!tmTaskOn) + { + memset(&myTmTask, 0, sizeof(TMTask)); + myTmTask.tmAddr = NewTimerProc(myTimer); + myTmTask.tmWakeUp = 0; + tmTaskOn = true; + InsXTime((QElemPtr)&myTmTask); + PrimeTime((QElemPtr)&myTmTask, theSound->milliSeconds); + } +} + +void AsioSample::timerOff() +{ + if(tmTaskOn) + { + RmvTime((QElemPtr)&myTmTask); + tmTaskOn = false; + } + theSound = 0; +} diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/makesamp.cpp b/src/hostapi/asio/ASIOSDK/driver/asiosample/makesamp.cpp new file mode 100644 index 0000000..25a2f41 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/makesamp.cpp @@ -0,0 +1,6 @@ +#include "asiosmpl.h" + +AsioDriver *getDriver() +{ + return new AsioSample(); +} diff --git a/src/hostapi/asio/ASIOSDK/driver/asiosample/wintimer.cpp b/src/hostapi/asio/ASIOSDK/driver/asiosample/wintimer.cpp new file mode 100644 index 0000000..c861bb3 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/driver/asiosample/wintimer.cpp @@ -0,0 +1,55 @@ +#include +#include "asiosmpl.h" + +static DWORD __stdcall ASIOThread (void *param); +static HANDLE ASIOThreadHandle = 0; +static bool done = false; +const double twoRaisedTo32 = 4294967296.; + +AsioSample* theDriver = 0; + +//------------------------------------------------------------------------------------------ +void getNanoSeconds (ASIOTimeStamp* ts) +{ + double nanoSeconds = (double)((unsigned long)timeGetTime ()) * 1000000.; + ts->hi = (unsigned long)(nanoSeconds / twoRaisedTo32); + ts->lo = (unsigned long)(nanoSeconds - (ts->hi * twoRaisedTo32)); +} + +//------------------------------------------------------------------------------------------ +void AsioSample::timerOn () +{ + theDriver = this; + DWORD asioId; + done = false; + ASIOThreadHandle = CreateThread (0, 0, &ASIOThread, 0, 0, &asioId); +} + +//------------------------------------------------------------------------------------------ +void AsioSample::timerOff () +{ + done = true; + if (ASIOThreadHandle) + WaitForSingleObject(ASIOThreadHandle, 1000); + ASIOThreadHandle = 0; +} + +//------------------------------------------------------------------------------------------ +static DWORD __stdcall ASIOThread (void *param) +{ + do + { + if (theDriver) + { + theDriver->bufferSwitch (); + Sleep (theDriver->getMilliSeconds ()); + } + else + { + double a = 1000. / 44100.; + Sleep ((long)(a * (double)kBlockFrames)); + + } + } while (!done); + return 0; +} diff --git a/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.cpp b/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.cpp new file mode 100644 index 0000000..16e441e --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.cpp @@ -0,0 +1,859 @@ +#include "ginclude.h" +#include "ASIOConvertSamples.h" +#include + +#if MAC +#define TRUNCATE 0 + +#elif ASIO_CPU_X86 || ASIO_CPU_SPARC || ASIO_CPU_MIPS +#define TRUNCATE 1 +#undef MAXFLOAT +#define MAXFLOAT 0x7fffff00L +#endif + +ASIOConvertSamples::ASIOConvertSamples() +{ +} + + +//------------------------------------------------------------------------------------------- +// mono + +void ASIOConvertSamples::convertMono8Unsigned(long *source, char *dest, long frames) +{ + unsigned char *c = (unsigned char *)source; + unsigned char a; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = c[3]; +#else + a = c[0]; +#endif + c += 4; + a -= 0x80U; + *++dest = a; + } +} + +void ASIOConvertSamples::convertMono8(long *source, char *dest, long frames) +{ + char *c = (char *)source; + char a; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = c[3]; +#else + a = c[0]; +#endif + c += 4; + *++dest = a; + } +} + +void ASIOConvertSamples::convertMono16(long *source, short *dest, long frames) +{ +#if ASIO_LITTLE_ENDIAN + char* s = (char*)source; + char* d = (char*)dest; + while(--frames >= 0) + { + *d++ = s[3]; // dest big endian, msb first + *d++ = s[2]; + s += 4; + } +#else + long l; + + source--; + dest--; + while(--frames >= 0) + { + l = *++source; + *++dest = (short)(l >> 16); + } +#endif +} + +void ASIOConvertSamples::convertMono24(long *source, char *dest, long frames) +{ + // work with chars in order to prevent misalignments + char *s = (char *)source; + char a, b, c; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = s[3]; // msb + b = s[2]; + c = s[1]; // lsb +#else + a = s[0]; + b = s[1]; + c = s[2]; +#endif + s += 4; + *++dest = a; // big endian, msb first + *++dest = b; + *++dest = c; + } +} + +// small endian + +void ASIOConvertSamples::convertMono16SmallEndian(long *source, short *dest, long frames) +{ + char *s = (char *)source; + char *d = (char *)dest; + char a, b; + + d--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = s[3]; + b = s[2]; +#else + a = s[0]; + b = s[1]; +#endif + s += 4; + *++d = b; // dest small endian, lsb first + *++d = a; + } +} + +void ASIOConvertSamples::convertMono24SmallEndian(long *source, char *dest, long frames) +{ + // work with chars in order to prevent misalignments + char *s = (char *)source; + char a, b, c; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = s[3]; + b = s[2]; + c = s[1]; +#else + a = s[0]; + b = s[1]; + c = s[2]; +#endif + s += 4; + *++dest = c; // lsb first + *++dest = b; + *++dest = a; + } +} + + +//------------------------------------------------------------------------------------------- +// stereo interleaved + +void ASIOConvertSamples::convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames) +{ + unsigned char *cl = (unsigned char *)left; + unsigned char *cr = (unsigned char *)right; + unsigned char a, b; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = cl[3]; + b = cr[3]; +#else + a = cl[0]; + b = cr[0]; +#endif + cl += 4; + cr += 4; + a -= 0x80U; + b -= 0x80U; + *++dest = a; + *++dest = b; + } +} + +void ASIOConvertSamples::convertStereo8Interleaved(long *left, long *right, char *dest, long frames) +{ + unsigned char *cl = (unsigned char *)left; + unsigned char *cr = (unsigned char *)right; + unsigned char a, b; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = cl[3]; + b = cr[3]; +#else + a = cl[0]; + b = cr[0]; +#endif + cl += 4; + cr += 4; + *++dest = a; + *++dest = b; + } +} + +void ASIOConvertSamples::convertStereo16Interleaved(long *left, long *right, short *dest, long frames) +{ +#if ASIO_LITTLE_ENDIAN + char* sl = (char*)left; + char* sr = (char*)right; + char* d = (char*)dest; + while(--frames >= 0) + { + *d++ = sl[3]; // msb first + *d++ = sl[2]; + *d++ = sr[3]; + *d++ = sr[2]; + sl += 4; + sr += 4; + } +#else + long l, r; + + left--; + right--; + dest--; + while(--frames >= 0) + { + l = *++left; + r = *++right; + *++dest = (short)(l >> 16); + *++dest = (short)(r >> 16); + } +#endif +} + +void ASIOConvertSamples::convertStereo24Interleaved(long *left, long *right, char *dest, long frames) +{ + // work with chars in order to prevent misalignments + char *sl = (char *)left; + char *sr = (char *)right; + char al, bl, cl, ar, br, cr; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + cl = sl[1]; + ar = sr[3]; + br = sr[2]; + cr = sr[1]; +#else + al = sl[0]; + bl = sl[1]; + cl = sl[2]; + ar = sr[0]; + br = sr[1]; + cr = sr[2]; +#endif + sl += 4; + sr += 4; + *++dest = al; + *++dest = bl; + *++dest = cl; + *++dest = ar; + *++dest = br; + *++dest = cr; + } +} + +void ASIOConvertSamples::convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames) +{ + char *sl = (char *)left; + char *sr = (char *)right; + char *d = (char *)dest; + char al, bl, ar, br; + + d--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + ar = sr[3]; + br = sr[2]; +#else + al = sl[0]; + bl = sl[1]; + ar = sr[0]; + br = sr[1]; +#endif + sl += 4; + sr += 4; + *++d = bl; // lsb first + *++d = al; + *++d = br; + *++d = ar; + } +} + +void ASIOConvertSamples::convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames) +{ + // work with chars in order to prevent misalignments + char *sl = (char *)left; + char *sr = (char *)right; + char al, bl, cl, ar, br, cr; + + dest--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + cl = sl[1]; + ar = sr[3]; + br = sr[2]; + cr = sr[1]; +#else + al = sl[0]; + bl = sl[1]; + cl = sl[2]; + ar = sr[0]; + br = sr[1]; + cr = sr[2]; +#endif + sl += 4; + sr += 4; + *++dest = cl; + *++dest = bl; + *++dest = al; + *++dest = cr; + *++dest = br; + *++dest = ar; + } +} + + +//------------------------------------------------------------------------------------------- +// stereo split + +void ASIOConvertSamples::convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames) +{ + unsigned char *cl = (unsigned char *)left; + unsigned char *cr = (unsigned char *)right; + unsigned char a, b; + + dLeft--; + dRight--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = cl[3]; + b = cr[3]; +#else + a = cl[0]; + b = cr[0]; +#endif + cl += 4; + cr += 4; + a -= 0x80U; + b -= 0x80U; + *++dLeft = a; + *++dRight = b; + } +} + +void ASIOConvertSamples::convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames) +{ + unsigned char *cl = (unsigned char *)left; + unsigned char *cr = (unsigned char *)right; + unsigned char a, b; + + dLeft--; + dRight--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = cl[3]; + b = cr[3]; +#else + a = cl[0]; + b = cr[0]; +#endif + cl += 4; + cr += 4; + *++dLeft = a; + *++dRight = b; + } +} + +void ASIOConvertSamples::convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames) +{ +#if ASIO_LITTLE_ENDIAN + char* sl = (char*)left; + char* sr = (char*)right; + char* dl = (char*)dLeft; + char* dr = (char*)dRight; + while(--frames >= 0) + { + *dl++ = sl[3]; // msb first + *dl++ = sl[2]; + *dr++ = sr[3]; + *dr++ = sr[2]; + sl += 4; + sr += 4; + } +#else + long l, r; + + left--; + right--; + dLeft--; + dRight--; + while(--frames >= 0) + { + l = *++left; + r = *++right; + *++dLeft = (short)(l >> 16); + *++dRight = (short)(r >> 16); + } +#endif +} + +void ASIOConvertSamples::convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames) +{ + // work with chars in order to prevent misalignments + char *sl = (char *)left; + char *sr = (char *)right; + char al, bl, cl, ar, br, cr; + + dLeft--; + dRight--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + cl = sl[1]; + ar = sr[3]; + br = sr[2]; + cr = sr[1]; +#else + al = sl[0]; + bl = sl[1]; + cl = sl[2]; + ar = sr[0]; + br = sr[1]; + cr = sr[2]; +#endif + sl += 4; + sr += 4; + *++dLeft = al; + *++dLeft = bl; + *++dLeft = cl; + *++dRight = ar; + *++dRight = br; + *++dRight = cr; + } +} + +// small endian +void ASIOConvertSamples::convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames) +{ + char *sl = (char *)left; + char *sr = (char *)right; + char *dl = (char *)dLeft; + char *dr = (char *)dRight; + char al, bl, ar, br; + + dl--; + dr--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + ar = sr[3]; + br = sr[2]; +#else + al = sl[0]; + bl = sl[1]; + ar = sr[0]; + br = sr[1]; +#endif + sl += 4; + sr += 4; + *++dl = bl; + *++dl = al; + *++dr = br; + *++dr = ar; + } +} + +void ASIOConvertSamples::convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames) +{ + // work with chars in order to prevent misalignments + char *sl = (char *)left; + char *sr = (char *)right; + char al, bl, cl, ar, br, cr; + + dLeft--; + dRight--; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + al = sl[3]; + bl = sl[2]; + cl = sl[1]; + ar = sr[3]; + br = sr[2]; + cr = sr[1]; +#else + al = sl[0]; + bl = sl[1]; + cl = sl[2]; + ar = sr[0]; + br = sr[1]; + cr = sr[2]; +#endif + sl += 4; + sr += 4; + *++dLeft = cl; + *++dLeft = bl; + *++dLeft = al; + *++dRight = cr; + *++dRight = br; + *++dRight = ar; + } +} + +//------------------------------------------------------------------------------------------ +// in place integer conversions + +void ASIOConvertSamples::int32msb16to16inPlace(long *in, long frames) +{ + short *d1 = (short *)in; + short* out = d1; +#if ASIO_LITTLE_ENDIAN + d1++; +#endif + while(--frames >= 0) + { + *out++ = *d1; + d1 += 2; + } +} + +void ASIOConvertSamples::int32lsb16to16inPlace(long *in, long frames) +{ + short *d1 = (short *)in; + short* out = d1; +#if !ASIO_LITTLE_ENDIAN + d1++; +#endif + while(--frames >= 0) + { + *out++ = *d1; + d1 += 2; + } +} + +void ASIOConvertSamples::int32msb16shiftedTo16inPlace(long *in, long frames, long shift) +{ + short* out = (short*)in; + while(--frames >= 0) + *out++ = (short)(*in++ >> shift); +} + +void ASIOConvertSamples::int24msbto16inPlace(unsigned char *in, long frames) +{ + short a; + short* out = (short*)in; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = (short)in[2]; + a <<= 8; + a |= (in[1] & 0xff); +#else + a = (short)in[0]; + a <<= 8; + a |= (in[1] & 0xff); +#endif + *out++ = a; + in += 3; + } +} + +//----------------------------------------------------------------------------------------- + +void ASIOConvertSamples::shift32(void* buffer, long shiftAmount, long targetByteWidth, + bool revertEndian, long sampleFrames) +{ + long a; + long frames = sampleFrames; + long* source = (long*)buffer; + if(revertEndian) + { + reverseEndian(buffer, 4, sampleFrames); + revertEndian = false; + } + + if(targetByteWidth == 2) + { + short* dest = (short*)buffer; + short* al = (short*)&a; +#if ASIO_LITTLE_ENDIAN + al++; +#endif + while(--frames >= 0) + { + a = *source++; + a <<= shiftAmount; + *dest++ = *al; + } + } + + else if(targetByteWidth == 3) + { + char* dest = (char*)buffer; + long* source = (long*)buffer; + char* aa = (char*)&a; + while(--frames >= 0) + { + a = *source++; + a <<= shiftAmount; +#if ASIO_LITTLE_ENDIAN + dest[0] = aa[1]; // lsb + dest[1] = aa[2]; + dest[2] = aa[3]; // msb +#else + dest[0] = aa[0]; // msb + dest[1] = aa[1]; + dest[2] = aa[2]; // lsb +#endif + dest += 3; + } + } + + else if(targetByteWidth == 4) + { + long* dest = source; + while(--frames >= 0) + *dest++ = *source++ << shiftAmount; + } +} + +void ASIOConvertSamples::reverseEndian(void* buffer, long byteWidth, long frames) +{ + char* a = (char*)buffer; + char* b = a; + char c; + if(byteWidth == 2) + { + while(--frames >= 0) + { + c = a[0]; + a[0] = a[1]; + a[1] = c; + a += 2; + } + } + else if(byteWidth == 3) + { + while(--frames >= 0) + { + c = a[0]; + a[0] = a[2]; + a[2] = c; + a += 3; + } + } + else if(byteWidth == 4) + { + while(--frames >= 0) + { + c = a[0]; + a[0] = a[3]; + a[3] = c; + c = a[1]; + a[1] = a[2]; + a[2] = c; + a += 4; + } + } +} + +//------------------------------------------------------------------------------------------------- + +void ASIOConvertSamples::int32to16inPlace(void* buffer, long frames) +{ + short* in = (short*)buffer; + short* out = in; +#if ASIO_LITTLE_ENDIAN + in++; +#endif + while(--frames >= 0) + { + *out++ = *in; + in += 2; + } +} + +void ASIOConvertSamples::int24to16inPlace(void* buffer, long frames) +{ + char* from = (char*)buffer; + char* to = from; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + to[0] = from[1]; + to[1] = from[2]; +#else + to[0] = from[0]; + to[1] = from[1]; +#endif + from += 3; + to += 2; + } +} + +void ASIOConvertSamples::int32to24inPlace(void* buffer, long frames) +{ + long* in = (long*)buffer; + char* out = (char*)buffer; + long a; + while(--frames >= 0) + { + a = *in++; + a >>= 8; // 32->24 +#if ASIO_LITTLE_ENDIAN + out[0] = (char)a; // lsb + a >>= 8; + out[1] = (char)a; + a >>= 8; + out[2] = (char)a; +#else + out[2] = (char)a; // lsb + a >>= 8; + out[1] = (char)a; + a >>= 8; + out[0] = (char)a; +#endif + out += 3; + } +} + +void ASIOConvertSamples::int16to24inPlace(void* buffer, long frames) +{ + char* in = (char*)buffer; + char* out = (char*)buffer; + in += frames * 2; + out += frames * 3; + while(--frames >= 0) + { + out -= 3; + in -= 2; +#if ASIO_LITTLE_ENDIAN + out[2] = in[1]; // msb + out[1] = in[0]; // lsb + out[0] = 0; +#else + out[2] = 0; + out[1] = in[1]; // lsb + out[0] = in[0]; // msb +#endif + } +} + +void ASIOConvertSamples::int24to32inPlace(void* buffer, long frames) +{ + long a, b, c; + char* in = (char*)buffer; + long* out = (long*)buffer; + in += (frames * 3); + out += frames; + while(--frames >= 0) + { +#if ASIO_LITTLE_ENDIAN + a = (long)in[-1]; // msb + b = (long)in[-2]; + c = (long)in[-3]; +#else + a = (long)in[-3]; // msb + b = (long)in[-2]; + c = (long)in[-1]; +#endif + a <<= 24; + b <<= 16; + b &= 0x00ff0000; + a |= b; + c <<= 8; + c &= 0x0000ff00; + a |= c; + *--out = a; + in -= 3; + } +} + +void ASIOConvertSamples::int16to32inPlace(void* buffer, long frames) +{ + short* in = (short*)buffer; + long* out = (long*)buffer; + in += frames; + out += frames; + while(--frames >= 0) + *--out = ((long)(*--in)) << 16; +} + +//------------------------------------------------------------------------------------------ +// float to int + +const double fScaler16 = (double)0x7fffL; +const double fScaler24 = (double)0x7fffffL; +const double fScaler32 = (double)0x7fffffffL; + +void ASIOConvertSamples::float32toInt16inPlace(float* buffer, long frames) +{ + double sc = fScaler16 + .49999; + short* b = (short*)buffer; + while(--frames >= 0) + *b++ = (short)((double)(*buffer++) * sc); +} + +void ASIOConvertSamples::float32toInt24inPlace(float* buffer, long frames) +{ + double sc = fScaler24 + .49999; + long a; + char* b = (char*)buffer; + char* aa = (char*)&a; + + while(--frames >= 0) + { + a = (long)((double)(*buffer++) * sc); +#if ASIO_LITTLE_ENDIAN + *b++ = aa[3]; + *b++ = aa[2]; + *b++ = aa[1]; +#else + *b++ = aa[1]; + *b++ = aa[2]; + *b++ = aa[3]; +#endif + } +} + +void ASIOConvertSamples::float32toInt32inPlace(float* buffer, long frames) +{ + double sc = fScaler32 + .49999; + long* b = (long*)buffer; + while(--frames >= 0) + *b++ = (long)((double)(*buffer++) * sc); +} + diff --git a/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.h b/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.h new file mode 100644 index 0000000..d1918a2 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/ASIOConvertSamples.h @@ -0,0 +1,62 @@ +#ifndef __ASIOConvertSamples__ +#define __ASIOConvertSamples__ + +class ASIOConvertSamples +{ +public: + ASIOConvertSamples(); + ~ASIOConvertSamples() {} + + // format converters, input 32 bit integer + // mono + void convertMono8(long *source, char *dest, long frames); + void convertMono8Unsigned(long *source, char *dest, long frames); + void convertMono16(long *source, short *dest, long frames); + void convertMono16SmallEndian(long *source, short *dest, long frames); + void convertMono24(long *source, char *dest, long frames); + void convertMono24SmallEndian(long *source, char *dest, long frames); + + // stereo interleaved + void convertStereo8Interleaved(long *left, long *right, char *dest, long frames); + void convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames); + void convertStereo16Interleaved(long *left, long *right, short *dest, long frames); + void convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames); + void convertStereo24Interleaved(long *left, long *right, char *dest, long frames); + void convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames); + + // stereo split + void convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames); + void convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames); + void convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames); + void convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames); + void convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames); + void convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames); + + // integer in place conversions + + void int32msb16to16inPlace(long *in, long frames); + void int32lsb16to16inPlace(long *in, long frames); + void int32msb16shiftedTo16inPlace(long *in1, long frames, long shift); + void int24msbto16inPlace(unsigned char *in, long frames); + + // integer to integer + + void shift32(void* buffer, long shiftAmount, long targetByteWidth, + bool reverseEndian, long frames); + void reverseEndian(void* buffer, long byteWidth, long frames); + + void int32to16inPlace(void* buffer, long frames); + void int24to16inPlace(void* buffer, long frames); + void int32to24inPlace(void* buffer, long frames); + void int16to24inPlace(void* buffer, long frames); + void int24to32inPlace(void* buffer, long frames); + void int16to32inPlace(void* buffer, long frames); + + // float to integer + + void float32toInt16inPlace(float* buffer, long frames); + void float32toInt24inPlace(float* buffer, long frames); + void float32toInt32inPlace(float* buffer, long frames); +}; + +#endif diff --git a/src/hostapi/asio/ASIOSDK/host/asiodrivers.cpp b/src/hostapi/asio/ASIOSDK/host/asiodrivers.cpp new file mode 100644 index 0000000..4067bc0 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/asiodrivers.cpp @@ -0,0 +1,186 @@ +#include +#include "asiodrivers.h" + +AsioDrivers* asioDrivers = 0; + +bool loadAsioDriver(char *name); + +bool loadAsioDriver(char *name) +{ + if(!asioDrivers) + asioDrivers = new AsioDrivers(); + if(asioDrivers) + return asioDrivers->loadDriver(name); + return false; +} + +//------------------------------------------------------------------------------------ + +#if MAC + +bool resolveASIO(unsigned long aconnID); + +AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio') +{ + connID = -1; + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ + removeCurrentDriver(); +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + if(curIndex >= 0) + return getName(curIndex, name); + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + for(long i = 0; i < getNumFragments() && i < maxDrivers; i++) + getName(i, names[i]); + return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers; +} + +bool AsioDrivers::loadDriver(char *name) +{ + char dname[64]; + unsigned long newID; + + for(long i = 0; i < getNumFragments(); i++) + { + if(getName(i, dname) && !strcmp(name, dname)) + { + if(newInstance(i, &newID)) + { + if(resolveASIO(newID)) + { + if(connID != -1) + removeInstance(curIndex, connID); + curIndex = i; + connID = newID; + return true; + } + } + break; + } + } + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ + if(connID != -1) + removeInstance(curIndex, connID); + connID = -1; + curIndex = -1; +} + +//------------------------------------------------------------------------------------ + +#elif WINDOWS + +#include "iasiodrv.h" + +extern IASIO* theAsioDriver; + +AsioDrivers::AsioDrivers() : AsioDriverList() +{ + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + if(curIndex >= 0) + return asioGetDriverName(curIndex, name, 32) == 0 ? true : false; + name[0] = 0; + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++) + asioGetDriverName(i, names[i], 32); + return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers; +} + +bool AsioDrivers::loadDriver(char *name) +{ + char dname[64]; + char curName[64]; + + for(long i = 0; i < asioGetNumDev(); i++) + { + if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname)) + { + curName[0] = 0; + getCurrentDriverName(curName); // in case we fail... + removeCurrentDriver(); + + if(!asioOpenDriver(i, (void **)&theAsioDriver)) + { + curIndex = i; + return true; + } + else + { + theAsioDriver = 0; + if(curName[0] && strcmp(dname, curName)) + loadDriver(curName); // try restore + } + break; + } + } + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ + if(curIndex != -1) + asioCloseDriver(curIndex); + curIndex = -1; +} + +#elif SGI || BEOS + +#include "asiolist.h" + +AsioDrivers::AsioDrivers() + : AsioDriverList() +{ + curIndex = -1; +} + +AsioDrivers::~AsioDrivers() +{ +} + +bool AsioDrivers::getCurrentDriverName(char *name) +{ + return false; +} + +long AsioDrivers::getDriverNames(char **names, long maxDrivers) +{ + return 0; +} + +bool AsioDrivers::loadDriver(char *name) +{ + return false; +} + +void AsioDrivers::removeCurrentDriver() +{ +} + +#else +#error implement me +#endif diff --git a/src/hostapi/asio/ASIOSDK/host/asiodrivers.h b/src/hostapi/asio/ASIOSDK/host/asiodrivers.h new file mode 100644 index 0000000..511f2ea --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/asiodrivers.h @@ -0,0 +1,41 @@ +#ifndef __AsioDrivers__ +#define __AsioDrivers__ + +#include "ginclude.h" + +#if MAC +#include "CodeFragments.hpp" + +class AsioDrivers : public CodeFragments + +#elif WINDOWS +#include +#include "asiolist.h" + +class AsioDrivers : public AsioDriverList + +#elif SGI || BEOS +#include "asiolist.h" + +class AsioDrivers : public AsioDriverList + +#else +#error implement me +#endif + +{ +public: + AsioDrivers(); + ~AsioDrivers(); + + bool getCurrentDriverName(char *name); + long getDriverNames(char **names, long maxDrivers); + bool loadDriver(char *name); + void removeCurrentDriver(); + long getCurrentDriverIndex() {return curIndex;} +protected: + unsigned long connID; + long curIndex; +}; + +#endif diff --git a/src/hostapi/asio/ASIOSDK/host/ginclude.h b/src/hostapi/asio/ASIOSDK/host/ginclude.h new file mode 100644 index 0000000..97cb7b7 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/ginclude.h @@ -0,0 +1,38 @@ +#ifndef __gInclude__ +#define __gInclude__ + +#if SGI + #undef BEOS + #undef MAC + #undef WINDOWS + // + #define ASIO_BIG_ENDIAN 1 + #define ASIO_CPU_MIPS 1 +#elif defined(_WIN32) || defined(_WIN64) + #undef BEOS + #undef MAC + #undef SGI + #define WINDOWS 1 + #define ASIO_LITTLE_ENDIAN 1 + #define ASIO_CPU_X86 1 +#elif BEOS + #undef MAC + #undef SGI + #undef WINDOWS + #define ASIO_LITTLE_ENDIAN 1 + #define ASIO_CPU_X86 1 + // +#else + #define MAC 1 + #undef BEOS + #undef WINDOWS + #undef SGI + #define ASIO_BIG_ENDIAN 1 + #define ASIO_CPU_PPC 1 +#endif + +// always +#define NATIVE_INT64 0 +#define IEEE754_64FLOAT 1 + +#endif // __gInclude__ diff --git a/src/hostapi/asio/ASIOSDK/host/mac/asioshlib.cpp b/src/hostapi/asio/ASIOSDK/host/mac/asioshlib.cpp new file mode 100644 index 0000000..77163e5 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/mac/asioshlib.cpp @@ -0,0 +1,342 @@ +// asio code fragment 'linker' +// mac specific +// loads the symbols via the fragment manager, and +// translates them into function pointers. this +// means no asio lib must be linked, as the +// 'real' asio functions are here + +#include "ginclude.h" +#include +#include +#include +#include "asio.h" + +// Macro below has to 0 if external drivers will be used. +// Can be set to 1 if a specific ASIO driver should be linked into the program +#define ASIOINCLUDED 0 + + + +// export +bool resolveASIO(unsigned long aconnID); + +//------------------------------------------------------------------------------------------------------ +// private + +#if ASIOINCLUDED +bool resolveASIO(unsigned long aconnID) {aconnID = aconnID; return true;} +#else + +enum +{ + kASIOInit = 0, + kASIOExit, + kASIOStart, + kASIOStop, + kASIOGetChannels, + kASIOGetLatencies, + kASIOGetBufferSize, + kASIOCanSampleRate, + kASIOGetSampleRate, + kASIOSetSampleRate, + kASIOGetClockSources, + kASIOSetClockSource, + kASIOGetSamplePosition, + kASIOGetChannelInfo, + kASIOCreateBuffers, + kASIODisposeBuffers, + kASIOControlPanel, + kASIOFuture, + + kASIOOutputReady, + + kNumSymbols, + kRequiredSymbols = kNumSymbols - 1 +}; + +static char *asioTable[kNumSymbols] = +{ + "ASIOInit", + "ASIOExit", + "ASIOStart", + "ASIOStop", + "ASIOGetChannels", + "ASIOGetLatencies", + "ASIOGetBufferSize", + "ASIOCanSampleRate", + "ASIOGetSampleRate", + "ASIOSetSampleRate", + "ASIOGetClockSources", + "ASIOSetClockSource", + "ASIOGetSamplePosition", + "ASIOGetChannelInfo", + "ASIOCreateBuffers", + "ASIODisposeBuffers", + "ASIOControlPanel", + "ASIOFuture", + "ASIOOutputReady" +}; + +typedef ASIOError (*fasioInit) (ASIODriverInfo *info); +typedef ASIOError (*fasioExit) (void); +typedef ASIOError (*fasioStart) (void); +typedef ASIOError (*fasioStop) (void); +typedef ASIOError (*asioGetChannels) (long *numInputChannels, long *numOutputChannels); +typedef ASIOError (*asioGetLatencies) (long *inputLatency, long *outputLatency); +typedef ASIOError (*asioGetBufferSize) (long *minSize, long *maxSize, long *preferredSize, long *granularity); +typedef ASIOError (*asioCanSampleRate) (ASIOSampleRate sampleRate); +typedef ASIOError (*asioGetSampleRate) (ASIOSampleRate *currentRate); +typedef ASIOError (*asioSetSampleRate) (ASIOSampleRate sampleRate); +typedef ASIOError (*asioGetClockSources) (ASIOClockSource *clocks, long *numSources); +typedef ASIOError (*asioSetClockSource) (long reference); +typedef ASIOError (*asioGetSamplePosition) (ASIOSamples *sPos, ASIOTimeStamp *tStamp); +typedef ASIOError (*asioGetChannelInfo) (ASIOChannelInfo *info); +typedef ASIOError (*asioCreateBuffers) (ASIOBufferInfo *channelInfos, long numChannels, + long bufferSize, ASIOCallbacks *callbacks); +typedef ASIOError (*asioDisposeBuffers) (void); +typedef ASIOError (*asioControlPanel) (void); +typedef ASIOError (*asioFuture)(long selector, void *opt); +typedef ASIOError (*asioOutputReady) (void); + +static void *functionTable[kNumSymbols] = {0}; +static bool inited = false; + +//--------------------------------------------------------------------------------------------------------- + +#include + +bool resolveASIO(unsigned long aconnID) +{ + OSErr err; + CFragConnectionID connID = (CFragConnectionID)aconnID; + CFragSymbolClass symClass; + Ptr symAddr = nil; + Str255 myName; + long myCount = 0; + + err = CountSymbols(connID, &myCount); + if(err != noErr || myCount < (kRequiredSymbols + 1)) // there must be a main() + return false; + + long n, c = 0; + for(n = kRequiredSymbols; n < kNumSymbols; n++) + functionTable[n] = 0; + for(n = 0; n < myCount; n++) + { + // we can't use FindSymbol(), as the compiler adds mangling + // (such as ASIOInit__Fv). also, the symbols don't appear + // in the order they are declared or implemented. + // so we use strncmp() + err = GetIndSymbol(connID, n, myName, &symAddr, &symClass); + if(err != noErr) + break; + PtoCstr(myName); + if(!strncmp((char *)myName, "main", 4L)) + c++; + else + { + for(long i = 0; i < kNumSymbols; i++) + { + long sc = strlen(asioTable[i]); + if(!strncmp((char *)myName, asioTable[i], sc)) + { + functionTable[i] = symAddr; + if(i < kRequiredSymbols) + c++; + break; + } + } + } + // if(c >= kNumSymbols + 1) + // break; + } + if(c >= kRequiredSymbols + 1) + { + inited = true; + return true; + } + return false; +} + +//--------------------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------------- + +#pragma export on + +static short curRes = 0; +#define saveRes() curRes = CurResFile() +#define restRes() UseResFile(curRes); + + +ASIOError ASIOInit(ASIODriverInfo *info) +{ + saveRes(); + strcpy(info->errorMessage, "No ASIO Driver could be Loaded!"); + if(!inited) + return ASE_NotPresent; + fasioInit f = (fasioInit)functionTable[kASIOInit]; + ASIOError e = (*f)(info); + restRes(); + return e; +} + +ASIOError ASIOExit(void) +{ + if(!inited) + return ASE_NotPresent; + saveRes(); + fasioExit f = (fasioExit)functionTable[kASIOExit]; + ASIOError e = (*f)(); + restRes(); + return e; +} + +ASIOError ASIOStart(void) +{ + if(!inited) + return ASE_NotPresent; + fasioStart f = (fasioStart)functionTable[kASIOStart]; + return (*f)(); +} + +ASIOError ASIOStop(void) +{ + if(!inited) + return ASE_NotPresent; + fasioStop f = (fasioStop)functionTable[kASIOStop]; + return (*f)(); +} + +ASIOError ASIOGetChannels(long *numInputChannels, long *numOutputChannels) +{ + if(!inited) + return ASE_NotPresent; + asioGetChannels f = (asioGetChannels)functionTable[kASIOGetChannels]; + return (*f)(numInputChannels, numOutputChannels); +} + +ASIOError ASIOGetLatencies(long *inputLatency, long *outputLatency) +{ + if(!inited) + return ASE_NotPresent; + asioGetLatencies f = (asioGetLatencies)functionTable[kASIOGetLatencies]; + return (*f)(inputLatency, outputLatency); +} + +ASIOError ASIOGetBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity) +{ + if(!inited) + return ASE_NotPresent; + asioGetBufferSize f = (asioGetBufferSize)functionTable[kASIOGetBufferSize]; + return (*f)(minSize, maxSize, preferredSize, granularity); +} + +ASIOError ASIOCanSampleRate(ASIOSampleRate sampleRate) +{ + if(!inited) + return ASE_NotPresent; + asioCanSampleRate f = (asioCanSampleRate)functionTable[kASIOCanSampleRate]; + return (*f)(sampleRate); +} + +ASIOError ASIOGetSampleRate(ASIOSampleRate *currentRate) +{ + if(!inited) + return ASE_NotPresent; + asioGetSampleRate f = (asioGetSampleRate)functionTable[kASIOGetSampleRate]; + return (*f)(currentRate); +} + +ASIOError ASIOSetSampleRate(ASIOSampleRate sampleRate) +{ + if(!inited) + return ASE_NotPresent; + asioSetSampleRate f = (asioSetSampleRate)functionTable[kASIOSetSampleRate]; + return (*f)(sampleRate); +} + +ASIOError ASIOGetClockSources(ASIOClockSource *clocks, long *numSources) +{ + if(!inited) + return ASE_NotPresent; + asioGetClockSources f = (asioGetClockSources)functionTable[kASIOGetClockSources]; + return (*f)(clocks, numSources); +} + +ASIOError ASIOSetClockSource(long reference) +{ + if(!inited) + return ASE_NotPresent; + asioSetClockSource f = (asioSetClockSource)functionTable[kASIOSetClockSource]; + return (*f)(reference); +} + +ASIOError ASIOGetSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp) +{ + if(!inited) + return ASE_NotPresent; + asioGetSamplePosition f = (asioGetSamplePosition)functionTable[kASIOGetSamplePosition]; + return (*f)(sPos, tStamp); +} + +ASIOError ASIOGetChannelInfo(ASIOChannelInfo *info) +{ + if(!inited) + return ASE_NotPresent; + asioGetChannelInfo f = (asioGetChannelInfo)functionTable[kASIOGetChannelInfo]; + return (*f)(info); +} + +ASIOError ASIOCreateBuffers(ASIOBufferInfo *channelInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks) +{ + if(!inited) + return ASE_NotPresent; + saveRes(); + asioCreateBuffers f = (asioCreateBuffers)functionTable[kASIOCreateBuffers]; + ASIOError e = (*f)(channelInfos, numChannels, bufferSize, callbacks); + restRes(); + return e; +} + +ASIOError ASIODisposeBuffers(void) +{ + if(!inited) + return ASE_NotPresent; + asioDisposeBuffers f = (asioDisposeBuffers)functionTable[kASIODisposeBuffers]; + return (*f)(); +} + +ASIOError ASIOControlPanel(void) +{ + if(!inited) + return ASE_NotPresent; + saveRes(); + asioControlPanel f = (asioControlPanel)functionTable[kASIOControlPanel]; + ASIOError e = (*f)(); + restRes(); + return e; +} + +ASIOError ASIOFuture(long selector, void *opt) +{ + if(!inited) + return 0; + saveRes(); + asioFuture f = (asioFuture)functionTable[kASIOFuture]; + ASIOError e = (*f)(selector, opt); + restRes(); + return e; +} + +ASIOError ASIOOutputReady(void) +{ + asioOutputReady f = (asioControlPanel)functionTable[kASIOOutputReady]; + if(!inited || !f) + return ASE_NotPresent; + return (*f)(); +} + +#pragma export off + +#endif // ASIOINCLUDED + diff --git a/src/hostapi/asio/ASIOSDK/host/mac/codefragments.cpp b/src/hostapi/asio/ASIOSDK/host/mac/codefragments.cpp new file mode 100644 index 0000000..6b3cb07 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/mac/codefragments.cpp @@ -0,0 +1,349 @@ +// very MAC specific; generic code fragment handler +#include "ginclude.h" +#include +#include +#include +#include +#include "CodeFragments.hpp" + +enum +{ + kNewCFragCopy = kPrivateCFragCopy +}; + +class CodeFragmentInstance +{ +private: +friend class CodeFragment; + CodeFragmentInstance() {next = 0; handle = 0; connID = (void*)-1;} + ~CodeFragmentInstance() {CloseConnection((CFragConnectionID*)&connID); DisposeHandle(handle);} + + CodeFragmentInstance *next; + Handle handle; + void* connID; +}; + +class CodeFragment +{ +public: + CodeFragment(); + ~CodeFragment(); + + bool newInstance(void** cID); + void removeInstance(void* id); + bool getName(char *name) {if(!resName[0]) return false; strcpy(name, resName); return true;} + +private: +friend class CodeFragments; + + CodeFragment *next; + CodeFragmentInstance *root; + Handle handle; + long numInstances; + long index; + char resName[64]; +}; + +//------------------------------------------------------------------------------------------ + +CodeFragment::CodeFragment() +{ + next = 0; + root = 0; + handle = 0; + numInstances = 0; + index = 0; + resName[0] = 0; +} + +CodeFragment::~CodeFragment() +{ + // could delete all instances + // rather omit it... +} + +bool CodeFragment::newInstance(void** cID) +{ + Ptr myMainAddr; + Str255 myErrName; + char pname[256]; + + *cID = (void*)-1; + if(!handle) + return false; + CodeFragmentInstance *c = new CodeFragmentInstance(); + if(!c) + return false; + c->handle = this->handle; + OSErr err = HandToHand(&c->handle); + if(err == noErr) + { + // use fragment loader + myMainAddr = 0; + strcpy(pname, resName); + CtoPstr(pname); + err = GetMemFragment(*handle, GetHandleSize(handle), + (unsigned char *)pname, kNewCFragCopy, (CFragConnectionID*)&c->connID, + &myMainAddr, myErrName); + if(err == noErr && myMainAddr) + { + if(!root) + root = c; + else + { + CodeFragmentInstance *cc = root; + while(cc->next) + cc = cc->next; + cc->next = c; + } + numInstances++; + *cID = c->connID; + return true; + } + } + return false; +} + +void CodeFragment::removeInstance(void* id) +{ + CodeFragmentInstance *c = root, *last = root; + while(c) + { + if(c->connID == id) + { + if(c == root) + root = root->next; + else + last->next = c->next; + delete c; + numInstances--; + return; + } + last = c; + c = c->next; + } +} + +//---------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------- + +CodeFragments::CodeFragments(char *folderName, long fileType, long resType) +{ + root = 0; + numFragments = 0; + gARefNum = -1; + + if(setFolder(folderName)) + { + loadFragments(gARefNum, fileType, resType); + SetVol(0L, defVol); + } +} + +CodeFragments::~CodeFragments() +{ + while(root) + { + CodeFragment *c = root->next; + delete root; + root = c; + } +} + +bool CodeFragments::newInstance(long index, unsigned long* cID) +{ + *cID = -1; + CodeFragment *c = root; + while(c) + { + if(c->index == index) + return c->newInstance((void**)cID); + c = c->next; + } + return false; +} + +void CodeFragments::removeInstance(long index, unsigned long cID) +{ + CodeFragment *c = root; + while(c) + { + if(c->index == index) + { + c->removeInstance((void*)cID); + break; + } + c = c->next; + } +} + +bool CodeFragments::getName(long index, char *name) +{ + CodeFragment *c = root; + while(c) + { + if(c->index == index) + { + strcpy(name, c->resName); + return true; + } + c = c->next; + } + return false; +} + +//------------------------------------------------------------------------------------ +// private + +void CodeFragments::loadFragments(short folderRef, long fileType, long resType) +{ + Str255 fileName; + HFileParam parmblock; + short resRef,index = 1,lindex; + short resID; + ResType resourceType; + Str255 resName; + Handle h; + short curResFile = CurResFile(); + + while(true) + { + // find any file in the folder + memset (&parmblock,0,(long)sizeof(HFileParam)); + parmblock.ioNamePtr = fileName; + parmblock.ioVRefNum = folderRef; + parmblock.ioFDirIndex = index; + if(PBHGetFInfoSync ((HParmBlkPtr)&parmblock) != noErr) + break; + + // see if the file type matches + if(parmblock.ioFlFndrInfo.fdType == fileType) + { + resRef = OpenResFile(fileName); + if(ResError()==noErr) + { + UseResFile(resRef); + lindex = 1; + // search resources in the file found which match + while(true) + { + h = Get1IndResource(resType, lindex); + if(h) + { + CodeFragment *c = new CodeFragment; + if(!root) + root = c; + else + { + CodeFragment *cc = root; + while(cc->next) + cc = cc->next; + cc->next = c; + } + GetResInfo(h, &resID, &resourceType, resName); + // PtoCstr(fileName); + // strcpy(c->fileName, (char *)fileName); + PtoCstr(resName); + strcpy(c->resName, (char*)resName); + DetachResource(h); + HLockHi(h); + c->handle = h; + c->index = numFragments; + numFragments++; + } + else + break; + lindex++; + } + CloseResFile(resRef); + } + } + index++; + } + UseResFile(curResFile); +} + +//----------------------------------------------------------------------------------------- + +bool CodeFragments::setFolder(char *folderName) +{ + FSSpec fss; + + if(gARefNum == -1) + { + if(!getFrontProcessDirectory(&fss)) + return false; + if(!openFragmentFolder(&fss, folderName, &gARefNum)) + return false; + } + defVol = getDefVol(); + SetVol(0L, gARefNum); + return true; +} + +bool CodeFragments::getFrontProcessDirectory(void *specs) +{ + FSSpec *fss = (FSSpec *)specs; + ProcessInfoRec pif; + ProcessSerialNumber psn; + + memset(&psn,0,(long)sizeof(ProcessSerialNumber)); + if(GetFrontProcess(&psn) == noErr) + { + pif.processName = 0; //(StringPtr)name; + pif.processAppSpec = fss; + pif.processInfoLength = sizeof(ProcessInfoRec); + if(GetProcessInformation(&psn, &pif) == noErr) + return true; + } + return false; +} + +bool CodeFragments::openFragmentFolder(void *specs, char *foldername, short *found_vref) +{ + FSSpec *fss = (FSSpec *)specs; + WDPBRec funcparms,homefolder; + HFileInfo my_funcfolder; + char funcFolder_name[32]; + + *found_vref = -1; + strcpy(funcFolder_name,foldername); + CtoPstr(funcFolder_name); + + memset (&homefolder,0,(long)sizeof(WDPBRec)); + homefolder.ioVRefNum = fss->vRefNum; + homefolder.ioWDDirID = fss->parID; + if(PBOpenWDSync(&homefolder) != noErr) + return false; + memset(&my_funcfolder,0,(long)sizeof(CInfoPBRec)); + my_funcfolder.ioNamePtr = (StringPtr)funcFolder_name; + my_funcfolder.ioVRefNum = homefolder.ioVRefNum; + if(PBGetCatInfoSync((CInfoPBPtr)&my_funcfolder) != noErr) + { + PBCloseWDSync(&homefolder); + return false; + } + memset (&funcparms,0,(long)sizeof(WDPBRec)); + funcparms.ioWDProcID = 'stCA'; + funcparms.ioVRefNum = my_funcfolder.ioVRefNum; + funcparms.ioWDDirID = my_funcfolder.ioDirID; + if(PBOpenWDSync(&funcparms) != noErr) + { + PBCloseWDSync(&homefolder); + return false; + } + PBCloseWDSync(&homefolder); + *found_vref = funcparms.ioVRefNum; + return true; +} + +short CodeFragments::getDefVol() +{ + unsigned char text[32]; + short vol_ref = 0; + + *text=0; + if(GetVol(text, &vol_ref) == noErr) + return (vol_ref); + return 0; +} diff --git a/src/hostapi/asio/ASIOSDK/host/mac/codefragments.hpp b/src/hostapi/asio/ASIOSDK/host/mac/codefragments.hpp new file mode 100644 index 0000000..2eb6ba2 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/mac/codefragments.hpp @@ -0,0 +1,30 @@ +#ifndef __CodeFragments__ +#define __CodeFragments__ + +class CodeFragment; + +class CodeFragments +{ +public: + CodeFragments(char *folderName, long fileType, long resType); + ~CodeFragments(); + + long getNumFragments() {return numFragments;} + bool newInstance(long index, unsigned long *cID); + void removeInstance(long index, unsigned long cID); + bool getName(long index, char *name); + +protected: + void loadFragments(short folderRef, long fileType, long resType); + bool setFolder(char *folderName); + bool openFragmentFolder(void *specs, char *foldername, short *found_vref); + bool getFrontProcessDirectory(void *specs); + short getDefVol(); + + CodeFragment *root; + long numFragments; + short gARefNum; + short defVol; +}; + +#endif diff --git a/src/hostapi/asio/ASIOSDK/host/pc/asiolist.cpp b/src/hostapi/asio/ASIOSDK/host/pc/asiolist.cpp new file mode 100644 index 0000000..88b1632 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/pc/asiolist.cpp @@ -0,0 +1,268 @@ +#include +#include "iasiodrv.h" +#include "asiolist.h" + +#define ASIODRV_DESC "description" +#define INPROC_SERVER "InprocServer32" +#define ASIO_PATH "software\\asio" +#define COM_CLSID "clsid" + +// ****************************************************************** +// Local Functions +// ****************************************************************** +static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize) +{ + HKEY hkEnum,hksub,hkpath; + char databuf[512]; + LONG cr,rc = -1; + DWORD datatype,datasize; + DWORD index; + OFSTRUCT ofs; + HFILE hfile; + BOOL found = FALSE; + + CharLowerBuff(clsidstr,strlen(clsidstr)); + if ((cr = RegOpenKey(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) { + + index = 0; + while (cr == ERROR_SUCCESS && !found) { + cr = RegEnumKey(hkEnum,index++,(LPTSTR)databuf,512); + if (cr == ERROR_SUCCESS) { + CharLowerBuff(databuf,strlen(databuf)); + if (!(strcmp(databuf,clsidstr))) { + if ((cr = RegOpenKeyEx(hkEnum,(LPCTSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + if ((cr = RegOpenKeyEx(hksub,(LPCTSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) { + datatype = REG_SZ; datasize = (DWORD)dllpathsize; + cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize); + if (cr == ERROR_SUCCESS) { + memset(&ofs,0,sizeof(OFSTRUCT)); + ofs.cBytes = sizeof(OFSTRUCT); + hfile = OpenFile(dllpath,&ofs,OF_EXIST); + if (hfile) rc = 0; + } + RegCloseKey(hkpath); + } + RegCloseKey(hksub); + } + found = TRUE; // break out + } + } + } + RegCloseKey(hkEnum); + } + return rc; +} + + +static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv) +{ + HKEY hksub; + char databuf[256]; + char dllpath[MAXPATHLEN]; + WORD wData[100]; + CLSID clsid; + DWORD datatype,datasize; + LONG cr,rc; + + if (!lpdrv) { + if ((cr = RegOpenKeyEx(hkey,(LPCTSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) { + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueEx(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + rc = findDrvPath (databuf,dllpath,MAXPATHLEN); + if (rc == 0) { + lpdrv = new ASIODRVSTRUCT[1]; + if (lpdrv) { + memset(lpdrv,0,sizeof(ASIODRVSTRUCT)); + lpdrv->drvID = drvID; + MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100); + if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) { + memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID)); + } + + datatype = REG_SZ; datasize = 256; + cr = RegQueryValueEx(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize); + if (cr == ERROR_SUCCESS) { + strcpy(lpdrv->drvname,databuf); + } + else strcpy(lpdrv->drvname,keyname); + } + } + } + RegCloseKey(hksub); + } + } + else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next); + + return lpdrv; +} + +static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv) +{ + IASIO *iasio; + + if (lpdrv != 0) { + deleteDrvStruct(lpdrv->next); + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + } + delete lpdrv; + } +} + + +static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv) +{ + while (lpdrv) { + if (lpdrv->drvID == drvID) return lpdrv; + lpdrv = lpdrv->next; + } + return 0; +} +// ****************************************************************** + + +// ****************************************************************** +// AsioDriverList +// ****************************************************************** +AsioDriverList::AsioDriverList () +{ + HKEY hkEnum = 0; + char keyname[MAXDRVNAMELEN]; + LPASIODRVSTRUCT pdl; + LONG cr; + DWORD index = 0; + BOOL fin = FALSE; + + numdrv = 0; + lpdrvlist = 0; + + cr = RegOpenKey(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum); + while (cr == ERROR_SUCCESS) { + if ((cr = RegEnumKey(hkEnum,index++,(LPTSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) { + lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist); + } + else fin = TRUE; + } + if (hkEnum) RegCloseKey(hkEnum); + + pdl = lpdrvlist; + while (pdl) { + numdrv++; + pdl = pdl->next; + } + + if (numdrv) CoInitialize(0); // initialize COM +} + +AsioDriverList::~AsioDriverList () +{ + if (numdrv) { + deleteDrvStruct(lpdrvlist); + CoUninitialize(); + } +} + + +LONG AsioDriverList::asioGetNumDev (VOID) +{ + return (LONG)numdrv; +} + + +LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv) +{ + LPASIODRVSTRUCT lpdrv = 0; + long rc; + + if (!asiodrv) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (!lpdrv->asiodrv) { + rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv); + if (rc == S_OK) { + lpdrv->asiodrv = *asiodrv; + return 0; + } + // else if (rc == REGDB_E_CLASSNOTREG) + // strcpy (info->messageText, "Driver not registered in the Registration Database!"); + } + else rc = DRVERR_DEVICE_ALREADY_OPEN; + } + else rc = DRVERR_DEVICE_NOT_FOUND; + + return rc; +} + + +LONG AsioDriverList::asioCloseDriver (int drvID) +{ + LPASIODRVSTRUCT lpdrv = 0; + IASIO *iasio; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (lpdrv->asiodrv) { + iasio = (IASIO *)lpdrv->asiodrv; + iasio->Release(); + lpdrv->asiodrv = 0; + } + } + + return 0; +} + +LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!drvname) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) { + strcpy(drvname,lpdrv->drvname); + } + else { + memcpy(drvname,lpdrv->drvname,drvnamesize-4); + drvname[drvnamesize-4] = '.'; + drvname[drvnamesize-3] = '.'; + drvname[drvnamesize-2] = '.'; + drvname[drvnamesize-1] = 0; + } + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!dllpath) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) { + strcpy(dllpath,lpdrv->dllpath); + return 0; + } + dllpath[0] = 0; + return DRVERR_INVALID_PARAM; + } + return DRVERR_DEVICE_NOT_FOUND; +} + +LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid) +{ + LPASIODRVSTRUCT lpdrv = 0; + + if (!clsid) return DRVERR_INVALID_PARAM; + + if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) { + memcpy(clsid,&lpdrv->clsid,sizeof(CLSID)); + return 0; + } + return DRVERR_DEVICE_NOT_FOUND; +} + + diff --git a/src/hostapi/asio/ASIOSDK/host/pc/asiolist.h b/src/hostapi/asio/ASIOSDK/host/pc/asiolist.h new file mode 100644 index 0000000..1f504af --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/pc/asiolist.h @@ -0,0 +1,46 @@ +#ifndef __asiolist__ +#define __asiolist__ + +#define DRVERR -5000 +#define DRVERR_INVALID_PARAM DRVERR-1 +#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2 +#define DRVERR_DEVICE_NOT_FOUND DRVERR-3 + +#define MAXPATHLEN 512 +#define MAXDRVNAMELEN 128 + +struct asiodrvstruct +{ + int drvID; + CLSID clsid; + char dllpath[MAXPATHLEN]; + char drvname[MAXDRVNAMELEN]; + LPVOID asiodrv; + struct asiodrvstruct *next; +}; + +typedef struct asiodrvstruct ASIODRVSTRUCT; +typedef ASIODRVSTRUCT *LPASIODRVSTRUCT; + +class AsioDriverList { +public: + AsioDriverList(); + ~AsioDriverList(); + + LONG asioOpenDriver (int,VOID **); + LONG asioCloseDriver (int); + + // nice to have + LONG asioGetNumDev (VOID); + LONG asioGetDriverName (int,char *,int); + LONG asioGetDriverPath (int,char *,int); + LONG asioGetDriverCLSID (int,CLSID *); + + // or use directly access + LPASIODRVSTRUCT lpdrvlist; + int numdrv; +}; + +typedef class AsioDriverList *LPASIODRIVERLIST; + +#endif diff --git a/src/hostapi/asio/ASIOSDK/host/sample/hostsample.cpp b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.cpp new file mode 100644 index 0000000..16283bc --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.cpp @@ -0,0 +1,526 @@ +// hostsample.cpp : a simple ASIO host example. +// - instantiates the driver +// - get the information from the driver +// - built up some audio channels +// - plays silence for 20 seconds +// - destruct the driver +// Note: This sample cannot work with the "ASIO DirectX Driver" as it does +// not have a valid Application Window handle, which is used as sysRef +// on the Windows platform. + +#include +#include +#include "asiosys.h" +#include "asio.h" +#include "asiodrivers.h" + +// name of the ASIO device to be used +#if WINDOWS +// #define ASIO_DRIVER_NAME "ASIO Multimedia Driver" + #define ASIO_DRIVER_NAME "ASIO Sample" +#elif MAC +// #define ASIO_DRIVER_NAME "Apple Sound Manager" + #define ASIO_DRIVER_NAME "ASIO Sample" +#endif + +#define TEST_RUN_TIME 20.0 // run for 20 seconds + + +enum { + // number of input and outputs supported by the host application + // you can change these to higher or lower values + kMaxInputChannels = 32, + kMaxOutputChannels = 32 +}; + + +// internal data storage +typedef struct DriverInfo +{ + // ASIOInit() + ASIODriverInfo driverInfo; + + // ASIOGetChannels() + long inputChannels; + long outputChannels; + + // ASIOGetBufferSize() + long minSize; + long maxSize; + long preferredSize; + long granularity; + + // ASIOGetSampleRate() + ASIOSampleRate sampleRate; + + // ASIOOutputReady() + bool postOutput; + + // ASIOGetLatencies () + long inputLatency; + long outputLatency; + + // ASIOCreateBuffers () + long inputBuffers; // becomes number of actual created input buffers + long outputBuffers; // becomes number of actual created output buffers + ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's + + // ASIOGetChannelInfo() + ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's + // The above two arrays share the same indexing, as the data in them are linked together + + // Information from ASIOGetSamplePosition() + // data is converted to double floats for easier use, however 64 bit integer can be used, too + double nanoSeconds; + double samples; + double tcSamples; // time code samples + + // bufferSwitchTimeInfo() + ASIOTime tInfo; // time info state + unsigned long sysRefTime; // system reference time, when bufferSwitch() was called + + // Signal the end of processing in this example + bool stopped; +} DriverInfo; + + +DriverInfo asioDriverInfo = {0}; +ASIOCallbacks asioCallbacks; + +//---------------------------------------------------------------------------------- +// some external references +extern AsioDrivers* asioDrivers; +bool loadAsioDriver(char *name); + +// internal prototypes (required for the Metrowerks CodeWarrior compiler) +int main(int argc, char* argv[]); +long init_asio_static_data (DriverInfo *asioDriverInfo); +ASIOError create_asio_buffers (DriverInfo *asioDriverInfo); +unsigned long get_sys_reference_time(); + + +// callback prototypes +void bufferSwitch(long index, ASIOBool processNow); +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow); +void sampleRateChanged(ASIOSampleRate sRate); +long asioMessages(long selector, long value, void* message, double* opt); + + + +//---------------------------------------------------------------------------------- +long init_asio_static_data (DriverInfo *asioDriverInfo) +{ // collect the informational data of the driver + // get the number of available channels + if(ASIOGetChannels(&asioDriverInfo->inputChannels, &asioDriverInfo->outputChannels) == ASE_OK) + { + printf ("ASIOGetChannels (inputs: %d, outputs: %d);\n", asioDriverInfo->inputChannels, asioDriverInfo->outputChannels); + + // get the usable buffer sizes + if(ASIOGetBufferSize(&asioDriverInfo->minSize, &asioDriverInfo->maxSize, &asioDriverInfo->preferredSize, &asioDriverInfo->granularity) == ASE_OK) + { + printf ("ASIOGetBufferSize (min: %d, max: %d, preferred: %d, granularity: %d);\n", + asioDriverInfo->minSize, asioDriverInfo->maxSize, + asioDriverInfo->preferredSize, asioDriverInfo->granularity); + + // get the currently selected sample rate + if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK) + { + printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate); + if (asioDriverInfo->sampleRate <= 0.0 || asioDriverInfo->sampleRate > 96000.0) + { + // Driver does not store it's internal sample rate, so set it to a know one. + // Usually you should check beforehand, that the selected sample rate is valid + // with ASIOCanSampleRate(). + if(ASIOSetSampleRate(44100.0) == ASE_OK) + { + if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK) + printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate); + else + return -6; + } + else + return -5; + } + + // check wether the driver requires the ASIOOutputReady() optimization + // (can be used by the driver to reduce output latency by one block) + if(ASIOOutputReady() == ASE_OK) + asioDriverInfo->postOutput = true; + else + asioDriverInfo->postOutput = false; + printf ("ASIOOutputReady(); - %s\n", asioDriverInfo->postOutput ? "Supported" : "Not supported"); + + return 0; + } + return -3; + } + return -2; + } + return -1; +} + + +//---------------------------------------------------------------------------------- +// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float +#if NATIVE_INT64 + #define ASIO64toDouble(a) (a) +#else + const double twoRaisedTo32 = 4294967296.; + #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32) +#endif + +ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) +{ // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that you take care + // about thread synchronization. This is omitted here for simplicity. + static long processedSamples = 0; + + // store the timeInfo for later use + asioDriverInfo.tInfo = *timeInfo; + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + if (timeInfo->timeInfo.flags & kSystemTimeValid) + asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime); + else + asioDriverInfo.nanoSeconds = 0; + + if (timeInfo->timeInfo.flags & kSamplePositionValid) + asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition); + else + asioDriverInfo.samples = 0; + + if (timeInfo->timeCode.flags & kTcValid) + asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples); + else + asioDriverInfo.tcSamples = 0; + + // get the system reference time + asioDriverInfo.sysRefTime = get_sys_reference_time(); + +#if WINDOWS && _DEBUG + // a few debug messages for the Windows device driver developer + // tells you the time when driver got its interrupt and the delay until the app receives + // the event notification. + static double last_samples = 0; + char tmp[128]; + sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples)); + OutputDebugString (tmp); + last_samples = asioDriverInfo.samples; +#endif + + // buffer size in samples + long buffSize = asioDriverInfo.preferredSize; + + // perform the processing + for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++) + { + if (asioDriverInfo.bufferInfos[i].isInput == false) + { + // OK do processing for the outputs only + switch (asioDriverInfo.channelInfos[i].type) + { + case ASIOSTInt16LSB: + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2); + break; + case ASIOSTInt24LSB: // used for 20 bits as well + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3); + break; + case ASIOSTInt32LSB: + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8); + break; + + // 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 + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + + case ASIOSTInt16MSB: + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2); + break; + case ASIOSTInt24MSB: // used for 20 bits as well + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3); + break; + case ASIOSTInt32MSB: + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8); + break; + + // 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 + memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4); + break; + } + } + } + + // finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place + if (asioDriverInfo.postOutput) + ASIOOutputReady(); + + if (processedSamples >= asioDriverInfo.sampleRate * TEST_RUN_TIME) // roughly measured + asioDriverInfo.stopped = true; + else + processedSamples += buffSize; + + return 0L; +} + +//---------------------------------------------------------------------------------- +void bufferSwitch(long index, ASIOBool processNow) +{ // the actual processing callback. + // Beware that this is normally in a seperate thread, hence be sure that you take care + // about thread synchronization. This is omitted here for simplicity. + + // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created + // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags + ASIOTime timeInfo; + memset (&timeInfo, 0, sizeof (timeInfo)); + + // get the time stamp of the buffer, not necessary if no + // synchronization to other media is required + if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK) + timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid; + + bufferSwitchTimeInfo (&timeInfo, index, processNow); +} + + +//---------------------------------------------------------------------------------- +void sampleRateChanged(ASIOSampleRate sRate) +{ + // do whatever you need to do if the sample rate changed + // usually this only happens during external sync. + // Audio processing is not stopped by the driver, actual sample rate + // might not have even changed, maybe only the sample rate status of an + // AES/EBU or S/PDIF digital input at the audio device. + // You might have to update time/sample related conversion routines, etc. +} + +//---------------------------------------------------------------------------------- +long asioMessages(long selector, long value, void* message, double* opt) +{ + // currently the parameters "value", "message" and "opt" are not used. + long ret = 0; + switch(selector) + { + case kAsioSelectorSupported: + if(value == kAsioResetRequest + || value == kAsioEngineVersion + || value == kAsioResyncRequest + || value == kAsioLatenciesChanged + // the following three were added for ASIO 2.0, you don't necessarily have to support them + || value == kAsioSupportsTimeInfo + || value == kAsioSupportsTimeCode + || value == kAsioSupportsInputMonitor) + ret = 1L; + break; + case kAsioResetRequest: + // defer the task and perform the reset of the driver during the next "safe" situation + // You cannot reset the driver right now, as this code is called from the driver. + // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction + // Afterwards you initialize the driver again. + asioDriverInfo.stopped; // In this sample the processing will just stop + ret = 1L; + break; + case kAsioResyncRequest: + // This informs the application, that the driver encountered some non fatal data loss. + // It is used for synchronization purposes of different media. + // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the + // Windows Multimedia system, which could loose data because the Mutex was hold too long + // by another thread. + // However a driver can issue it in other situations, too. + ret = 1L; + break; + case kAsioLatenciesChanged: + // This will inform the host application that the drivers were latencies changed. + // Beware, it this does not mean that the buffer sizes have changed! + // You might need to update internal delay data. + ret = 1L; + break; + case kAsioEngineVersion: + // return the supported ASIO version of the host application + // If a host applications does not implement this selector, ASIO 1.0 is assumed + // by the driver + ret = 2L; + break; + case kAsioSupportsTimeInfo: + // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback + // is supported. + // For compatibility with ASIO 1.0 drivers the host application should always support + // the "old" bufferSwitch method, too. + ret = 1; + break; + case kAsioSupportsTimeCode: + // informs the driver wether application is interested in time code info. + // If an application does not need to know about time code, the driver has less work + // to do. + ret = 0; + break; + } + return ret; +} + + +//---------------------------------------------------------------------------------- +ASIOError create_asio_buffers (DriverInfo *asioDriverInfo) +{ // create buffers for all inputs and outputs of the card with the + // preferredSize from ASIOGetBufferSize() as buffer size + long i; + ASIOError result; + + // fill the bufferInfos from the start without a gap + ASIOBufferInfo *info = asioDriverInfo->bufferInfos; + + // prepare inputs (Though this is not necessaily required, no opened inputs will work, too + if (asioDriverInfo->inputChannels > kMaxInputChannels) + asioDriverInfo->inputBuffers = kMaxInputChannels; + else + asioDriverInfo->inputBuffers = asioDriverInfo->inputChannels; + for(i = 0; i < asioDriverInfo->inputBuffers; i++, info++) + { + info->isInput = ASIOTrue; + info->channelNum = i; + info->buffers[0] = info->buffers[1] = 0; + } + + // prepare outputs + if (asioDriverInfo->outputChannels > kMaxOutputChannels) + asioDriverInfo->outputBuffers = kMaxOutputChannels; + else + asioDriverInfo->outputBuffers = asioDriverInfo->outputChannels; + for(i = 0; i < asioDriverInfo->outputBuffers; i++, info++) + { + info->isInput = ASIOFalse; + info->channelNum = i; + info->buffers[0] = info->buffers[1] = 0; + } + + // create and activate buffers + result = ASIOCreateBuffers(asioDriverInfo->bufferInfos, + asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers, + asioDriverInfo->preferredSize, &asioCallbacks); + if (result == ASE_OK) + { + // now get all the buffer details, sample word length, name, word clock group and activation + for (i = 0; i < asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers; i++) + { + asioDriverInfo->channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum; + asioDriverInfo->channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput; + result = ASIOGetChannelInfo(&asioDriverInfo->channelInfos[i]); + if (result != ASE_OK) + break; + } + + if (result == ASE_OK) + { + // get the input and output latencies + // Latencies often are only valid after ASIOCreateBuffers() + // (input latency is the age of the first sample in the currently returned audio block) + // (output latency is the time the first sample in the currently returned audio block requires to get to the output) + result = ASIOGetLatencies(&asioDriverInfo->inputLatency, &asioDriverInfo->outputLatency); + if (result == ASE_OK) + printf ("ASIOGetLatencies (input: %d, output: %d);\n", asioDriverInfo->inputLatency, asioDriverInfo->outputLatency); + } + } + return result; +} + +int main(int argc, char* argv[]) +{ + // load the driver, this will setup all the necessary internal data structures + if (loadAsioDriver (ASIO_DRIVER_NAME)) + { + // initialize the driver + if (ASIOInit (&asioDriverInfo.driverInfo) == ASE_OK) + { + printf ("asioVersion: %d\n" + "driverVersion: %d\n" + "Name: %s\n" + "ErrorMessage: %s\n", + asioDriverInfo.driverInfo.asioVersion, asioDriverInfo.driverInfo.driverVersion, + asioDriverInfo.driverInfo.name, asioDriverInfo.driverInfo.errorMessage); + if (init_asio_static_data (&asioDriverInfo) == 0) + { + // ASIOControlPanel(); you might want to check wether the ASIOControlPanel() can open + + // set up the asioCallback structure and create the ASIO data buffer + asioCallbacks.bufferSwitch = &bufferSwitch; + asioCallbacks.sampleRateDidChange = &sampleRateChanged; + asioCallbacks.asioMessage = &asioMessages; + asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo; + if (create_asio_buffers (&asioDriverInfo) == ASE_OK) + { + if (ASIOStart() == ASE_OK) + { + // Now all is up and running + fprintf (stdout, "\nASIO Driver started succefully.\n\n"); + while (!asioDriverInfo.stopped) + { +#if WINDOWS + Sleep(100); // goto sleep for 100 milliseconds +#elif MAC + unsigned long dummy; + Delay (6, &dummy); +#endif + fprintf (stdout, "%d ms / %d ms / %d samples", asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)asioDriverInfo.samples); + + // create a more readable time code format (the quick and dirty way) + double remainder = asioDriverInfo.tcSamples; + long hours = (long)(remainder / (asioDriverInfo.sampleRate * 3600)); + remainder -= hours * asioDriverInfo.sampleRate * 3600; + long minutes = (long)(remainder / (asioDriverInfo.sampleRate * 60)); + remainder -= minutes * asioDriverInfo.sampleRate * 60; + long seconds = (long)(remainder / asioDriverInfo.sampleRate); + remainder -= seconds * asioDriverInfo.sampleRate; + fprintf (stdout, " / TC: %2.2d:%2.2d:%2.2d:%5.5d", (long)hours, (long)minutes, (long)seconds, (long)remainder); + + fprintf (stdout, " \r"); + #if !MAC + fflush (stdout); + #endif + } + ASIOStop(); + } + ASIODisposeBuffers(); + } + } + ASIOExit(); + } + asioDrivers->removeCurrentDriver(); + } + return 0; +} + + +unsigned long get_sys_reference_time() +{ // get the system 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 +} diff --git a/src/hostapi/asio/ASIOSDK/host/sample/hostsample.dsp b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.dsp new file mode 100644 index 0000000..1c38f06 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.dsp @@ -0,0 +1,134 @@ +# Microsoft Developer Studio Project File - Name="hostsample" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=hostsample - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "hostsample.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "hostsample.mak" CFG="hostsample - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "hostsample - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "hostsample - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "hostsample - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "../../common" /I "../../host" /I "../../host/pc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x809 /d "NDEBUG" +# ADD RSC /l 0x809 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "hostsample - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../common" /I "../../host" /I "../../host/pc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x809 /d "_DEBUG" +# ADD RSC /l 0x809 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "hostsample - Win32 Release" +# Name "hostsample - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\common\asio.cpp +# End Source File +# Begin Source File + +SOURCE=..\asiodrivers.cpp +# End Source File +# Begin Source File + +SOURCE=..\pc\asiolist.cpp +# End Source File +# Begin Source File + +SOURCE=.\hostsample.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\common\asio.h +# End Source File +# Begin Source File + +SOURCE=..\asiodrivers.h +# End Source File +# Begin Source File + +SOURCE=..\pc\asiolist.h +# End Source File +# Begin Source File + +SOURCE=..\ginclude.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project diff --git a/src/hostapi/asio/ASIOSDK/host/sample/hostsample.vcproj b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.vcproj new file mode 100644 index 0000000..130fc5c --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/host/sample/hostsample.vcproj @@ -0,0 +1,571 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/hostapi/asio/ASIOSDK/readme.txt b/src/hostapi/asio/ASIOSDK/readme.txt new file mode 100644 index 0000000..35f62e6 --- /dev/null +++ b/src/hostapi/asio/ASIOSDK/readme.txt @@ -0,0 +1,55 @@ +ASIO 2.3 SDK Contents +--------------------- + +readme.txt - this file +changes.txt - contains change information between + SDK releases +ASIO SDK 2.3.pdf - ASIO SDK 2.3 specification +Steinberg ASIO Licensing Agreement.pdf - Licencing Agreement + +common: +asio.h - ASIO C definition +iasiodrv.h - interface definition for the ASIO driver class +asio.cpp - asio host interface (not used on Mac) +asiodrvr.h +asiodrvr.cpp - ASIO driver class base definition +combase.h +combase.cpp - COM base definitions (PC only) +dllentry.cpp - DLL functions (PC only) +register.cpp - driver self registration functionality +wxdebug.h +debugmessage.cpp - some debugging help + +host: +asiodrivers.h +asiodrivers.cpp - ASIO driver managment (enumeration and instantiation) +ASIOConvertSamples.h +ASIOConvertSamples.cpp - sample data format conversion class +ginclude.h - platform specific definitions + +host/mac: +asioshlib.cpp - asio.cpp for the Mac, resolves the symbols +codefragments.hpp +codefragments.cpp - code fragment loader + +host/pc: +asiolist.h +asiolist.cpp - instantiates an ASIO driver via the COM model + +host/sample: +hostsample.cpp - a simple console app which shows ASIO hosting +hostsample.dsp - MSVC++ 5.0 project +hostsample.vcproj - Visual Studio 2005 project (32 and 64 bit targets) + +driver/asiosample: +asiosmpl.h +asiosmpl.cpp - ASIO 2.0 sample driver +wintimer.cpp - bufferSwitch() wakeup thread (Windows) +asiosample.def - Windows DLL module export definition +mactimer.cpp - bufferSwitch() wakeup thread (Macintosh) +macnanosecs.cpp - Macintosh system reference time +makesamp.cpp - Macintosh driver object instantiation + +driver/asiosample/asiosample: +asiosample.dsp - MSVC++ 5.0 project +asiosample.vcproj - Visual Studio 2005 project (32 and 64 bit targets) diff --git a/src/hostapi/asio/asiosdk2.3.zip b/src/hostapi/asio/asiosdk2.3.zip new file mode 100644 index 0000000..fc513a0 Binary files /dev/null and b/src/hostapi/asio/asiosdk2.3.zip differ