mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-02-06 04:00:08 +00:00
Cleaned up some ASIO code and added some logging.
This commit is contained in:
parent
74bd1ea8e6
commit
0d477bb422
1 changed files with 212 additions and 189 deletions
|
|
@ -323,6 +323,7 @@ public:
|
|||
minSize (0), maxSize (0),
|
||||
preferredSize (0),
|
||||
granularity (0),
|
||||
numClockSources (0),
|
||||
currentBlockSizeSamples (0),
|
||||
currentBitDepth (16),
|
||||
currentSampleRate (0),
|
||||
|
|
@ -376,12 +377,10 @@ public:
|
|||
|
||||
if (newRates.size() == 0)
|
||||
{
|
||||
double cr = 0;
|
||||
const long err = asioObject->getSampleRate (&cr);
|
||||
double cr = getSampleRate();
|
||||
JUCE_ASIO_LOG ("No sample rates supported - current rate: " + String ((int) cr));
|
||||
JUCE_ASIO_LOG_ERROR ("getSampleRate", err);
|
||||
|
||||
if (err == 0)
|
||||
if (cr > 0)
|
||||
newRates.add ((int) cr);
|
||||
}
|
||||
|
||||
|
|
@ -431,46 +430,11 @@ public:
|
|||
|
||||
isStarted = false;
|
||||
bufferIndex = -1;
|
||||
minSize = 0;
|
||||
maxSize = 0;
|
||||
granularity = 0;
|
||||
|
||||
long err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans);
|
||||
jassert (err == ASE_OK);
|
||||
|
||||
long newPreferredSize = 0;
|
||||
if (asioObject->getBufferSize (&minSize, &maxSize, &newPreferredSize, &granularity) == ASE_OK)
|
||||
{
|
||||
if (preferredSize != 0 && newPreferredSize != 0 && newPreferredSize != preferredSize)
|
||||
shouldUsePreferredSize = true;
|
||||
|
||||
if (bufferSizeSamples < minSize || bufferSizeSamples > maxSize)
|
||||
shouldUsePreferredSize = true;
|
||||
|
||||
preferredSize = newPreferredSize;
|
||||
}
|
||||
|
||||
// unfortunate workaround for certain manufacturers whose drivers crash horribly if you make
|
||||
// dynamic changes to the buffer size...
|
||||
shouldUsePreferredSize = shouldUsePreferredSize
|
||||
|| getName().containsIgnoreCase ("Digidesign");
|
||||
|
||||
if (shouldUsePreferredSize)
|
||||
{
|
||||
JUCE_ASIO_LOG ("Using preferred size for buffer..");
|
||||
|
||||
if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == ASE_OK)
|
||||
{
|
||||
bufferSizeSamples = preferredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSizeSamples = 1024;
|
||||
JUCE_ASIO_LOG_ERROR ("getBufferSize1", err);
|
||||
}
|
||||
|
||||
shouldUsePreferredSize = false;
|
||||
}
|
||||
bufferSizeSamples = readBufferSizes (bufferSizeSamples);
|
||||
|
||||
int sampleRate = roundToInt (sr);
|
||||
currentSampleRate = sampleRate;
|
||||
|
|
@ -489,71 +453,13 @@ public:
|
|||
if (sampleRate == 0)
|
||||
sampleRate = 44100;
|
||||
|
||||
ASIOClockSource clocks[32] = { 0 };
|
||||
long numSources = numElementsInArray (clocks);
|
||||
asioObject->getClockSources (clocks, &numSources);
|
||||
bool isSourceSet = false;
|
||||
|
||||
// careful not to remove this loop because it does more than just logging!
|
||||
for (int i = 0; i < numSources; ++i)
|
||||
{
|
||||
String s ("clock: ");
|
||||
s += clocks[i].name;
|
||||
|
||||
if (clocks[i].isCurrentSource)
|
||||
{
|
||||
isSourceSet = true;
|
||||
s << " (cur)";
|
||||
}
|
||||
|
||||
JUCE_ASIO_LOG (s);
|
||||
}
|
||||
|
||||
if (numSources > 1 && ! isSourceSet)
|
||||
{
|
||||
JUCE_ASIO_LOG ("setting clock source");
|
||||
err = asioObject->setClockSource (clocks[0].index);
|
||||
JUCE_ASIO_LOG_ERROR ("setClockSource1", err);
|
||||
Thread::sleep (20);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numSources == 0)
|
||||
JUCE_ASIO_LOG ("no clock sources!");
|
||||
}
|
||||
|
||||
{
|
||||
double cr = 0;
|
||||
err = asioObject->getSampleRate (&cr);
|
||||
JUCE_ASIO_LOG_ERROR ("getSampleRate", err);
|
||||
currentSampleRate = cr;
|
||||
}
|
||||
updateClockSources();
|
||||
currentSampleRate = getSampleRate();
|
||||
|
||||
error = String::empty;
|
||||
err = 0;
|
||||
buffersCreated = false;
|
||||
|
||||
if (currentSampleRate != sampleRate)
|
||||
{
|
||||
JUCE_ASIO_LOG ("rate change: " + String (currentSampleRate) + " to " + String (sampleRate));
|
||||
err = asioObject->setSampleRate (sampleRate);
|
||||
|
||||
if (err == ASE_NoClock && numSources > 0)
|
||||
{
|
||||
JUCE_ASIO_LOG ("trying to set a clock source..");
|
||||
Thread::sleep (10);
|
||||
err = asioObject->setClockSource (clocks[0].index);
|
||||
JUCE_ASIO_LOG_ERROR ("setClockSource2", err);
|
||||
|
||||
Thread::sleep (10);
|
||||
err = asioObject->setSampleRate (sampleRate);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
currentSampleRate = sampleRate;
|
||||
|
||||
// on fail, ignore the attempt to change rate, and run with the current one..
|
||||
}
|
||||
setSampleRate (sampleRate);
|
||||
|
||||
if (needToReset)
|
||||
{
|
||||
|
|
@ -652,12 +558,7 @@ public:
|
|||
outputFormat[i].clear (bufferInfos [numActiveInputChans + i].buffers[1], currentBlockSizeSamples);
|
||||
}
|
||||
|
||||
inputLatency = outputLatency = 0;
|
||||
|
||||
if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
|
||||
JUCE_ASIO_LOG ("no latencies");
|
||||
else
|
||||
JUCE_ASIO_LOG ("latencies: " + String ((int) outputLatency) + ", " + String ((int) inputLatency));
|
||||
readLatencies();
|
||||
|
||||
asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity);
|
||||
deviceIsOpen = true;
|
||||
|
|
@ -866,6 +767,8 @@ private:
|
|||
Array<int> sampleRates, bufferSizes;
|
||||
long inputLatency, outputLatency;
|
||||
long minSize, maxSize, preferredSize, granularity;
|
||||
ASIOClockSource clocks[32];
|
||||
int numClockSources;
|
||||
|
||||
int volatile currentBlockSizeSamples;
|
||||
int volatile currentBitDepth;
|
||||
|
|
@ -930,6 +833,50 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
int readBufferSizes (int bufferSizeSamples)
|
||||
{
|
||||
minSize = 0;
|
||||
maxSize = 0;
|
||||
granularity = 0;
|
||||
|
||||
long newPreferredSize = 0;
|
||||
|
||||
if (asioObject->getBufferSize (&minSize, &maxSize, &newPreferredSize, &granularity) == ASE_OK)
|
||||
{
|
||||
if (preferredSize != 0 && newPreferredSize != 0 && newPreferredSize != preferredSize)
|
||||
shouldUsePreferredSize = true;
|
||||
|
||||
if (bufferSizeSamples < minSize || bufferSizeSamples > maxSize)
|
||||
shouldUsePreferredSize = true;
|
||||
|
||||
preferredSize = newPreferredSize;
|
||||
}
|
||||
|
||||
// unfortunate workaround for certain drivers which crash if you make
|
||||
// dynamic changes to the buffer size...
|
||||
shouldUsePreferredSize = shouldUsePreferredSize || getName().containsIgnoreCase ("Digidesign");
|
||||
|
||||
if (shouldUsePreferredSize)
|
||||
{
|
||||
JUCE_ASIO_LOG ("Using preferred size for buffer..");
|
||||
long err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity);
|
||||
|
||||
if (err == ASE_OK)
|
||||
{
|
||||
bufferSizeSamples = (int) preferredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferSizeSamples = 1024;
|
||||
JUCE_ASIO_LOG_ERROR ("getBufferSize1", err);
|
||||
}
|
||||
|
||||
shouldUsePreferredSize = false;
|
||||
}
|
||||
|
||||
return bufferSizeSamples;
|
||||
}
|
||||
|
||||
int resetBuffers (const BigInteger& inputChannels,
|
||||
const BigInteger& outputChannels)
|
||||
{
|
||||
|
|
@ -996,6 +943,157 @@ private:
|
|||
bufferSizes.sort (comparator);
|
||||
}
|
||||
|
||||
double getSampleRate() const
|
||||
{
|
||||
double cr = 0;
|
||||
long err = asioObject->getSampleRate (&cr);
|
||||
JUCE_ASIO_LOG_ERROR ("getSampleRate", err);
|
||||
return cr;
|
||||
}
|
||||
|
||||
void setSampleRate (int newRate)
|
||||
{
|
||||
if (currentSampleRate != newRate)
|
||||
{
|
||||
JUCE_ASIO_LOG ("rate change: " + String (currentSampleRate) + " to " + String (newRate));
|
||||
long err = asioObject->setSampleRate (newRate);
|
||||
|
||||
if (err == ASE_NoClock && numClockSources > 0)
|
||||
{
|
||||
JUCE_ASIO_LOG ("trying to set a clock source..");
|
||||
Thread::sleep (10);
|
||||
err = asioObject->setClockSource (clocks[0].index);
|
||||
JUCE_ASIO_LOG_ERROR ("setClockSource2", err);
|
||||
|
||||
Thread::sleep (10);
|
||||
err = asioObject->setSampleRate (newRate);
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
currentSampleRate = newRate;
|
||||
|
||||
// on fail, ignore the attempt to change rate, and run with the current one..
|
||||
}
|
||||
}
|
||||
|
||||
void updateClockSources()
|
||||
{
|
||||
zeromem (clocks, sizeof (clocks));
|
||||
long numSources = numElementsInArray (clocks);
|
||||
asioObject->getClockSources (clocks, &numSources);
|
||||
numClockSources = (int) numSources;
|
||||
|
||||
bool isSourceSet = false;
|
||||
|
||||
// careful not to remove this loop because it does more than just logging!
|
||||
for (int i = 0; i < numClockSources; ++i)
|
||||
{
|
||||
String s ("clock: ");
|
||||
s += clocks[i].name;
|
||||
|
||||
if (clocks[i].isCurrentSource)
|
||||
{
|
||||
isSourceSet = true;
|
||||
s << " (cur)";
|
||||
}
|
||||
|
||||
JUCE_ASIO_LOG (s);
|
||||
}
|
||||
|
||||
if (numClockSources > 1 && ! isSourceSet)
|
||||
{
|
||||
JUCE_ASIO_LOG ("setting clock source");
|
||||
long err = asioObject->setClockSource (clocks[0].index);
|
||||
JUCE_ASIO_LOG_ERROR ("setClockSource1", err);
|
||||
Thread::sleep (20);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numClockSources == 0)
|
||||
JUCE_ASIO_LOG ("no clock sources!");
|
||||
}
|
||||
}
|
||||
|
||||
void readLatencies()
|
||||
{
|
||||
inputLatency = outputLatency = 0;
|
||||
|
||||
if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
|
||||
JUCE_ASIO_LOG ("getLatencies() failed");
|
||||
else
|
||||
JUCE_ASIO_LOG ("Latencies: in = " + String ((int) inputLatency) + ", out = " + String ((int) outputLatency));
|
||||
}
|
||||
|
||||
void createDummyBuffers (long preferredSize)
|
||||
{
|
||||
numActiveInputChans = 0;
|
||||
numActiveOutputChans = 0;
|
||||
|
||||
ASIOBufferInfo* info = bufferInfos;
|
||||
int numChans = 0;
|
||||
|
||||
for (int i = 0; i < jmin (2, (int) totalNumInputChans); ++i)
|
||||
{
|
||||
info->isInput = 1;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = nullptr;
|
||||
++info;
|
||||
++numChans;
|
||||
}
|
||||
|
||||
const int outputBufferIndex = numChans;
|
||||
|
||||
for (int i = 0; i < jmin (2, (int) totalNumOutputChans); ++i)
|
||||
{
|
||||
info->isInput = 0;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = nullptr;
|
||||
++info;
|
||||
++numChans;
|
||||
}
|
||||
|
||||
setCallbackFunctions();
|
||||
|
||||
JUCE_ASIO_LOG ("creating buffers (dummy): " + String (numChans) + ", " + String ((int) preferredSize));
|
||||
|
||||
if (preferredSize > 0)
|
||||
{
|
||||
long err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks);
|
||||
JUCE_ASIO_LOG_ERROR ("dummy buffers", err);
|
||||
}
|
||||
|
||||
long newInps = 0, newOuts = 0;
|
||||
asioObject->getChannels (&newInps, &newOuts);
|
||||
|
||||
if (totalNumInputChans != newInps || totalNumOutputChans != newOuts)
|
||||
{
|
||||
totalNumInputChans = newInps;
|
||||
totalNumOutputChans = newOuts;
|
||||
|
||||
JUCE_ASIO_LOG (String ((int) totalNumInputChans) + " in; " + String ((int) totalNumOutputChans) + " out");
|
||||
}
|
||||
|
||||
updateSampleRates();
|
||||
reloadChannelNames();
|
||||
|
||||
for (int i = 0; i < totalNumOutputChans; ++i)
|
||||
{
|
||||
ASIOChannelInfo channelInfo = { 0 };
|
||||
channelInfo.channel = i;
|
||||
channelInfo.isInput = 0;
|
||||
asioObject->getChannelInfo (&channelInfo);
|
||||
|
||||
outputFormat[i] = ASIOSampleFormat (channelInfo.type);
|
||||
|
||||
if (i < 2)
|
||||
{
|
||||
// clear the channels that are used with the dummy stuff
|
||||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[0], preferredSize);
|
||||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[1], preferredSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeCurrentDriver()
|
||||
{
|
||||
if (asioObject != nullptr)
|
||||
|
|
@ -1115,16 +1213,15 @@ private:
|
|||
{
|
||||
addBufferSizes (minSize, maxSize, preferredSize, granularity);
|
||||
|
||||
double currentRate = 0;
|
||||
asioObject->getSampleRate (¤tRate);
|
||||
double currentRate = getSampleRate();
|
||||
|
||||
if (currentRate <= 0.0 || currentRate > 192001.0)
|
||||
if (currentRate < 1.0 || currentRate > 192001.0)
|
||||
{
|
||||
JUCE_ASIO_LOG ("setting sample rate");
|
||||
JUCE_ASIO_LOG ("setting default sample rate");
|
||||
err = asioObject->setSampleRate (44100.0);
|
||||
JUCE_ASIO_LOG_ERROR ("setting sample rate", err);
|
||||
|
||||
asioObject->getSampleRate (¤tRate);
|
||||
currentRate = getSampleRate();
|
||||
}
|
||||
|
||||
currentSampleRate = currentRate;
|
||||
|
|
@ -1135,85 +1232,11 @@ private:
|
|||
|
||||
updateSampleRates();
|
||||
|
||||
// ..because cubase does it at this point
|
||||
inputLatency = outputLatency = 0;
|
||||
if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
|
||||
JUCE_ASIO_LOG ("no latencies");
|
||||
|
||||
JUCE_ASIO_LOG ("latencies: " + String ((int) inputLatency) + ", " + String ((int) outputLatency));
|
||||
|
||||
// create some dummy buffers now.. because cubase does..
|
||||
numActiveInputChans = 0;
|
||||
numActiveOutputChans = 0;
|
||||
|
||||
ASIOBufferInfo* info = bufferInfos;
|
||||
int numChans = 0;
|
||||
|
||||
for (int i = 0; i < jmin (2, (int) totalNumInputChans); ++i)
|
||||
{
|
||||
info->isInput = 1;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = nullptr;
|
||||
++info;
|
||||
++numChans;
|
||||
}
|
||||
|
||||
const int outputBufferIndex = numChans;
|
||||
|
||||
for (int i = 0; i < jmin (2, (int) totalNumOutputChans); ++i)
|
||||
{
|
||||
info->isInput = 0;
|
||||
info->channelNum = i;
|
||||
info->buffers[0] = info->buffers[1] = nullptr;
|
||||
++info;
|
||||
++numChans;
|
||||
}
|
||||
|
||||
setCallbackFunctions();
|
||||
|
||||
JUCE_ASIO_LOG ("creating buffers (dummy): " + String (numChans) + ", " + String ((int) preferredSize));
|
||||
|
||||
if (preferredSize > 0)
|
||||
{
|
||||
err = asioObject->createBuffers (bufferInfos, numChans, preferredSize, &callbacks);
|
||||
JUCE_ASIO_LOG_ERROR ("dummy buffers", err);
|
||||
}
|
||||
|
||||
long newInps = 0, newOuts = 0;
|
||||
asioObject->getChannels (&newInps, &newOuts);
|
||||
|
||||
if (totalNumInputChans != newInps || totalNumOutputChans != newOuts)
|
||||
{
|
||||
totalNumInputChans = newInps;
|
||||
totalNumOutputChans = newOuts;
|
||||
|
||||
JUCE_ASIO_LOG (String ((int) totalNumInputChans) + " in; " + String ((int) totalNumOutputChans) + " out");
|
||||
}
|
||||
|
||||
updateSampleRates();
|
||||
|
||||
reloadChannelNames();
|
||||
|
||||
for (int i = 0; i < totalNumOutputChans; ++i)
|
||||
{
|
||||
ASIOChannelInfo channelInfo = { 0 };
|
||||
channelInfo.channel = i;
|
||||
channelInfo.isInput = 0;
|
||||
asioObject->getChannelInfo (&channelInfo);
|
||||
|
||||
outputFormat[i] = ASIOSampleFormat (channelInfo.type);
|
||||
|
||||
if (i < 2)
|
||||
{
|
||||
// clear the channels that are used with the dummy stuff
|
||||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[0], preferredSize);
|
||||
outputFormat[i].clear (bufferInfos [outputBufferIndex + i].buffers[1], preferredSize);
|
||||
}
|
||||
}
|
||||
readLatencies(); // ..doing these steps because cubase does so at this stage
|
||||
createDummyBuffers (preferredSize); // in initialisation, and some devices fail if we don't.
|
||||
readLatencies();
|
||||
|
||||
// start and stop because cubase does it..
|
||||
asioObject->getLatencies (&inputLatency, &outputLatency);
|
||||
|
||||
err = asioObject->start();
|
||||
// ignore an error here, as it might start later after setting other stuff up
|
||||
JUCE_ASIO_LOG_ERROR ("start", err);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue