| @@ -35,12 +35,13 @@ | |||||
| //============================================================================== | //============================================================================== | ||||
| namespace ASIODebugging | namespace ASIODebugging | ||||
| { | { | ||||
| #if ASIO_DEBUGGING | |||||
| #if JUCE_ASIO_DEBUGGING | |||||
| #define JUCE_ASIO_LOG(a) ASIODebugging::logMessage (a) | #define JUCE_ASIO_LOG(a) ASIODebugging::logMessage (a) | ||||
| #define JUCE_ASIO_LOG_ERROR(a, b) ASIODebugging::logError ((a), (b)) | #define JUCE_ASIO_LOG_ERROR(a, b) ASIODebugging::logError ((a), (b)) | ||||
| static void logMessage (const String& message) | |||||
| static void logMessage (String message) | |||||
| { | { | ||||
| message = "ASIO: " + message; | |||||
| DBG (message); | DBG (message); | ||||
| Logger::writeToLog (message); | Logger::writeToLog (message); | ||||
| } | } | ||||
| @@ -62,7 +63,7 @@ namespace ASIODebugging | |||||
| default: break; | default: break; | ||||
| } | } | ||||
| logMessage ("ASIO error: " + context + " - " + err); | |||||
| logMessage ("error: " + context + " - " + err); | |||||
| } | } | ||||
| #else | #else | ||||
| static void dummyLog() {} | static void dummyLog() {} | ||||
| @@ -341,7 +342,7 @@ public: | |||||
| currentASIODev[i] = nullptr; | currentASIODev[i] = nullptr; | ||||
| close(); | close(); | ||||
| JUCE_ASIO_LOG ("ASIO - exiting"); | |||||
| JUCE_ASIO_LOG ("closed"); | |||||
| removeCurrentDriver(); | removeCurrentDriver(); | ||||
| } | } | ||||
| @@ -493,7 +494,7 @@ public: | |||||
| else | else | ||||
| { | { | ||||
| if (numSources == 0) | if (numSources == 0) | ||||
| JUCE_ASIO_LOG ("ASIO - no clock sources!"); | |||||
| JUCE_ASIO_LOG ("no clock sources!"); | |||||
| } | } | ||||
| { | { | ||||
| @@ -509,7 +510,7 @@ public: | |||||
| if (currentSampleRate != sampleRate) | if (currentSampleRate != sampleRate) | ||||
| { | { | ||||
| JUCE_ASIO_LOG ("ASIO samplerate: " + String (currentSampleRate) + " to " + String (sampleRate)); | |||||
| JUCE_ASIO_LOG ("rate change: " + String (currentSampleRate) + " to " + String (sampleRate)); | |||||
| err = asioObject->setSampleRate (sampleRate); | err = asioObject->setSampleRate (sampleRate); | ||||
| if (err == ASE_NoClock && numSources > 0) | if (err == ASE_NoClock && numSources > 0) | ||||
| @@ -522,192 +523,157 @@ public: | |||||
| Thread::sleep (10); | Thread::sleep (10); | ||||
| err = asioObject->setSampleRate (sampleRate); | err = asioObject->setSampleRate (sampleRate); | ||||
| } | } | ||||
| } | |||||
| if (err == 0) | |||||
| { | |||||
| currentSampleRate = sampleRate; | |||||
| if (err == 0) | |||||
| currentSampleRate = sampleRate; | |||||
| if (needToReset) | |||||
| { | |||||
| JUCE_ASIO_LOG ("! Resetting ASIO after sample rate change"); | |||||
| removeCurrentDriver(); | |||||
| // on fail, ignore the attempt to change rate, and run with the current one.. | |||||
| } | |||||
| loadDriver(); | |||||
| const String error (initDriver()); | |||||
| if (needToReset) | |||||
| { | |||||
| JUCE_ASIO_LOG (" Resetting"); | |||||
| removeCurrentDriver(); | |||||
| if (error.isNotEmpty()) | |||||
| JUCE_ASIO_LOG ("ASIOInit: " + error); | |||||
| loadDriver(); | |||||
| const String error (initDriver()); | |||||
| needToReset = false; | |||||
| } | |||||
| if (error.isNotEmpty()) | |||||
| JUCE_ASIO_LOG ("ASIOInit: " + error); | |||||
| numActiveInputChans = 0; | |||||
| numActiveOutputChans = 0; | |||||
| needToReset = false; | |||||
| } | |||||
| ASIOBufferInfo* info = bufferInfos; | |||||
| for (int i = 0; i < totalNumInputChans; ++i) | |||||
| { | |||||
| if (inputChannels[i]) | |||||
| { | |||||
| currentChansIn.setBit (i); | |||||
| info->isInput = 1; | |||||
| info->channelNum = i; | |||||
| info->buffers[0] = info->buffers[1] = nullptr; | |||||
| ++info; | |||||
| ++numActiveInputChans; | |||||
| } | |||||
| } | |||||
| const int totalBuffers = resetBuffers (inputChannels, outputChannels); | |||||
| for (int i = 0; i < totalNumOutputChans; ++i) | |||||
| { | |||||
| if (outputChannels[i]) | |||||
| { | |||||
| currentChansOut.setBit (i); | |||||
| info->isInput = 0; | |||||
| info->channelNum = i; | |||||
| info->buffers[0] = info->buffers[1] = nullptr; | |||||
| ++info; | |||||
| ++numActiveOutputChans; | |||||
| } | |||||
| } | |||||
| setCallbackFunctions(); | |||||
| const int totalBuffers = numActiveInputChans + numActiveOutputChans; | |||||
| JUCE_ASIO_LOG ("disposing buffers"); | |||||
| err = asioObject->disposeBuffers(); | |||||
| setCallbackFunctions(); | |||||
| JUCE_ASIO_LOG ("creating buffers: " + String (totalBuffers) + ", " + String (currentBlockSizeSamples)); | |||||
| err = asioObject->createBuffers (bufferInfos, | |||||
| totalBuffers, | |||||
| currentBlockSizeSamples, | |||||
| &callbacks); | |||||
| JUCE_ASIO_LOG ("disposing buffers"); | |||||
| err = asioObject->disposeBuffers(); | |||||
| if (err != 0) | |||||
| { | |||||
| currentBlockSizeSamples = preferredSize; | |||||
| JUCE_ASIO_LOG_ERROR ("create buffers 2", err); | |||||
| JUCE_ASIO_LOG ("creating buffers: " + String (totalBuffers) + ", " + String (currentBlockSizeSamples)); | |||||
| asioObject->disposeBuffers(); | |||||
| err = asioObject->createBuffers (bufferInfos, | err = asioObject->createBuffers (bufferInfos, | ||||
| totalBuffers, | totalBuffers, | ||||
| currentBlockSizeSamples, | currentBlockSizeSamples, | ||||
| &callbacks); | &callbacks); | ||||
| } | |||||
| if (err != 0) | |||||
| { | |||||
| currentBlockSizeSamples = preferredSize; | |||||
| JUCE_ASIO_LOG_ERROR ("create buffers 2", err); | |||||
| asioObject->disposeBuffers(); | |||||
| err = asioObject->createBuffers (bufferInfos, | |||||
| totalBuffers, | |||||
| currentBlockSizeSamples, | |||||
| &callbacks); | |||||
| } | |||||
| if (err == 0) | |||||
| { | |||||
| buffersCreated = true; | |||||
| if (err == 0) | |||||
| { | |||||
| buffersCreated = true; | |||||
| tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32); | |||||
| tempBuffer.calloc (totalBuffers * currentBlockSizeSamples + 32); | |||||
| int n = 0; | |||||
| Array <int> types; | |||||
| currentBitDepth = 16; | |||||
| int n = 0; | |||||
| Array <int> types; | |||||
| currentBitDepth = 16; | |||||
| for (int i = 0; i < (int) totalNumInputChans; ++i) | |||||
| for (int i = 0; i < (int) totalNumInputChans; ++i) | |||||
| { | |||||
| if (inputChannels[i]) | |||||
| { | { | ||||
| if (inputChannels[i]) | |||||
| { | |||||
| inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n); | |||||
| inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n); | |||||
| ASIOChannelInfo channelInfo = { 0 }; | |||||
| channelInfo.channel = i; | |||||
| channelInfo.isInput = 1; | |||||
| asioObject->getChannelInfo (&channelInfo); | |||||
| ASIOChannelInfo channelInfo = { 0 }; | |||||
| channelInfo.channel = i; | |||||
| channelInfo.isInput = 1; | |||||
| asioObject->getChannelInfo (&channelInfo); | |||||
| types.addIfNotAlreadyThere (channelInfo.type); | |||||
| inputFormat[n] = ASIOSampleFormat (channelInfo.type); | |||||
| types.addIfNotAlreadyThere (channelInfo.type); | |||||
| inputFormat[n] = ASIOSampleFormat (channelInfo.type); | |||||
| currentBitDepth = jmax (currentBitDepth, inputFormat[n].bitDepth); | |||||
| ++n; | |||||
| } | |||||
| currentBitDepth = jmax (currentBitDepth, inputFormat[n].bitDepth); | |||||
| ++n; | |||||
| } | } | ||||
| } | |||||
| jassert (numActiveInputChans == n); | |||||
| n = 0; | |||||
| jassert (numActiveInputChans == n); | |||||
| n = 0; | |||||
| for (int i = 0; i < (int) totalNumOutputChans; ++i) | |||||
| for (int i = 0; i < (int) totalNumOutputChans; ++i) | |||||
| { | |||||
| if (outputChannels[i]) | |||||
| { | { | ||||
| if (outputChannels[i]) | |||||
| { | |||||
| outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n)); | |||||
| outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n)); | |||||
| ASIOChannelInfo channelInfo = { 0 }; | |||||
| channelInfo.channel = i; | |||||
| channelInfo.isInput = 0; | |||||
| asioObject->getChannelInfo (&channelInfo); | |||||
| ASIOChannelInfo channelInfo = { 0 }; | |||||
| channelInfo.channel = i; | |||||
| channelInfo.isInput = 0; | |||||
| asioObject->getChannelInfo (&channelInfo); | |||||
| types.addIfNotAlreadyThere (channelInfo.type); | |||||
| outputFormat[n] = ASIOSampleFormat (channelInfo.type); | |||||
| types.addIfNotAlreadyThere (channelInfo.type); | |||||
| outputFormat[n] = ASIOSampleFormat (channelInfo.type); | |||||
| currentBitDepth = jmax (currentBitDepth, outputFormat[n].bitDepth); | |||||
| ++n; | |||||
| } | |||||
| currentBitDepth = jmax (currentBitDepth, outputFormat[n].bitDepth); | |||||
| ++n; | |||||
| } | } | ||||
| } | |||||
| jassert (numActiveOutputChans == n); | |||||
| jassert (numActiveOutputChans == n); | |||||
| for (int i = types.size(); --i >= 0;) | |||||
| JUCE_ASIO_LOG ("channel format: " + String (types[i])); | |||||
| for (int i = types.size(); --i >= 0;) | |||||
| JUCE_ASIO_LOG ("channel format: " + String (types[i])); | |||||
| jassert (n <= totalBuffers); | |||||
| jassert (n <= totalBuffers); | |||||
| for (int i = 0; i < numActiveOutputChans; ++i) | |||||
| { | |||||
| outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[0], currentBlockSizeSamples); | |||||
| outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[1], currentBlockSizeSamples); | |||||
| } | |||||
| for (int i = 0; i < numActiveOutputChans; ++i) | |||||
| { | |||||
| outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[0], currentBlockSizeSamples); | |||||
| outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[1], currentBlockSizeSamples); | |||||
| } | |||||
| inputLatency = outputLatency = 0; | |||||
| inputLatency = outputLatency = 0; | |||||
| if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0) | |||||
| JUCE_ASIO_LOG ("ASIO - no latencies"); | |||||
| else | |||||
| JUCE_ASIO_LOG ("ASIO latencies: " + String ((int) outputLatency) + ", " + String ((int) inputLatency)); | |||||
| if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0) | |||||
| JUCE_ASIO_LOG ("no latencies"); | |||||
| else | |||||
| JUCE_ASIO_LOG ("latencies: " + String ((int) outputLatency) + ", " + String ((int) inputLatency)); | |||||
| deviceIsOpen = true; | |||||
| deviceIsOpen = true; | |||||
| JUCE_ASIO_LOG ("starting ASIO"); | |||||
| calledback = false; | |||||
| err = asioObject->start(); | |||||
| JUCE_ASIO_LOG ("starting"); | |||||
| calledback = false; | |||||
| err = asioObject->start(); | |||||
| if (err != 0) | |||||
| { | |||||
| deviceIsOpen = false; | |||||
| JUCE_ASIO_LOG ("ASIO - stop on failure"); | |||||
| Thread::sleep (10); | |||||
| asioObject->stop(); | |||||
| error = "Can't start device"; | |||||
| if (err != 0) | |||||
| { | |||||
| deviceIsOpen = false; | |||||
| JUCE_ASIO_LOG ("stop on failure"); | |||||
| Thread::sleep (10); | |||||
| asioObject->stop(); | |||||
| error = "Can't start device"; | |||||
| Thread::sleep (10); | |||||
| } | |||||
| else | |||||
| { | |||||
| int count = 300; | |||||
| while (--count > 0 && ! calledback) | |||||
| Thread::sleep (10); | Thread::sleep (10); | ||||
| } | |||||
| else | |||||
| { | |||||
| int count = 300; | |||||
| while (--count > 0 && ! calledback) | |||||
| Thread::sleep (10); | |||||
| isStarted = true; | |||||
| isStarted = true; | |||||
| if (! calledback) | |||||
| { | |||||
| error = "Device didn't start correctly"; | |||||
| JUCE_ASIO_LOG ("ASIO didn't callback - stopping.."); | |||||
| asioObject->stop(); | |||||
| } | |||||
| if (! calledback) | |||||
| { | |||||
| error = "Device didn't start correctly"; | |||||
| JUCE_ASIO_LOG ("no callbacks - stopping.."); | |||||
| asioObject->stop(); | |||||
| } | } | ||||
| } | } | ||||
| else | |||||
| { | |||||
| error = "Can't create i/o buffers"; | |||||
| } | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| error = "Can't set sample rate: "; | |||||
| error << sampleRate; | |||||
| error = "Can't create i/o buffers"; | |||||
| } | } | ||||
| if (error.isNotEmpty()) | if (error.isNotEmpty()) | ||||
| @@ -742,7 +708,7 @@ public: | |||||
| isStarted = false; | isStarted = false; | ||||
| needToReset = false; | needToReset = false; | ||||
| JUCE_ASIO_LOG ("ASIO - stopping"); | |||||
| JUCE_ASIO_LOG ("stopping"); | |||||
| if (asioObject != nullptr) | if (asioObject != nullptr) | ||||
| { | { | ||||
| @@ -798,7 +764,7 @@ public: | |||||
| bool showControlPanel() | bool showControlPanel() | ||||
| { | { | ||||
| JUCE_ASIO_LOG ("ASIO - showing control panel"); | |||||
| JUCE_ASIO_LOG ("showing control panel"); | |||||
| bool done = false; | bool done = false; | ||||
| @@ -843,7 +809,7 @@ public: | |||||
| stopTimer(); | stopTimer(); | ||||
| // used to cause a reset | // used to cause a reset | ||||
| JUCE_ASIO_LOG ("! ASIO restart request!"); | |||||
| JUCE_ASIO_LOG ("restart request!"); | |||||
| if (deviceIsOpen) | if (deviceIsOpen) | ||||
| { | { | ||||
| @@ -914,6 +880,42 @@ private: | |||||
| return wideVersion; | return wideVersion; | ||||
| } | } | ||||
| int resetBuffers (const BigInteger& inputChannels, | |||||
| const BigInteger& outputChannels) | |||||
| { | |||||
| numActiveInputChans = 0; | |||||
| numActiveOutputChans = 0; | |||||
| ASIOBufferInfo* info = bufferInfos; | |||||
| for (int i = 0; i < totalNumInputChans; ++i) | |||||
| { | |||||
| if (inputChannels[i]) | |||||
| { | |||||
| currentChansIn.setBit (i); | |||||
| info->isInput = 1; | |||||
| info->channelNum = i; | |||||
| info->buffers[0] = info->buffers[1] = nullptr; | |||||
| ++info; | |||||
| ++numActiveInputChans; | |||||
| } | |||||
| } | |||||
| for (int i = 0; i < totalNumOutputChans; ++i) | |||||
| { | |||||
| if (outputChannels[i]) | |||||
| { | |||||
| currentChansOut.setBit (i); | |||||
| info->isInput = 0; | |||||
| info->channelNum = i; | |||||
| info->buffers[0] = info->buffers[1] = nullptr; | |||||
| ++info; | |||||
| ++numActiveOutputChans; | |||||
| } | |||||
| } | |||||
| return numActiveInputChans + numActiveOutputChans; | |||||
| } | |||||
| void removeCurrentDriver() | void removeCurrentDriver() | ||||
| { | { | ||||
| if (asioObject != nullptr) | if (asioObject != nullptr) | ||||
| @@ -1004,7 +1006,7 @@ private: | |||||
| String openDevice() | String openDevice() | ||||
| { | { | ||||
| // open the device and get its info.. | // open the device and get its info.. | ||||
| JUCE_ASIO_LOG ("opening ASIO device: " + getName()); | |||||
| JUCE_ASIO_LOG ("opening device: " + getName()); | |||||
| needToReset = false; | needToReset = false; | ||||
| outputChannelNames.clear(); | outputChannelNames.clear(); | ||||
| @@ -1089,14 +1091,14 @@ private: | |||||
| postOutput = (asioObject->outputReady() == 0); | postOutput = (asioObject->outputReady() == 0); | ||||
| if (postOutput) | if (postOutput) | ||||
| JUCE_ASIO_LOG ("ASIO outputReady = ok"); | |||||
| JUCE_ASIO_LOG ("outputReady true"); | |||||
| updateSampleRates(); | updateSampleRates(); | ||||
| // ..because cubase does it at this point | // ..because cubase does it at this point | ||||
| inputLatency = outputLatency = 0; | inputLatency = outputLatency = 0; | ||||
| if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0) | if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0) | ||||
| JUCE_ASIO_LOG ("ASIO - no latencies"); | |||||
| JUCE_ASIO_LOG ("no latencies"); | |||||
| JUCE_ASIO_LOG ("latencies: " + String ((int) inputLatency) + ", " + String ((int) outputLatency)); | JUCE_ASIO_LOG ("latencies: " + String ((int) inputLatency) + ", " + String ((int) outputLatency)); | ||||
| @@ -1187,7 +1189,7 @@ private: | |||||
| err = asioObject->start(); | err = asioObject->start(); | ||||
| // ignore an error here, as it might start later after setting other stuff up | // ignore an error here, as it might start later after setting other stuff up | ||||
| JUCE_ASIO_LOG_ERROR ("ASIO start", err); | |||||
| JUCE_ASIO_LOG_ERROR ("start", err); | |||||
| Thread::sleep (100); | Thread::sleep (100); | ||||
| asioObject->stop(); | asioObject->stop(); | ||||
| @@ -1218,7 +1220,7 @@ private: | |||||
| else | else | ||||
| { | { | ||||
| isASIOOpen = true; | isASIOOpen = true; | ||||
| JUCE_ASIO_LOG ("ASIO device open"); | |||||
| JUCE_ASIO_LOG ("device open"); | |||||
| } | } | ||||
| deviceIsOpen = false; | deviceIsOpen = false; | ||||