diff --git a/build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp b/build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp index 0b67c1e482..1af1458ee4 100644 --- a/build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp +++ b/build/macosx/platform_specific_code/juce_mac_CoreAudio.cpp @@ -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; } diff --git a/build/win32/platform_specific_code/juce_win32_ASIO.cpp b/build/win32/platform_specific_code/juce_win32_ASIO.cpp index 16b64de326..e0ca308694 100644 --- a/build/win32/platform_specific_code/juce_win32_ASIO.cpp +++ b/build/win32/platform_specific_code/juce_win32_ASIO.cpp @@ -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 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 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; diff --git a/build/win32/platform_specific_code/juce_win32_DirectSound.cpp b/build/win32/platform_specific_code/juce_win32_DirectSound.cpp index 039ac9053d..74b9878779 100644 --- a/build/win32/platform_specific_code/juce_win32_DirectSound.cpp +++ b/build/win32/platform_specific_code/juce_win32_DirectSound.cpp @@ -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); diff --git a/docs/JUCE changelist.txt b/docs/JUCE changelist.txt index 4ba7eaf981..d5572c417f 100644 --- a/docs/JUCE changelist.txt +++ b/docs/JUCE changelist.txt @@ -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 diff --git a/docs/JUCE readme.html b/docs/JUCE readme.html index 40d7f56ed6..8a669a64c8 100644 --- a/docs/JUCE readme.html +++ b/docs/JUCE readme.html @@ -194,7 +194,8 @@ your "External Frameworks and Libraries" list, or to add switch to the linker's or "-ljucedebug".
  • 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: -
    Carbon.framework
    +
    Cocoa.framework
    +Carbon.framework
     IOKit.framework
     CoreAudio.framework
     CoreMIDI.framework
    diff --git a/src/juce_appframework/audio/devices/juce_AudioIODevice.h b/src/juce_appframework/audio/devices/juce_AudioIODevice.h
    index f62c126215..b70b9ee4c0 100644
    --- a/src/juce_appframework/audio/devices/juce_AudioIODevice.h
    +++ b/src/juce_appframework/audio/devices/juce_AudioIODevice.h
    @@ -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.