test: add headless QA harness
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#include <JuceHeader.h>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "../PluginProcessor.h"
|
||||
|
||||
// ===========================================================================
|
||||
// Headless QA harness: instantiates the processor, plays notes through every
|
||||
// factory preset and reports NaN/inf and silence failures.
|
||||
// ===========================================================================
|
||||
namespace
|
||||
{
|
||||
bool hasNaN (const juce::AudioBuffer<float>& b)
|
||||
{
|
||||
for (int ch = 0; ch < b.getNumChannels(); ++ch)
|
||||
{
|
||||
const float* d = b.getReadPointer (ch);
|
||||
for (int i = 0; i < b.getNumSamples(); ++i)
|
||||
if (! std::isfinite (d[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float peak (const juce::AudioBuffer<float>& b)
|
||||
{
|
||||
float p = 0.0f;
|
||||
for (int ch = 0; ch < b.getNumChannels(); ++ch)
|
||||
{
|
||||
const float* d = b.getReadPointer (ch);
|
||||
for (int i = 0; i < b.getNumSamples(); ++i)
|
||||
p = std::max (p, std::abs (d[i]));
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
juce::ScopedJuceInitialiser_GUI initialiser;
|
||||
|
||||
serum::SerumAltAudioProcessor processor;
|
||||
processor.prepareToPlay (44100.0, 512);
|
||||
|
||||
const int numPresets = processor.getNumPrograms();
|
||||
int failures = 0;
|
||||
|
||||
const int notes[3] = { 48, 60, 67 };
|
||||
|
||||
// Default (init) preset.
|
||||
{
|
||||
juce::MidiBuffer midi;
|
||||
for (int n : notes)
|
||||
midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0);
|
||||
|
||||
juce::AudioBuffer<float> buffer (2, 512);
|
||||
float maxPeak = 0.0f;
|
||||
bool nan = false;
|
||||
|
||||
for (int block = 0; block < 240; ++block)
|
||||
{
|
||||
buffer.clear();
|
||||
processor.processBlock (buffer, midi);
|
||||
midi.clear();
|
||||
if (block == 180)
|
||||
for (int n : notes)
|
||||
midi.addEvent (juce::MidiMessage::noteOff (1, n), 0);
|
||||
nan = nan || hasNaN (buffer);
|
||||
maxPeak = std::max (maxPeak, peak (buffer));
|
||||
}
|
||||
|
||||
const bool ok = ! nan && maxPeak > 0.001f;
|
||||
if (! ok) ++failures;
|
||||
std::cout << (ok ? "PASS" : "FAIL") << " [Init] peak=" << maxPeak << (nan ? " <NaN!>" : "") << "\n";
|
||||
}
|
||||
|
||||
// Every factory preset.
|
||||
for (int preset = 0; preset < numPresets; ++preset)
|
||||
{
|
||||
processor.setCurrentProgram (preset);
|
||||
|
||||
juce::MidiBuffer midi;
|
||||
for (int n : notes)
|
||||
midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0);
|
||||
|
||||
juce::AudioBuffer<float> buffer (2, 512);
|
||||
float maxPeak = 0.0f;
|
||||
bool nan = false;
|
||||
|
||||
for (int block = 0; block < 240; ++block)
|
||||
{
|
||||
buffer.clear();
|
||||
processor.processBlock (buffer, midi);
|
||||
midi.clear();
|
||||
if (block == 180)
|
||||
for (int n : notes)
|
||||
midi.addEvent (juce::MidiMessage::noteOff (1, n), 0);
|
||||
nan = nan || hasNaN (buffer);
|
||||
maxPeak = std::max (maxPeak, peak (buffer));
|
||||
}
|
||||
|
||||
const bool ok = ! nan && maxPeak > 0.001f;
|
||||
if (! ok) ++failures;
|
||||
std::cout << (ok ? "PASS" : "FAIL") << " [" << processor.getProgramName (preset) << "]"
|
||||
<< " peak=" << maxPeak << (nan ? " <NaN!>" : "") << "\n";
|
||||
}
|
||||
|
||||
// RAVE toggle + parameter churn while playing (no crash / NaN).
|
||||
{
|
||||
processor.setCurrentProgram (0);
|
||||
juce::MidiBuffer midi;
|
||||
for (int n : notes)
|
||||
midi.addEvent (juce::MidiMessage::noteOn (1, n, (juce::uint8) 100), 0);
|
||||
|
||||
processor.setRaveEnabled (true);
|
||||
|
||||
juce::AudioBuffer<float> buffer (2, 512);
|
||||
bool nan = false;
|
||||
for (int block = 0; block < 120; ++block)
|
||||
{
|
||||
buffer.clear();
|
||||
processor.processBlock (buffer, midi);
|
||||
midi.clear();
|
||||
if (block == 60)
|
||||
processor.setRaveEnabled (false);
|
||||
nan = nan || hasNaN (buffer);
|
||||
}
|
||||
const bool ok = ! nan;
|
||||
if (! ok) ++failures;
|
||||
std::cout << (ok ? "PASS" : "FAIL") << " [RAVE toggle / param churn]" << (nan ? " <NaN!>" : "") << "\n";
|
||||
}
|
||||
|
||||
std::cout << "\n" << (failures == 0 ? "ALL QA CHECKS PASSED" : "QA FAILURES DETECTED")
|
||||
<< " (" << failures << " failures)\n";
|
||||
return failures == 0 ? 0 : 1;
|
||||
}
|
||||
Reference in New Issue
Block a user