Browse Source

tags/2021-05-28
jules 17 years ago
parent
commit
ec4c0a5985
6 changed files with 396 additions and 443 deletions
  1. +18
    -20
      build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp
  2. +290
    -273
      build/win32/platform_specific_code/juce_win32_ASIO.cpp
  3. +70
    -133
      build/win32/platform_specific_code/juce_win32_DirectSound.cpp
  4. +1
    -0
      docs/JUCE changelist.txt
  5. +2
    -1
      docs/JUCE readme.html
  6. +15
    -16
      src/juce_appframework/audio/devices/juce_AudioIODevice.h

+ 18
- 20
build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp View File

@@ -140,13 +140,11 @@ public:
int count = 0;
int i;
for (i = maxNumChans; --i >= 0;)
if (activeInputChans[i])
tempInputBuffers[i] = audioBuffer + count++ * numSamples;
for (i = 0; i < numInputChans; ++i)
tempInputBuffers[i] = audioBuffer + count++ * numSamples;
for (i = maxNumChans; --i >= 0;)
if (activeOutputChans[i])
tempOutputBuffers[i] = audioBuffer + count++ * numSamples;
for (i = 0; i < numOutputChans; ++i)
tempOutputBuffers[i] = audioBuffer + count++ * numSamples;
}
// returns the number of actual available channels
@@ -424,8 +422,17 @@ public:
activeInputChans = inputChannels;
activeOutputChans = outputChannels;
numInputChans = inputChannels.countNumberOfSetBits();
numOutputChans = outputChannels.countNumberOfSetBits();
activeInputChans.setRange (inChanNames.size(),
activeInputChans.getHighestBit() + 1 - inChanNames.size(),
false);
activeOutputChans.setRange (outChanNames.size(),
activeOutputChans.getHighestBit() + 1 - outChanNames.size(),
false);
numInputChans = activeInputChans.countNumberOfSetBits();
numOutputChans = activeOutputChans.countNumberOfSetBits();
// set sample rate
Float64 sr = newSampleRate;
@@ -461,17 +468,6 @@ public:
if (bufferSizes.size() == 0)
error = "Device has no available buffer-sizes";
numInputChans = jmin (numInputChans, numInputChannelInfos);
numOutputChans = jmin (numOutputChans, numOutputChannelInfos);
activeInputChans.setRange (inChanNames.size(),
activeInputChans.getHighestBit() + 1 - inChanNames.size(),
false);
activeOutputChans.setRange (outChanNames.size(),
activeOutputChans.getHighestBit() + 1 - outChanNames.size(),
false);
if (inputDevice != 0 && error.isEmpty())
error = inputDevice->reopen (inputChannels,
outputChannels,
@@ -703,7 +699,9 @@ public:
const bool thisIsInput = inChanNames.size() > 0 && outChanNames.size() == 0;
const bool otherIsInput = result->inChanNames.size() > 0 && result->outChanNames.size() == 0;
if (thisIsInput != otherIsInput)
if (thisIsInput != otherIsInput
|| (inChanNames.size() + outChanNames.size() == 0)
|| (result->inChanNames.size() + result->outChanNames.size()) == 0)
break;
}


+ 290
- 273
build/win32/platform_specific_code/juce_win32_ASIO.cpp View File

@@ -113,18 +113,10 @@ static void logError (const String& context, long error)
//==============================================================================
class ASIOAudioIODevice;
static ASIOAudioIODevice* volatile currentASIODev = 0;
static IASIO* volatile asioObject = 0;
static ASIOAudioIODevice* volatile currentASIODev[3] = { 0, 0, 0 };
static const int maxASIOChannels = 160;
static ASIOCallbacks callbacks;
static ASIOBufferInfo bufferInfos[64];
static bool volatile insideControlPanelModalLoop = false;
static bool volatile shouldUsePreferredSize = false;
//==============================================================================
class JUCE_API ASIOAudioIODevice : public AudioIODevice,
@@ -134,47 +126,42 @@ class JUCE_API ASIOAudioIODevice : public AudioIODevice,
public:
Component ourWindow;
ASIOAudioIODevice (const String& name_, CLSID classId_)
ASIOAudioIODevice (const String& name_, const CLSID classId_, const int slotNumber)
: AudioIODevice (name_, T("ASIO")),
Thread ("Juce ASIO"),
asioObject (0),
classId (classId_),
currentBitDepth (16),
currentSampleRate (0),
tempBuffer (0),
isOpen_ (false),
isStarted (false),
postOutput (true)
postOutput (true),
insideControlPanelModalLoop (false),
shouldUsePreferredSize (false)
{
name = name_;
ourWindow.addToDesktop (0);
windowHandle = ourWindow.getWindowHandle();
jassert (currentASIODev == 0);
currentASIODev = this;
shouldUseThread = false;
jassert (currentASIODev [slotNumber] == 0);
currentASIODev [slotNumber] = this;
openDevice();
}
~ASIOAudioIODevice()
{
jassert (currentASIODev == this);
if (currentASIODev == this)
currentASIODev = 0;
for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
if (currentASIODev[i] == this)
currentASIODev[i] = 0;
close();
log ("ASIO - exiting");
removeCurrentDriver();
juce_free (tempBuffer);
if (isUsingThread)
{
signalThreadShouldExit();
event1.signal();
stopThread (3000);
}
}
void updateSampleRates()
@@ -314,6 +301,8 @@ public:
currentBlockSizeSamples = bufferSizeSamples;
currentChansOut.clear();
currentChansIn.clear();
zeromem (inBuffers, sizeof (inBuffers));
zeromem (outBuffers, sizeof (outBuffers));
updateSampleRates();
@@ -429,7 +418,7 @@ public:
ASIOBufferInfo* info = bufferInfos;
int i;
for (i = 0; i < numInputs; ++i)
for (i = 0; i < totalNumInputChans; ++i)
{
if (inputChannels[i])
{
@@ -442,7 +431,7 @@ public:
}
}
for (i = 0; i < numOutputs; ++i)
for (i = 0; i < totalNumOutputChans; ++i)
{
if (outputChannels[i])
{
@@ -457,10 +446,30 @@ public:
const int totalBuffers = numActiveInputChans + numActiveOutputChans;
callbacks.bufferSwitch = &bufferSwitchCallback;
callbacks.sampleRateDidChange = &sampleRateChangedCallback;
callbacks.asioMessage = &asioMessagesCallback;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback;
if (currentASIODev[0] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback0;
callbacks.asioMessage = &asioMessagesCallback0;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0;
}
else if (currentASIODev[1] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback1;
callbacks.asioMessage = &asioMessagesCallback1;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1;
}
else if (currentASIODev[2] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback2;
callbacks.asioMessage = &asioMessagesCallback2;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2;
}
else
{
jassertfalse
}
log ("disposing buffers");
err = asioObject->disposeBuffers();
@@ -497,11 +506,11 @@ public:
Array <int> types;
currentBitDepth = 16;
for (i = 0; i < jmin (numInputs, maxASIOChannels); ++i)
for (i = 0; i < jmin (totalNumInputChans, maxASIOChannels); ++i)
{
if (inputChannels[i])
{
inBuffers[i] = tempBuffer + (currentBlockSizeSamples * n++);
inBuffers[n] = tempBuffer + (currentBlockSizeSamples * n);
ASIOChannelInfo channelInfo;
zerostruct (channelInfo);
@@ -512,24 +521,25 @@ public:
types.addIfNotAlreadyThere (channelInfo.type);
typeToFormatParameters (channelInfo.type,
inputChannelBitDepths[i],
inputChannelBytesPerSample[i],
inputChannelIsFloat[i],
inputChannelLittleEndian[i]);
inputChannelBitDepths[n],
inputChannelBytesPerSample[n],
inputChannelIsFloat[n],
inputChannelLittleEndian[n]);
currentBitDepth = jmax (currentBitDepth, inputChannelBitDepths[i]);
}
else
{
inBuffers[i] = 0;
currentBitDepth = jmax (currentBitDepth, inputChannelBitDepths[n]);
++n;
}
}
for (i = 0; i < jmin (numOutputs, maxASIOChannels); ++i)
jassert (numActiveInputChans == n);
n = 0;
for (i = 0; i < jmin (totalNumOutputChans, maxASIOChannels); ++i)
{
if (outputChannels[i])
{
outBuffers[i] = tempBuffer + (currentBlockSizeSamples * n++);
outBuffers[n] = tempBuffer + (currentBlockSizeSamples * (numActiveInputChans + n));
ASIOChannelInfo channelInfo;
zerostruct (channelInfo);
@@ -540,19 +550,19 @@ public:
types.addIfNotAlreadyThere (channelInfo.type);
typeToFormatParameters (channelInfo.type,
outputChannelBitDepths[i],
outputChannelBytesPerSample[i],
outputChannelIsFloat[i],
outputChannelLittleEndian[i]);
outputChannelBitDepths[n],
outputChannelBytesPerSample[n],
outputChannelIsFloat[n],
outputChannelLittleEndian[n]);
currentBitDepth = jmax (currentBitDepth, outputChannelBitDepths[i]);
}
else
{
outBuffers[i] = 0;
currentBitDepth = jmax (currentBitDepth, outputChannelBitDepths[n]);
++n;
}
}
jassert (numActiveOutputChans == n);
for (i = types.size(); --i >= 0;)
{
log (T("channel format: ") + String (types[i]));
@@ -560,30 +570,22 @@ public:
jassert (n <= totalBuffers);
n = numActiveInputChans;
for (i = 0; i < numOutputs; ++i)
for (i = 0; i < numActiveOutputChans; ++i)
{
if (outputChannels[i])
{
const int size = currentBlockSizeSamples * (outputChannelBitDepths[i] >> 3);
const int size = currentBlockSizeSamples * (outputChannelBitDepths[i] >> 3);
if (bufferInfos[n].buffers[0] == 0
|| bufferInfos[n].buffers[1] == 0)
{
log ("!! Null buffers");
}
else
{
zeromem (bufferInfos[n].buffers[0], size);
zeromem (bufferInfos[n].buffers[1], size);
}
++n;
if (bufferInfos [numActiveInputChans + i].buffers[0] == 0
|| bufferInfos [numActiveInputChans + i].buffers[1] == 0)
{
log ("!! Null buffers");
}
else
{
zeromem (bufferInfos[numActiveInputChans + i].buffers[0], size);
zeromem (bufferInfos[numActiveInputChans + i].buffers[1], size);
}
}
jassert (n <= totalBuffers);
inputLatency = outputLatency = 0;
if (asioObject->getLatencies (&inputLatency, &outputLatency) != 0)
@@ -601,56 +603,32 @@ public:
isOpen_ = true;
isThreadReady = false;
if (isUsingThread)
{
event1.wait (1); // reset the event in case it was flipped by a callback from the ASIO->start call in openDevice()
startThread (8);
int count = 5000;
while (--count > 0 && ! isThreadReady)
sleep (1);
}
log ("starting ASIO");
calledback = false;
err = asioObject->start();
if (isUsingThread && ! isThreadRunning())
if (err != 0)
{
error = "Can't start thread!";
isOpen_ = false;
log ("ASIO - stop on failure");
Thread::sleep (10);
asioObject->stop();
error = "Can't start device";
Thread::sleep (10);
}
else
{
log ("starting ASIO");
calledback = false;
err = asioObject->start();
if (err != 0)
{
if (isUsingThread)
{
signalThreadShouldExit();
event1.signal();
stopThread (3000);
}
isOpen_ = false;
log ("ASIO - stop on failure");
int count = 300;
while (--count > 0 && ! calledback)
Thread::sleep (10);
asioObject->stop();
error = "Can't start device";
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";
log ("ASIO didn't callback - stopping..");
asioObject->stop();
}
if (! calledback)
{
error = "Device didn't start correctly";
log ("ASIO didn't callback - stopping..");
asioObject->stop();
}
}
}
@@ -694,13 +672,6 @@ public:
{
const ScopedLock sl (callbackLock);
if (isUsingThread)
{
signalThreadShouldExit();
event1.signal();
stopThread (3000);
}
isOpen_ = false;
isStarted = false;
needToReset = false;
@@ -786,9 +757,7 @@ public:
bool isPlaying()
{
return isASIOOpen
&& (isThreadRunning() || ! isUsingThread)
&& (currentCallback != 0);
return isASIOOpen && (currentCallback != 0);
}
const String getLastError()
@@ -796,11 +765,6 @@ public:
return error;
}
void setUsingThread (bool b)
{
shouldUseThread = b;
}
bool hasControlPanel() const
{
return true;
@@ -907,12 +871,15 @@ public:
private:
//==============================================================================
IASIO* volatile asioObject;
ASIOCallbacks callbacks;
void* windowHandle;
CLSID classId;
String error;
long numInputs, numOutputs;
StringArray outputChannelNames, inputChannelNames;
long totalNumInputChans, totalNumOutputChans;
StringArray inputChannelNames, outputChannelNames;
Array<int> sampleRates, bufferSizes;
long inputLatency, outputLatency;
@@ -925,30 +892,33 @@ private:
AudioIODeviceCallback* volatile currentCallback;
CriticalSection callbackLock;
float* inBuffers[maxASIOChannels];
float* outBuffers[maxASIOChannels];
int inputChannelBitDepths[maxASIOChannels];
int outputChannelBitDepths[maxASIOChannels];
int inputChannelBytesPerSample[maxASIOChannels];
int outputChannelBytesPerSample[maxASIOChannels];
bool inputChannelIsFloat[maxASIOChannels];
bool outputChannelIsFloat[maxASIOChannels];
bool inputChannelLittleEndian[maxASIOChannels];
bool outputChannelLittleEndian[maxASIOChannels];
ASIOBufferInfo bufferInfos [maxASIOChannels];
float* inBuffers [maxASIOChannels];
float* outBuffers [maxASIOChannels];
int inputChannelBitDepths [maxASIOChannels];
int outputChannelBitDepths [maxASIOChannels];
int inputChannelBytesPerSample [maxASIOChannels];
int outputChannelBytesPerSample [maxASIOChannels];
bool inputChannelIsFloat [maxASIOChannels];
bool outputChannelIsFloat [maxASIOChannels];
bool inputChannelLittleEndian [maxASIOChannels];
bool outputChannelLittleEndian [maxASIOChannels];
WaitableEvent event1;
float* tempBuffer;
int volatile bufferIndex, numActiveInputChans, numActiveOutputChans;
bool isOpen_, isStarted;
bool isUsingThread, shouldUseThread;
bool volatile isASIOOpen;
bool volatile calledback;
bool volatile littleEndian, postOutput, needToReset, isReSync, isThreadReady;
bool volatile insideControlPanelModalLoop;
bool volatile shouldUsePreferredSize;
//==============================================================================
static void removeCurrentDriver()
void removeCurrentDriver()
{
if (asioObject != 0)
{
@@ -1006,8 +976,6 @@ private:
modalWindow.addToDesktop (0);
modalWindow.enterModalState();
isUsingThread = shouldUseThread;
// open the device and get its info..
log (T("opening ASIO device: ") + getName());
@@ -1019,8 +987,10 @@ private:
sampleRates.clear();
isASIOOpen = false;
isOpen_ = false;
numInputs = 0;
numOutputs = 0;
totalNumInputChans = 0;
totalNumOutputChans = 0;
numActiveInputChans = 0;
numActiveOutputChans = 0;
currentCallback = 0;
error = String::empty;
@@ -1032,17 +1002,17 @@ private:
if (loadDriver())
{
String driverName;
if ((error = initDriver()).isEmpty())
{
numInputs = 0;
numOutputs = 0;
numActiveInputChans = 0;
numActiveOutputChans = 0;
totalNumInputChans = 0;
totalNumOutputChans = 0;
if (asioObject != 0
&& (err = asioObject->getChannels (&numInputs, &numOutputs)) == 0)
&& (err = asioObject->getChannels (&totalNumInputChans, &totalNumOutputChans)) == 0)
{
log (String ((int) numInputs) + T(" in, ") + String ((int) numOutputs) + T(" out"));
log (String ((int) totalNumInputChans) + T(" in, ") + String ((int) totalNumOutputChans) + T(" out"));
if ((err = asioObject->getBufferSize (&minSize, &maxSize, &preferredSize, &granularity)) == 0)
{
@@ -1112,7 +1082,7 @@ private:
ASIOBufferInfo* info = bufferInfos;
int i, numChans = 0;
for (i = 0; i < jmin (2, numInputs); ++i)
for (i = 0; i < jmin (2, totalNumInputChans); ++i)
{
info->isInput = 1;
info->channelNum = i;
@@ -1123,7 +1093,7 @@ private:
const int outputBufferIndex = numChans;
for (i = 0; i < jmin (2, numOutputs); ++i)
for (i = 0; i < jmin (2, totalNumOutputChans); ++i)
{
info->isInput = 0;
info->channelNum = i;
@@ -1132,10 +1102,31 @@ private:
++numChans;
}
callbacks.bufferSwitch = &bufferSwitchCallback;
callbacks.sampleRateDidChange = &sampleRateChangedCallback;
callbacks.asioMessage = &asioMessagesCallback;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback;
if (currentASIODev[0] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback0;
callbacks.asioMessage = &asioMessagesCallback0;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback0;
}
else if (currentASIODev[1] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback1;
callbacks.asioMessage = &asioMessagesCallback1;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback1;
}
else if (currentASIODev[2] == this)
{
callbacks.bufferSwitch = &bufferSwitchCallback2;
callbacks.asioMessage = &asioMessagesCallback2;
callbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfoCallback2;
}
else
{
jassertfalse
}
log (T("creating buffers (dummy): ") + String (numChans)
+ T(", ") + String ((int) preferredSize));
@@ -1152,13 +1143,13 @@ private:
long newInps = 0, newOuts = 0;
asioObject->getChannels (&newInps, &newOuts);
if (numInputs != newInps || numOutputs != newOuts)
if (totalNumInputChans != newInps || totalNumOutputChans != newOuts)
{
numInputs = newInps;
numOutputs = newOuts;
totalNumInputChans = newInps;
totalNumOutputChans = newOuts;
log (String ((int) numInputs) + T(" in; ")
+ String ((int) numOutputs) + T(" out"));
log (String ((int) totalNumInputChans) + T(" in; ")
+ String ((int) totalNumOutputChans) + T(" out"));
}
updateSampleRates();
@@ -1166,7 +1157,7 @@ private:
ASIOChannelInfo channelInfo;
channelInfo.type = 0;
for (i = 0; i < numInputs; ++i)
for (i = 0; i < totalNumInputChans; ++i)
{
zerostruct (channelInfo);
channelInfo.channel = i;
@@ -1176,7 +1167,7 @@ private:
inputChannelNames.add (String (channelInfo.name));
}
for (i = 0; i < numOutputs; ++i)
for (i = 0; i < totalNumOutputChans; ++i)
{
zerostruct (channelInfo);
channelInfo.channel = i;
@@ -1262,18 +1253,7 @@ private:
if (isStarted)
{
bufferIndex = index;
if (isUsingThread) // if not started, just use processBuffer() to clear the buffers directly
{
event1.signal();
if (postOutput && (! isThreadRunning()) && asioObject != 0)
asioObject->outputReady();
}
else
{
processBuffer();
}
processBuffer();
}
else
{
@@ -1312,117 +1292,99 @@ private:
if (currentCallback != 0)
{
int n = 0;
int i;
for (i = 0; i < numInputs; ++i)
for (i = 0; i < numActiveInputChans; ++i)
{
float* const dst = inBuffers[i];
if (dst != 0)
jassert (dst != 0);
const char* const src = (const char*) (infos[i].buffers[bi]);
if (inputChannelIsFloat[i])
{
memcpy (dst, src, samps * sizeof (float));
}
else
{
const char* const src = (const char*) (infos[n].buffers[bi]);
jassert (dst == tempBuffer + (samps * i));
if (inputChannelIsFloat[i])
{
memcpy (dst, src, samps * sizeof (float));
}
else
switch (inputChannelBitDepths[i])
{
jassert (dst == tempBuffer + (samps * n));
switch (inputChannelBitDepths[i])
{
case 16:
convertInt16ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 24:
convertInt24ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 32:
convertInt32ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 64:
jassertfalse
break;
}
case 16:
convertInt16ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 24:
convertInt24ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 32:
convertInt32ToFloat (src, dst, inputChannelBytesPerSample[i],
samps, inputChannelLittleEndian[i]);
break;
case 64:
jassertfalse
break;
}
++n;
}
}
currentCallback->audioDeviceIOCallback ((const float**) inBuffers,
numInputs,
numActiveInputChans,
outBuffers,
numOutputs,
numActiveOutputChans,
samps);
for (i = 0; i < numOutputs; ++i)
for (i = 0; i < numActiveOutputChans; ++i)
{
float* const src = outBuffers[i];
if (src != 0)
jassert (src != 0);
char* const dst = (char*) (infos [numActiveInputChans + i].buffers[bi]);
if (outputChannelIsFloat[i])
{
memcpy (dst, src, samps * sizeof (float));
}
else
{
char* const dst = (char*) (infos[n].buffers[bi]);
jassert (src == tempBuffer + (samps * (numActiveInputChans + i)));
if (outputChannelIsFloat[i])
switch (outputChannelBitDepths[i])
{
memcpy (dst, src, samps * sizeof (float));
case 16:
convertFloatToInt16 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 24:
convertFloatToInt24 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 32:
convertFloatToInt32 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 64:
jassertfalse
break;
}
else
{
jassert (src == tempBuffer + (samps * n));
switch (outputChannelBitDepths[i])
{
case 16:
convertFloatToInt16 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 24:
convertFloatToInt24 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 32:
convertFloatToInt32 (src, dst, outputChannelBytesPerSample[i],
samps, outputChannelLittleEndian[i]);
break;
case 64:
jassertfalse
break;
}
}
++n;
}
}
}
else
{
int n = 0;
int i;
for (i = 0; i < numInputs; ++i)
if (inBuffers[i] != 0)
++n;
for (i = 0; i < numOutputs; ++i)
for (int i = 0; i < numActiveOutputChans; ++i)
{
if (outBuffers[i] != 0)
{
const int bytesPerBuffer = samps * (outputChannelBitDepths[i] >> 3);
zeromem (infos[n].buffers[bi], bytesPerBuffer);
++n;
}
const int bytesPerBuffer = samps * (outputChannelBitDepths[i] >> 3);
zeromem (infos[numActiveInputChans + i].buffers[bi], bytesPerBuffer);
}
}
}
@@ -1432,21 +1394,65 @@ private:
}
//==============================================================================
static ASIOTime* bufferSwitchTimeInfoCallback (ASIOTime*, long index, long) throw()
static ASIOTime* bufferSwitchTimeInfoCallback0 (ASIOTime*, long index, long) throw()
{
if (currentASIODev[0] != 0)
currentASIODev[0]->callback (index);
return 0;
}
static ASIOTime* bufferSwitchTimeInfoCallback1 (ASIOTime*, long index, long) throw()
{
if (currentASIODev[1] != 0)
currentASIODev[1]->callback (index);
return 0;
}
static ASIOTime* bufferSwitchTimeInfoCallback2 (ASIOTime*, long index, long) throw()
{
if (currentASIODev != 0)
currentASIODev->callback (index);
if (currentASIODev[2] != 0)
currentASIODev[2]->callback (index);
return 0;
}
static void bufferSwitchCallback (long index, long) throw()
static void bufferSwitchCallback0 (long index, long) throw()
{
if (currentASIODev != 0)
currentASIODev->callback (index);
if (currentASIODev[0] != 0)
currentASIODev[0]->callback (index);
}
static long asioMessagesCallback (long selector, long value, void*, double*) throw()
static void bufferSwitchCallback1 (long index, long) throw()
{
if (currentASIODev[1] != 0)
currentASIODev[1]->callback (index);
}
static void bufferSwitchCallback2 (long index, long) throw()
{
if (currentASIODev[2] != 0)
currentASIODev[2]->callback (index);
}
static long asioMessagesCallback0 (long selector, long value, void*, double*) throw()
{
return asioMessagesCallback (selector, value, 0);
}
static long asioMessagesCallback1 (long selector, long value, void*, double*) throw()
{
return asioMessagesCallback (selector, value, 1);
}
static long asioMessagesCallback2 (long selector, long value, void*, double*) throw()
{
return asioMessagesCallback (selector, value, 2);
}
//==============================================================================
static long asioMessagesCallback (long selector, long value, const int deviceIndex) throw()
{
switch (selector)
{
@@ -1463,14 +1469,14 @@ private:
break;
case kAsioResetRequest:
if (currentASIODev != 0)
currentASIODev->resetRequest();
if (currentASIODev[deviceIndex] != 0)
currentASIODev[deviceIndex]->resetRequest();
return 1;
case kAsioResyncRequest:
if (currentASIODev != 0)
currentASIODev->resyncRequest();
if (currentASIODev[deviceIndex] != 0)
currentASIODev[deviceIndex]->resyncRequest();
return 1;
@@ -1827,11 +1833,22 @@ public:
if (index >= 0)
{
jassert (currentASIODev == 0); // unfortunately you can't have more than one ASIO device
// open at the same time..
int freeSlot = -1;
for (int i = 0; i < numElementsInArray (currentASIODev); ++i)
{
if (currentASIODev[i] == 0)
{
freeSlot = i;
break;
}
}
jassert (freeSlot >= 0); // unfortunately you can only have a finite number
// of ASIO devices open at the same time..
if (currentASIODev == 0)
return new ASIOAudioIODevice (deviceName, *(classIds [index]));
if (freeSlot >= 0)
return new ASIOAudioIODevice (deviceName, *(classIds [index]), freeSlot);
}
return 0;


+ 70
- 133
build/win32/platform_specific_code/juce_win32_DirectSound.cpp View File

@@ -1110,12 +1110,10 @@ public:
int i, bits = 256;
for (i = inChans.size(); --i >= 0;)
if (inChans[i] != 0)
bits = jmin (bits, inChans[i]->bitDepth);
bits = jmin (bits, inChans[i]->bitDepth);
for (i = outChans.size(); --i >= 0;)
if (outChans[i] != 0)
bits = jmin (bits, outChans[i]->bitDepth);
bits = jmin (bits, outChans[i]->bitDepth);
if (bits > 32)
bits = 16;
@@ -1250,18 +1248,10 @@ private:
{
int i;
for (i = outChans.size(); --i >= 0;)
{
DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
if (out != 0)
out->close();
}
outChans.getUnchecked(i)->close();
for (i = inChans.size(); --i >= 0;)
{
DSoundInternalInChannel* const in = inChans.getUnchecked(i);
if (in != 0)
in->close();
}
inChans.getUnchecked(i)->close();
if (threadShouldExit())
return;
@@ -1273,30 +1263,20 @@ private:
SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
for (i = outChans.size(); --i >= 0;)
{
DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
if (out != 0)
out->open();
}
outChans.getUnchecked(i)->open();
for (i = inChans.size(); --i >= 0;)
{
DSoundInternalInChannel* const in = inChans.getUnchecked(i);
if (in != 0)
in->open();
}
inChans.getUnchecked(i)->open();
if (! threadShouldExit())
{
sleep (5);
for (i = 0; i < numOutputBuffers; ++i)
if (outChans[i] != 0)
outChans[i]->synchronisePosition();
for (i = 0; i < outChans.size(); ++i)
outChans.getUnchecked(i)->synchronisePosition();
for (i = 0; i < numInputBuffers; ++i)
if (inChans[i] != 0)
inChans[i]->synchronisePosition();
for (i = 0; i < inChans.size(); ++i)
inChans.getUnchecked(i)->synchronisePosition();
}
SetThreadPriority (GetCurrentThread(), oldThreadPri);
@@ -1323,24 +1303,14 @@ public:
int i;
for (i = inChans.size(); --i >= 0;)
{
DSoundInternalInChannel* const in = inChans.getUnchecked(i);
if (in != 0)
{
in->doneFlag = false;
++numToDo;
}
inChans.getUnchecked(i)->doneFlag = false;
++numToDo;
}
for (i = outChans.size(); --i >= 0;)
{
DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
if (out != 0)
{
out->doneFlag = false;
++numToDo;
}
outChans.getUnchecked(i)->doneFlag = false;
++numToDo;
}
if (numToDo > 0)
@@ -1354,13 +1324,10 @@ public:
{
DSoundInternalInChannel* const in = inChans.getUnchecked(i);
if (in != 0 && !in->doneFlag)
if ((! in->doneFlag) && in->service())
{
if (in->service())
{
in->doneFlag = true;
--numToDo;
}
in->doneFlag = true;
--numToDo;
}
}
@@ -1368,13 +1335,10 @@ public:
{
DSoundInternalOutChannel* const out = outChans.getUnchecked(i);
if (out != 0 && !out->doneFlag)
if ((! out->doneFlag) && out->service())
{
if (out->service())
{
out->doneFlag = true;
--numToDo;
}
out->doneFlag = true;
--numToDo;
}
}
@@ -1649,71 +1613,52 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
DSoundAudioIODeviceType dlh;
dlh.scanForDevices();
numInputBuffers = 2 * dlh.inputDeviceNames.size();
enabledInputs = inputChannels;
numInputBuffers = inputChannels.countNumberOfSetBits();
inputBuffers = new float* [numInputBuffers + 2];
zeromem (inputBuffers, sizeof (inputBuffers));
int i, numIns = 0;
numOutputBuffers = 2 * dlh.outputDeviceNames.size();
outputBuffers = new float* [numOutputBuffers + 2];
int i;
for (i = 0; i < numInputBuffers + 2; ++i)
for (i = 0; i < inputChannels.getHighestBit(); i += 2)
{
if (inputChannels[i] && i < numInputBuffers)
{
inputBuffers[i] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
enabledInputs.setBit (i);
}
else
{
inputBuffers[i] = 0;
}
}
float* left = 0;
float* right = 0;
for (i = 0; i < numOutputBuffers + 2; ++i)
{
if (outputChannels[i] && i < numOutputBuffers)
{
outputBuffers[i] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
enabledOutputs.setBit (i);
}
else
{
outputBuffers[i] = 0;
}
}
if (inputChannels[i])
left = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
for (i = 0; i < numInputBuffers; ++i)
{
if (inputChannels[i] || inputChannels[i + 1])
{
if (inputChannels[i + 1])
right = inputBuffers[numIns++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
if (left != 0 || right != 0)
inChans.add (new DSoundInternalInChannel (dlh.inputDeviceNames [i / 2],
dlh.inputGuids [i / 2],
(int) sampleRate, bufferSizeSamples,
inputBuffers[i], inputBuffers[i + 1]));
}
else
{
inChans.add (0);
}
++i;
left, right));
}
for (i = 0; i < numOutputBuffers; ++i)
enabledOutputs = outputChannels;
numOutputBuffers = outputChannels.countNumberOfSetBits();
outputBuffers = new float* [numOutputBuffers + 2];
zeromem (outputBuffers, sizeof (outputBuffers));
int numOuts = 0;
for (i = 0; i < outputChannels.getHighestBit(); i += 2)
{
if (outputChannels[i] || outputChannels[i + 1])
{
float* left = 0;
float* right = 0;
if (inputChannels[i])
left = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
if (inputChannels[i + 1])
right = outputBuffers[numOuts++] = (float*) juce_calloc ((bufferSizeSamples + 16) * sizeof (float));
if (left != 0 || right != 0)
outChans.add (new DSoundInternalOutChannel (dlh.outputDeviceNames[i / 2],
dlh.outputGuids [i / 2],
(int) sampleRate, bufferSizeSamples,
outputBuffers[i], outputBuffers[i + 1]));
}
else
{
outChans.add (0);
}
++i;
left, right));
}
String error;
@@ -1724,35 +1669,29 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
SetPriorityClass (GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
for (i = 0; i < numOutputBuffers; ++i)
for (i = 0; i < outChans.size(); ++i)
{
if (outChans[i] != 0)
{
error = outChans[i]->open();
error = outChans[i]->open();
if (error.isNotEmpty())
{
error = T("Error opening ") + dlh.outputDeviceNames[i]
+ T(": \"") + error + T("\"");
break;
}
if (error.isNotEmpty())
{
error = T("Error opening ") + dlh.outputDeviceNames[i]
+ T(": \"") + error + T("\"");
break;
}
}
if (error.isEmpty())
{
for (i = 0; i < numInputBuffers; ++i)
for (i = 0; i < inChans.size(); ++i)
{
if (inChans[i] != 0)
{
error = inChans[i]->open();
error = inChans[i]->open();
if (error.isNotEmpty())
{
error = T("Error opening ") + dlh.inputDeviceNames[i]
+ T(": \"") + error + T("\"");
break;
}
if (error.isNotEmpty())
{
error = T("Error opening ") + dlh.inputDeviceNames[i]
+ T(": \"") + error + T("\"");
break;
}
}
}
@@ -1761,13 +1700,11 @@ const String DSoundAudioIODevice::openDevice (const BitArray& inputChannels,
{
totalSamplesOut = 0;
for (i = 0; i < numOutputBuffers; ++i)
if (outChans[i] != 0)
outChans[i]->synchronisePosition();
for (i = 0; i < outChans.size(); ++i)
outChans.getUnchecked(i)->synchronisePosition();
for (i = 0; i < numInputBuffers; ++i)
if (inChans[i] != 0)
inChans[i]->synchronisePosition();
for (i = 0; i < inChans.size(); ++i)
inChans.getUnchecked(i)->synchronisePosition();
startThread (9);
sleep (10);


+ 1
- 0
docs/JUCE changelist.txt View File

@@ -30,6 +30,7 @@ Changelist for version 1.46
- added an option to splash screens to close themselves when the mouse is clicked
- change to ProgressBar to allow custom text and bars that are just spinning without a known progress position. This also meant a change to the params for LookAndFeel::drawProgressBar
- ditched win98 non-unicode support (presumably nobody will miss that!)
- change to the way that channel data is passed to an AudioIODeviceCallback. Previously, some of the channels could be null, but now is uses a packed array of all the active channels

==============================================================================
Changelist for version 1.45


+ 2
- 1
docs/JUCE readme.html View File

@@ -194,7 +194,8 @@ your "External Frameworks and Libraries" list, or to add switch to the linker's
or "-ljucedebug".</li>
<li>You'll also need to add some of the following OSX frameworks to your "External Frameworks and Libraries" list,
depending on what features your application uses:
<pre>Carbon.framework
<pre>Cocoa.framework
Carbon.framework
IOKit.framework
CoreAudio.framework
CoreMIDI.framework


+ 15
- 16
src/juce_appframework/audio/devices/juce_AudioIODevice.h View File

@@ -68,23 +68,22 @@ public:
@param inputChannelData a set of arrays containing the audio data for each
incoming channel - this data is valid until the function
returns. Some members of the array may be null pointers, if
that channel wasn't enabled when the audio device was
opened (see AudioIODevice::open())
@param totalNumInputChannels the total number of pointers to channel data in
the inputChannelData array. Note that not all of these
channels may be active, so some may be null pointers
returns. There will be one channel of data for each input
channel that was enabled when the audio device was opened
(see AudioIODevice::open())
@param numInputChannels the number of pointers to channel data in the
inputChannelData array.
@param outputChannelData a set of arrays which need to be filled with the data
that should be sent to each outgoing channel of the device.
As for the input array, some of these pointers may be null, if
those channels weren't enabled when the audio device was
opened. The contents of the array are undefined, so the
There will be one channel of data for each output channel
that was enabled when the audio device was opened (see
AudioIODevice::open())
The initial contents of the array is undefined, so the
callback function must fill all the channels with zeros if
it wants to output silence - not doing this could cause quite
its output is silence. Failing to do this could cause quite
an unpleasant noise!
@param totalNumOutputChannels the total number of pointers to channel data in
the outputChannelData array. Note that not all of these
channels may be active, so some may be null pointers
@param numOutputChannels the number of pointers to channel data in the
outputChannelData array.
@param numSamples the number of samples in each channel of the input and
output arrays. The number of samples will depend on the
audio device's buffer size and will usually remain constant,
@@ -93,9 +92,9 @@ public:
callback to the next.
*/
virtual void audioDeviceIOCallback (const float** inputChannelData,
int totalNumInputChannels,
int numInputChannels,
float** outputChannelData,
int totalNumOutputChannels,
int numOutputChannels,
int numSamples) = 0;
/** Called to indicate that the device is about to start calling back.
@@ -122,7 +121,7 @@ public:
//==============================================================================
/**
Base class for an audio device with synchoronised input and output channels.
Base class for an audio device with synchronised input and output channels.
Subclasses of this are used to implement different protocols such as DirectSound,
ASIO, CoreAudio, etc.


Loading…
Cancel
Save