Bake window derives itself: %-knob fold, declick pad, Gate held to exhaustion, preview velocity; Hold is the one knob a loop needs
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
// Standalone tests for reasampler::instrument::ui::bake_hold — the Hold knob's map onto the
|
||||
// note-length ladder. No VST3, no REAPER, no framework.
|
||||
//
|
||||
// Covers: both ends of the knob, the round trip from every rung, out-of-range and non-finite
|
||||
// input, and that every rung is reachable (no rung is skipped by the rounding).
|
||||
|
||||
#include "../src/core/instrument/ui/bake_hold.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
using namespace reasampler::instrument::ui;
|
||||
using namespace reasampler::instrument::note;
|
||||
|
||||
static int g_fail = 0;
|
||||
#define CHECK(cond) do { if(!(cond)) { \
|
||||
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
||||
|
||||
int main() {
|
||||
// --- The ends of the travel are the ends of the ladder ---------------------------
|
||||
CHECK(bakeHoldFromNorm(0.0) == divisionAt(0));
|
||||
CHECK(bakeHoldFromNorm(1.0) == divisionAt(kDivisionCount - 1));
|
||||
|
||||
// --- Out of range clamps rather than wrapping ------------------------------------
|
||||
CHECK(bakeHoldFromNorm(-3.0) == divisionAt(0));
|
||||
CHECK(bakeHoldFromNorm(9.5) == divisionAt(kDivisionCount - 1));
|
||||
CHECK(bakeHoldFromNorm(std::nan("")) == divisionAt(0));
|
||||
|
||||
// --- Round trip: a knob painted from a stored rung and released reproduces it -----
|
||||
for (int i = 0; i < kDivisionCount; ++i) {
|
||||
const Division d = divisionAt(i);
|
||||
CHECK(bakeHoldFromNorm(bakeHoldNorm(d)) == d);
|
||||
}
|
||||
|
||||
// --- Every rung is reachable from the knob, and each owns a contiguous slice ------
|
||||
// Swept finely enough to catch a rounding that skipped one: 39 rungs over [0,1].
|
||||
{
|
||||
std::vector<bool> seen(static_cast<std::size_t>(kDivisionCount), false);
|
||||
for (int step = 0; step <= 4000; ++step) {
|
||||
const Division d = bakeHoldFromNorm(static_cast<double>(step) / 4000.0);
|
||||
seen[static_cast<std::size_t>(divisionIndex(d))] = true;
|
||||
}
|
||||
for (int i = 0; i < kDivisionCount; ++i) CHECK(seen[static_cast<std::size_t>(i)]);
|
||||
}
|
||||
|
||||
// --- The map is monotone: turning the knob up never shortens the note -------------
|
||||
{
|
||||
int previous = -1;
|
||||
for (int step = 0; step <= 4000; ++step) {
|
||||
const int index = divisionIndex(bakeHoldFromNorm(static_cast<double>(step) / 4000.0));
|
||||
CHECK(index >= previous);
|
||||
previous = index;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_fail == 0) std::printf("bake_hold: all tests passed\n");
|
||||
return g_fail ? 1 : 0;
|
||||
}
|
||||
Reference in New Issue
Block a user