// The one gated case that runs the WHOLE load->voice wire through REAL detection, closing the // gap between two halves proven separately: testBuildSampleDataDetectsThirtyHertzSourcePeriod // (test_sample_map.cpp, detectPeriod -> SampleData) never renders, and // testSourcePeriodChangesTheRenderedStream (test_sampler_core.cpp, SampleData -> Voice -> audio) // sets sourcePeriodFrames by hand rather than detecting it from PCM. Deliberately its own // target: sample_map_tests and sampler_core_tests each keep their one-lib-only structural proof // (map doesn't link the voice engine, the engine doesn't link period_detect), so bridging the // two lives here instead of extending either. #include "../src/core/instrument/map/sample_map.h" #include "../src/core/instrument/engine/voice_engine.h" #include #include #include #include #include using namespace reasampler; using namespace reasampler::instrument::engine; using namespace reasampler::instrument::map; static int g_fail = 0; #define CHECK(cond) do { if(!(cond)) { \ std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0) constexpr double kPi = 3.14159265358979323846; // An ADSR that stays fully open (level 1) forever while held — isolates the render from // envelope shaping (matches test_sampler_core.cpp's flatAdsr; not shared, both files stand // alone). static AdsrParams flatAdsr() { AdsrParams a; a.attackFrames = 0; a.decayFrames = 0; a.sustainLevel = 1.0; a.releaseFrames = 0; return a; } // FNV-1a over the raw float bits (matches test_sampler_core.cpp's hashStream). static std::uint64_t hashStream(const std::vector& v) { std::uint64_t h = 1469598103934665603ull; for (const AudioSample s : v) { std::uint32_t bits = 0; std::memcpy(&bits, &s, sizeof(bits)); for (int b = 0; b < 4; ++b) { h ^= static_cast((bits >> (8 * b)) & 0xffu); h *= 1099511628211ull; } } return h; } static void renderVoice(const SampleData& s, int note, std::int64_t window, std::size_t outFrames, std::vector& out) { Voice v; v.presizePreserveShifters(window); v.start(note, 127, s, /*declickTakeover=*/false, /*rate=*/1.0); out.resize(outFrames); for (std::size_t i = 0; i < outFrames; ++i) out[i] = v.renderFrame(); } // 30 Hz @ 44.1k through the REAL wire: buildSampleData (sample_map.cpp:333-334) calls // detectPeriod itself, so this proves the detected period actually reaches and moves the // Preserve render — not just that a hand-set sourcePeriodFrames does (that is the sampler_core // half; this is the missing map->engine seam). static void testDetectedPeriodReachesAndMovesThePreserveRender() { const std::int64_t w = 2205; // the product window at 44.1k const int rate = 44100; const std::size_t frames = 30000; std::vector pcm(frames); for (std::size_t i = 0; i < frames; ++i) { pcm[i] = static_cast( std::sin(2.0 * kPi * 30.0 * static_cast(i) / rate)); } SelectedSample ref; ref.relativePath = "b/a.wav"; ref.rootNote = 60; SampleData on = buildSampleData(resolveCapture(ref, InstrumentParams{}), DecodedPcm{pcm, rate, {}}); CHECK(std::fabs(on.sourcePeriodFrames - 1470.0) < 2.0); // 44100 / 30 Hz, real detection on.play.adsr = flatAdsr(); on.play.pitchEngine = PitchEngine::Preserve; SampleData off = on; off.sourcePeriodFrames = 0.0; // the fixed-window fallback the pre-wire render used std::vector outOn, outOff; renderVoice(on, /*note=*/67, w, 6000, outOn); // +7 st: real splices renderVoice(off, 67, w, 6000, outOff); for (AudioSample v : outOn) CHECK(std::isfinite(v)); CHECK(hashStream(outOn) != hashStream(outOff)); // the detected period actually moved the render } int main() { testDetectedPeriodReachesAndMovesThePreserveRender(); if (g_fail == 0) { std::printf("all period_render_integration tests passed\n"); return 0; } std::printf("%d period_render_integration check(s) failed\n", g_fail); return 1; }