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
BIN
Binary file not shown.
Executable
Executable
BIN
Binary file not shown.
Executable
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
+526
@@ -0,0 +1,526 @@
|
||||
// hostsample.cpp : a simple ASIO host example.
|
||||
// - instantiates the driver
|
||||
// - get the information from the driver
|
||||
// - built up some audio channels
|
||||
// - plays silence for 20 seconds
|
||||
// - destruct the driver
|
||||
// Note: This sample cannot work with the "ASIO DirectX Driver" as it does
|
||||
// not have a valid Application Window handle, which is used as sysRef
|
||||
// on the Windows platform.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "asiosys.h"
|
||||
#include "asio.h"
|
||||
#include "asiodrivers.h"
|
||||
|
||||
// name of the ASIO device to be used
|
||||
#if WINDOWS
|
||||
// #define ASIO_DRIVER_NAME "ASIO Multimedia Driver"
|
||||
#define ASIO_DRIVER_NAME "ASIO Sample"
|
||||
#elif MAC
|
||||
// #define ASIO_DRIVER_NAME "Apple Sound Manager"
|
||||
#define ASIO_DRIVER_NAME "ASIO Sample"
|
||||
#endif
|
||||
|
||||
#define TEST_RUN_TIME 20.0 // run for 20 seconds
|
||||
|
||||
|
||||
enum {
|
||||
// number of input and outputs supported by the host application
|
||||
// you can change these to higher or lower values
|
||||
kMaxInputChannels = 32,
|
||||
kMaxOutputChannels = 32
|
||||
};
|
||||
|
||||
|
||||
// internal data storage
|
||||
typedef struct DriverInfo
|
||||
{
|
||||
// ASIOInit()
|
||||
ASIODriverInfo driverInfo;
|
||||
|
||||
// ASIOGetChannels()
|
||||
long inputChannels;
|
||||
long outputChannels;
|
||||
|
||||
// ASIOGetBufferSize()
|
||||
long minSize;
|
||||
long maxSize;
|
||||
long preferredSize;
|
||||
long granularity;
|
||||
|
||||
// ASIOGetSampleRate()
|
||||
ASIOSampleRate sampleRate;
|
||||
|
||||
// ASIOOutputReady()
|
||||
bool postOutput;
|
||||
|
||||
// ASIOGetLatencies ()
|
||||
long inputLatency;
|
||||
long outputLatency;
|
||||
|
||||
// ASIOCreateBuffers ()
|
||||
long inputBuffers; // becomes number of actual created input buffers
|
||||
long outputBuffers; // becomes number of actual created output buffers
|
||||
ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
|
||||
|
||||
// ASIOGetChannelInfo()
|
||||
ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
|
||||
// The above two arrays share the same indexing, as the data in them are linked together
|
||||
|
||||
// Information from ASIOGetSamplePosition()
|
||||
// data is converted to double floats for easier use, however 64 bit integer can be used, too
|
||||
double nanoSeconds;
|
||||
double samples;
|
||||
double tcSamples; // time code samples
|
||||
|
||||
// bufferSwitchTimeInfo()
|
||||
ASIOTime tInfo; // time info state
|
||||
unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
|
||||
|
||||
// Signal the end of processing in this example
|
||||
bool stopped;
|
||||
} DriverInfo;
|
||||
|
||||
|
||||
DriverInfo asioDriverInfo = {0};
|
||||
ASIOCallbacks asioCallbacks;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// some external references
|
||||
extern AsioDrivers* asioDrivers;
|
||||
bool loadAsioDriver(char *name);
|
||||
|
||||
// internal prototypes (required for the Metrowerks CodeWarrior compiler)
|
||||
int main(int argc, char* argv[]);
|
||||
long init_asio_static_data (DriverInfo *asioDriverInfo);
|
||||
ASIOError create_asio_buffers (DriverInfo *asioDriverInfo);
|
||||
unsigned long get_sys_reference_time();
|
||||
|
||||
|
||||
// callback prototypes
|
||||
void bufferSwitch(long index, ASIOBool processNow);
|
||||
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
|
||||
void sampleRateChanged(ASIOSampleRate sRate);
|
||||
long asioMessages(long selector, long value, void* message, double* opt);
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
long init_asio_static_data (DriverInfo *asioDriverInfo)
|
||||
{ // collect the informational data of the driver
|
||||
// get the number of available channels
|
||||
if(ASIOGetChannels(&asioDriverInfo->inputChannels, &asioDriverInfo->outputChannels) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetChannels (inputs: %d, outputs: %d);\n", asioDriverInfo->inputChannels, asioDriverInfo->outputChannels);
|
||||
|
||||
// get the usable buffer sizes
|
||||
if(ASIOGetBufferSize(&asioDriverInfo->minSize, &asioDriverInfo->maxSize, &asioDriverInfo->preferredSize, &asioDriverInfo->granularity) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetBufferSize (min: %d, max: %d, preferred: %d, granularity: %d);\n",
|
||||
asioDriverInfo->minSize, asioDriverInfo->maxSize,
|
||||
asioDriverInfo->preferredSize, asioDriverInfo->granularity);
|
||||
|
||||
// get the currently selected sample rate
|
||||
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
|
||||
if (asioDriverInfo->sampleRate <= 0.0 || asioDriverInfo->sampleRate > 96000.0)
|
||||
{
|
||||
// Driver does not store it's internal sample rate, so set it to a know one.
|
||||
// Usually you should check beforehand, that the selected sample rate is valid
|
||||
// with ASIOCanSampleRate().
|
||||
if(ASIOSetSampleRate(44100.0) == ASE_OK)
|
||||
{
|
||||
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
|
||||
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
|
||||
else
|
||||
return -6;
|
||||
}
|
||||
else
|
||||
return -5;
|
||||
}
|
||||
|
||||
// check wether the driver requires the ASIOOutputReady() optimization
|
||||
// (can be used by the driver to reduce output latency by one block)
|
||||
if(ASIOOutputReady() == ASE_OK)
|
||||
asioDriverInfo->postOutput = true;
|
||||
else
|
||||
asioDriverInfo->postOutput = false;
|
||||
printf ("ASIOOutputReady(); - %s\n", asioDriverInfo->postOutput ? "Supported" : "Not supported");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
|
||||
#if NATIVE_INT64
|
||||
#define ASIO64toDouble(a) (a)
|
||||
#else
|
||||
const double twoRaisedTo32 = 4294967296.;
|
||||
#define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
|
||||
#endif
|
||||
|
||||
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
|
||||
{ // the actual processing callback.
|
||||
// Beware that this is normally in a seperate thread, hence be sure that you take care
|
||||
// about thread synchronization. This is omitted here for simplicity.
|
||||
static processedSamples = 0;
|
||||
|
||||
// store the timeInfo for later use
|
||||
asioDriverInfo.tInfo = *timeInfo;
|
||||
|
||||
// get the time stamp of the buffer, not necessary if no
|
||||
// synchronization to other media is required
|
||||
if (timeInfo->timeInfo.flags & kSystemTimeValid)
|
||||
asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
|
||||
else
|
||||
asioDriverInfo.nanoSeconds = 0;
|
||||
|
||||
if (timeInfo->timeInfo.flags & kSamplePositionValid)
|
||||
asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
|
||||
else
|
||||
asioDriverInfo.samples = 0;
|
||||
|
||||
if (timeInfo->timeCode.flags & kTcValid)
|
||||
asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
|
||||
else
|
||||
asioDriverInfo.tcSamples = 0;
|
||||
|
||||
// get the system reference time
|
||||
asioDriverInfo.sysRefTime = get_sys_reference_time();
|
||||
|
||||
#if WINDOWS && _DEBUG
|
||||
// a few debug messages for the Windows device driver developer
|
||||
// tells you the time when driver got its interrupt and the delay until the app receives
|
||||
// the event notification.
|
||||
static double last_samples = 0;
|
||||
char tmp[128];
|
||||
sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
|
||||
OutputDebugString (tmp);
|
||||
last_samples = asioDriverInfo.samples;
|
||||
#endif
|
||||
|
||||
// buffer size in samples
|
||||
long buffSize = asioDriverInfo.preferredSize;
|
||||
|
||||
// perform the processing
|
||||
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
|
||||
{
|
||||
if (asioDriverInfo.bufferInfos[i].isInput == false)
|
||||
{
|
||||
// OK do processing for the outputs only
|
||||
switch (asioDriverInfo.channelInfos[i].type)
|
||||
{
|
||||
case ASIOSTInt16LSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||
break;
|
||||
case ASIOSTInt24LSB: // used for 20 bits as well
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||
break;
|
||||
case ASIOSTInt32LSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||
break;
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can more easily used with these
|
||||
case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
|
||||
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
|
||||
case ASIOSTInt16MSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||
break;
|
||||
case ASIOSTInt24MSB: // used for 20 bits as well
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||
break;
|
||||
case ASIOSTInt32MSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||
break;
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can more easily used with these
|
||||
case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
|
||||
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
|
||||
if (asioDriverInfo.postOutput)
|
||||
ASIOOutputReady();
|
||||
|
||||
if (processedSamples >= asioDriverInfo.sampleRate * TEST_RUN_TIME) // roughly measured
|
||||
asioDriverInfo.stopped = true;
|
||||
else
|
||||
processedSamples += buffSize;
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void bufferSwitch(long index, ASIOBool processNow)
|
||||
{ // the actual processing callback.
|
||||
// Beware that this is normally in a seperate thread, hence be sure that you take care
|
||||
// about thread synchronization. This is omitted here for simplicity.
|
||||
|
||||
// as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
|
||||
// though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
|
||||
ASIOTime timeInfo;
|
||||
memset (&timeInfo, 0, sizeof (timeInfo));
|
||||
|
||||
// get the time stamp of the buffer, not necessary if no
|
||||
// synchronization to other media is required
|
||||
if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
|
||||
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
|
||||
|
||||
bufferSwitchTimeInfo (&timeInfo, index, processNow);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void sampleRateChanged(ASIOSampleRate sRate)
|
||||
{
|
||||
// do whatever you need to do if the sample rate changed
|
||||
// usually this only happens during external sync.
|
||||
// Audio processing is not stopped by the driver, actual sample rate
|
||||
// might not have even changed, maybe only the sample rate status of an
|
||||
// AES/EBU or S/PDIF digital input at the audio device.
|
||||
// You might have to update time/sample related conversion routines, etc.
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
long asioMessages(long selector, long value, void* message, double* opt)
|
||||
{
|
||||
// currently the parameters "value", "message" and "opt" are not used.
|
||||
long ret = 0;
|
||||
switch(selector)
|
||||
{
|
||||
case kAsioSelectorSupported:
|
||||
if(value == kAsioResetRequest
|
||||
|| value == kAsioEngineVersion
|
||||
|| value == kAsioResyncRequest
|
||||
|| value == kAsioLatenciesChanged
|
||||
// the following three were added for ASIO 2.0, you don't necessarily have to support them
|
||||
|| value == kAsioSupportsTimeInfo
|
||||
|| value == kAsioSupportsTimeCode
|
||||
|| value == kAsioSupportsInputMonitor)
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioResetRequest:
|
||||
// defer the task and perform the reset of the driver during the next "safe" situation
|
||||
// You cannot reset the driver right now, as this code is called from the driver.
|
||||
// Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
|
||||
// Afterwards you initialize the driver again.
|
||||
asioDriverInfo.stopped; // In this sample the processing will just stop
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioResyncRequest:
|
||||
// This informs the application, that the driver encountered some non fatal data loss.
|
||||
// It is used for synchronization purposes of different media.
|
||||
// Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
|
||||
// Windows Multimedia system, which could loose data because the Mutex was hold too long
|
||||
// by another thread.
|
||||
// However a driver can issue it in other situations, too.
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioLatenciesChanged:
|
||||
// This will inform the host application that the drivers were latencies changed.
|
||||
// Beware, it this does not mean that the buffer sizes have changed!
|
||||
// You might need to update internal delay data.
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioEngineVersion:
|
||||
// return the supported ASIO version of the host application
|
||||
// If a host applications does not implement this selector, ASIO 1.0 is assumed
|
||||
// by the driver
|
||||
ret = 2L;
|
||||
break;
|
||||
case kAsioSupportsTimeInfo:
|
||||
// informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
|
||||
// is supported.
|
||||
// For compatibility with ASIO 1.0 drivers the host application should always support
|
||||
// the "old" bufferSwitch method, too.
|
||||
ret = 1;
|
||||
break;
|
||||
case kAsioSupportsTimeCode:
|
||||
// informs the driver wether application is interested in time code info.
|
||||
// If an application does not need to know about time code, the driver has less work
|
||||
// to do.
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
ASIOError create_asio_buffers (DriverInfo *asioDriverInfo)
|
||||
{ // create buffers for all inputs and outputs of the card with the
|
||||
// preferredSize from ASIOGetBufferSize() as buffer size
|
||||
long i;
|
||||
ASIOError result;
|
||||
|
||||
// fill the bufferInfos from the start without a gap
|
||||
ASIOBufferInfo *info = asioDriverInfo->bufferInfos;
|
||||
|
||||
// prepare inputs (Though this is not necessaily required, no opened inputs will work, too
|
||||
if (asioDriverInfo->inputChannels > kMaxInputChannels)
|
||||
asioDriverInfo->inputBuffers = kMaxInputChannels;
|
||||
else
|
||||
asioDriverInfo->inputBuffers = asioDriverInfo->inputChannels;
|
||||
for(i = 0; i < asioDriverInfo->inputBuffers; i++, info++)
|
||||
{
|
||||
info->isInput = ASIOTrue;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
}
|
||||
|
||||
// prepare outputs
|
||||
if (asioDriverInfo->outputChannels > kMaxOutputChannels)
|
||||
asioDriverInfo->outputBuffers = kMaxOutputChannels;
|
||||
else
|
||||
asioDriverInfo->outputBuffers = asioDriverInfo->outputChannels;
|
||||
for(i = 0; i < asioDriverInfo->outputBuffers; i++, info++)
|
||||
{
|
||||
info->isInput = ASIOFalse;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
}
|
||||
|
||||
// create and activate buffers
|
||||
result = ASIOCreateBuffers(asioDriverInfo->bufferInfos,
|
||||
asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers,
|
||||
asioDriverInfo->preferredSize, &asioCallbacks);
|
||||
if (result == ASE_OK)
|
||||
{
|
||||
// now get all the buffer details, sample word length, name, word clock group and activation
|
||||
for (i = 0; i < asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers; i++)
|
||||
{
|
||||
asioDriverInfo->channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum;
|
||||
asioDriverInfo->channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput;
|
||||
result = ASIOGetChannelInfo(&asioDriverInfo->channelInfos[i]);
|
||||
if (result != ASE_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == ASE_OK)
|
||||
{
|
||||
// get the input and output latencies
|
||||
// Latencies often are only valid after ASIOCreateBuffers()
|
||||
// (input latency is the age of the first sample in the currently returned audio block)
|
||||
// (output latency is the time the first sample in the currently returned audio block requires to get to the output)
|
||||
result = ASIOGetLatencies(&asioDriverInfo->inputLatency, &asioDriverInfo->outputLatency);
|
||||
if (result == ASE_OK)
|
||||
printf ("ASIOGetLatencies (input: %d, output: %d);\n", asioDriverInfo->inputLatency, asioDriverInfo->outputLatency);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// load the driver, this will setup all the necessary internal data structures
|
||||
if (loadAsioDriver (ASIO_DRIVER_NAME))
|
||||
{
|
||||
// initialize the driver
|
||||
if (ASIOInit (&asioDriverInfo.driverInfo) == ASE_OK)
|
||||
{
|
||||
printf ("asioVersion: %d\n"
|
||||
"driverVersion: %d\n"
|
||||
"Name: %s\n"
|
||||
"ErrorMessage: %s\n",
|
||||
asioDriverInfo.driverInfo.asioVersion, asioDriverInfo.driverInfo.driverVersion,
|
||||
asioDriverInfo.driverInfo.name, asioDriverInfo.driverInfo.errorMessage);
|
||||
if (init_asio_static_data (&asioDriverInfo) == 0)
|
||||
{
|
||||
// ASIOControlPanel(); you might want to check wether the ASIOControlPanel() can open
|
||||
|
||||
// set up the asioCallback structure and create the ASIO data buffer
|
||||
asioCallbacks.bufferSwitch = &bufferSwitch;
|
||||
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
|
||||
asioCallbacks.asioMessage = &asioMessages;
|
||||
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
|
||||
if (create_asio_buffers (&asioDriverInfo) == ASE_OK)
|
||||
{
|
||||
if (ASIOStart() == ASE_OK)
|
||||
{
|
||||
// Now all is up and running
|
||||
fprintf (stdout, "\nASIO Driver started succefully.\n\n");
|
||||
while (!asioDriverInfo.stopped)
|
||||
{
|
||||
#if WINDOWS
|
||||
Sleep(100); // goto sleep for 100 milliseconds
|
||||
#elif MAC
|
||||
unsigned long dummy;
|
||||
Delay (6, &dummy);
|
||||
#endif
|
||||
fprintf (stdout, "%d ms / %d ms / %d samples", asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)asioDriverInfo.samples);
|
||||
|
||||
// create a more readable time code format (the quick and dirty way)
|
||||
double remainder = asioDriverInfo.tcSamples;
|
||||
long hours = (long)(remainder / (asioDriverInfo.sampleRate * 3600));
|
||||
remainder -= hours * asioDriverInfo.sampleRate * 3600;
|
||||
long minutes = (long)(remainder / (asioDriverInfo.sampleRate * 60));
|
||||
remainder -= minutes * asioDriverInfo.sampleRate * 60;
|
||||
long seconds = (long)(remainder / asioDriverInfo.sampleRate);
|
||||
remainder -= seconds * asioDriverInfo.sampleRate;
|
||||
fprintf (stdout, " / TC: %2.2d:%2.2d:%2.2d:%5.5d", (long)hours, (long)minutes, (long)seconds, (long)remainder);
|
||||
|
||||
fprintf (stdout, " \r");
|
||||
#if !MAC
|
||||
fflush (stdout);
|
||||
#endif
|
||||
}
|
||||
ASIOStop();
|
||||
}
|
||||
ASIODisposeBuffers();
|
||||
}
|
||||
}
|
||||
ASIOExit();
|
||||
}
|
||||
asioDrivers->removeCurrentDriver();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned long get_sys_reference_time()
|
||||
{ // get the system reference time
|
||||
#if WINDOWS
|
||||
return timeGetTime();
|
||||
#elif MAC
|
||||
static const double twoRaisedTo32 = 4294967296.;
|
||||
UnsignedWide ys;
|
||||
Microseconds(&ys);
|
||||
double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
|
||||
return (unsigned long)(r / 1000.);
|
||||
#endif
|
||||
}
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
# Microsoft Developer Studio Project File - Name="hostsample" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** NICHT BEARBEITEN **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Console Application" 0x0103
|
||||
|
||||
CFG=hostsample - Win32 Debug
|
||||
!MESSAGE Dies ist kein gültiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
|
||||
!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und führen Sie den Befehl
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "hostsample.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE Sie können beim Ausführen von NMAKE eine Konfiguration angeben
|
||||
!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "hostsample.mak" CFG="hostsample - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Für die Konfiguration stehen zur Auswahl:
|
||||
!MESSAGE
|
||||
!MESSAGE "hostsample - Win32 Release" (basierend auf "Win32 (x86) Console Application")
|
||||
!MESSAGE "hostsample - Win32 Debug" (basierend auf "Win32 (x86) Console Application")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "hostsample - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
|
||||
# ADD CPP /nologo /W3 /GX /O2 /I "../../common" /I "../../host" /I "../../host/pc" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
|
||||
# ADD BASE RSC /l 0x809 /d "NDEBUG"
|
||||
# ADD RSC /l 0x809 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "hostsample - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Ignore_Export_Lib 0
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
|
||||
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../common" /I "../../host" /I "../../host/pc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE RSC /l 0x809 /d "_DEBUG"
|
||||
# ADD RSC /l 0x809 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "hostsample - Win32 Release"
|
||||
# Name "hostsample - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\common\asio.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\asiodrivers.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\pc\asiolist.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\jahostsample.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\..\common\asio.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\asiodrivers.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\pc\asiolist.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\ginclude.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ReadMe.txt
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
Microsoft Developer Studio Workspace File, Format Version 6.00
|
||||
# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GELÖSCHT WERDEN!
|
||||
|
||||
###############################################################################
|
||||
|
||||
Project: "hostsample"=.\hostsample.dsp - Package Owner=<4>
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<4>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Global:
|
||||
|
||||
Package=<5>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
Package=<3>
|
||||
{{{
|
||||
}}}
|
||||
|
||||
###############################################################################
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
+35
@@ -0,0 +1,35 @@
|
||||
<html>
|
||||
<body>
|
||||
<pre>
|
||||
<h1>Erstellungsprotokoll</h1>
|
||||
<h3>
|
||||
--------------------Konfiguration: hostsample - Win32 Debug--------------------
|
||||
</h3>
|
||||
<h3>Befehlszeilen</h3>
|
||||
Erstellen der temporären Datei "F:\DOCUME~1\jens\LOCALS~1\Temp\RSP1E2.tmp" mit Inhalten
|
||||
[
|
||||
/nologo /MLd /W3 /Gm /GX /ZI /Od /I "../../common" /I "../../host" /I "../../host/pc" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR"Debug/" /Fp"Debug/hostsample.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
|
||||
"E:\home\Develop\SDKs\ASIO\asiosdk2\host\pc\asiolist.cpp"
|
||||
]
|
||||
Creating command line "cl.exe @F:\DOCUME~1\jens\LOCALS~1\Temp\RSP1E2.tmp"
|
||||
Erstellen der temporären Datei "F:\DOCUME~1\jens\LOCALS~1\Temp\RSP1E3.tmp" mit Inhalten
|
||||
[
|
||||
kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib /nologo /subsystem:console /incremental:yes /pdb:"Debug/hostsample.pdb" /debug /machine:I386 /out:"Debug/hostsample.exe" /pdbtype:sept
|
||||
.\Debug\asio.obj
|
||||
.\Debug\asiodrivers.obj
|
||||
.\Debug\asiolist.obj
|
||||
.\Debug\jahostsample.obj
|
||||
]
|
||||
Erstellen der Befehlzeile "link.exe @F:\DOCUME~1\jens\LOCALS~1\Temp\RSP1E3.tmp"
|
||||
<h3>Ausgabefenster</h3>
|
||||
Kompilierung läuft...
|
||||
asiolist.cpp
|
||||
Linker-Vorgang läuft...
|
||||
|
||||
|
||||
|
||||
<h3>Ergebnisse</h3>
|
||||
hostsample.exe - 0 Fehler, 0 Warnung(en)
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+583
@@ -0,0 +1,583 @@
|
||||
// hostsample.cpp : a simple ASIO host example.
|
||||
// - instantiates the driver
|
||||
// - get the information from the driver
|
||||
// - built up some audio channels
|
||||
// - plays silence for 20 seconds
|
||||
// - destruct the driver
|
||||
// Note: This sample cannot work with the "ASIO DirectX Driver" as it does
|
||||
// not have a valid Application Window handle, which is used as sysRef
|
||||
// on the Windows platform.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "asiosys.h"
|
||||
#include "asio.h"
|
||||
#include "asiodrivers.h"
|
||||
#include "iasiodrv.h"
|
||||
|
||||
// name of the ASIO device to be used
|
||||
#if WINDOWS
|
||||
// #define ASIO_DRIVER_NAME "ASIO Multimedia Driver"
|
||||
#define ASIO_DRIVER_NAME "ASIO Sample"
|
||||
#elif MAC
|
||||
// #define ASIO_DRIVER_NAME "Apple Sound Manager"
|
||||
#define ASIO_DRIVER_NAME "ASIO Sample"
|
||||
#endif
|
||||
|
||||
#define TEST_RUN_TIME 60.0 // run for 20 seconds
|
||||
|
||||
|
||||
enum {
|
||||
// number of input and outputs supported by the host application
|
||||
// you can change these to higher or lower values
|
||||
kMaxInputChannels = 32,
|
||||
kMaxOutputChannels = 32
|
||||
};
|
||||
|
||||
|
||||
// internal data storage
|
||||
typedef struct DriverInfo
|
||||
{
|
||||
// ASIOInit()
|
||||
ASIODriverInfo driverInfo;
|
||||
|
||||
// ASIOGetChannels()
|
||||
long inputChannels;
|
||||
long outputChannels;
|
||||
|
||||
// ASIOGetBufferSize()
|
||||
long minSize;
|
||||
long maxSize;
|
||||
long preferredSize;
|
||||
long granularity;
|
||||
|
||||
// ASIOGetSampleRate()
|
||||
ASIOSampleRate sampleRate;
|
||||
|
||||
// ASIOOutputReady()
|
||||
bool postOutput;
|
||||
|
||||
// ASIOGetLatencies ()
|
||||
long inputLatency;
|
||||
long outputLatency;
|
||||
|
||||
// ASIOCreateBuffers ()
|
||||
long inputBuffers; // becomes number of actual created input buffers
|
||||
long outputBuffers; // becomes number of actual created output buffers
|
||||
ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
|
||||
|
||||
// ASIOGetChannelInfo()
|
||||
ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
|
||||
// The above two arrays share the same indexing, as the data in them are linked together
|
||||
|
||||
// Information from ASIOGetSamplePosition()
|
||||
// data is converted to double floats for easier use, however 64 bit integer can be used, too
|
||||
double nanoSeconds;
|
||||
double samples;
|
||||
double tcSamples; // time code samples
|
||||
|
||||
// bufferSwitchTimeInfo()
|
||||
ASIOTime tInfo; // time info state
|
||||
unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
|
||||
|
||||
// Signal the end of processing in this example
|
||||
bool stopped;
|
||||
} DriverInfo;
|
||||
|
||||
|
||||
DriverInfo asioDriverInfo = {0};
|
||||
ASIOCallbacks asioCallbacks;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// some external references
|
||||
extern AsioDrivers* asioDrivers;
|
||||
bool loadAsioDriver(char *name);
|
||||
|
||||
// internal prototypes (required for the Metrowerks CodeWarrior compiler)
|
||||
int main(int argc, char* argv[]);
|
||||
long init_asio_static_data (DriverInfo *asioDriverInfo);
|
||||
ASIOError create_asio_buffers (DriverInfo *asioDriverInfo);
|
||||
unsigned long get_sys_reference_time();
|
||||
|
||||
|
||||
// callback prototypes
|
||||
void bufferSwitch(long index, ASIOBool processNow);
|
||||
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
|
||||
void sampleRateChanged(ASIOSampleRate sRate);
|
||||
long asioMessages(long selector, long value, void* message, double* opt);
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
long init_asio_static_data (DriverInfo *asioDriverInfo)
|
||||
{ // collect the informational data of the driver
|
||||
// get the number of available channels
|
||||
if(ASIOGetChannels(&asioDriverInfo->inputChannels, &asioDriverInfo->outputChannels) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetChannels (inputs: %d, outputs: %d);\n", asioDriverInfo->inputChannels, asioDriverInfo->outputChannels);
|
||||
|
||||
// get the usable buffer sizes
|
||||
if(ASIOGetBufferSize(&asioDriverInfo->minSize, &asioDriverInfo->maxSize, &asioDriverInfo->preferredSize, &asioDriverInfo->granularity) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetBufferSize (min: %d, max: %d, preferred: %d, granularity: %d);\n",
|
||||
asioDriverInfo->minSize, asioDriverInfo->maxSize,
|
||||
asioDriverInfo->preferredSize, asioDriverInfo->granularity);
|
||||
|
||||
// get the currently selected sample rate
|
||||
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
|
||||
{
|
||||
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
|
||||
if (asioDriverInfo->sampleRate <= 0.0 || asioDriverInfo->sampleRate > 96000.0)
|
||||
{
|
||||
// Driver does not store it's internal sample rate, so set it to a know one.
|
||||
// Usually you should check beforehand, that the selected sample rate is valid
|
||||
// with ASIOCanSampleRate().
|
||||
if(ASIOSetSampleRate(44100.0) == ASE_OK)
|
||||
{
|
||||
if(ASIOGetSampleRate(&asioDriverInfo->sampleRate) == ASE_OK)
|
||||
printf ("ASIOGetSampleRate (sampleRate: %f);\n", asioDriverInfo->sampleRate);
|
||||
else
|
||||
return -6;
|
||||
}
|
||||
else
|
||||
return -5;
|
||||
}
|
||||
|
||||
// check wether the driver requires the ASIOOutputReady() optimization
|
||||
// (can be used by the driver to reduce output latency by one block)
|
||||
if(ASIOOutputReady() == ASE_OK)
|
||||
asioDriverInfo->postOutput = true;
|
||||
else
|
||||
asioDriverInfo->postOutput = false;
|
||||
printf ("ASIOOutputReady(); - %s\n", asioDriverInfo->postOutput ? "Supported" : "Not supported");
|
||||
|
||||
return 0;
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
|
||||
#if NATIVE_INT64
|
||||
#define ASIO64toDouble(a) (a)
|
||||
#else
|
||||
const double twoRaisedTo32 = 4294967296.;
|
||||
#define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
|
||||
#endif
|
||||
|
||||
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
|
||||
{ // the actual processing callback.
|
||||
// Beware that this is normally in a seperate thread, hence be sure that you take care
|
||||
// about thread synchronization. This is omitted here for simplicity.
|
||||
static processedSamples = 0;
|
||||
|
||||
// store the timeInfo for later use
|
||||
asioDriverInfo.tInfo = *timeInfo;
|
||||
|
||||
// get the time stamp of the buffer, not necessary if no
|
||||
// synchronization to other media is required
|
||||
if (timeInfo->timeInfo.flags & kSystemTimeValid)
|
||||
asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
|
||||
else
|
||||
asioDriverInfo.nanoSeconds = 0;
|
||||
|
||||
if (timeInfo->timeInfo.flags & kSamplePositionValid)
|
||||
asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
|
||||
else
|
||||
asioDriverInfo.samples = 0;
|
||||
|
||||
if (timeInfo->timeCode.flags & kTcValid)
|
||||
asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
|
||||
else
|
||||
asioDriverInfo.tcSamples = 0;
|
||||
|
||||
// get the system reference time
|
||||
asioDriverInfo.sysRefTime = get_sys_reference_time();
|
||||
|
||||
#if WINDOWS && _DEBUG
|
||||
// a few debug messages for the Windows device driver developer
|
||||
// tells you the time when driver got its interrupt and the delay until the app receives
|
||||
// the event notification.
|
||||
static double last_samples = 0;
|
||||
char tmp[128];
|
||||
sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
|
||||
OutputDebugString (tmp);
|
||||
last_samples = asioDriverInfo.samples;
|
||||
#endif
|
||||
|
||||
// buffer size in samples
|
||||
long buffSize = asioDriverInfo.preferredSize;
|
||||
|
||||
// perform the processing
|
||||
for (int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++)
|
||||
{
|
||||
if (asioDriverInfo.bufferInfos[i].isInput == false)
|
||||
{
|
||||
// OK do processing for the outputs only
|
||||
switch (asioDriverInfo.channelInfos[i].type)
|
||||
{
|
||||
case ASIOSTInt16LSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||
break;
|
||||
case ASIOSTInt24LSB: // used for 20 bits as well
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||
break;
|
||||
case ASIOSTInt32LSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||
break;
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can more easily used with these
|
||||
case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
|
||||
case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
|
||||
case ASIOSTInt16MSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 2);
|
||||
break;
|
||||
case ASIOSTInt24MSB: // used for 20 bits as well
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 3);
|
||||
break;
|
||||
case ASIOSTInt32MSB:
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 8);
|
||||
break;
|
||||
|
||||
// these are used for 32 bit data buffer, with different alignment of the data inside
|
||||
// 32 bit PCI bus systems can more easily used with these
|
||||
case ASIOSTInt32MSB16: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
|
||||
case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
|
||||
case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
|
||||
memset (asioDriverInfo.bufferInfos[i].buffers[index], 0, buffSize * 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
|
||||
if (asioDriverInfo.postOutput)
|
||||
ASIOOutputReady();
|
||||
|
||||
if (processedSamples >= asioDriverInfo.sampleRate * TEST_RUN_TIME) // roughly measured
|
||||
asioDriverInfo.stopped = true;
|
||||
else
|
||||
processedSamples += buffSize;
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void bufferSwitch(long index, ASIOBool processNow)
|
||||
{ // the actual processing callback.
|
||||
// Beware that this is normally in a seperate thread, hence be sure that you take care
|
||||
// about thread synchronization. This is omitted here for simplicity.
|
||||
|
||||
// as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
|
||||
// though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
|
||||
ASIOTime timeInfo;
|
||||
memset (&timeInfo, 0, sizeof (timeInfo));
|
||||
|
||||
// get the time stamp of the buffer, not necessary if no
|
||||
// synchronization to other media is required
|
||||
if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
|
||||
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
|
||||
|
||||
bufferSwitchTimeInfo (&timeInfo, index, processNow);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
void sampleRateChanged(ASIOSampleRate sRate)
|
||||
{
|
||||
// do whatever you need to do if the sample rate changed
|
||||
// usually this only happens during external sync.
|
||||
// Audio processing is not stopped by the driver, actual sample rate
|
||||
// might not have even changed, maybe only the sample rate status of an
|
||||
// AES/EBU or S/PDIF digital input at the audio device.
|
||||
// You might have to update time/sample related conversion routines, etc.
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
long asioMessages(long selector, long value, void* message, double* opt)
|
||||
{
|
||||
// currently the parameters "value", "message" and "opt" are not used.
|
||||
long ret = 0;
|
||||
switch(selector)
|
||||
{
|
||||
case kAsioSelectorSupported:
|
||||
if(value == kAsioResetRequest
|
||||
|| value == kAsioEngineVersion
|
||||
|| value == kAsioResyncRequest
|
||||
|| value == kAsioLatenciesChanged
|
||||
// the following three were added for ASIO 2.0, you don't necessarily have to support them
|
||||
|| value == kAsioSupportsTimeInfo
|
||||
|| value == kAsioSupportsTimeCode
|
||||
|| value == kAsioSupportsInputMonitor)
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioResetRequest:
|
||||
// defer the task and perform the reset of the driver during the next "safe" situation
|
||||
// You cannot reset the driver right now, as this code is called from the driver.
|
||||
// Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
|
||||
// Afterwards you initialize the driver again.
|
||||
asioDriverInfo.stopped; // In this sample the processing will just stop
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioResyncRequest:
|
||||
// This informs the application, that the driver encountered some non fatal data loss.
|
||||
// It is used for synchronization purposes of different media.
|
||||
// Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
|
||||
// Windows Multimedia system, which could loose data because the Mutex was hold too long
|
||||
// by another thread.
|
||||
// However a driver can issue it in other situations, too.
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioLatenciesChanged:
|
||||
// This will inform the host application that the drivers were latencies changed.
|
||||
// Beware, it this does not mean that the buffer sizes have changed!
|
||||
// You might need to update internal delay data.
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioEngineVersion:
|
||||
// return the supported ASIO version of the host application
|
||||
// If a host applications does not implement this selector, ASIO 1.0 is assumed
|
||||
// by the driver
|
||||
ret = 2L;
|
||||
break;
|
||||
case kAsioSupportsTimeInfo:
|
||||
// informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
|
||||
// is supported.
|
||||
// For compatibility with ASIO 1.0 drivers the host application should always support
|
||||
// the "old" bufferSwitch method, too.
|
||||
ret = 1;
|
||||
break;
|
||||
case kAsioSupportsTimeCode:
|
||||
// informs the driver wether application is interested in time code info.
|
||||
// If an application does not need to know about time code, the driver has less work
|
||||
// to do.
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
ASIOError create_asio_buffers (DriverInfo *asioDriverInfo)
|
||||
{ // create buffers for all inputs and outputs of the card with the
|
||||
// preferredSize from ASIOGetBufferSize() as buffer size
|
||||
long i;
|
||||
ASIOError result;
|
||||
|
||||
// fill the bufferInfos from the start without a gap
|
||||
ASIOBufferInfo *info = asioDriverInfo->bufferInfos;
|
||||
|
||||
// prepare inputs (Though this is not necessaily required, no opened inputs will work, too
|
||||
if (asioDriverInfo->inputChannels > kMaxInputChannels)
|
||||
asioDriverInfo->inputBuffers = kMaxInputChannels;
|
||||
else
|
||||
asioDriverInfo->inputBuffers = asioDriverInfo->inputChannels;
|
||||
for(i = 0; i < asioDriverInfo->inputBuffers; i++, info++)
|
||||
{
|
||||
info->isInput = ASIOTrue;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
}
|
||||
|
||||
// prepare outputs
|
||||
if (asioDriverInfo->outputChannels > kMaxOutputChannels)
|
||||
asioDriverInfo->outputBuffers = kMaxOutputChannels;
|
||||
else
|
||||
asioDriverInfo->outputBuffers = asioDriverInfo->outputChannels;
|
||||
for(i = 0; i < asioDriverInfo->outputBuffers; i++, info++)
|
||||
{
|
||||
info->isInput = ASIOFalse;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = 0;
|
||||
}
|
||||
|
||||
// create and activate buffers
|
||||
result = ASIOCreateBuffers(asioDriverInfo->bufferInfos,
|
||||
asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers,
|
||||
asioDriverInfo->preferredSize, &asioCallbacks);
|
||||
if (result == ASE_OK)
|
||||
{
|
||||
// now get all the buffer details, sample word length, name, word clock group and activation
|
||||
for (i = 0; i < asioDriverInfo->inputBuffers + asioDriverInfo->outputBuffers; i++)
|
||||
{
|
||||
asioDriverInfo->channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum;
|
||||
asioDriverInfo->channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput;
|
||||
result = ASIOGetChannelInfo(&asioDriverInfo->channelInfos[i]);
|
||||
if (result != ASE_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == ASE_OK)
|
||||
{
|
||||
// get the input and output latencies
|
||||
// Latencies often are only valid after ASIOCreateBuffers()
|
||||
// (input latency is the age of the first sample in the currently returned audio block)
|
||||
// (output latency is the time the first sample in the currently returned audio block requires to get to the output)
|
||||
result = ASIOGetLatencies(&asioDriverInfo->inputLatency, &asioDriverInfo->outputLatency);
|
||||
if (result == ASE_OK)
|
||||
printf ("ASIOGetLatencies (input: %d, output: %d);\n", asioDriverInfo->inputLatency, asioDriverInfo->outputLatency);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define MAX_DRV_NAME 256
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
AsioDrivers drivers;
|
||||
ASIOChannelInfo *pChannelInfoInput, *pChannelInfoOutput;
|
||||
|
||||
char **ppDriverNames;
|
||||
long numInstalledDrivers, numInputs, numOutputs;
|
||||
|
||||
numInstalledDrivers = drivers.asioGetNumDev();
|
||||
|
||||
ppDriverNames = new char*[numInstalledDrivers];
|
||||
for (int i=0; i < numInstalledDrivers; i++)
|
||||
ppDriverNames[i] = new char[MAX_DRV_NAME];
|
||||
|
||||
drivers.getDriverNames(ppDriverNames, numInstalledDrivers);
|
||||
|
||||
printf("* Available ASIO-Drivers:\n");
|
||||
for (i=0; i < numInstalledDrivers; i++)
|
||||
printf("Driver #%d: %s\n",i+1,ppDriverNames[i]);
|
||||
|
||||
printf("\n");
|
||||
|
||||
|
||||
// load the driver, this will setup all the necessary internal data structures
|
||||
if (loadAsioDriver (ppDriverNames[0]))
|
||||
{
|
||||
// initialize the driver
|
||||
if (ASIOInit (&asioDriverInfo.driverInfo) == ASE_OK)
|
||||
{
|
||||
printf ("asioVersion: %d\n"
|
||||
"driverVersion: %d\n"
|
||||
"Name: %s\n"
|
||||
"ErrorMessage: %s\n",
|
||||
asioDriverInfo.driverInfo.asioVersion, asioDriverInfo.driverInfo.driverVersion,
|
||||
asioDriverInfo.driverInfo.name, asioDriverInfo.driverInfo.errorMessage);
|
||||
|
||||
ASIOGetChannels(&numInputs, &numOutputs);
|
||||
|
||||
pChannelInfoInput = new ASIOChannelInfo[numInputs];
|
||||
pChannelInfoOutput = new ASIOChannelInfo[numOutputs];
|
||||
|
||||
for (i=0; i < numInputs; i++)
|
||||
ASIOGetChannelInfoInput(&pChannelInfoInput[i], i);
|
||||
|
||||
for (i=0; i < numOutputs; i++)
|
||||
ASIOGetChannelInfoOutput(&pChannelInfoOutput[i], i);
|
||||
|
||||
printf("* Input Channels:\n");
|
||||
for (i=0; i < numInputs; i++)
|
||||
{
|
||||
printf("%s\n",pChannelInfoInput[i].name);
|
||||
}
|
||||
|
||||
printf("* Out Channels:\n");
|
||||
for (i=0; i < numOutputs; i++)
|
||||
{
|
||||
printf("%s\n",pChannelInfoOutput[i].name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (init_asio_static_data (&asioDriverInfo) == 0)
|
||||
{
|
||||
// ASIOControlPanel(); you might want to check wether the ASIOControlPanel() can open
|
||||
|
||||
// set up the asioCallback structure and create the ASIO data buffer
|
||||
asioCallbacks.bufferSwitch = &bufferSwitch;
|
||||
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
|
||||
asioCallbacks.asioMessage = &asioMessages;
|
||||
asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
|
||||
if (create_asio_buffers (&asioDriverInfo) == ASE_OK)
|
||||
{
|
||||
if (ASIOStart() == ASE_OK)
|
||||
{
|
||||
// Now all is up and running
|
||||
fprintf (stdout, "\nASIO Driver started succefully.\n\n");
|
||||
while (!asioDriverInfo.stopped)
|
||||
{
|
||||
#if WINDOWS
|
||||
Sleep(100); // goto sleep for 100 milliseconds
|
||||
#elif MAC
|
||||
unsigned long dummy;
|
||||
Delay (6, &dummy);
|
||||
#endif
|
||||
fprintf (stdout, "%d ms / %d ms / %d samples", asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)asioDriverInfo.samples);
|
||||
|
||||
// create a more readable time code format (the quick and dirty way)
|
||||
double remainder = asioDriverInfo.tcSamples;
|
||||
long hours = (long)(remainder / (asioDriverInfo.sampleRate * 3600));
|
||||
remainder -= hours * asioDriverInfo.sampleRate * 3600;
|
||||
long minutes = (long)(remainder / (asioDriverInfo.sampleRate * 60));
|
||||
remainder -= minutes * asioDriverInfo.sampleRate * 60;
|
||||
long seconds = (long)(remainder / asioDriverInfo.sampleRate);
|
||||
remainder -= seconds * asioDriverInfo.sampleRate;
|
||||
fprintf (stdout, " / TC: %2.2d:%2.2d:%2.2d:%5.5d", (long)hours, (long)minutes, (long)seconds, (long)remainder);
|
||||
|
||||
fprintf (stdout, " \r");
|
||||
#if !MAC
|
||||
fflush (stdout);
|
||||
#endif
|
||||
// asioDriverInfo.
|
||||
}
|
||||
ASIOStop();
|
||||
}
|
||||
ASIODisposeBuffers();
|
||||
}
|
||||
}
|
||||
ASIOExit();
|
||||
}
|
||||
asioDrivers->removeCurrentDriver();
|
||||
|
||||
for (int i=0; i < numInstalledDrivers; i++)
|
||||
delete [] ppDriverNames[i];
|
||||
|
||||
delete ppDriverNames;
|
||||
delete [] pChannelInfoInput;
|
||||
delete [] pChannelInfoOutput;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
unsigned long get_sys_reference_time()
|
||||
{ // get the system reference time
|
||||
#if WINDOWS
|
||||
return timeGetTime();
|
||||
#elif MAC
|
||||
static const double twoRaisedTo32 = 4294967296.;
|
||||
UnsignedWide ys;
|
||||
Microseconds(&ys);
|
||||
double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
|
||||
return (unsigned long)(r / 1000.);
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user