# The shifter is hand-rolled rather than WDL_SimplePitchShifter because that header drags
# <windows.h> in via wdltypes.h, which cannot enter the pure engine.
reasampler_pure_library(pitch_shift SOURCES pitch_shift.cpp LINK PUBLIC peaks)
# Links only pitch_shift: linking more would break the plain-data-boundary proof — and
# specifically the compile-time proof it does not drag in the WDL <windows.h> chain.
reasampler_test(pitch_shift LINK pitch_shift)

# Deliberately NOT linked by sampler_core, enforcing period_detect.h's off-audio-thread
# invariant at build time: sampler_core_tests links sampler_core and nothing else, so no TU
# on the render path can name detectPeriod without failing to link.
reasampler_pure_library(period_detect SOURCES period_detect.cpp LINK PUBLIC peaks)
reasampler_test(period_detect LINK period_detect)

reasampler_pure_library(velocity_curve SOURCES velocity_curve.cpp)
# Links only velocity_curve, deliberately not editor_geometry: the proof the engine can
# depend on the curve without inheriting the editor's layout types.
reasampler_test(velocity_curve LINK velocity_curve)

reasampler_pure_library(master_gain SOURCES master_gain.cpp)
reasampler_test(master_gain LINK master_gain)

# Declared before sampler_core because the voice now runs one per sounding note.
add_subdirectory(filter)

# The sustain loop's validity + crossfade geometry, shared by the voice and the editor's
# marker layer. After filter: it links play_params' dependency set, which includes it.
add_subdirectory(loop)

# The live-parameter block: the value layer plus its publication, deliberately linking no
# engine — the block is a plain value the voice observes, not a thing the engine owns.
reasampler_pure_library(live_params
    SOURCES live_params.cpp
    LINK PUBLIC peaks velocity_curve filter curve_law)
reasampler_test(live_params LINK live_params)

# Two TUs on the engine's own responsibility seam (per-note setup vs. note routing and
# block render). The per-sample render half stays inline in voice.h precisely so this TU
# boundary costs the hot path nothing.
reasampler_pure_library(sampler_core
    SOURCES voice.cpp voice_engine.cpp
    LINK PUBLIC peaks pitch_shift velocity_curve filter live_params curve_law loop_span
                time_stretch)
# Links only sampler_core: linking more would break the plain-data-boundary proof — a VST3
# or REAPER type reaching the core would fail to compile or link here.
reasampler_test(sampler_core LINK sampler_core)

# The filter's own seams are covered by the four targets in filter/; this one covers the
# integration: pipeline order, per-voice independence, and the off-by-default bit-identity.
reasampler_test(sampler_filter LINK sampler_core)

# Live delivery is the third integration seam over the same engine: what a published block
# does to a voice that is already sounding, and what it must leave alone.
reasampler_test(live_delivery LINK sampler_core)

# The staged-envelope system across the same engine: per-segment curves, the sustain-less AHD
# both mode shapes share, and the Trigger tail's terminal behaviour.
reasampler_test(staged_envelopes LINK sampler_core)

# Measurement harness for Preserve on low-frequency material: how the splice search's
# reachable relocation interval interacts with a long source period. Written longhand and
# deliberately NOT add_test()'d — it sweeps frequencies, windows and spectra and takes ~2m40s
# in Debug, which does not belong in a gate whose other targets run in seconds. It still
# builds with everything else, so it cannot rot into non-compilation. Run it by hand, in
# Release, when the question is what Preserve does to a given frequency.
add_executable(preserve_low_frequency_tests
    ${REASAMPLER_TESTS_DIR}/test_preserve_low_frequency.cpp)
# period_detect beside sampler_core, not through it: the harness plays the role the loader
# does, which is exactly the seam under measurement.
target_link_libraries(preserve_low_frequency_tests PRIVATE sampler_core period_detect)

# Bridges the two structural proofs above (sample_map never links the voice engine;
# sampler_core never links period_detect) for the one case that needs both: a REAL detected
# period reaching a real Preserve render. Its own target rather than extending either.
reasampler_test(period_render_integration LINK sample_map sampler_core)

# The Preserve read's source-feed schedule — the TIME half beside pitch_shift's PITCH half.
# Header-only (it sits on the per-sample feed), hence INTERFACE.
add_library(time_stretch INTERFACE)
target_include_directories(time_stretch INTERFACE ${REASAMPLER_SRC_DIR})
target_link_libraries(time_stretch INTERFACE loop_span)
reasampler_test(time_stretch LINK time_stretch)

# The master bus's two pure halves. Neither links the engine: the limiter runs on the summed
# output, and the ballistics run on what the audio thread published about it.
reasampler_pure_library(limiter SOURCES limiter.cpp)
reasampler_test(limiter LINK limiter)

reasampler_pure_library(meter_ballistics SOURCES meter_ballistics.cpp)
reasampler_test(meter_ballistics LINK meter_ballistics)

# The meter's ACCUMULATE half, beside the ballistics that consume it. Header-only (the folds
# sit on the audio thread's per-block path), hence INTERFACE.
add_library(meter_accumulate INTERFACE)
target_include_directories(meter_accumulate INTERFACE ${REASAMPLER_SRC_DIR})
reasampler_test(meter_accumulate LINK meter_accumulate)
