📄 pa_asio.cpp
字号:
static void Pa_ASIO_Callback_Input(long index);
static void Pa_ASIO_Callback_Output(long index, long framePerBuffer);
static void Pa_ASIO_Callback_End();
static void Pa_ASIO_Clear_User_Buffers();
// Some external references
extern AsioDrivers* asioDrivers ;
bool loadAsioDriver(char *name);
unsigned long get_sys_reference_time();
/************************************************************************************/
/****************** Macro ************************************************************/
/************************************************************************************/
#define SwapLong(v) ((((v)>>24)&0xFF)|(((v)>>8)&0xFF00)|(((v)&0xFF00)<<8)|(((v)&0xFF)<<24)) ;
#define SwapShort(v) ((((v)>>8)&0xFF)|(((v)&0xFF)<<8)) ;
#define ClipShort(v) (((v)<MIN_INT16)?MIN_INT16:(((v)>MAX_INT16)?MAX_INT16:(v)))
#define ClipChar(v) (((v)<MIN_INT8)?MIN_INT8:(((v)>MAX_INT8)?MAX_INT8:(v)))
#define ClipFloat(v) (((v)<-1.0f)?-1.0f:(((v)>1.0f)?1.0f:(v)))
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif
#ifndef max
#define max(a,b) ((a)>=(b)?(a):(b))
#endif
static bool Pa_ASIO_loadAsioDriver(char *name)
{
#ifdef WINDOWS
CoInitialize(0);
#endif
return loadAsioDriver(name);
}
// Utilities for alignement buffer size computation
static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);}
static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);}
// Takes the size of host buffer and user buffer : returns the number of frames needed for buffer adaptation
static int Pa_ASIO_CalcFrameShift (int M, int N)
{
int res = 0;
for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); }
return res;
}
// We have the following relation :
// Pa_ASIO_CalcFrameShift (M,N) + M = Pa_ASIO_CalcFrameShift (N,M) + N
/* ASIO sample type to PortAudio sample type conversion */
static PaSampleFormat Pa_ASIO_Convert_SampleFormat(ASIOSampleType type)
{
switch (type) {
case ASIOSTInt16MSB:
case ASIOSTInt16LSB:
case ASIOSTInt32MSB16:
case ASIOSTInt32LSB16:
return paInt16;
case ASIOSTFloat32MSB:
case ASIOSTFloat32LSB:
case ASIOSTFloat64MSB:
case ASIOSTFloat64LSB:
return paFloat32;
case ASIOSTInt32MSB:
case ASIOSTInt32LSB:
case ASIOSTInt32MSB18:
case ASIOSTInt32MSB20:
case ASIOSTInt32MSB24:
case ASIOSTInt32LSB18:
case ASIOSTInt32LSB20:
case ASIOSTInt32LSB24:
return paInt32;
case ASIOSTInt24MSB:
case ASIOSTInt24LSB:
return paInt24;
default:
return paCustomFormat;
}
}
//--------------------------------------------------------------------------------------------------------------------
static void PaHost_CalcBufferOffset(internalPortAudioStream *past)
{
if (asioDriverInfo.past_FramesPerHostBuffer > past->past_FramesPerUserBuffer){
// Computes the MINIMUM value of null frames shift for the output buffer alignement
asioDriverInfo.pahsc_OutputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
asioDriverInfo.pahsc_InputBufferOffset = 0;
DBUG(("PaHost_CalcBufferOffset : Minimum BufferOffset for Output = %d\n", asioDriverInfo.pahsc_OutputBufferOffset));
}else{
//Computes the MINIMUM value of null frames shift for the input buffer alignement
asioDriverInfo.pahsc_InputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
asioDriverInfo.pahsc_OutputBufferOffset = 0;
DBUG(("PaHost_CalcBufferOffset : Minimum BufferOffset for Input = %d\n", asioDriverInfo.pahsc_InputBufferOffset));
}
}
//--------------------------------------------------------------------------------------------------------------------
/* Allocate ASIO buffers, initialise channels */
static ASIOError Pa_ASIO_CreateBuffers (PaHostSoundControl *asioDriverInfo, long InputChannels,
long OutputChannels, long framesPerBuffer)
{
ASIOError err;
int i;
ASIOBufferInfo *info = asioDriverInfo->bufferInfos;
// Check parameters
if ((InputChannels > kMaxInputChannels) || (OutputChannels > kMaxOutputChannels)) return ASE_InvalidParameter;
for(i = 0; i < InputChannels; i++, info++){
info->isInput = ASIOTrue;
info->channelNum = i;
info->buffers[0] = info->buffers[1] = 0;
}
for(i = 0; i < OutputChannels; i++, info++){
info->isInput = ASIOFalse;
info->channelNum = i;
info->buffers[0] = info->buffers[1] = 0;
}
// Set up the asioCallback structure and create the ASIO data buffer
asioDriverInfo->pahsc_asioCallbacks.bufferSwitch = &bufferSwitch;
asioDriverInfo->pahsc_asioCallbacks.sampleRateDidChange = &sampleRateChanged;
asioDriverInfo->pahsc_asioCallbacks.asioMessage = &asioMessages;
asioDriverInfo->pahsc_asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with inputChannels = %ld \n", InputChannels));
DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with OutputChannels = %ld \n", OutputChannels));
DBUG(("Pa_ASIO_CreateBuffers : ASIOCreateBuffers with size = %ld \n", framesPerBuffer));
err = ASIOCreateBuffers( asioDriverInfo->bufferInfos, InputChannels+OutputChannels,
framesPerBuffer, &asioDriverInfo->pahsc_asioCallbacks);
if (err != ASE_OK) return err;
// Initialise buffers
for (i = 0; i < InputChannels + OutputChannels; i++)
{
asioDriverInfo->pahsc_channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum;
asioDriverInfo->pahsc_channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput;
err = ASIOGetChannelInfo(&asioDriverInfo->pahsc_channelInfos[i]);
if (err != ASE_OK) break;
}
err = ASIOGetLatencies(&asioDriverInfo->pahsc_inputLatency, &asioDriverInfo->pahsc_outputLatency);
DBUG(("Pa_ASIO_CreateBuffers : InputLatency = %ld latency = %ld msec \n",
asioDriverInfo->pahsc_inputLatency,
(long)((asioDriverInfo->pahsc_inputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
DBUG(("Pa_ASIO_CreateBuffers : OuputLatency = %ld latency = %ld msec \n",
asioDriverInfo->pahsc_outputLatency,
(long)((asioDriverInfo->pahsc_outputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
return err;
}
/*
Query ASIO driver info :
First we get all available ASIO drivers located in the ASIO folder,
then try to load each one. For each loaded driver, get all needed informations.
*/
static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad )
{
#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
#define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */
#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
ASIOSampleRate possibleSampleRates[]
= {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0};
ASIOChannelInfo channelInfos;
long InputChannels,OutputChannels;
double *sampleRates;
char* names[PA_MAX_DEVICE_INFO] ;
PaDeviceInfo *dev;
int i;
int numDrivers;
ASIOError asioError;
/* Allocate names */
for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) {
names[i] = (char*)PaHost_AllocateFastMemory(32);
/* check memory */
if(!names[i]) return paInsufficientMemory;
}
/* MUST BE CHECKED : to force fragments loading on Mac */
Pa_ASIO_loadAsioDriver("dummy");
/* Get names of all available ASIO drivers */
asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO);
/* Check all available ASIO drivers */
#if MAC
numDrivers = asioDrivers->getNumFragments();
#elif WINDOWS
numDrivers = asioDrivers->asioGetNumDev();
#endif
DBUG(("PaASIO_QueryDeviceInfo: number of installed drivers = %d\n", numDrivers ));
for (int driver = 0 ; driver < numDrivers ; driver++)
{
#if WINDOWS
asioDriverInfo.pahsc_driverInfo.asioVersion = 2; // FIXME - is this right? PLB
asioDriverInfo.pahsc_driverInfo.sysRef = GetDesktopWindow(); // FIXME - is this right? PLB
#endif
DBUG(("---------------------------------------\n"));
DBUG(("PaASIO_QueryDeviceInfo: Driver name = %s\n", names[driver]));
/* If the driver can be loaded : */
if ( !Pa_ASIO_loadAsioDriver(names[driver]) ){
DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver]));
} else {
DBUG(("PaASIO_QueryDeviceInfo: loadAsioDriver OK\n"));
if((asioError = ASIOInit(&asioDriverInfo.pahsc_driverInfo)) != ASE_OK){
DBUG(("PaASIO_QueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, names[driver]));
}else {
DBUG(("PaASIO_QueryDeviceInfo: ASIOInit OK \n"));
if(ASIOGetChannels(&InputChannels, &OutputChannels) != ASE_OK){
DBUG(("PaASIO_QueryDeviceInfo could not ASIOGetChannels for %s\n", names[driver]));
}else {
DBUG(("PaASIO_QueryDeviceInfo: ASIOGetChannels OK \n"));
/* Gets the name */
dev = &(ipad[sNumDevices].pad_Info);
dev->name = names[driver];
names[driver] = 0;
/* Gets Input and Output channels number */
dev->maxInputChannels = InputChannels;
dev->maxOutputChannels = OutputChannels;
DBUG(("PaASIO_QueryDeviceInfo: InputChannels = %d\n", InputChannels ));
DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels ));
/* Make room in case device supports all rates. */
sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double));
/* check memory */
if (!sampleRates) {
ASIOExit();
return paInsufficientMemory;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -