| @@ -35,12 +35,13 @@ | |||
| //============================================================================== | |||
| namespace ASIODebugging | |||
| { | |||
| #if ASIO_DEBUGGING | |||
| #if JUCE_ASIO_DEBUGGING | |||
| #define JUCE_ASIO_LOG(a) ASIODebugging::logMessage (a) | |||
| #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); | |||
| Logger::writeToLog (message); | |||
| } | |||
| @@ -62,7 +63,7 @@ namespace ASIODebugging | |||
| default: break; | |||
| } | |||
| logMessage ("ASIO error: " + context + " - " + err); | |||
| logMessage ("error: " + context + " - " + err); | |||
| } | |||
| #else | |||
| static void dummyLog() {} | |||
| @@ -341,7 +342,7 @@ public: | |||
| currentASIODev[i] = nullptr; | |||
| close(); | |||
| JUCE_ASIO_LOG ("ASIO - exiting"); | |||
| JUCE_ASIO_LOG ("closed"); | |||
| removeCurrentDriver(); | |||
| } | |||
| @@ -493,7 +494,7 @@ public: | |||
| else | |||
| { | |||
| if (numSources == 0) | |||
| JUCE_ASIO_LOG ("ASIO - no clock sources!"); | |||
| JUCE_ASIO_LOG ("no clock sources!"); | |||
| } | |||
| { | |||
| @@ -509,7 +510,7 @@ public: | |||
| 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); | |||
| if (err == ASE_NoClock && numSources > 0) | |||
| @@ -522,192 +523,157 @@ public: | |||
| Thread::sleep (10); | |||
| 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, | |||
| totalBuffers, | |||
| currentBlockSizeSamples, | |||
| &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); | |||
| } | |||
| 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 | |||
| { | |||
| error = "Can't set sample rate: "; | |||
| error << sampleRate; | |||
| error = "Can't create i/o buffers"; | |||
| } | |||
| if (error.isNotEmpty()) | |||
| @@ -742,7 +708,7 @@ public: | |||
| isStarted = false; | |||
| needToReset = false; | |||
| JUCE_ASIO_LOG ("ASIO - stopping"); | |||
| JUCE_ASIO_LOG ("stopping"); | |||
| if (asioObject != nullptr) | |||
| { | |||
| @@ -798,7 +764,7 @@ public: | |||
| bool showControlPanel() | |||
| { | |||
| JUCE_ASIO_LOG ("ASIO - showing control panel"); | |||
| JUCE_ASIO_LOG ("showing control panel"); | |||
| bool done = false; | |||
| @@ -843,7 +809,7 @@ public: | |||
| stopTimer(); | |||
| // used to cause a reset | |||
| JUCE_ASIO_LOG ("! ASIO restart request!"); | |||
| JUCE_ASIO_LOG ("restart request!"); | |||
| if (deviceIsOpen) | |||
| { | |||
| @@ -914,6 +880,42 @@ private: | |||
| 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() | |||
| { | |||
| if (asioObject != nullptr) | |||
| @@ -1004,7 +1006,7 @@ private: | |||
| String openDevice() | |||
| { | |||
| // open the device and get its info.. | |||
| JUCE_ASIO_LOG ("opening ASIO device: " + getName()); | |||
| JUCE_ASIO_LOG ("opening device: " + getName()); | |||
| needToReset = false; | |||
| outputChannelNames.clear(); | |||
| @@ -1089,14 +1091,14 @@ private: | |||
| postOutput = (asioObject->outputReady() == 0); | |||
| if (postOutput) | |||
| JUCE_ASIO_LOG ("ASIO outputReady = ok"); | |||
| JUCE_ASIO_LOG ("outputReady true"); | |||
| updateSampleRates(); | |||
| // ..because cubase does it at this point | |||
| 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)); | |||
| @@ -1187,7 +1189,7 @@ private: | |||
| err = asioObject->start(); | |||
| // 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); | |||
| asioObject->stop(); | |||
| @@ -1218,7 +1220,7 @@ private: | |||
| else | |||
| { | |||
| isASIOOpen = true; | |||
| JUCE_ASIO_LOG ("ASIO device open"); | |||
| JUCE_ASIO_LOG ("device open"); | |||
| } | |||
| deviceIsOpen = false; | |||