diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 8e50b5d836..efd585412f 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -6692,7 +6692,8 @@ public: WebInputStream (const URL& url, const bool isPost_, URL::OpenStreamProgressCallback* const progressCallback_, - void* const progressCallbackContext_) + void* const progressCallbackContext_, + const String& extraHeaders) : position (0), finished (false), isPost (isPost_), @@ -6704,6 +6705,11 @@ public: if (isPost_) createHeadersAndPostData (url); + headers += extraHeaders; + + if (! headers.endsWithChar (T('\n'))) + headers << "\r\n"; + handle = juce_openInternetFile (server, headers, postData, isPost, progressCallback_, progressCallbackContext_); } @@ -6876,10 +6882,12 @@ private: InputStream* URL::createInputStream (const bool usePostCommand, OpenStreamProgressCallback* const progressCallback, - void* const progressCallbackContext) const + void* const progressCallbackContext, + const String& extraHeaders) const { WebInputStream* wi = new WebInputStream (*this, usePostCommand, - progressCallback, progressCallbackContext); + progressCallback, progressCallbackContext, + extraHeaders); if (wi->isError()) { @@ -18253,14 +18261,12 @@ public: #ifdef WIN32 if (InitializeQTML (0) != noErr) return; +#elif JUCE_MAC + EnterMoviesOnThread (0); #endif if (EnterMovies() != noErr) return; -#if JUCE_MAC - EnterMoviesOnThread (0); -#endif - bool opened = juce_OpenQuickTimeMovieFromStream (input_, movie, dataHandle); if (! opened) @@ -18391,6 +18397,10 @@ public: juce_free (bufferList->mBuffers[0].mData); juce_free (bufferList); + +#if JUCE_MAC + ExitMoviesOnThread (); +#endif } bool read (int** destSamples, @@ -19390,7 +19400,9 @@ AudioSourcePlayer::AudioSourcePlayer() : source (0), sampleRate (0), bufferSize (0), - tempBuffer (2, 8) + tempBuffer (2, 8), + lastGain (1.0f), + gain (1.0f) { } @@ -19418,6 +19430,11 @@ void AudioSourcePlayer::setSource (AudioSource* newSource) } } +void AudioSourcePlayer::setGain (const float newGain) throw() +{ + gain = newGain; +} + void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData, int totalNumInputChannels, float** outputChannelData, @@ -19502,6 +19519,11 @@ void AudioSourcePlayer::audioDeviceIOCallback (const float** inputChannelData, info.numSamples = numSamples; source->getNextAudioBlock (info); + + for (int i = info.buffer->getNumChannels(); --i >= 0;) + info.buffer->applyGainRamp (i, info.startSample, info.numSamples, lastGain, gain); + + lastGain = gain; } else { @@ -79422,7 +79444,6 @@ private: uint8* const data; const int stride; uint8* lineStart; - uint8 gammaTable [256]; AlphaBitmapRenderer (const AlphaBitmapRenderer&); const AlphaBitmapRenderer& operator= (const AlphaBitmapRenderer&); @@ -79433,8 +79454,6 @@ private: : data (data_), stride (stride_) { - for (int i = 0; i < 256; ++i) - gammaTable[i] = (uint8) (255.0f * powf (i * (1.0f / 255.0f), 1.2f)); } forcedinline void setEdgeTableYPos (const int y) throw() @@ -79444,7 +79463,7 @@ private: forcedinline void handleEdgeTablePixel (const int x, const int alphaLevel) const throw() { - lineStart [x] = (uint8) gammaTable [alphaLevel]; + lineStart [x] = (uint8) alphaLevel; } forcedinline void handleEdgeTableLine (const int x, int width, const int alphaLevel) const throw() @@ -79452,7 +79471,7 @@ private: uint8* d = lineStart + x; while (--width >= 0) - *d++ = (uint8) gammaTable [alphaLevel]; + *d++ = (uint8) alphaLevel; } }; @@ -79474,7 +79493,7 @@ private: im = new Image (Image::SingleChannel, bitmapWidth, bitmapHeight, true); - EdgeTable edgeTable (0, bitmapHeight, EdgeTable::Oversampling_32times); + EdgeTable edgeTable (0, bitmapHeight, EdgeTable::Oversampling_16times); edgeTable.addPath (path, AffineTransform::scale (xScale, yScale) .translated (subPixelOffsetX - topLeftX, -topLeftY)); @@ -231104,18 +231123,10 @@ static void logError (const String& context, long error) #endif 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, private Thread, private Timer @@ -231123,47 +231134,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() @@ -231303,6 +231309,8 @@ public: currentBlockSizeSamples = bufferSizeSamples; currentChansOut.clear(); currentChansIn.clear(); + zeromem (inBuffers, sizeof (inBuffers)); + zeromem (outBuffers, sizeof (outBuffers)); updateSampleRates(); @@ -231418,7 +231426,7 @@ public: ASIOBufferInfo* info = bufferInfos; int i; - for (i = 0; i < numInputs; ++i) + for (i = 0; i < totalNumInputChans; ++i) { if (inputChannels[i]) { @@ -231431,7 +231439,7 @@ public: } } - for (i = 0; i < numOutputs; ++i) + for (i = 0; i < totalNumOutputChans; ++i) { if (outputChannels[i]) { @@ -231446,10 +231454,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(); @@ -231486,11 +231514,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); @@ -231501,24 +231529,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); @@ -231529,19 +231558,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])); @@ -231549,30 +231578,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); + + if (bufferInfos [numActiveInputChans + i].buffers[0] == 0 + || bufferInfos [numActiveInputChans + i].buffers[1] == 0) { - 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; + 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) @@ -231590,56 +231611,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); + log ("starting ASIO"); + calledback = false; + err = asioObject->start(); - int count = 5000; - while (--count > 0 && ! isThreadReady) - sleep (1); - } - - 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); + + isStarted = true; + + if (! calledback) + { + error = "Device didn't start correctly"; + log ("ASIO didn't callback - stopping.."); asioObject->stop(); - error = "Can't start device"; - Thread::sleep (10); - } - else - { - int count = 300; - while (--count > 0 && ! calledback) - Thread::sleep (10); - - isStarted = true; - - if (! calledback) - { - error = "Device didn't start correctly"; - log ("ASIO didn't callback - stopping.."); - asioObject->stop(); - } } } } @@ -231683,13 +231680,6 @@ public: { const ScopedLock sl (callbackLock); - if (isUsingThread) - { - signalThreadShouldExit(); - event1.signal(); - stopThread (3000); - } - isOpen_ = false; isStarted = false; needToReset = false; @@ -231775,9 +231765,7 @@ public: bool isPlaying() { - return isASIOOpen - && (isThreadRunning() || ! isUsingThread) - && (currentCallback != 0); + return isASIOOpen && (currentCallback != 0); } const String getLastError() @@ -231785,11 +231773,6 @@ public: return error; } - void setUsingThread (bool b) - { - shouldUseThread = b; - } - bool hasControlPanel() const { return true; @@ -231895,12 +231878,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; @@ -231913,28 +231899,31 @@ 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) { @@ -231992,8 +231981,6 @@ private: modalWindow.addToDesktop (0); modalWindow.enterModalState(); - isUsingThread = shouldUseThread; - // open the device and get its info.. log (T("opening ASIO device: ") + getName()); @@ -232005,8 +231992,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; @@ -232018,17 +232007,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) { @@ -232098,7 +232087,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; @@ -232109,7 +232098,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; @@ -232118,10 +232107,30 @@ 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)); @@ -232138,13 +232147,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(); @@ -232152,7 +232161,7 @@ private: ASIOChannelInfo channelInfo; channelInfo.type = 0; - for (i = 0; i < numInputs; ++i) + for (i = 0; i < totalNumInputChans; ++i) { zerostruct (channelInfo); channelInfo.channel = i; @@ -232162,7 +232171,7 @@ private: inputChannelNames.add (String (channelInfo.name)); } - for (i = 0; i < numOutputs; ++i) + for (i = 0; i < totalNumOutputChans; ++i) { zerostruct (channelInfo); channelInfo.channel = i; @@ -232247,18 +232256,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 { @@ -232297,117 +232295,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]) { - const char* const src = (const char*) (infos[n].buffers[bi]); + memcpy (dst, src, samps * sizeof (float)); + } + else + { + jassert (dst == tempBuffer + (samps * i)); - if (inputChannelIsFloat[i]) + switch (inputChannelBitDepths[i]) { - memcpy (dst, src, samps * sizeof (float)); + 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; } - else - { - 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; - } - } - - ++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]) { - char* const dst = (char*) (infos[n].buffers[bi]); + memcpy (dst, src, samps * sizeof (float)); + } + else + { + 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); } } } @@ -232416,21 +232396,64 @@ private: asioObject->outputReady(); } - static ASIOTime* bufferSwitchTimeInfoCallback (ASIOTime*, long index, long) throw() + static ASIOTime* bufferSwitchTimeInfoCallback0 (ASIOTime*, long index, long) throw() { - if (currentASIODev != 0) - currentASIODev->callback (index); + if (currentASIODev[0] != 0) + currentASIODev[0]->callback (index); return 0; } - static void bufferSwitchCallback (long index, long) throw() + static ASIOTime* bufferSwitchTimeInfoCallback1 (ASIOTime*, long index, long) throw() { - if (currentASIODev != 0) - currentASIODev->callback (index); + if (currentASIODev[1] != 0) + currentASIODev[1]->callback (index); + + return 0; } - static long asioMessagesCallback (long selector, long value, void*, double*) throw() + static ASIOTime* bufferSwitchTimeInfoCallback2 (ASIOTime*, long index, long) throw() + { + if (currentASIODev[2] != 0) + currentASIODev[2]->callback (index); + + return 0; + } + + static void bufferSwitchCallback0 (long index, long) throw() + { + if (currentASIODev[0] != 0) + currentASIODev[0]->callback (index); + } + + 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) { @@ -232447,14 +232470,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; @@ -232807,11 +232830,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; - if (currentASIODev == 0) - return new ASIOAudioIODevice (deviceName, *(classIds [index])); + 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 (freeSlot >= 0) + return new ASIOAudioIODevice (deviceName, *(classIds [index]), freeSlot); } return 0; @@ -236372,12 +236406,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; @@ -236511,18 +236543,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; @@ -236534,30 +236558,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); @@ -236584,24 +236598,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) @@ -236615,13 +236619,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; } } @@ -236629,13 +236630,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; } } @@ -236902,71 +236900,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; @@ -236977,35 +236956,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; } } } @@ -237014,13 +236987,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); @@ -253400,13 +253371,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 @@ -253682,8 +253651,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; @@ -253719,17 +253697,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, @@ -253961,7 +253928,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/juce_amalgamated.h b/juce_amalgamated.h index e434ed13d4..dd7151ee77 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -2035,6 +2035,9 @@ public: This will replace the contents of the string with the output of this formatted printf. + Note that using the %s token with a juce string is probably a bad idea, as + this may expect differect encodings on different platforms. + @see formatted */ void printf (const tchar* const format, ...) throw(); @@ -2044,6 +2047,9 @@ public: This will return a string which is the result of a sprintf using the arguments passed-in. + Note that using the %s token with a juce string is probably a bad idea, as + this may expect differect encodings on different platforms. + @see printf, vprintf */ static const String formatted (const tchar* const format, ...) throw(); @@ -2054,6 +2060,9 @@ public: formatted printf. Used by other methods, this is public in case it's useful for other purposes where you want to pass a va_list through directly. + Note that using the %s token with a juce string is probably a bad idea, as + this may expect differect encodings on different platforms. + @see printf, formatted */ void vprintf (const tchar* const format, va_list& args) throw(); @@ -12265,7 +12274,8 @@ public: */ InputStream* createInputStream (const bool usePostCommand, OpenStreamProgressCallback* const progressCallback = 0, - void* const progressCallbackContext = 0) const; + void* const progressCallbackContext = 0, + const String& extraHeaders = String::empty) const; /** Tries to download the entire contents of this URL into a binary data block. @@ -28166,6 +28176,10 @@ public: This is the same as show(), but uses a specific location (in global screen co-ordinates) rather than the current mouse position. + Note that the co-ordinates don't specify the top-left of the menu - they + indicate a point of interest, and the menu will position itself nearby to + this point, trying to keep it fully on-screen. + @see show() */ int showAt (const int screenX, @@ -28868,23 +28882,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, @@ -28893,9 +28906,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. @@ -28920,7 +28933,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. @@ -30977,6 +30990,9 @@ public: */ AudioSource* getCurrentSource() const throw() { return source; } + /** Sets a gain to apply to the audio data. */ + void setGain (const float newGain) throw(); + /** Implementation of the AudioIODeviceCallback method. */ void audioDeviceIOCallback (const float** inputChannelData, int totalNumInputChannels, @@ -31002,6 +31018,7 @@ private: float* outputChans [128]; const float* inputChans [128]; AudioSampleBuffer tempBuffer; + float lastGain, gain; AudioSourcePlayer (const AudioSourcePlayer&); const AudioSourcePlayer& operator= (const AudioSourcePlayer&);