Initial import

git-svn-id: http://moon:8086/svn/software/trunk/libsrc/asiosdk2@1 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-07-19 07:44:42 +00:00
commit 562920dd85
83 changed files with 14225 additions and 0 deletions
+859
View File
@@ -0,0 +1,859 @@
#include "ginclude.h"
#include "ASIOConvertSamples.h"
#include <math.h>
#if MAC
#define TRUNCATE 0
#elif ASIO_CPU_X86 || ASIO_CPU_SPARC || ASIO_CPU_MIPS
#define TRUNCATE 1
#undef MAXFLOAT
#define MAXFLOAT 0x7fffff00L
#endif
ASIOConvertSamples::ASIOConvertSamples()
{
}
//-------------------------------------------------------------------------------------------
// mono
void ASIOConvertSamples::convertMono8Unsigned(long *source, char *dest, long frames)
{
unsigned char *c = (unsigned char *)source;
unsigned char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
a -= 0x80U;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono8(long *source, char *dest, long frames)
{
char *c = (char *)source;
char a;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = c[3];
#else
a = c[0];
#endif
c += 4;
*++dest = a;
}
}
void ASIOConvertSamples::convertMono16(long *source, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* s = (char*)source;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = s[3]; // dest big endian, msb first
*d++ = s[2];
s += 4;
}
#else
long l;
source--;
dest--;
while(--frames >= 0)
{
l = *++source;
*++dest = (short)(l >> 16);
}
#endif
}
void ASIOConvertSamples::convertMono24(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3]; // msb
b = s[2];
c = s[1]; // lsb
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = a; // big endian, msb first
*++dest = b;
*++dest = c;
}
}
// small endian
void ASIOConvertSamples::convertMono16SmallEndian(long *source, short *dest, long frames)
{
char *s = (char *)source;
char *d = (char *)dest;
char a, b;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
#else
a = s[0];
b = s[1];
#endif
s += 4;
*++d = b; // dest small endian, lsb first
*++d = a;
}
}
void ASIOConvertSamples::convertMono24SmallEndian(long *source, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *s = (char *)source;
char a, b, c;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = s[3];
b = s[2];
c = s[1];
#else
a = s[0];
b = s[1];
c = s[2];
#endif
s += 4;
*++dest = c; // lsb first
*++dest = b;
*++dest = a;
}
}
//-------------------------------------------------------------------------------------------
// stereo interleaved
void ASIOConvertSamples::convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo8Interleaved(long *left, long *right, char *dest, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dest = a;
*++dest = b;
}
}
void ASIOConvertSamples::convertStereo16Interleaved(long *left, long *right, short *dest, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* d = (char*)dest;
while(--frames >= 0)
{
*d++ = sl[3]; // msb first
*d++ = sl[2];
*d++ = sr[3];
*d++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dest--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dest = (short)(l >> 16);
*++dest = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24Interleaved(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = al;
*++dest = bl;
*++dest = cl;
*++dest = ar;
*++dest = br;
*++dest = cr;
}
}
void ASIOConvertSamples::convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *d = (char *)dest;
char al, bl, ar, br;
d--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++d = bl; // lsb first
*++d = al;
*++d = br;
*++d = ar;
}
}
void ASIOConvertSamples::convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dest--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dest = cl;
*++dest = bl;
*++dest = al;
*++dest = cr;
*++dest = br;
*++dest = ar;
}
}
//-------------------------------------------------------------------------------------------
// stereo split
void ASIOConvertSamples::convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
a -= 0x80U;
b -= 0x80U;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames)
{
unsigned char *cl = (unsigned char *)left;
unsigned char *cr = (unsigned char *)right;
unsigned char a, b;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = cl[3];
b = cr[3];
#else
a = cl[0];
b = cr[0];
#endif
cl += 4;
cr += 4;
*++dLeft = a;
*++dRight = b;
}
}
void ASIOConvertSamples::convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames)
{
#if ASIO_LITTLE_ENDIAN
char* sl = (char*)left;
char* sr = (char*)right;
char* dl = (char*)dLeft;
char* dr = (char*)dRight;
while(--frames >= 0)
{
*dl++ = sl[3]; // msb first
*dl++ = sl[2];
*dr++ = sr[3];
*dr++ = sr[2];
sl += 4;
sr += 4;
}
#else
long l, r;
left--;
right--;
dLeft--;
dRight--;
while(--frames >= 0)
{
l = *++left;
r = *++right;
*++dLeft = (short)(l >> 16);
*++dRight = (short)(r >> 16);
}
#endif
}
void ASIOConvertSamples::convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = al;
*++dLeft = bl;
*++dLeft = cl;
*++dRight = ar;
*++dRight = br;
*++dRight = cr;
}
}
// small endian
void ASIOConvertSamples::convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames)
{
char *sl = (char *)left;
char *sr = (char *)right;
char *dl = (char *)dLeft;
char *dr = (char *)dRight;
char al, bl, ar, br;
dl--;
dr--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
ar = sr[3];
br = sr[2];
#else
al = sl[0];
bl = sl[1];
ar = sr[0];
br = sr[1];
#endif
sl += 4;
sr += 4;
*++dl = bl;
*++dl = al;
*++dr = br;
*++dr = ar;
}
}
void ASIOConvertSamples::convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames)
{
// work with chars in order to prevent misalignments
char *sl = (char *)left;
char *sr = (char *)right;
char al, bl, cl, ar, br, cr;
dLeft--;
dRight--;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
al = sl[3];
bl = sl[2];
cl = sl[1];
ar = sr[3];
br = sr[2];
cr = sr[1];
#else
al = sl[0];
bl = sl[1];
cl = sl[2];
ar = sr[0];
br = sr[1];
cr = sr[2];
#endif
sl += 4;
sr += 4;
*++dLeft = cl;
*++dLeft = bl;
*++dLeft = al;
*++dRight = cr;
*++dRight = br;
*++dRight = ar;
}
}
//------------------------------------------------------------------------------------------
// in place integer conversions
void ASIOConvertSamples::int32msb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32lsb16to16inPlace(long *in, long frames)
{
short *d1 = (short *)in;
short* out = d1;
#if !ASIO_LITTLE_ENDIAN
d1++;
#endif
while(--frames >= 0)
{
*out++ = *d1;
d1 += 2;
}
}
void ASIOConvertSamples::int32msb16shiftedTo16inPlace(long *in, long frames, long shift)
{
short* out = (short*)in;
while(--frames >= 0)
*out++ = (short)(*in++ >> shift);
}
void ASIOConvertSamples::int24msbto16inPlace(unsigned char *in, long frames)
{
short a;
short* out = (short*)in;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (short)in[2];
a <<= 8;
a |= (in[1] & 0xff);
#else
a = (short)in[0];
a <<= 8;
a |= (in[1] & 0xff);
#endif
*out++ = a;
in += 3;
}
}
//-----------------------------------------------------------------------------------------
void ASIOConvertSamples::shift32(void* buffer, long shiftAmount, long targetByteWidth,
bool revertEndian, long sampleFrames)
{
long a;
long frames = sampleFrames;
long* source = (long*)buffer;
if(revertEndian)
{
reverseEndian(buffer, 4, sampleFrames);
revertEndian = false;
}
if(targetByteWidth == 2)
{
short* dest = (short*)buffer;
short* al = (short*)&a;
#if ASIO_LITTLE_ENDIAN
al++;
#endif
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
*dest++ = *al;
}
}
else if(targetByteWidth == 3)
{
char* dest = (char*)buffer;
long* source = (long*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = *source++;
a <<= shiftAmount;
#if ASIO_LITTLE_ENDIAN
dest[0] = aa[1]; // lsb
dest[1] = aa[2];
dest[2] = aa[3]; // msb
#else
dest[0] = aa[0]; // msb
dest[1] = aa[1];
dest[2] = aa[2]; // lsb
#endif
dest += 3;
}
}
else if(targetByteWidth == 4)
{
long* dest = source;
while(--frames >= 0)
*dest++ = *source++ << shiftAmount;
}
}
void ASIOConvertSamples::reverseEndian(void* buffer, long byteWidth, long frames)
{
char* a = (char*)buffer;
char* b = a;
char c;
if(byteWidth == 2)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[1];
a[1] = c;
a += 2;
}
}
else if(byteWidth == 3)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[2];
a[2] = c;
a += 3;
}
}
else if(byteWidth == 4)
{
while(--frames >= 0)
{
c = a[0];
a[0] = a[3];
a[3] = c;
c = a[1];
a[1] = a[2];
a[2] = c;
a += 4;
}
}
}
//-------------------------------------------------------------------------------------------------
void ASIOConvertSamples::int32to16inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
short* out = in;
#if ASIO_LITTLE_ENDIAN
in++;
#endif
while(--frames >= 0)
{
*out++ = *in;
in += 2;
}
}
void ASIOConvertSamples::int24to16inPlace(void* buffer, long frames)
{
char* from = (char*)buffer;
char* to = from;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
to[0] = from[1];
to[1] = from[2];
#else
to[0] = from[0];
to[1] = from[1];
#endif
from += 3;
to += 2;
}
}
void ASIOConvertSamples::int32to24inPlace(void* buffer, long frames)
{
long* in = (long*)buffer;
char* out = (char*)buffer;
long a;
while(--frames >= 0)
{
a = *in++;
a >>= 8; // 32->24
#if ASIO_LITTLE_ENDIAN
out[0] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[2] = (char)a;
#else
out[2] = (char)a; // lsb
a >>= 8;
out[1] = (char)a;
a >>= 8;
out[0] = (char)a;
#endif
out += 3;
}
}
void ASIOConvertSamples::int16to24inPlace(void* buffer, long frames)
{
char* in = (char*)buffer;
char* out = (char*)buffer;
in += frames * 2;
out += frames * 3;
while(--frames >= 0)
{
out -= 3;
in -= 2;
#if ASIO_LITTLE_ENDIAN
out[2] = in[1]; // msb
out[1] = in[0]; // lsb
out[0] = 0;
#else
out[2] = 0;
out[1] = in[1]; // lsb
out[0] = in[0]; // msb
#endif
}
}
void ASIOConvertSamples::int24to32inPlace(void* buffer, long frames)
{
long a, b, c;
char* in = (char*)buffer;
long* out = (long*)buffer;
in += (frames * 3);
out += frames;
while(--frames >= 0)
{
#if ASIO_LITTLE_ENDIAN
a = (long)in[-1]; // msb
b = (long)in[-2];
c = (long)in[-3];
#else
a = (long)in[-3]; // msb
b = (long)in[-2];
c = (long)in[-1];
#endif
a <<= 24;
b <<= 16;
b &= 0x00ff0000;
a |= b;
c <<= 8;
c &= 0x0000ff00;
a |= c;
*--out = a;
in -= 3;
}
}
void ASIOConvertSamples::int16to32inPlace(void* buffer, long frames)
{
short* in = (short*)buffer;
long* out = (long*)buffer;
in += frames;
out += frames;
while(--frames >= 0)
*--out = ((long)(*--in)) << 16;
}
//------------------------------------------------------------------------------------------
// float to int
const double fScaler16 = (double)0x7fffL;
const double fScaler24 = (double)0x7fffffL;
const double fScaler32 = (double)0x7fffffffL;
void ASIOConvertSamples::float32toInt16inPlace(float* buffer, long frames)
{
double sc = fScaler16 + .49999;
short* b = (short*)buffer;
while(--frames >= 0)
*b++ = (short)((double)(*buffer++) * sc);
}
void ASIOConvertSamples::float32toInt24inPlace(float* buffer, long frames)
{
double sc = fScaler24 + .49999;
long a;
char* b = (char*)buffer;
char* aa = (char*)&a;
while(--frames >= 0)
{
a = (long)((double)(*buffer++) * sc);
#if ASIO_LITTLE_ENDIAN
*b++ = aa[3];
*b++ = aa[2];
*b++ = aa[1];
#else
*b++ = aa[1];
*b++ = aa[2];
*b++ = aa[3];
#endif
}
}
void ASIOConvertSamples::float32toInt32inPlace(float* buffer, long frames)
{
double sc = fScaler32 + .49999;
long* b = (long*)buffer;
while(--frames >= 0)
*b++ = (long)((double)(*buffer++) * sc);
}
+62
View File
@@ -0,0 +1,62 @@
#ifndef __ASIOConvertSamples__
#define __ASIOConvertSamples__
class ASIOConvertSamples
{
public:
ASIOConvertSamples();
~ASIOConvertSamples() {}
// format converters, input 32 bit integer
// mono
void convertMono8(long *source, char *dest, long frames);
void convertMono8Unsigned(long *source, char *dest, long frames);
void convertMono16(long *source, short *dest, long frames);
void convertMono16SmallEndian(long *source, short *dest, long frames);
void convertMono24(long *source, char *dest, long frames);
void convertMono24SmallEndian(long *source, char *dest, long frames);
// stereo interleaved
void convertStereo8Interleaved(long *left, long *right, char *dest, long frames);
void convertStereo8InterleavedUnsigned(long *left, long *right, char *dest, long frames);
void convertStereo16Interleaved(long *left, long *right, short *dest, long frames);
void convertStereo16InterleavedSmallEndian(long *left, long *right, short *dest, long frames);
void convertStereo24Interleaved(long *left, long *right, char *dest, long frames);
void convertStereo24InterleavedSmallEndian(long *left, long *right, char *dest, long frames);
// stereo split
void convertStereo8(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo8Unsigned(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo16(long *left, long *right, short *dLeft, short *dRight, long frames);
void convertStereo16SmallEndian(long *left, long *right, short *dLeft, short *dRight, long frames);
void convertStereo24(long *left, long *right, char *dLeft, char *dRight, long frames);
void convertStereo24SmallEndian(long *left, long *right, char *dLeft, char *dRight, long frames);
// integer in place conversions
void int32msb16to16inPlace(long *in, long frames);
void int32lsb16to16inPlace(long *in, long frames);
void int32msb16shiftedTo16inPlace(long *in1, long frames, long shift);
void int24msbto16inPlace(unsigned char *in, long frames);
// integer to integer
void shift32(void* buffer, long shiftAmount, long targetByteWidth,
bool reverseEndian, long frames);
void reverseEndian(void* buffer, long byteWidth, long frames);
void int32to16inPlace(void* buffer, long frames);
void int24to16inPlace(void* buffer, long frames);
void int32to24inPlace(void* buffer, long frames);
void int16to24inPlace(void* buffer, long frames);
void int24to32inPlace(void* buffer, long frames);
void int16to32inPlace(void* buffer, long frames);
// float to integer
void float32toInt16inPlace(float* buffer, long frames);
void float32toInt24inPlace(float* buffer, long frames);
void float32toInt32inPlace(float* buffer, long frames);
};
#endif
+186
View File
@@ -0,0 +1,186 @@
#include <string.h>
#include "asiodrivers.h"
AsioDrivers* asioDrivers = 0;
bool loadAsioDriver(char *name);
bool loadAsioDriver(char *name)
{
if(!asioDrivers)
asioDrivers = new AsioDrivers();
if(asioDrivers)
return asioDrivers->loadDriver(name);
return false;
}
//------------------------------------------------------------------------------------
#if MAC
bool resolveASIO(unsigned long aconnID);
AsioDrivers::AsioDrivers() : CodeFragments("ASIO Drivers", 'AsDr', 'Asio')
{
connID = -1;
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
removeCurrentDriver();
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
if(curIndex >= 0)
return getName(curIndex, name);
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
for(long i = 0; i < getNumFragments() && i < maxDrivers; i++)
getName(i, names[i]);
return getNumFragments() < maxDrivers ? getNumFragments() : maxDrivers;
}
bool AsioDrivers::loadDriver(char *name)
{
char dname[64];
unsigned long newID;
for(long i = 0; i < getNumFragments(); i++)
{
if(getName(i, dname) && !strcmp(name, dname))
{
if(newInstance(i, &newID))
{
if(resolveASIO(newID))
{
if(connID != -1)
removeInstance(curIndex, connID);
curIndex = i;
connID = newID;
return true;
}
}
break;
}
}
return false;
}
void AsioDrivers::removeCurrentDriver()
{
if(connID != -1)
removeInstance(curIndex, connID);
connID = -1;
curIndex = -1;
}
//------------------------------------------------------------------------------------
#elif WINDOWS
#include "iasiodrv.h"
extern IASIO* theAsioDriver;
AsioDrivers::AsioDrivers() : AsioDriverList()
{
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
if(curIndex >= 0)
return asioGetDriverName(curIndex, name, 32) == 0 ? true : false;
name[0] = 0;
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
for(long i = 0; i < asioGetNumDev() && i < maxDrivers; i++)
asioGetDriverName(i, names[i], 32);
return asioGetNumDev() < maxDrivers ? asioGetNumDev() : maxDrivers;
}
bool AsioDrivers::loadDriver(char *name)
{
char dname[64];
char curName[64];
for(long i = 0; i < asioGetNumDev(); i++)
{
if(!asioGetDriverName(i, dname, 32) && !strcmp(name, dname))
{
curName[0] = 0;
getCurrentDriverName(curName); // in case we fail...
removeCurrentDriver();
if(!asioOpenDriver(i, (void **)&theAsioDriver))
{
curIndex = i;
return true;
}
else
{
theAsioDriver = 0;
if(curName[0] && strcmp(dname, curName))
loadDriver(curName); // try restore
}
break;
}
}
return false;
}
void AsioDrivers::removeCurrentDriver()
{
if(curIndex != -1)
asioCloseDriver(curIndex);
curIndex = -1;
}
#elif SGI || BEOS
#include "asiolist.h"
AsioDrivers::AsioDrivers()
: AsioDriverList()
{
curIndex = -1;
}
AsioDrivers::~AsioDrivers()
{
}
bool AsioDrivers::getCurrentDriverName(char *name)
{
return false;
}
long AsioDrivers::getDriverNames(char **names, long maxDrivers)
{
return 0;
}
bool AsioDrivers::loadDriver(char *name)
{
return false;
}
void AsioDrivers::removeCurrentDriver()
{
}
#else
#error implement me
#endif
+41
View File
@@ -0,0 +1,41 @@
#ifndef __AsioDrivers__
#define __AsioDrivers__
#include "ginclude.h"
#if MAC
#include "CodeFragments.hpp"
class AsioDrivers : public CodeFragments
#elif WINDOWS
#include <windows.h>
#include "asiolist.h"
class AsioDrivers : public AsioDriverList
#elif SGI || BEOS
#include "asiolist.h"
class AsioDrivers : public AsioDriverList
#else
#error implement me
#endif
{
public:
AsioDrivers();
~AsioDrivers();
bool getCurrentDriverName(char *name);
long getDriverNames(char **names, long maxDrivers);
bool loadDriver(char *name);
void removeCurrentDriver();
long getCurrentDriverIndex() {return curIndex;}
protected:
unsigned long connID;
long curIndex;
};
#endif
+38
View File
@@ -0,0 +1,38 @@
#ifndef __gInclude__
#define __gInclude__
#if SGI
#undef BEOS
#undef MAC
#undef WINDOWS
//
#define ASIO_BIG_ENDIAN 1
#define ASIO_CPU_MIPS 1
#elif defined WIN32
#undef BEOS
#undef MAC
#undef SGI
#define WINDOWS 1
#define ASIO_LITTLE_ENDIAN 1
#define ASIO_CPU_X86 1
#elif BEOS
#undef MAC
#undef SGI
#undef WINDOWS
#define ASIO_LITTLE_ENDIAN 1
#define ASIO_CPU_X86 1
//
#else
#define MAC 1
#undef BEOS
#undef WINDOWS
#undef SGI
#define ASIO_BIG_ENDIAN 1
#define ASIO_CPU_PPC 1
#endif
// always
#define NATIVE_INT64 0
#define IEEE754_64FLOAT 1
#endif // __gInclude__
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
#ifndef __CodeFragments__
+268
View File
@@ -0,0 +1,268 @@
#include <windows.h>
#include "iasiodrv.h"
#include "asiolist.h"
#define ASIODRV_DESC "description"
#define INPROC_SERVER "InprocServer32"
#define ASIO_PATH "software\\asio"
#define COM_CLSID "clsid"
// ******************************************************************
// Local Functions
// ******************************************************************
static LONG findDrvPath (char *clsidstr,char *dllpath,int dllpathsize)
{
HKEY hkEnum,hksub,hkpath;
char databuf[512];
LONG cr,rc = -1;
DWORD datatype,datasize;
DWORD index;
OFSTRUCT ofs;
HFILE hfile;
BOOL found = FALSE;
CharLowerBuffA(clsidstr,strlen(clsidstr));
if ((cr = RegOpenKeyA(HKEY_CLASSES_ROOT,COM_CLSID,&hkEnum)) == ERROR_SUCCESS) {
index = 0;
while (cr == ERROR_SUCCESS && !found) {
cr = RegEnumKeyA(hkEnum,index++,(LPSTR)databuf,512);
if (cr == ERROR_SUCCESS) {
CharLowerBuffA(databuf,strlen(databuf));
if (!(strcmp(databuf,clsidstr))) {
if ((cr = RegOpenKeyExA(hkEnum,(LPCSTR)databuf,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
if ((cr = RegOpenKeyExA(hksub,(LPCSTR)INPROC_SERVER,0,KEY_READ,&hkpath)) == ERROR_SUCCESS) {
datatype = REG_SZ; datasize = (DWORD)dllpathsize;
cr = RegQueryValueEx(hkpath,0,0,&datatype,(LPBYTE)dllpath,&datasize);
if (cr == ERROR_SUCCESS) {
memset(&ofs,0,sizeof(OFSTRUCT));
ofs.cBytes = sizeof(OFSTRUCT);
hfile = OpenFile(dllpath,&ofs,OF_EXIST);
if (hfile) rc = 0;
}
RegCloseKey(hkpath);
}
RegCloseKey(hksub);
}
found = TRUE; // break out
}
}
}
RegCloseKey(hkEnum);
}
return rc;
}
static LPASIODRVSTRUCT newDrvStruct (HKEY hkey,char *keyname,int drvID,LPASIODRVSTRUCT lpdrv)
{
HKEY hksub;
char databuf[256];
char dllpath[MAXPATHLEN];
WORD wData[100];
CLSID clsid;
DWORD datatype,datasize;
LONG cr,rc;
if (!lpdrv) {
if ((cr = RegOpenKeyExA(hkey,(LPCSTR)keyname,0,KEY_READ,&hksub)) == ERROR_SUCCESS) {
datatype = REG_SZ; datasize = 256;
cr = RegQueryValueExA(hksub,COM_CLSID,0,&datatype,(LPBYTE)databuf,&datasize);
if (cr == ERROR_SUCCESS) {
rc = findDrvPath (databuf,dllpath,MAXPATHLEN);
if (rc == 0) {
lpdrv = new ASIODRVSTRUCT[1];
if (lpdrv) {
memset(lpdrv,0,sizeof(ASIODRVSTRUCT));
lpdrv->drvID = drvID;
MultiByteToWideChar(CP_ACP,0,(LPCSTR)databuf,-1,(LPWSTR)wData,100);
if ((cr = CLSIDFromString((LPOLESTR)wData,(LPCLSID)&clsid)) == S_OK) {
memcpy(&lpdrv->clsid,&clsid,sizeof(CLSID));
}
datatype = REG_SZ; datasize = 256;
cr = RegQueryValueExA(hksub,ASIODRV_DESC,0,&datatype,(LPBYTE)databuf,&datasize);
if (cr == ERROR_SUCCESS) {
strcpy(lpdrv->drvname,databuf);
}
else strcpy(lpdrv->drvname,keyname);
}
}
}
RegCloseKey(hksub);
}
}
else lpdrv->next = newDrvStruct(hkey,keyname,drvID+1,lpdrv->next);
return lpdrv;
}
static void deleteDrvStruct (LPASIODRVSTRUCT lpdrv)
{
IASIO *iasio;
if (lpdrv != 0) {
deleteDrvStruct(lpdrv->next);
if (lpdrv->asiodrv) {
iasio = (IASIO *)lpdrv->asiodrv;
iasio->Release();
}
delete lpdrv;
}
}
static LPASIODRVSTRUCT getDrvStruct (int drvID,LPASIODRVSTRUCT lpdrv)
{
while (lpdrv) {
if (lpdrv->drvID == drvID) return lpdrv;
lpdrv = lpdrv->next;
}
return 0;
}
// ******************************************************************
// ******************************************************************
// AsioDriverList
// ******************************************************************
AsioDriverList::AsioDriverList ()
{
HKEY hkEnum = 0;
char keyname[MAXDRVNAMELEN];
LPASIODRVSTRUCT pdl;
LONG cr;
DWORD index = 0;
BOOL fin = FALSE;
numdrv = 0;
lpdrvlist = 0;
cr = RegOpenKeyA(HKEY_LOCAL_MACHINE,ASIO_PATH,&hkEnum);
while (cr == ERROR_SUCCESS) {
if ((cr = RegEnumKeyA(hkEnum,index++,(LPSTR)keyname,MAXDRVNAMELEN))== ERROR_SUCCESS) {
lpdrvlist = newDrvStruct (hkEnum,keyname,0,lpdrvlist);
}
else fin = TRUE;
}
if (hkEnum) RegCloseKey(hkEnum);
pdl = lpdrvlist;
while (pdl) {
numdrv++;
pdl = pdl->next;
}
if (numdrv) CoInitialize(0); // initialize COM
}
AsioDriverList::~AsioDriverList ()
{
if (numdrv) {
deleteDrvStruct(lpdrvlist);
CoUninitialize();
}
}
LONG AsioDriverList::asioGetNumDev (VOID)
{
return (LONG)numdrv;
}
LONG AsioDriverList::asioOpenDriver (int drvID,LPVOID *asiodrv)
{
LPASIODRVSTRUCT lpdrv = 0;
long rc;
if (!asiodrv) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (!lpdrv->asiodrv) {
rc = CoCreateInstance(lpdrv->clsid,0,CLSCTX_INPROC_SERVER,lpdrv->clsid,asiodrv);
if (rc == S_OK) {
lpdrv->asiodrv = *asiodrv;
return 0;
}
// else if (rc == REGDB_E_CLASSNOTREG)
// strcpy (info->messageText, "Driver not registered in the Registration Database!");
}
else rc = DRVERR_DEVICE_ALREADY_OPEN;
}
else rc = DRVERR_DEVICE_NOT_FOUND;
return rc;
}
LONG AsioDriverList::asioCloseDriver (int drvID)
{
LPASIODRVSTRUCT lpdrv = 0;
IASIO *iasio;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (lpdrv->asiodrv) {
iasio = (IASIO *)lpdrv->asiodrv;
iasio->Release();
lpdrv->asiodrv = 0;
}
}
return 0;
}
LONG AsioDriverList::asioGetDriverName (int drvID,char *drvname,int drvnamesize)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!drvname) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (strlen(lpdrv->drvname) < (unsigned int)drvnamesize) {
strcpy(drvname,lpdrv->drvname);
}
else {
memcpy(drvname,lpdrv->drvname,drvnamesize-4);
drvname[drvnamesize-4] = '.';
drvname[drvnamesize-3] = '.';
drvname[drvnamesize-2] = '.';
drvname[drvnamesize-1] = 0;
}
return 0;
}
return DRVERR_DEVICE_NOT_FOUND;
}
LONG AsioDriverList::asioGetDriverPath (int drvID,char *dllpath,int dllpathsize)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!dllpath) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
if (strlen(lpdrv->dllpath) < (unsigned int)dllpathsize) {
strcpy(dllpath,lpdrv->dllpath);
return 0;
}
dllpath[0] = 0;
return DRVERR_INVALID_PARAM;
}
return DRVERR_DEVICE_NOT_FOUND;
}
LONG AsioDriverList::asioGetDriverCLSID (int drvID,CLSID *clsid)
{
LPASIODRVSTRUCT lpdrv = 0;
if (!clsid) return DRVERR_INVALID_PARAM;
if ((lpdrv = getDrvStruct(drvID,lpdrvlist)) != 0) {
memcpy(clsid,&lpdrv->clsid,sizeof(CLSID));
return 0;
}
return DRVERR_DEVICE_NOT_FOUND;
}
+46
View File
@@ -0,0 +1,46 @@
#ifndef __asiolist__
#define __asiolist__
#define DRVERR -5000
#define DRVERR_INVALID_PARAM DRVERR-1
#define DRVERR_DEVICE_ALREADY_OPEN DRVERR-2
#define DRVERR_DEVICE_NOT_FOUND DRVERR-3
#define MAXPATHLEN 512
#define MAXDRVNAMELEN 128
struct asiodrvstruct
{
int drvID;
CLSID clsid;
char dllpath[MAXPATHLEN];
char drvname[MAXDRVNAMELEN];
LPVOID asiodrv;
struct asiodrvstruct *next;
};
typedef struct asiodrvstruct ASIODRVSTRUCT;
typedef ASIODRVSTRUCT *LPASIODRVSTRUCT;
class AsioDriverList {
public:
AsioDriverList();
~AsioDriverList();
LONG asioOpenDriver (int,VOID **);
LONG asioCloseDriver (int);
// nice to have
LONG asioGetNumDev (VOID);
LONG asioGetDriverName (int,char *,int);
LONG asioGetDriverPath (int,char *,int);
LONG asioGetDriverCLSID (int,CLSID *);
// or use directly access
LPASIODRVSTRUCT lpdrvlist;
int numdrv;
};
typedef class AsioDriverList *LPASIODRIVERLIST;
#endif
BIN
View File
Binary file not shown.
View File
BIN
View File
Binary file not shown.
View File
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
View File
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+526
View File
@@ -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
}
+134
View File
@@ -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
+29
View File
@@ -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>
{{{
}}}
###############################################################################
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+35
View File
@@ -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>
+583
View File
@@ -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
}