mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added class AudioProcessLoadMeasurer, and a new version of the method AudioDeviceManager::getAudioDeviceSetup()
This commit is contained in:
parent
ab8202f04d
commit
93ea3d922f
9 changed files with 218 additions and 69 deletions
|
|
@ -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);
|
||||
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,8 +52,7 @@ 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)
|
||||
|
|
|
|||
|
|
@ -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…
Add table
Add a link
Reference in a new issue