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
+859
@@ -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);
|
||||
}
|
||||
|
||||
Executable
+62
@@ -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
|
||||
Executable
+186
@@ -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
|
||||
Executable
+41
@@ -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
|
||||
Executable
+38
@@ -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__
|
||||
Executable
+1
File diff suppressed because one or more lines are too long
Executable
+1
File diff suppressed because one or more lines are too long
Executable
+1
@@ -0,0 +1 @@
|
||||
#ifndef __CodeFragments__
|
||||
Executable
+268
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Executable
+46
@@ -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
|
||||
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