Initial import
git-svn-id: http://moon:8086/svn/software/trunk/libsrc/asiosdk2@1 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
Executable
+277
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
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 <string.h>
|
||||
#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 ASIOGetChannelInfoInput(ASIOChannelInfo *info, long idx)
|
||||
{
|
||||
info->isInput = 1;
|
||||
info->isActive = 0;
|
||||
info->type = 0;
|
||||
info->channelGroup = 0;
|
||||
info->channel = idx;
|
||||
return ASIOGetChannelInfo(info);
|
||||
}
|
||||
|
||||
ASIOError ASIOGetChannelInfoOutput(ASIOChannelInfo *info, long idx)
|
||||
{
|
||||
info->isInput = 0;
|
||||
info->isActive = 0;
|
||||
info->type = 0;
|
||||
info->channelGroup = 0;
|
||||
info->channel = idx;
|
||||
return ASIOGetChannelInfo(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
|
||||
|
||||
|
||||
Executable
+957
@@ -0,0 +1,957 @@
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
Steinberg Audio Stream I/O API
|
||||
(c) 1997 - 1999, Steinberg Soft- und Hardware GmbH
|
||||
|
||||
ASIO Interface Specification v 2.0
|
||||
|
||||
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 18 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
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// 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 <value>, 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 <value>, 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, // supports time code reading/writing
|
||||
|
||||
kAsioSupportsInputMonitor, // supports input monitoring
|
||||
|
||||
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 ASIOGetChannelInfoInput(ASIOChannelInfo *info, long idx);
|
||||
ASIOError ASIOGetChannelInfoOutput(ASIOChannelInfo *info, long idx);
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
Executable
+139
@@ -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 <string.h>
|
||||
#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;
|
||||
}
|
||||
Executable
+76
@@ -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 <windows.h>
|
||||
#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
|
||||
Executable
+82
@@ -0,0 +1,82 @@
|
||||
#ifndef __asiosys__
|
||||
#define __asiosys__
|
||||
|
||||
#ifdef WIN32
|
||||
#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
|
||||
Executable
+202
@@ -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 <windows.h>
|
||||
#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<LPUNKNOWN>( static_cast<PNDUNKNOWN>(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<class T> 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);
|
||||
}
|
||||
Executable
+281
@@ -0,0 +1,281 @@
|
||||
//==========================================================================;
|
||||
//
|
||||
// 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);
|
||||
|
||||
|
||||
};
|
||||
|
||||
/* The standard InterlockedXXX functions won't take volatiles */
|
||||
static inline LONG InterlockedIncrement( volatile LONG * plong )
|
||||
{ return InterlockedIncrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG InterlockedDecrement( volatile LONG * plong )
|
||||
{ return InterlockedDecrement( const_cast<LONG*>( plong ) ); }
|
||||
|
||||
static inline LONG InterlockedExchange( volatile LONG * plong, LONG new_value )
|
||||
{ return InterlockedExchange( const_cast<LONG*>( plong ), new_value ); }
|
||||
|
||||
|
||||
/* 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__ */
|
||||
|
||||
|
||||
Executable
+14
@@ -0,0 +1,14 @@
|
||||
#include "asiosys.h"
|
||||
|
||||
#if DEBUG
|
||||
#if MAC
|
||||
#include <TextUtils.h>
|
||||
void DEBUGGERMESSAGE(char *string)
|
||||
{
|
||||
c2pstr(string);
|
||||
DebugStr((unsigned char *)string);
|
||||
}
|
||||
#else
|
||||
#error debugmessage
|
||||
#endif
|
||||
#endif
|
||||
Executable
+323
@@ -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 <windows.h>
|
||||
#include "wxdebug.h"
|
||||
#include "combase.h"
|
||||
#ifdef DEBUG
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Executable
+37
@@ -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;
|
||||
};
|
||||
Executable
+332
@@ -0,0 +1,332 @@
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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_CLASSES_ROOT,szregpath,SZREGSTR_ASIO);
|
||||
}
|
||||
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname>
|
||||
sprintf(szregpath,"%s\\%s",SZREGSTR_SOFTWARE,SZREGSTR_ASIO);
|
||||
createRegPath (HKEY_LOCAL_MACHINE,szregpath,szregname);
|
||||
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname> -> CLSID
|
||||
// HKEY_LOCAL_MACHINE\SOFTWARE\ASIO\<szregname> -> 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;
|
||||
}
|
||||
|
||||
Executable
+326
@@ -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__
|
||||
|
||||
Reference in New Issue
Block a user