📄 pa_asio.cpp
字号:
dev->sampleRates = sampleRates;
dev->numSampleRates = 0;
/* Loop through the possible sampling rates and check each to see if the device supports it. */
for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) {
if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) {
DBUG(("PaASIO_QueryDeviceInfo: possible sample rate = %d\n", (long)possibleSampleRates[index]));
dev->numSampleRates += 1;
*sampleRates = possibleSampleRates[index];
sampleRates++;
}
}
/* We assume that all channels have the same SampleType, so check the first */
channelInfos.channel = 0;
channelInfos.isInput = 1;
if ((asioError = ASIOGetChannelInfo(&channelInfos)) == ASE_NotPresent) {
DBUG(("PaASIO_QueryDeviceInfo: ASIOGetChannelInfo returned %d \n",asioError));
}
dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type);
/* unload the driver */
if ((asioError = ASIOExit()) != ASE_OK) {
DBUG(("PaASIO_QueryDeviceInfo: ASIOExit returned %d \n",asioError));
}
sNumDevices++;
}
}
}
}
/* free only unused names */
for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) if (names[i]) PaHost_FreeFastMemory(names[i],32);
return paNoError;
}
//----------------------------------------------------------------------------------
// TAKEN FROM THE ASIO SDK:
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.
}
//----------------------------------------------------------------------------------
// TAKEN FROM THE ASIO SDK:
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 kAsioBufferSizeChange:
//printf("kAsioBufferSizeChange \n");
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;
//printf("kAsioLatenciesChanged \n");
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;
}
//----------------------------------------------------------------------------------
// 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
static 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.
// 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 0
// 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
// To avoid the callback accessing a desallocated stream
if (asioDriverInfo.past == NULL) return 0L;
// Keep sample position
asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
// Reentrancy control
if( ++asioDriverInfo.reenterCount) {
asioDriverInfo.reenterError++;
DBUG(("bufferSwitchTimeInfo : reentrancy detection = %d\n", asioDriverInfo.reenterError));
return 0L;
}
do {
/* Has a user callback returned '1' to indicate finished at the last ASIO callback? */
if( asioDriverInfo.past->past_StopSoon ) {
Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
asioDriverInfo.pahsc_channelInfos[0].type,
asioDriverInfo.pahsc_NumInputChannels ,
asioDriverInfo.pahsc_NumOutputChannels,
index,
0,
asioDriverInfo.past_FramesPerHostBuffer);
asioDriverInfo.past->past_IsActive = 0;
// Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
}else {
/* CPU usage */
Pa_StartUsageCalculation(asioDriverInfo.past);
Pa_ASIO_Callback_Input(index);
// Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
Pa_ASIO_Callback_End();
/* CPU usage */
Pa_EndUsageCalculation(asioDriverInfo.past);
}
} while(asioDriverInfo.reenterCount--);
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;
// Call the real callback
bufferSwitchTimeInfo (&timeInfo, index, processNow);
}
//----------------------------------------------------------------------------------
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
}
/*************************************************************
** Calculate 2 LSB dither signal with a triangular distribution.
** Ranged properly for adding to a 32 bit integer prior to >>15.
*/
#define DITHER_BITS (15)
#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -