git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
91
deps/juce/extras/AudioPerformanceTest/Source/Main.cpp
vendored
Normal file
91
deps/juce/extras/AudioPerformanceTest/Source/Main.cpp
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "MainComponent.h"
|
||||
|
||||
//==============================================================================
|
||||
class AudioPerformanceTestApplication : public JUCEApplication
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
AudioPerformanceTestApplication() {}
|
||||
|
||||
const String getApplicationName() override { return ProjectInfo::projectName; }
|
||||
const String getApplicationVersion() override { return ProjectInfo::versionString; }
|
||||
bool moreThanOneInstanceAllowed() override { return true; }
|
||||
|
||||
//==============================================================================
|
||||
void initialise (const String&) override
|
||||
{
|
||||
mainWindow.reset (new MainWindow (getApplicationName()));
|
||||
}
|
||||
|
||||
void shutdown() override
|
||||
{
|
||||
mainWindow = nullptr; // (deletes our window)
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void systemRequestedQuit() override
|
||||
{
|
||||
quit();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class MainWindow : public DocumentWindow
|
||||
{
|
||||
public:
|
||||
explicit MainWindow (String name)
|
||||
: DocumentWindow (name, Colours::lightgrey, DocumentWindow::allButtons)
|
||||
{
|
||||
setUsingNativeTitleBar (true);
|
||||
setContentOwned (createMainContentComponent(), true);
|
||||
setResizable (false, false);
|
||||
|
||||
#if JUCE_IOS || JUCE_ANDROID
|
||||
setFullScreen (true);
|
||||
#else
|
||||
centreWithSize (getWidth(), getHeight());
|
||||
#endif
|
||||
|
||||
setVisible (true);
|
||||
}
|
||||
|
||||
void closeButtonPressed() override
|
||||
{
|
||||
JUCEApplication::getInstance()->systemRequestedQuit();
|
||||
}
|
||||
|
||||
private:
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
|
||||
};
|
||||
|
||||
private:
|
||||
std::unique_ptr<MainWindow> mainWindow;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
START_JUCE_APPLICATION (AudioPerformanceTestApplication)
|
277
deps/juce/extras/AudioPerformanceTest/Source/MainComponent.h
vendored
Normal file
277
deps/juce/extras/AudioPerformanceTest/Source/MainComponent.h
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
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 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include <mutex>
|
||||
|
||||
//==============================================================================
|
||||
class MainContentComponent : public AudioAppComponent,
|
||||
private Timer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
MainContentComponent()
|
||||
{
|
||||
setSize (400, 400);
|
||||
setAudioChannels (0, 2);
|
||||
|
||||
initGui();
|
||||
Desktop::getInstance().setScreenSaverEnabled (false);
|
||||
startTimer (1000);
|
||||
}
|
||||
|
||||
~MainContentComponent() override
|
||||
{
|
||||
shutdownAudio();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void prepareToPlay (int bufferSize, double sampleRate) override
|
||||
{
|
||||
currentSampleRate = sampleRate;
|
||||
allocateBuffers (static_cast<size_t> (bufferSize));
|
||||
printHeader();
|
||||
}
|
||||
|
||||
void releaseResources() override
|
||||
{
|
||||
a.clear();
|
||||
b.clear();
|
||||
c.clear();
|
||||
currentSampleRate = 0.0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) override
|
||||
{
|
||||
const double startTimeMs = getPreciseTimeMs();
|
||||
|
||||
AudioBuffer<float>& outputAudio = *bufferToFill.buffer;
|
||||
std::size_t bufferSize = (std::size_t) outputAudio.getNumSamples();
|
||||
initialiseBuffers (bufferToFill, bufferSize);
|
||||
|
||||
for (int ch = 0; ch < outputAudio.getNumChannels(); ++ch)
|
||||
crunchSomeNumbers (outputAudio.getWritePointer (ch), bufferSize, numLoopIterationsPerCallback);
|
||||
|
||||
std::lock_guard<std::mutex> lock (metricMutex);
|
||||
|
||||
double endTimeMs = getPreciseTimeMs();
|
||||
addCallbackMetrics (startTimeMs, endTimeMs);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void addCallbackMetrics (double startTimeMs, double endTimeMs)
|
||||
{
|
||||
double runtimeMs = endTimeMs - startTimeMs;
|
||||
audioCallbackRuntimeMs.addValue (runtimeMs);
|
||||
|
||||
if (runtimeMs > getPhysicalTimeLimitMs())
|
||||
numCallbacksOverPhysicalTimeLimit++;
|
||||
|
||||
if (lastCallbackStartTimeMs > 0.0)
|
||||
{
|
||||
double gapMs = startTimeMs - lastCallbackStartTimeMs;
|
||||
audioCallbackGapMs.addValue (gapMs);
|
||||
|
||||
if (gapMs > 1.5 * getPhysicalTimeLimitMs())
|
||||
numLateCallbacks++;
|
||||
}
|
||||
|
||||
lastCallbackStartTimeMs = startTimeMs;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (Colours::black);
|
||||
g.setFont (Font (16.0f));
|
||||
g.setColour (Colours::white);
|
||||
g.drawText ("loop iterations / audio callback",
|
||||
getLocalBounds().withY (loopIterationsSlider.getHeight()), Justification::centred, true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void resized() override
|
||||
{
|
||||
loopIterationsSlider.setBounds (getLocalBounds().withSizeKeepingCentre (proportionOfWidth (0.9f), 50));
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
void initGui()
|
||||
{
|
||||
loopIterationsSlider.setSliderStyle (Slider::LinearBar);
|
||||
loopIterationsSlider.setRange (0, 30000, 250);
|
||||
loopIterationsSlider.setValue (15000);
|
||||
loopIterationsSlider.setColour (Slider::thumbColourId, Colours::white);
|
||||
loopIterationsSlider.setColour (Slider::textBoxTextColourId, Colours::grey);
|
||||
updateNumLoopIterationsPerCallback();
|
||||
addAndMakeVisible (loopIterationsSlider);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void allocateBuffers (std::size_t bufferSize)
|
||||
{
|
||||
a.resize (bufferSize);
|
||||
b.resize (bufferSize);
|
||||
c.resize (bufferSize);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void initialiseBuffers (const AudioSourceChannelInfo& bufferToFill, std::size_t bufferSize)
|
||||
{
|
||||
if (bufferSize != a.size())
|
||||
{
|
||||
jassertfalse;
|
||||
Logger::writeToLog ("WARNING: Unexpected buffer size received."
|
||||
"expected: " + String (a.size()) +
|
||||
", actual: " + String (bufferSize));
|
||||
|
||||
if (bufferSize > a.size())
|
||||
Logger::writeToLog ("WARNING: Need to allocate larger buffers on audio thread!");
|
||||
|
||||
allocateBuffers (bufferSize);
|
||||
}
|
||||
|
||||
bufferToFill.clearActiveBufferRegion();
|
||||
std::fill (a.begin(), a.end(), 0.09f);
|
||||
std::fill (b.begin(), b.end(), 0.1f );
|
||||
std::fill (c.begin(), c.end(), 0.11f);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void crunchSomeNumbers (float* outBuffer, std::size_t bufferSize, int numIterations) noexcept
|
||||
{
|
||||
jassert (a.size() == bufferSize && b.size() == bufferSize && c.size() == bufferSize);
|
||||
|
||||
for (int i = 0; i < numIterations; ++i)
|
||||
{
|
||||
FloatVectorOperations::multiply (c.data(), a.data(), b.data(), (int) bufferSize);
|
||||
FloatVectorOperations::addWithMultiply (outBuffer, b.data(), c.data(), (int) bufferSize);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void timerCallback() override
|
||||
{
|
||||
printAndResetPerformanceMetrics();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void printHeader() const
|
||||
{
|
||||
Logger::writeToLog ("buffer size = " + String (a.size()) + " samples");
|
||||
Logger::writeToLog ("sample rate = " + String (currentSampleRate) + " Hz");
|
||||
Logger::writeToLog ("physical time limit / callback = " + String (getPhysicalTimeLimitMs() )+ " ms");
|
||||
Logger::writeToLog ("");
|
||||
Logger::writeToLog (" | callback exec time / physLimit | callback time gap / physLimit | callback counters ");
|
||||
Logger::writeToLog ("numLoops | avg min max stddev | avg min max stddev | called late >limit ");
|
||||
Logger::writeToLog ("----- | ----- ----- ----- ----- | ----- ----- ----- ----- | --- --- --- ");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void printAndResetPerformanceMetrics()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock (metricMutex);
|
||||
|
||||
auto runtimeMetric = audioCallbackRuntimeMs;
|
||||
auto gapMetric = audioCallbackGapMs;
|
||||
auto late = numLateCallbacks;
|
||||
auto overLimit = numCallbacksOverPhysicalTimeLimit;
|
||||
|
||||
resetPerformanceMetrics();
|
||||
updateNumLoopIterationsPerCallback();
|
||||
|
||||
lock.unlock();
|
||||
|
||||
Logger::writeToLog (String (numLoopIterationsPerCallback).paddedRight (' ', 8) + " | "
|
||||
+ getPercentFormattedMetricString (runtimeMetric) + " | "
|
||||
+ getPercentFormattedMetricString (gapMetric) + " | "
|
||||
+ String (runtimeMetric.getCount()).paddedRight (' ', 8)
|
||||
+ String (late).paddedRight (' ', 8)
|
||||
+ String (overLimit).paddedRight (' ', 8) + " | ");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String getPercentFormattedMetricString (const StatisticsAccumulator<double> metric) const
|
||||
{
|
||||
auto physTimeLimit = getPhysicalTimeLimitMs();
|
||||
|
||||
return (String (100.0 * metric.getAverage() / physTimeLimit, 1) + "%").paddedRight (' ', 8)
|
||||
+ (String (100.0 * metric.getMinValue() / physTimeLimit, 1) + "%").paddedRight (' ', 8)
|
||||
+ (String (100.0 * metric.getMaxValue() / physTimeLimit, 1) + "%").paddedRight (' ', 8)
|
||||
+ String (metric.getStandardDeviation(), 3).paddedRight (' ', 8);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void resetPerformanceMetrics()
|
||||
{
|
||||
audioCallbackRuntimeMs.reset();
|
||||
audioCallbackGapMs.reset();
|
||||
numLateCallbacks = 0;
|
||||
numCallbacksOverPhysicalTimeLimit = 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void updateNumLoopIterationsPerCallback()
|
||||
{
|
||||
numLoopIterationsPerCallback = (int) loopIterationsSlider.getValue();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static double getPreciseTimeMs() noexcept
|
||||
{
|
||||
return 1000.0 * (double) Time::getHighResolutionTicks() / (double) Time::getHighResolutionTicksPerSecond();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
double getPhysicalTimeLimitMs() const noexcept
|
||||
{
|
||||
return 1000.0 * (double) a.size() / currentSampleRate;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
std::vector<float> a, b, c; // must always be of size == current bufferSize
|
||||
double currentSampleRate = 0.0;
|
||||
|
||||
StatisticsAccumulator<double> audioCallbackRuntimeMs;
|
||||
StatisticsAccumulator<double> audioCallbackGapMs;
|
||||
double lastCallbackStartTimeMs = 0.0;
|
||||
int numLateCallbacks = 0;
|
||||
int numCallbacksOverPhysicalTimeLimit = 0;
|
||||
int numLoopIterationsPerCallback;
|
||||
|
||||
Slider loopIterationsSlider;
|
||||
std::mutex metricMutex;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainContentComponent)
|
||||
};
|
||||
|
||||
|
||||
// (This function is called by the app startup code to create our main component)
|
||||
Component* createMainContentComponent() { return new MainContentComponent(); }
|
Reference in New Issue
Block a user