Browse Source

Added class AudioProcessLoadMeasurer, and a new version of the method AudioDeviceManager::getAudioDeviceSetup()

tags/2021-05-28
jules 7 years ago
parent
commit
93ea3d922f
9 changed files with 218 additions and 69 deletions
  1. +1
    -2
      examples/DemoRunner/Source/Demos/JUCEDemos.cpp
  2. +79
    -0
      modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp
  3. +96
    -0
      modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h
  4. +1
    -0
      modules/juce_audio_basics/juce_audio_basics.cpp
  5. +1
    -0
      modules/juce_audio_basics/juce_audio_basics.h
  6. +18
    -36
      modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp
  7. +17
    -21
      modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h
  8. +2
    -3
      modules/juce_audio_utils/gui/juce_AudioAppComponent.cpp
  9. +3
    -7
      modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp

+ 1
- 2
examples/DemoRunner/Source/Demos/JUCEDemos.cpp View File

@@ -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());


+ 79
- 0
modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.cpp View File

@@ -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

+ 96
- 0
modules/juce_audio_basics/buffers/juce_AudioProcessLoadMeasurer.h View File

@@ -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

+ 1
- 0
modules/juce_audio_basics/juce_audio_basics.cpp View File

@@ -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"


+ 1
- 0
modules/juce_audio_basics/juce_audio_basics.h View File

@@ -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"


+ 18
- 36
modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.cpp View File

@@ -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

+ 17
- 21
modules/juce_audio_devices/audio_io/juce_AudioDeviceManager.h View File

@@ -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() };


+ 2
- 3
modules/juce_audio_utils/gui/juce_AudioAppComponent.cpp View File

@@ -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();


+ 3
- 7
modules/juce_audio_utils/gui/juce_AudioDeviceSelectorComponent.cpp View File

@@ -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)
{


Loading…
Cancel
Save