// Standalone tests for reasampler::card_meta — no REAPER, no test framework. Asserts the // L7 decorative overlay formatters: bars.beats.subdivisions (F1 tempo+meter stamp) and // seconds.milliseconds. // // Covers: bar-1 origin (zero length), sub-bar, exact bar boundary rollover, multi-bar, // long capture, non-4/4 meters (3/4 and 6/8), unstamped meter -> blank, unknown tempo -> // blank (s.ms still derivable); s.ms zero / sub-second / multi-second / ms carry / negative. #include "../src/card_meta.h" #include #include using namespace reasampler; static int g_fail = 0; #define CHECK(cond) do { if(!(cond)) { \ std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0) // Beat length in 4/4 at 120 BPM: (60/120)*(4/4) = 0.5 s/beat, so a 4/4 bar = 2.0 s. // --- bars.beats.subdivisions ------------------------------------------------- static void testZeroLengthIsBarOneOrigin() { // Zero length -> the musical origin, "1.1.00". CHECK(formatBarsBeats(MusicalLength{0.0, 120.0, 4, 4}) == "1.1.00"); } static void testSubBeat() { // 0.25 s at 120 BPM 4/4 = 0.5 beats -> bar 1, beat 1, .50. CHECK(formatBarsBeats(MusicalLength{0.25, 120.0, 4, 4}) == "1.1.50"); } static void testWholeBeatWithinBar() { // 0.5 s = exactly 1 beat -> bar 1, beat 2, .00. CHECK(formatBarsBeats(MusicalLength{0.5, 120.0, 4, 4}) == "1.2.00"); } static void testExactBarBoundaryRollsOver() { // 2.0 s = exactly 4 beats = 1 bar in 4/4 -> rolls to bar 2, beat 1 (NOT "1.5.00"). CHECK(formatBarsBeats(MusicalLength{2.0, 120.0, 4, 4}) == "2.1.00"); } static void testMultiBar() { // 5.0 s at 120 4/4 = 10 beats = 2 bars + 2 beats -> "3.3.00". CHECK(formatBarsBeats(MusicalLength{5.0, 120.0, 4, 4}) == "3.3.00"); } static void testLongCaptureNoBarCap() { // 256 s at 120 4/4 = 512 beats = 128 bars exactly -> bar 129, beat 1. CHECK(formatBarsBeats(MusicalLength{256.0, 120.0, 4, 4}) == "129.1.00"); } static void testThreeFourMeter() { // 3/4 at 120 BPM: beat = (60/120)*(4/4)=0.5 s, bar = 3 beats = 1.5 s. 1.5 s -> bar 2,1. CHECK(formatBarsBeats(MusicalLength{1.5, 120.0, 3, 4}) == "2.1.00"); // 1.0 s = 2 beats -> bar 1, beat 3. CHECK(formatBarsBeats(MusicalLength{1.0, 120.0, 3, 4}) == "1.3.00"); } static void testSixEightMeter() { // 6/8 at 120 BPM: an eighth-beat = (60/120)*(4/8) = 0.25 s; bar = 6 beats = 1.5 s. // 1.5 s -> bar 2, beat 1. CHECK(formatBarsBeats(MusicalLength{1.5, 120.0, 6, 8}) == "2.1.00"); // 0.25 s = exactly 1 eighth-beat -> bar 1, beat 2. CHECK(formatBarsBeats(MusicalLength{0.25, 120.0, 6, 8}) == "1.2.00"); } static void testUnstampedMeterIsBlank() { // 0/0 (pre-L7 sample) -> no musical read-out. CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 0, 0}).empty()); CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 4, 0}).empty()); // partial stamp also blank CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 0, 4}).empty()); } static void testUnknownTempoIsBlank() { // Tempo 0 -> no musical read-out even with a meter (cannot derive beats). CHECK(formatBarsBeats(MusicalLength{3.0, 0.0, 4, 4}).empty()); } static void testNegativeLengthClampsToOrigin() { // Defensive: a negative length reads as the origin, not garbage. CHECK(formatBarsBeats(MusicalLength{-5.0, 120.0, 4, 4}) == "1.1.00"); } // --- seconds.milliseconds ---------------------------------------------------- static void testSecondsMsZero() { CHECK(formatSecondsMs(0.0) == "0.000"); } static void testSecondsMsSubSecond() { CHECK(formatSecondsMs(0.5) == "0.500"); } static void testSecondsMsMultiSecond() { CHECK(formatSecondsMs(1.5) == "1.500"); CHECK(formatSecondsMs(62.037) == "62.037"); } static void testSecondsMsNegativeClamps() { CHECK(formatSecondsMs(-1.0) == "0.000"); } static void testSecondsMsNearWholeSecondCarry() { // 0.9999 s: floor to ms could hit 999 or 1000; the carry keeps it well-formed. const std::string r = formatSecondsMs(0.9999); CHECK(r == "0.999" || r == "1.000"); } int main() { testZeroLengthIsBarOneOrigin(); testSubBeat(); testWholeBeatWithinBar(); testExactBarBoundaryRollsOver(); testMultiBar(); testLongCaptureNoBarCap(); testThreeFourMeter(); testSixEightMeter(); testUnstampedMeterIsBlank(); testUnknownTempoIsBlank(); testNegativeLengthClampsToOrigin(); testSecondsMsZero(); testSecondsMsSubSecond(); testSecondsMsMultiSecond(); testSecondsMsNegativeClamps(); testSecondsMsNearWholeSecondCarry(); if (g_fail == 0) std::printf("card_meta: all tests passed\n"); else std::printf("card_meta: %d CHECK(s) FAILED\n", g_fail); return g_fail == 0 ? 0 : 1; }