|
|
@@ -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;
|
|
|
|