| @@ -127,8 +127,7 @@ AudioDeviceManager& getSharedAudioDeviceManager (int numInputChannels, int numOu | |||
| if (sharedAudioDeviceManager->getCurrentAudioDevice() != nullptr) | |||
| { | |||
| AudioDeviceManager::AudioDeviceSetup setup; | |||
| sharedAudioDeviceManager->getAudioDeviceSetup (setup); | |||
| auto setup = sharedAudioDeviceManager->getAudioDeviceSetup(); | |||
| auto numInputs = jmax (numInputChannels, setup.inputChannels.countNumberOfSetBits()); | |||
| auto numOutputs = jmax (numOutputChannels, setup.outputChannels.countNumberOfSetBits()); | |||
| @@ -0,0 +1,79 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| AudioProcessLoadMeasurer::AudioProcessLoadMeasurer() {} | |||
| AudioProcessLoadMeasurer::~AudioProcessLoadMeasurer() {} | |||
| void AudioProcessLoadMeasurer::reset() | |||
| { | |||
| reset (0, 0); | |||
| } | |||
| void AudioProcessLoadMeasurer::reset (double sampleRate, int blockSize) | |||
| { | |||
| cpuUsageMs = 0; | |||
| xruns = 0; | |||
| if (sampleRate > 0.0 && blockSize > 0) | |||
| { | |||
| msPerBlock = 1000.0 * blockSize / sampleRate; | |||
| timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0; | |||
| } | |||
| else | |||
| { | |||
| msPerBlock = 0; | |||
| timeToCpuScale = 0; | |||
| } | |||
| } | |||
| void AudioProcessLoadMeasurer::registerBlockRenderTime (double milliseconds) | |||
| { | |||
| const double filterAmount = 0.2; | |||
| cpuUsageMs += filterAmount * (milliseconds - cpuUsageMs); | |||
| if (milliseconds > msPerBlock) | |||
| ++xruns; | |||
| } | |||
| double AudioProcessLoadMeasurer::getLoadAsProportion() const { return jlimit (0.0, 1.0, timeToCpuScale * cpuUsageMs); } | |||
| double AudioProcessLoadMeasurer::getLoadAsPercentage() const { return 100.0 * getLoadAsProportion(); } | |||
| int AudioProcessLoadMeasurer::getXRunCount() const { return xruns; } | |||
| AudioProcessLoadMeasurer::ScopedTimer::ScopedTimer (AudioProcessLoadMeasurer& p) | |||
| : owner (p), startTime (Time::getMillisecondCounterHiRes()) | |||
| { | |||
| } | |||
| AudioProcessLoadMeasurer::ScopedTimer::~ScopedTimer() | |||
| { | |||
| owner.registerBlockRenderTime (Time::getMillisecondCounterHiRes() - startTime); | |||
| } | |||
| } // namespace juce | |||
| @@ -0,0 +1,96 @@ | |||
| /* | |||
| ============================================================================== | |||
| This file is part of the JUCE library. | |||
| Copyright (c) 2017 - ROLI Ltd. | |||
| JUCE is an open source library subject to commercial or open-source | |||
| licensing. | |||
| By using JUCE, you agree to the terms of both the JUCE 5 End-User License | |||
| Agreement and JUCE 5 Privacy Policy (both updated and effective as of the | |||
| 27th April 2017). | |||
| End User License Agreement: www.juce.com/juce-5-licence | |||
| Privacy Policy: www.juce.com/juce-5-privacy-policy | |||
| Or: You may also use this code under the terms of the GPL v3 (see | |||
| www.gnu.org/licenses). | |||
| JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER | |||
| EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE | |||
| DISCLAIMED. | |||
| ============================================================================== | |||
| */ | |||
| namespace juce | |||
| { | |||
| //============================================================================== | |||
| /** | |||
| Maintains an ongoing measurement of the proportion of time which is being | |||
| spent inside an audio callback. | |||
| */ | |||
| class JUCE_API AudioProcessLoadMeasurer | |||
| { | |||
| public: | |||
| /** */ | |||
| AudioProcessLoadMeasurer(); | |||
| /** Destructor. */ | |||
| ~AudioProcessLoadMeasurer(); | |||
| //============================================================================== | |||
| /** Resets the state. */ | |||
| void reset(); | |||
| /** Resets the counter, in preparation for use with the given sample rate and block size. */ | |||
| void reset (double sampleRate, int blockSize); | |||
| /** Returns the current load as a proportion 0 to 1.0 */ | |||
| double getLoadAsProportion() const; | |||
| /** Returns the current load as a percentage 0 to 100.0 */ | |||
| double getLoadAsPercentage() const; | |||
| /** Returns the number of over- (or under-) runs recorded since the state was reset. */ | |||
| int getXRunCount() const; | |||
| //============================================================================== | |||
| /** This class measures the time between its construction and destruction and | |||
| adds it to an AudioProcessLoadMeasurer. | |||
| e.g. | |||
| @code | |||
| { | |||
| AudioProcessLoadMeasurer::ScopedTimer timer (myProcessLoadMeasurer); | |||
| myCallback->doTheCallback(); | |||
| } | |||
| @endcode | |||
| */ | |||
| struct JUCE_API ScopedTimer | |||
| { | |||
| ScopedTimer (AudioProcessLoadMeasurer&); | |||
| ~ScopedTimer(); | |||
| private: | |||
| AudioProcessLoadMeasurer& owner; | |||
| double startTime; | |||
| JUCE_DECLARE_NON_COPYABLE (ScopedTimer) | |||
| }; | |||
| /** Can be called manually to add the time of a callback to the stats. | |||
| Normally you probably would never call this - it's simpler and more robust to | |||
| use a ScopedTimer to measure the time using an RAII pattern. | |||
| */ | |||
| void registerBlockRenderTime (double millisecondsTaken); | |||
| private: | |||
| double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0; | |||
| int xruns = 0; | |||
| }; | |||
| } // namespace juce | |||
| @@ -56,6 +56,7 @@ | |||
| #include "buffers/juce_AudioDataConverters.cpp" | |||
| #include "buffers/juce_FloatVectorOperations.cpp" | |||
| #include "buffers/juce_AudioChannelSet.cpp" | |||
| #include "buffers/juce_AudioProcessLoadMeasurer.cpp" | |||
| #include "effects/juce_IIRFilter.cpp" | |||
| #include "effects/juce_LagrangeInterpolator.cpp" | |||
| #include "effects/juce_CatmullRomInterpolator.cpp" | |||
| @@ -84,6 +84,7 @@ | |||
| #include "buffers/juce_FloatVectorOperations.h" | |||
| #include "buffers/juce_AudioSampleBuffer.h" | |||
| #include "buffers/juce_AudioChannelSet.h" | |||
| #include "buffers/juce_AudioProcessLoadMeasurer.h" | |||
| #include "effects/juce_Decibels.h" | |||
| #include "effects/juce_IIRFilter.h" | |||
| #include "effects/juce_LagrangeInterpolator.h" | |||
| @@ -23,14 +23,6 @@ | |||
| namespace juce | |||
| { | |||
| AudioDeviceManager::AudioDeviceSetup::AudioDeviceSetup() | |||
| : sampleRate (0), | |||
| bufferSize (0), | |||
| useDefaultInputChannels (true), | |||
| useDefaultOutputChannels (true) | |||
| { | |||
| } | |||
| bool AudioDeviceManager::AudioDeviceSetup::operator== (const AudioDeviceManager::AudioDeviceSetup& other) const | |||
| { | |||
| return outputDeviceName == other.outputDeviceName | |||
| @@ -367,6 +359,11 @@ AudioIODeviceType* AudioDeviceManager::findType (const String& inputName, const | |||
| return {}; | |||
| } | |||
| AudioDeviceManager::AudioDeviceSetup AudioDeviceManager::getAudioDeviceSetup() const | |||
| { | |||
| return currentSetup; | |||
| } | |||
| void AudioDeviceManager::getAudioDeviceSetup (AudioDeviceSetup& setup) const | |||
| { | |||
| setup = currentSetup; | |||
| @@ -582,7 +579,7 @@ void AudioDeviceManager::closeAudioDevice() | |||
| { | |||
| stopDevice(); | |||
| currentAudioDevice.reset(); | |||
| cpuUsageMs = 0; | |||
| loadMeasurer.reset(); | |||
| } | |||
| void AudioDeviceManager::restartLastAudioDevice() | |||
| @@ -694,7 +691,7 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| if (callbacks.size() > 0) | |||
| { | |||
| auto callbackStartTime = Time::getMillisecondCounterHiRes(); | |||
| AudioProcessLoadMeasurer::ScopedTimer timer (loadMeasurer); | |||
| tempBuffer.setSize (jmax (1, numOutputChannels), jmax (1, numSamples), false, false, true); | |||
| @@ -716,13 +713,6 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| dst[j] += src[j]; | |||
| } | |||
| } | |||
| auto msTaken = Time::getMillisecondCounterHiRes() - callbackStartTime; | |||
| const double filterAmount = 0.2; | |||
| cpuUsageMs += filterAmount * (msTaken - cpuUsageMs); | |||
| if (msTaken > msPerBlock) | |||
| ++xruns; | |||
| } | |||
| else | |||
| { | |||
| @@ -748,17 +738,8 @@ void AudioDeviceManager::audioDeviceIOCallbackInt (const float** inputChannelDat | |||
| void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device) | |||
| { | |||
| cpuUsageMs = 0; | |||
| xruns = 0; | |||
| auto sampleRate = device->getCurrentSampleRate(); | |||
| auto blockSize = device->getCurrentBufferSizeSamples(); | |||
| if (sampleRate > 0.0 && blockSize > 0) | |||
| { | |||
| msPerBlock = 1000.0 * blockSize / sampleRate; | |||
| timeToCpuScale = (msPerBlock > 0.0) ? (1.0 / msPerBlock) : 0.0; | |||
| } | |||
| loadMeasurer.reset (device->getCurrentSampleRate(), | |||
| device->getCurrentBufferSizeSamples()); | |||
| { | |||
| const ScopedLock sl (audioCallbackLock); | |||
| @@ -772,13 +753,12 @@ void AudioDeviceManager::audioDeviceAboutToStartInt (AudioIODevice* const device | |||
| void AudioDeviceManager::audioDeviceStoppedInt() | |||
| { | |||
| cpuUsageMs = 0; | |||
| timeToCpuScale = 0; | |||
| xruns = 0; | |||
| sendChangeMessage(); | |||
| const ScopedLock sl (audioCallbackLock); | |||
| loadMeasurer.reset(); | |||
| for (int i = callbacks.size(); --i >= 0;) | |||
| callbacks.getUnchecked(i)->audioDeviceStopped(); | |||
| } | |||
| @@ -793,7 +773,7 @@ void AudioDeviceManager::audioDeviceErrorInt (const String& message) | |||
| double AudioDeviceManager::getCpuUsage() const | |||
| { | |||
| return jlimit (0.0, 1.0, timeToCpuScale * cpuUsageMs); | |||
| return loadMeasurer.getLoadAsProportion(); | |||
| } | |||
| //============================================================================== | |||
| @@ -980,7 +960,7 @@ void AudioDeviceManager::playTestSound() | |||
| auto phasePerSample = MathConstants<double>::twoPi / (sampleRate / frequency); | |||
| auto* newSound = new AudioBuffer<float> (1, soundLength); | |||
| std::unique_ptr<AudioBuffer<float>> newSound (new AudioBuffer<float> (1, soundLength)); | |||
| for (int i = 0; i < soundLength; ++i) | |||
| newSound->setSample (0, i, amplitude * (float) std::sin (i * phasePerSample)); | |||
| @@ -988,15 +968,17 @@ void AudioDeviceManager::playTestSound() | |||
| newSound->applyGainRamp (0, 0, soundLength / 10, 0.0f, 1.0f); | |||
| newSound->applyGainRamp (0, soundLength - soundLength / 4, soundLength / 4, 1.0f, 0.0f); | |||
| const ScopedLock sl (audioCallbackLock); | |||
| testSound.reset (newSound); | |||
| { | |||
| const ScopedLock sl (audioCallbackLock); | |||
| std::swap (testSound, newSound); | |||
| } | |||
| } | |||
| } | |||
| int AudioDeviceManager::getXRunCount() const noexcept | |||
| { | |||
| auto deviceXRuns = (currentAudioDevice != nullptr ? currentAudioDevice->getXRunCount() : -1); | |||
| return jmax (0, deviceXRuns) + xruns; | |||
| return jmax (0, deviceXRuns) + loadMeasurer.getXRunCount(); | |||
| } | |||
| } // namespace juce | |||
| @@ -89,17 +89,6 @@ public: | |||
| */ | |||
| struct JUCE_API AudioDeviceSetup | |||
| { | |||
| /** Creates an AudioDeviceSetup object. | |||
| The default constructor sets all the member variables to indicate default values. | |||
| You can then fill-in any values you want to before passing the object to | |||
| AudioDeviceManager::initialise(). | |||
| */ | |||
| AudioDeviceSetup(); | |||
| bool operator== (const AudioDeviceSetup& other) const; | |||
| bool operator!= (const AudioDeviceSetup& other) const; | |||
| /** The name of the audio device used for output. | |||
| The name has to be one of the ones listed by the AudioDeviceManager's currently | |||
| selected device type. | |||
| @@ -119,13 +108,13 @@ public: | |||
| A value of 0 indicates that you don't care what rate is used, and the | |||
| device will choose a sensible rate for you. | |||
| */ | |||
| double sampleRate; | |||
| double sampleRate = 0; | |||
| /** The buffer size, in samples. | |||
| This buffer size is used for both the input and output devices. | |||
| A value of 0 indicates the default buffer size. | |||
| */ | |||
| int bufferSize; | |||
| int bufferSize = 0; | |||
| /** The set of active input channels. | |||
| The bits that are set in this array indicate the channels of the | |||
| @@ -138,7 +127,7 @@ public: | |||
| should be ignored, and instead, the device's default channels | |||
| should be used. | |||
| */ | |||
| bool useDefaultInputChannels; | |||
| bool useDefaultInputChannels = true; | |||
| /** The set of active output channels. | |||
| The bits that are set in this array indicate the channels of the | |||
| @@ -151,7 +140,10 @@ public: | |||
| should be ignored, and instead, the device's default channels | |||
| should be used. | |||
| */ | |||
| bool useDefaultOutputChannels; | |||
| bool useDefaultOutputChannels = true; | |||
| bool operator== (const AudioDeviceSetup&) const; | |||
| bool operator!= (const AudioDeviceSetup&) const; | |||
| }; | |||
| @@ -211,6 +203,13 @@ public: | |||
| /** Returns the current device properties that are in use. | |||
| @see setAudioDeviceSetup | |||
| */ | |||
| AudioDeviceSetup getAudioDeviceSetup() const; | |||
| /** Returns the current device properties that are in use. | |||
| This is an old method, kept around for compatibility, but you should prefer the new | |||
| version which returns the result rather than taking an out-parameter. | |||
| @see getAudioDeviceSetup() | |||
| */ | |||
| void getAudioDeviceSetup (AudioDeviceSetup& result) const; | |||
| /** Changes the current device or its settings. | |||
| @@ -232,8 +231,7 @@ public: | |||
| @see getAudioDeviceSetup | |||
| */ | |||
| String setAudioDeviceSetup (const AudioDeviceSetup& newSetup, | |||
| bool treatAsChosenDevice); | |||
| String setAudioDeviceSetup (const AudioDeviceSetup& newSetup, bool treatAsChosenDevice); | |||
| /** Returns the currently-active audio device. */ | |||
| @@ -257,8 +255,7 @@ public: | |||
| For a list of types, see getAvailableDeviceTypes(). | |||
| */ | |||
| void setCurrentAudioDeviceType (const String& type, | |||
| bool treatAsChosenDevice); | |||
| void setCurrentAudioDeviceType (const String& type, bool treatAsChosenDevice); | |||
| /** Closes the currently-open device. | |||
| You can call restartLastAudioDevice() later to reopen it in the same state | |||
| @@ -496,8 +493,7 @@ private: | |||
| std::unique_ptr<AudioBuffer<float>> testSound; | |||
| int testSoundPosition = 0; | |||
| double cpuUsageMs = 0, timeToCpuScale = 0, msPerBlock = 0; | |||
| int xruns = 0; | |||
| AudioProcessLoadMeasurer loadMeasurer; | |||
| LevelMeter::Ptr inputLevelGetter { new LevelMeter() }, | |||
| outputLevelGetter { new LevelMeter() }; | |||
| @@ -52,11 +52,10 @@ void AudioAppComponent::setAudioChannels (int numInputChannels, int numOutputCha | |||
| if (usingCustomDeviceManager && xml == nullptr) | |||
| { | |||
| AudioDeviceManager::AudioDeviceSetup setup; | |||
| deviceManager.getAudioDeviceSetup (setup); | |||
| auto setup = deviceManager.getAudioDeviceSetup(); | |||
| if (setup.inputChannels.countNumberOfSetBits() != numInputChannels | |||
| || setup.outputChannels.countNumberOfSetBits() != numOutputChannels) | |||
| || setup.outputChannels.countNumberOfSetBits() != numOutputChannels) | |||
| { | |||
| setup.inputChannels.clear(); | |||
| setup.outputChannels.clear(); | |||
| @@ -330,8 +330,7 @@ public: | |||
| void updateConfig (bool updateOutputDevice, bool updateInputDevice, bool updateSampleRate, bool updateBufferSize) | |||
| { | |||
| AudioDeviceManager::AudioDeviceSetup config; | |||
| setup.manager->getAudioDeviceSetup (config); | |||
| auto config = setup.manager->getAudioDeviceSetup(); | |||
| String error; | |||
| if (updateOutputDevice || updateInputDevice) | |||
| @@ -769,9 +768,7 @@ public: | |||
| auto item = items[row]; | |||
| bool enabled = false; | |||
| AudioDeviceManager::AudioDeviceSetup config; | |||
| setup.manager->getAudioDeviceSetup (config); | |||
| auto config = setup.manager->getAudioDeviceSetup(); | |||
| if (setup.useStereoPairs) | |||
| { | |||
| @@ -868,8 +865,7 @@ public: | |||
| if (isPositiveAndBelow (row, items.size())) | |||
| { | |||
| AudioDeviceManager::AudioDeviceSetup config; | |||
| setup.manager->getAudioDeviceSetup (config); | |||
| auto config = setup.manager->getAudioDeviceSetup(); | |||
| if (setup.useStereoPairs) | |||
| { | |||