Commit 11ebc640 authored by Jonas Stienen's avatar Jonas Stienen
Browse files

Improving ITAsio streaming info and including panic watch for dropouts in...

Improving ITAsio streaming info and including panic watch for dropouts in audio output stream (triggers std::cout prints on occurance and a statistics print on ITAsioStop)
parent 516c72f7
......@@ -26,14 +26,16 @@ class ITAStreamInfo
{
public:
uint64_t nSamples; //!< Number of samples processed
double dTimecode; //!< Time code
double dStreamTimeCode; //!< Stream time code (starts with zero)
double dSysTimeCode; //!< System time stamp code (begings with current time stamp of system)
inline ITAStreamInfo()
: nSamples( 0 )
, dTimecode( 0 )
, dStreamTimeCode( 0.0f )
, dSysTimeCode( 0.0f )
{};
virtual ~ITAStreamInfo() {};
inline virtual ~ITAStreamInfo() {};
};
#endif // INCLUDE_WATCHER_ITA_STREAM_INFO
#include <ITAAsioInterface.h>
#include <ITAAtomicPrimitives.h>
#include <ITADatasource.h>
#include <ITAException.h>
#include <ITAStreamInfo.h>
#include <ITADatasource.h>
#include <ITADatasourceRealization.h>
#include <ITAAtomicPrimitives.h>
#include <ITAClock.h>
#include <ITADatasource.h>
#include <ITAException.h>
#include <ITAStopWatch.h>
#include <ITAStringUtils.h>
#include <host/asiodrivers.h>
#include <windows.h>
......@@ -17,17 +21,14 @@
// Puffer-Vielfachheit (Doppelpuffer, Dreifachpuffer, etc.)
const unsigned int ASIOSOURCE_BUFFER_MULTIPLICITY = 16;
class ASIOSource : public ITADatasourceRealization {
class ASIOSource : public ITADatasourceRealization
{
public:
ASIOSource(unsigned int uiChannels,
double dSamplerate,
unsigned int uiBlocklength)
: ITADatasourceRealization(uiChannels,
dSamplerate,
uiBlocklength,
ASIOSOURCE_BUFFER_MULTIPLICITY) {}
friend ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
inline ASIOSource( unsigned int uiChannels, double dSamplerate, unsigned int uiBlocklength )
: ITADatasourceRealization( uiChannels, dSamplerate, uiBlocklength, ASIOSOURCE_BUFFER_MULTIPLICITY )
{};
friend ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool processNow );
};
// WICHTIG: Dieses Makro legt fest, wieviele Blöcke Eingangsdaten nach
......@@ -43,13 +44,14 @@ public:
// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
#if NATIVE_INT64
#define ASIO64toDouble(a) (a)
#define ASIO64toDouble(a) (a)
#else
const double twoRaisedTo32 = 4294967296.;
#define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
const double twoRaisedTo32 = 4294967296.;
#define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
#endif
typedef struct DriverInfo {
typedef struct DriverInfo
{
// Zugehörige ASIO-Treiberinfo (Achtung: Datentyp "ASIODriverInfo")
ASIODriverInfo driverInfo;
......@@ -76,11 +78,11 @@ typedef struct DriverInfo {
// Anzahl der Ein-/Ausgabepuffer
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
// ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
std::vector<ASIOBufferInfo> bufferInfos; // buffer info's
// ASIOGetChannelInfo()
// ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
// ASIOChannelInfo channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
std::vector<ASIOChannelInfo> channelInfos; // channel info's
// The above two arrays share the same indexing, as the data in them are linked together
......@@ -99,42 +101,45 @@ typedef struct DriverInfo {
} DriverInfo;
// Statusflags
const long LIBRAW = -1; // Bibliothek wurde noch nicht initialisiert
const long LOADED = 0; // Bibliothek wurde initialisiert
const long LIBRAW = -1; // Bibliothek wurde noch nicht initialisiert
const long LOADED = 0; // Bibliothek wurde initialisiert
const long INITIALIZED = 1; // ASIO-Treiber wurde initialisiert
const long PREPARED = 2; // ASIO-Streaming wurde vorbereitet
const long RUNNING = 3; // ASIO-Streaming läuft
const long PREPARED = 2; // ASIO-Streaming wurde vorbereitet
const long RUNNING = 3; // ASIO-Streaming läuft
HANDLE hStopEvent = 0; // Event, welches "Bereit zum Stoppen" signalisiert
CRITICAL_SECTION csInternal; // Kritischer Bereich: Interne Synchronisation
CRITICAL_SECTION csExternal; // Kritischer Bereich: Externe Synchronisation
long lState=LIBRAW; // Aktueller Zustand
bool bPreInit=false; // Treiber-Komponente initialisiert und aufgezählt?
long lState = LIBRAW; // Aktueller Zustand
bool bPreInit = false; // Treiber-Komponente initialisiert und aufgezählt?
int iZeroBlocks; // Anzahl der noch zu spielenden Nullblöcke (nach Stop)
long lNumDrivers; // Anzahl der installierten Treiber
char** asioDriverNames = NULL; // Zwischerspeicher für die Treibernamen
DriverInfo asioDriverInfo; // Eigene Treiberinfos
float fOutputGain=1.0; // Verstärkungsfaktor für Wiedergabe
float fOutputGain = 1.0; // Verstärkungsfaktor für Wiedergabe
long volatile lAsioBufferIndex;
ASIOBool abProcessNow;
float *pfSilence=0;
float *pfInputBuffer=0;
float *pfInputDummyBuffer=0; // Puffer für die zu verwerfenden ersten zwei Blöcke
float *pfSilence = 0;
float *pfInputBuffer = 0;
float *pfInputDummyBuffer = 0; // Puffer für die zu verwerfenden ersten zwei Blöcke
ASIOSource* pasInputDatasource=0; // Eingabedatenquelle
ITADatasource* pidsOutputDatasource=0; // Ausgabedatenquelle
ASIOSource* pasInputDatasource = 0; // Eingabedatenquelle
ITADatasource* pidsOutputDatasource = 0; // Ausgabedatenquelle
ITAStreamInfo siStreamInfo; // Zustandsinformationen des Streams
double g_dStreamStartTimeStamp = ITAClock::getDefaultClock()->getTime(); //!< Time stamp at beginning of streaming
unsigned long ulOutputCounter=0;
unsigned long ulInputCounter=0;
unsigned long ulInputPresentCounter=0;
int iInputBufferNrOffset=0;
unsigned long ulOutputBlockCounter = 0;
unsigned long ulInputCounter = 0;
unsigned long ulInputPresentCounter = 0;
int iInputBufferNrOffset = 0;
long lBuffersize=0; // Ausgewählte Puffergröße
long lBuffersize = 0; // Ausgewählte Puffergröße
ITAAtomicInt iBufferswitchEntrances(0);
ITAAtomicInt iBufferswitchEntrances( 0 );
ITAStopWatch g_swStreamOutputProcessing;
// -= Externe Referenzen =-
extern AsioDrivers *asioDrivers;
......@@ -145,113 +150,113 @@ extern AsioDrivers *asioDrivers;
| ASIO-Callbacks |
| |
+------------------+
*/
*/
ASIOCallbacks asioCallbacks;
ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow) {
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.
hence be sure that you take care about thread synchronization.
This is omitted here for simplicity. */
if (++iBufferswitchEntrances > 1)
if( ++iBufferswitchEntrances > 1 )
std::cerr << "Problem: ASIO bufferswitch callback reentrance!\n" << std::endl;
// Internen Mutex in Besitz bringen
EnterCriticalSection(&csInternal);
EnterCriticalSection( &csInternal );
// Store the timeInfo for later use
asioDriverInfo.tInfo = *timeInfo;
lAsioBufferIndex = index;
abProcessNow = processNow;
long lCounter = 0;
static long processedSamples = 0;
// 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);
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);
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);
if( timeInfo->timeCode.flags & kTcValid )
asioDriverInfo.tcSamples = ASIO64toDouble( timeInfo->timeCode.timeCodeSamples );
else
asioDriverInfo.tcSamples = 0;
// Get the system reference time
asioDriverInfo.sysRefTime = timeGetTime(); // link winmm.lib
/*
DEBUG_PRINTF("[ITAsioInterface] nanoSeconds = %0.1f, samples = %0.1f, tcSamples = %0.1f, sysRefTime = %0.1f\n",
asioDriverInfo.nanoSeconds, asioDriverInfo.samples, asioDriverInfo.tcSamples, asioDriverInfo.sysRefTime);
*/
/*
DEBUG_PRINTF("[ITAsioInterface] nanoSeconds = %0.1f, samples = %0.1f, tcSamples = %0.1f, sysRefTime = %0.1f\n",
asioDriverInfo.nanoSeconds, asioDriverInfo.samples, asioDriverInfo.tcSamples, asioDriverInfo.sysRefTime);
*/
// [Bugfix fwe]: Schwerer Bug! long buffSize = asioDriverInfo.preferredSize;
int j;
int iCount = 0;
float fScaling = 0;
int iChannelNumber = 0;
// -= Eingabedaten lesen =-
/* Hinweis: Eingabedaten werden nur gelesen, falls ASIO-Stop noch
nicht aufgerufen wurde, d.h. iZeroBlocks == -1 ist. */
if (iZeroBlocks == -1)
/* Hinweis: Eingabedaten werden nur gelesen, falls ASIO-Stop noch
nicht aufgerufen wurde, d.h. iZeroBlocks == -1 ist. */
if( iZeroBlocks == -1 )
{
bool bInputDataPresent = (ulInputPresentCounter >= NUM_INPUT_BLOCKS_TO_DISCARD) && (pasInputDatasource != 0);
bool bInputDataPresent = ( ulInputPresentCounter >= NUM_INPUT_BLOCKS_TO_DISCARD ) && ( pasInputDatasource != 0 );
// Input-Kanaele lesen
for (int i=0; i<asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++) {
if (asioDriverInfo.bufferInfos[i].isInput == TRUE) {
if (i >= asioDriverInfo.inputBuffers)
MessageBoxA(0, "Error", "Input Buffer Overflow", MB_OK|MB_SYSTEMMODAL| MB_APPLMODAL );
for( int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++ ) {
if( asioDriverInfo.bufferInfos[ i ].isInput == TRUE ) {
if( i >= asioDriverInfo.inputBuffers )
MessageBoxA( 0, "Error", "Input Buffer Overflow", MB_OK | MB_SYSTEMMODAL | MB_APPLMODAL );
else
iChannelNumber = i;
if (!bInputDataPresent) {
if( !bInputDataPresent ) {
// Noch keine Eingabesamples: Stille bereistellen
float* pfBuffer = pasInputDatasource->GetWritePointer(iChannelNumber);
for (j=0; j<lBuffersize; j++) pfBuffer[j] = 0;
} else {
float* pfBuffer = pasInputDatasource->GetWritePointer( iChannelNumber );
for( j = 0; j < lBuffersize; j++ ) pfBuffer[ j ] = 0;
}
else {
// Eingabesamples verfügbar. Samples konvertieren.
pfInputBuffer = pasInputDatasource->GetWritePointer(iChannelNumber);
pfInputBuffer = pasInputDatasource->GetWritePointer( iChannelNumber );
switch (asioDriverInfo.channelInfos[i].type) {
case ASIOSTInt16LSB:
switch( asioDriverInfo.channelInfos[ i ].type ) {
case ASIOSTInt16LSB:
__int16 *psAsioBufPtr;
psAsioBufPtr = (__int16*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
psAsioBufPtr = ( __int16* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
// Konvertierung Int16 nach Float
for (j=0; j<lBuffersize; j++)
pfInputBuffer[j] = ((float) psAsioBufPtr[j]) / 32767.0F;
for( j = 0; j < lBuffersize; j++ )
pfInputBuffer[ j ] = ( ( float ) psAsioBufPtr[ j ] ) / 32767.0F;
break;
case ASIOSTInt24LSB: // used for 20 bits as well
char *pcAsioBufPtr;
pcAsioBufPtr = (char*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
pcAsioBufPtr = ( char* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
__int32 i32Temp;
i32Temp = 0;
// Konvertierung 20/24-Bit Integer nach Float
for (j=0; j<lBuffersize; j++) {
memcpy(&i32Temp , pcAsioBufPtr, 3);
for( j = 0; j < lBuffersize; j++ ) {
memcpy( &i32Temp, pcAsioBufPtr, 3 );
pcAsioBufPtr += 3;
pfInputBuffer[j] = ((float) i32Temp) / 8388607.0F;
}
pfInputBuffer[ j ] = ( ( float ) i32Temp ) / 8388607.0F;
}
break;
case ASIOSTInt32LSB:
__int32 *piAsioBufPtr;
piAsioBufPtr = (__int32*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
piAsioBufPtr = ( __int32* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
/*
* Bugfix [fwe 2008-09-24]:
......@@ -263,16 +268,16 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
* (Entspricht wieder den 24 Bit nominell). Demnach ist
* der Skalierungsfaktor für Vollaussteuerung nicht
* 2^31-1 = 2147483647, sondern (2^23-1)*2^8 = 2147483392
*
*
* Klärung mit RME Audio steht noch aus...
*/
// Konvertierung 32-Bit Integer nach Float
for (j=0; j<lBuffersize; j++)
for( j = 0; j < lBuffersize; j++ )
// Standard-Implementierung:
//pfInputBuffer[j] = ((float) piAsioBufPtr[j]) / 2147483647.0F;
// RME-Hammerfall Safe Implementierung
pfInputBuffer[j] = ((float) piAsioBufPtr[j]) / 2147483392.0F;
pfInputBuffer[ j ] = ( ( float ) piAsioBufPtr[ j ] ) / 2147483392.0F;
break;
}
......@@ -280,20 +285,25 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
}
}
if (pasInputDatasource) pasInputDatasource->IncrementWritePointer();
if( pasInputDatasource )
pasInputDatasource->IncrementWritePointer();
}
// -= Ausgabedaten schreiben =-
/* Hinweis: Falls iZeroBlocks != -1 ist wurde ASIOStop bereits ausgelöst und
jetzt müssen Nullblöcke abgespielt werden.
jetzt müssen Nullblöcke abgespielt werden.
iZeroBlocks muß heruntergezählt werden. */
// Output-Kanaele schreiben
for (int i=0; i<asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++) {
if (asioDriverInfo.bufferInfos[i].isInput == FALSE) {
if (i - asioDriverInfo.inputBuffers >= asioDriverInfo.outputBuffers)
MessageBoxA(0, "Error", "Output Buffer Overflow", MB_OK|MB_SYSTEMMODAL| MB_APPLMODAL );
// Provide ouput data
g_swStreamOutputProcessing.start();
for( int i = 0; i < asioDriverInfo.inputBuffers + asioDriverInfo.outputBuffers; i++ )
{
if( asioDriverInfo.bufferInfos[ i ].isInput == FALSE )
{
if( i - asioDriverInfo.inputBuffers >= asioDriverInfo.outputBuffers )
MessageBoxA( 0, "Error", "Output Buffer Overflow", MB_OK | MB_SYSTEMMODAL | MB_APPLMODAL );
else
iChannelNumber = i - asioDriverInfo.inputBuffers;
......@@ -302,49 +312,52 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
// TODO: Streaminfo zusammenstellen? TimeCode aus ASIO rein?
// Gibts eine Ausgabedatenquelle?
if (pidsOutputDatasource && (iZeroBlocks == -1)) {
if( pidsOutputDatasource && ( iZeroBlocks == -1 ) )
{
// Dann Datenzeiger der Quelle abrufen
// Wichtig: false ist enorm wichtig, damit nicht auf Daten gewartet wird!
pfOutputData = pidsOutputDatasource->GetBlockPointer((unsigned int) iChannelNumber, &siStreamInfo);
pfOutputData = pidsOutputDatasource->GetBlockPointer( ( unsigned int ) iChannelNumber, &siStreamInfo );
// Falls die Quelle keine Daten hat, Stille verwenden
if (!pfOutputData) pfOutputData = pfSilence;
if( !pfOutputData )
pfOutputData = pfSilence;
}
switch (asioDriverInfo.channelInfos[i].type)
switch( asioDriverInfo.channelInfos[ i ].type )
{
case ASIOSTInt16LSB:
#if DEBUG_OUT
std::cout << "ASIOSTInt16LSB nicht unterstuetzt " ;
#endif
#if DEBUG_OUT
std::cout << "ASIOSTInt16LSB nicht unterstuetzt ";
#endif
__int16 *psAsioBufPtr;
psAsioBufPtr = (__int16*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
fScaling = 32767.0F * fOutputGain;
for (j=0; j<lBuffersize; j++)
psAsioBufPtr[j] = (__int16) (pfOutputData[j] * fScaling);
psAsioBufPtr = ( __int16* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
fScaling = 32767.0F * fOutputGain;
for( j = 0; j < lBuffersize; j++ )
psAsioBufPtr[ j ] = ( __int16 ) ( pfOutputData[ j ] * fScaling );
break;
case ASIOSTInt24LSB: // used for 20 bits as well
#if DEBUG_OUT
std::cout << "ASIOSTInt24LSB nicht unterstuetzt " ;
#endif
#if DEBUG_OUT
std::cout << "ASIOSTInt24LSB nicht unterstuetzt ";
#endif
char *pcAsioBufPtr;
pcAsioBufPtr = (char*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
pcAsioBufPtr = ( char* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
__int32 i32Temp;
char *pcSourcePointer;
fScaling = 8388607.0F * fOutputGain;
for (j=0; j<lBuffersize; j++) {
i32Temp = (__int32) (pfOutputData[j] * fScaling);
pcSourcePointer = (char*) &i32Temp;
memcpy(pcAsioBufPtr, pcSourcePointer, 3);
for( j = 0; j < lBuffersize; j++ )
{
i32Temp = ( __int32 ) ( pfOutputData[ j ] * fScaling );
pcSourcePointer = ( char* ) &i32Temp;
memcpy( pcAsioBufPtr, pcSourcePointer, 3 );
pcAsioBufPtr += 3;
}
}
break;
case ASIOSTInt32LSB:
#if DEBUG_OUT
std::cout << "ASIOSTInt32LSB nicht unterstuetzt" ;
#endif
#if DEBUG_OUT
std::cout << "ASIOSTInt32LSB nicht unterstuetzt";
#endif
/*
* Bugfix [fwe 2008-09-24]:
......@@ -356,20 +369,20 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
* (Entspricht wieder den 24 Bit nominell). Demnach ist
* der Skalierungsfaktor für Vollaussteuerung nicht
* 2^31-1 = 2147483647, sondern (2^23-1)*2^8 = 2147483392
*
*
* Klärung mit RME Audio steht noch aus...
*/
__int32 *piAsioBufPtr;
piAsioBufPtr = (__int32*) asioDriverInfo.bufferInfos[i].buffers[lAsioBufferIndex];
piAsioBufPtr = ( __int32* ) asioDriverInfo.bufferInfos[ i ].buffers[ lAsioBufferIndex ];
//fScaling = 2147483647.0F * fOutputGain;
fScaling = 2147483392.0F * fOutputGain;
for (j=0; j < lBuffersize; j++)
piAsioBufPtr[j] = (__int32) (pfOutputData[j] * fScaling);
break;
for( j = 0; j < lBuffersize; j++ )
piAsioBufPtr[ j ] = ( __int32 ) ( pfOutputData[ j ] * fScaling );
break;
// Alles weitere wird noch nicht unterstützt!!
// Int
// Alles weitere wird noch nicht unterstützt!!
// Int
case ASIOSTInt32LSB16: // 32 bit data with 18 bit alignment
std::cout << "ASIOSTInt32LSB16 nicht unterstuetzt ";
break;
......@@ -392,8 +405,8 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
std::cout << "ASIOSTInt32MSB nicht unterstuetzt ";
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
// 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
std::cout << "ASIOSTInt32MSB16 nicht unterstuetzt ";
break;
......@@ -407,7 +420,7 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
std::cout << "ASIOSTInt32MSB24 nicht unterstuetzt ";
break;
// Float
// Float
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
std::cout << "ASIOSTFloat32LSB nicht unterstuetzt ";
break;
......@@ -422,34 +435,40 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
std::cout << "ASIOSTFloat64MSB nicht unterstuetzt";
break;
default:
std::cout << "- " ;
std::cout << "- ";
}
}
}
ulOutputCounter++;
const double dOutputProcessingTime = g_swStreamOutputProcessing.stop();
const double dAvailabelProcessingTime = double( lBuffersize ) / double( asioDriverInfo.sampleRate );
if( dOutputProcessingTime > dAvailabelProcessingTime )
std::cerr << "[ ITAAsioInterface ] Output stream panic, processing time exceeded ( took " << timeToString( dOutputProcessingTime ) << " but got only " << timeToString( dAvailabelProcessingTime ) << " )" << std::endl;
if (ulInputPresentCounter <= 1)
ulOutputBlockCounter++;
if( ulInputPresentCounter <= 1 )
ulInputPresentCounter++;
else
ulInputCounter++;
processedSamples += lBuffersize;
// Zwischenlüsung: Streaminfo einfach inkrementieren. Keinen Timcode.
siStreamInfo.nSamples += lBuffersize;
siStreamInfo.dTimecode = (double) (siStreamInfo.nSamples) / (double) asioDriverInfo.sampleRate;
//siStreamInfo.dStreamTimeCode = (double) (siStreamInfo.nSamples) / (double) asioDriverInfo.sampleRate;
siStreamInfo.dStreamTimeCode = ITAClock::getDefaultClock()->getTime() - g_dStreamStartTimeStamp;
siStreamInfo.dSysTimeCode = ITAClock::getDefaultClock()->getTime();
// Gibts eine Ausgabedatenquelle? Dann Blockzeiger weitersetzen
if (pidsOutputDatasource && (iZeroBlocks == -1)) pidsOutputDatasource->IncrementBlockPointer();
if( pidsOutputDatasource && ( iZeroBlocks == -1 ) ) pidsOutputDatasource->IncrementBlockPointer();
// Stop triggert? Herunterzählen? Bei 0 das Event für wartendes ITAAsioStop() setzen.
if (iZeroBlocks > 0)
if ((--iZeroBlocks) == 0) SetEvent(hStopEvent);
if( iZeroBlocks > 0 )
if( ( --iZeroBlocks ) == 0 ) SetEvent( hStopEvent );
// Internen Mutex freigeben
LeaveCriticalSection(&csInternal);
LeaveCriticalSection( &csInternal );
// Finally if the driver supports the ASIOOutputReady() optimization,
// do it here, all data are in place
//if (asioDriverInfo.postOutput)
......@@ -460,7 +479,7 @@ ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processN
return 0L;
}
void bufferSwitch(long index, ASIOBool processNow) { // the actual processing callback.
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.
......@@ -471,20 +490,21 @@ void bufferSwitch(long index, ASIOBool processNow) { // the actual processing ca
// 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));
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)
if( ASIOGetSamplePosition( &timeInfo.timeInfo.samplePosition,
&timeInfo.timeInfo.systemTime ) == ASE_OK )
timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
bufferSwitchTimeInfo(&timeInfo, index, processNow);
bufferSwitchTimeInfo( &timeInfo, index, processNow );
}
void sampleRateChanged(ASIOSampleRate sRate) {
void sampleRateChanged( ASIOSampleRate )
{
// MessageBox (0, "Callback sampleRateChanged", "Callback sampleRateChanged", MB_OK|MB_SYSTEMMODAL| MB_APPLMODAL );
// 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
......@@ -494,68 +514,69 @@ void sampleRateChanged(ASIOSampleRate sRate) {
}
long asioMessages(long selector, long value, void* message, double* opt) {
long asioMessages( long selector, long value, void*, double* )
{
// MessageBox (0, "Callback asioMessages", "Callback asioMessages", MB_OK|MB_SYSTEMMODAL| MB_APPLMODAL );
// Currently the parameters "value", "message" and "opt" are not used.
long ret = 0;
switch(selector) {
case kAsioSelectorSupported:
if(value == kAsioResetRequest
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