Files
reasampler/CMakeLists.txt
T
daniel 34df2563e4 feat(m11): native OS drag-out of bank samples (copy-only)
Pure drag_out (gesture boundary + path-list assembly) + Windows OLE
CF_HDROP / SWELL file-list shell; bank_panel hands off when a dragged
selection leaves the client area. COPY-ONLY mask; internal drag intact.
2026-07-26 20:02:46 -04:00

509 lines
30 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
cmake_minimum_required(VERSION 3.19)
# ---------------------------------------------------------------------------
# Version — SINGLE SOURCE OF TRUTH (Phase V, V1). Edit REASAMPLER_VERSION here and
# nowhere else: it flows to the binary constant, the ext-state writing-version stamp,
# and the "show version" action via a configure_file'd header (below). The string is
# authoritative verbatim — leading zero preserved (Daniel-fixed: exactly "0.9.01",
# two-digit zero-padded patch). We deliberately do NOT reconstruct the display string
# from project(VERSION)'s numeric components, since CMake may normalize a numeric patch
# field; the string variable is what renders. project(VERSION ...) is still set (with a
# normalized 0.9.1 triple) for CMake hygiene / any downstream numeric use, but it is NOT
# the rendered source of truth.
set(REASAMPLER_VERSION "0.9.01")
project(reaper_reasampler VERSION 0.9.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# ---------------------------------------------------------------------------
# Channel — SINGLE SOURCE OF TRUTH for beta-in-isolation (Phase V, V4). One flag,
# `-DREASAMPLER_CHANNEL=beta`, forks the whole channel identity from one build tree:
# absent (or `stable`) = today's build with BYTE-IDENTICAL identity (binary name,
# ext-state namespace, command-id strings, version render); `beta` = a fully isolated
# `reaper_reasampler_beta` that coexists with stable in one REAPER. The flag reduces to
# ONE bit (REASAMPLER_CHANNEL_IS_BETA) threaded through the SAME configure_file'd header
# as the version string, so the pure app_version module derives every channel-qualified
# identity from it — no scattered #ifdefs. Any value other than exactly `beta` is treated
# as stable (a typo must not silently produce a half-forked build), and we hard-error on
# an unrecognized non-empty value so a misspelled `-DREASAMPLER_CHANNEL=betaa` is caught
# at configure time rather than shipping stable identity under a beta intent.
set(REASAMPLER_CHANNEL "stable" CACHE STRING "Build channel: stable (default) or beta")
if(REASAMPLER_CHANNEL STREQUAL "beta")
set(REASAMPLER_CHANNEL_IS_BETA 1)
set(REASAMPLER_OUTPUT_NAME "reaper_reasampler_beta")
elseif(REASAMPLER_CHANNEL STREQUAL "stable")
set(REASAMPLER_CHANNEL_IS_BETA 0)
set(REASAMPLER_OUTPUT_NAME "reaper_reasampler")
else()
message(FATAL_ERROR
"REASAMPLER_CHANNEL must be 'stable' or 'beta' (got '${REASAMPLER_CHANNEL}')")
endif()
# Generate version_generated.h from the one REASAMPLER_VERSION variable + the channel bit.
# Regenerated at configure time whenever either changes; the exact string is substituted
# verbatim and the channel bit fans out through app_version.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/src/version_generated.h.in
${CMAKE_CURRENT_BINARY_DIR}/generated/version_generated.h
@ONLY)
# ---------------------------------------------------------------------------
# Vendored dependencies — add as git submodules (see README):
# git submodule add https://github.com/justinfrankel/reaper-sdk vendor/reaper-sdk
# git submodule add https://github.com/justinfrankel/WDL vendor/WDL
# ---------------------------------------------------------------------------
set(SDK_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/reaper-sdk/sdk)
set(WDL_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/WDL/WDL)
set(SWELL ${WDL_INC}/swell)
# ---------------------------------------------------------------------------
# 1) Pure model library — NO REAPER, NO SWELL. Builds & tests anywhere.
# The sampler's heart: Sample metadata + BankIndex (Milestone 1).
# ---------------------------------------------------------------------------
add_library(bank_model STATIC src/bank_model.cpp)
target_include_directories(bank_model PUBLIC src)
# ---------------------------------------------------------------------------
# 2) Pure peaks library — NO REAPER, NO SWELL. Waveform min/max thumbnails from
# raw PCM (Milestone 2). A sibling pure lib, kept distinct from bank_model.
# ---------------------------------------------------------------------------
add_library(peaks STATIC src/peaks.cpp)
target_include_directories(peaks PUBLIC src)
# ---------------------------------------------------------------------------
# 2b) Pure capture-path arithmetic — NO REAPER, NO SWELL. Bank-folder / unique
# file-name / project-relative path derivation for the capture shell (M3).
# Split out so the fiddly path logic is unit-tested outside the DAW.
# ---------------------------------------------------------------------------
add_library(capture_paths STATIC src/capture_paths.cpp)
target_include_directories(capture_paths PUBLIC src)
# ---------------------------------------------------------------------------
# 2c) Pure bank-grid layout — NO REAPER, NO SWELL. Grid tiling math (panel WxH +
# cell size + N -> cell rects, wrapping, partial last row) and the thumbnail
# cache key for the docked bank_panel (M5). Split out so the layout logic is
# unit-tested outside the DAW; the panel shell (SWELL/LICE/PCM) is DAW-verified.
# ---------------------------------------------------------------------------
add_library(bank_grid STATIC src/bank_grid.cpp)
target_include_directories(bank_grid PUBLIC src)
# ---------------------------------------------------------------------------
# 2c') Pure mode_switch layout — NO REAPER, NO SWELL. The Design-View mode-switch
# geometry (D5): header rect + N modes -> N equal segment rects (exact tiling),
# and point -> segment hit-test. Split out so the switch's layout math is
# unit-tested outside the DAW; the bank_panel header strip that draws it and
# routes clicks to view::applyMode is DAW-verified. Mirror of bank_grid.
# ---------------------------------------------------------------------------
add_library(mode_switch STATIC src/mode_switch.cpp)
target_include_directories(mode_switch PUBLIC src)
# ---------------------------------------------------------------------------
# 2c'') Pure tab_strip layout — NO REAPER, NO SWELL. The named-banks tab-strip
# geometry (B4): strip rect + N tabs at a fixed tab width + scroll offset ->
# per-tab rects (overflow-clipped), overflow chevron reservation + maxScroll,
# and point -> tab / chevron hit-test. Split out so the strip's layout +
# overflow/scroll math is unit-tested outside the DAW; the bank_panel region
# that draws it and routes clicks is DAW-verified. Mirror of mode_switch.
# ---------------------------------------------------------------------------
add_library(tab_strip STATIC src/tab_strip.cpp)
target_include_directories(tab_strip PUBLIC src)
# ---------------------------------------------------------------------------
# 2d) Pure view_mode_model library — NO REAPER, NO SWELL. The Design View heart
# (Phase D1): mode registry + GUID-keyed membership index + folder-tree-aware
# visibility derivation + parking/restore planner + JSON round-trip. Mirror of
# bank_model; the folder tree is an INPUT supplied by the D2 shell.
# ---------------------------------------------------------------------------
add_library(view_mode_model STATIC src/view_mode_model.cpp)
target_include_directories(view_mode_model PUBLIC src)
# The pure lane-minting decision (planLaneMinting) names managed lanes via the ONE
# durable-key convention in lane_keys (laneNameForMode), so the model depends on that
# pure sibling. PUBLIC so every consumer (tests + module) resolves the symbol.
target_link_libraries(view_mode_model PUBLIC lane_keys)
# ---------------------------------------------------------------------------
# 2d) Pure view_tree library — NO REAPER, NO SWELL. The one testable-outside-DAW
# piece of the D2 view shell: turning REAPER's linear I_FOLDERDEPTH stream into
# the parent<->child FolderTree the model consumes. The REAPER reads stay in
# view.cpp; this fiddly folder-depth walk is unit-tested here (mirrors
# capture_paths splitting the path math out of the capture shell).
# ---------------------------------------------------------------------------
add_library(view_tree STATIC src/view_tree.cpp)
target_include_directories(view_tree PUBLIC src)
target_link_libraries(view_tree PUBLIC view_mode_model)
# ---------------------------------------------------------------------------
# 2d'') Pure guid_diff library — NO REAPER, NO SWELL. The D2 Wave-2 new-content
# detection core: current \ previous GUID diff + the first-poll-after-open
# baseline guard (and per-project reset). Split out so the fiddly baseline/diff
# logic is unit-tested outside the DAW; the bank_panel timer that reads REAPER's
# live track/item GUID set and applies the tags is DAW-verified. Mirror of
# view_tree splitting the folder-depth walk out of view.cpp.
# ---------------------------------------------------------------------------
add_library(guid_diff STATIC src/guid_diff.cpp)
target_include_directories(guid_diff PUBLIC src)
# ---------------------------------------------------------------------------
# 2d''') Pure lane_keys library — NO REAPER, NO SWELL. The managed/manual fixed-lane
# heuristic (D2 Wave-2): a lane whose durable P_LANENAME:n carries the
# "reasampler:" prefix is tool-managed and keyed by that stable name; any other
# lane is user-minted manual and off-limits. Resolves design point #1 (auto-tag
# exemption) and #2 (name-keyed identity survives ordinal renumber). Split out
# so the prefix rule is unit-tested; view.cpp reads the names from REAPER.
# ---------------------------------------------------------------------------
add_library(lane_keys STATIC src/lane_keys.cpp)
target_include_directories(lane_keys PUBLIC src)
# ---------------------------------------------------------------------------
# 2e) Pure insert_plan library — NO REAPER, NO SWELL. The InsertMedia `mode`
# bitmask arithmetic behind the `insert` shell (M6). Split out so the
# load-bearing bit computation (no silent stretch, opt-in conform) is
# unit-tested outside the DAW; the InsertMedia call itself is DAW-verified.
# ---------------------------------------------------------------------------
add_library(insert_plan STATIC src/insert_plan.cpp)
target_include_directories(insert_plan PUBLIC src)
# ---------------------------------------------------------------------------
# 2f) Pure render_settings library — NO REAPER, NO SWELL. The M7 capture-family
# logic: source-mode + wet/dry -> RENDER_SETTINGS bit value, P_RAZOREDITS
# string -> time ranges + union bound, and the capture-action taxonomy table.
# Split out so the fiddly bit-mapping / razor-parsing is unit-tested outside
# the DAW; the render-driving + selection reads stay in capture.cpp / main.cpp.
# Depends on bank_model for the pure SourceMode enum.
# ---------------------------------------------------------------------------
add_library(render_settings STATIC src/render_settings.cpp)
target_include_directories(render_settings PUBLIC src)
target_link_libraries(render_settings PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2f'') Pure batch_capture library — NO REAPER, NO SWELL. The M11 batch-capture
# logic: an ordered list of source ranges (one per selected item / per razor
# area) -> validated, ordinal-assigned capture units (empty/inverted dropped),
# plus order-preserving per-unit result aggregation into a mixed-result summary
# line. Split out so the plan/aggregate/summary is unit-tested outside the DAW;
# the selection read, transient re-selection, and render loop stay in main.cpp.
# No dependency on bank_model — it takes plain ranges/values at its boundary.
# ---------------------------------------------------------------------------
add_library(batch_capture STATIC src/batch_capture.cpp)
target_include_directories(batch_capture PUBLIC src)
# ---------------------------------------------------------------------------
# 2f') Pure tail_control library — NO REAPER, NO SWELL. The docked bank_panel's
# tail-mode toggle logic (T1 exposure): TailSetting state, cycle order
# (None->Auto->Manual->None), the manual-length clamp to the 8 s cap, and the
# toggle label text. Split out so the toggle's cycle/clamp/label is unit-tested
# outside the DAW; the bank_panel footer that draws it + routes clicks is
# DAW-verified. Depends on render_settings for the pure TailMode enum + caps.
# ---------------------------------------------------------------------------
add_library(tail_control STATIC src/tail_control.cpp)
target_include_directories(tail_control PUBLIC src)
target_link_libraries(tail_control PUBLIC render_settings)
# ---------------------------------------------------------------------------
# 2g') Pure bank_book library — NO REAPER, NO SWELL. The multi-bank phase heart
# (Phase B1): an ordered registry of banks (pool seeded as bank-zero + named
# banks), each wrapping a BankIndex; create/rename/reorder/delete named banks,
# pool privileges enforced in-model, active-bank id, index-only move/copy of a
# sample between banks, JSON round-trip + legacy-bank_index→pool migration.
# Mirror of bank_model / view_mode_model; wraps BankIndex (bank_model untouched).
# ---------------------------------------------------------------------------
add_library(bank_book STATIC src/bank_book.cpp)
target_include_directories(bank_book PUBLIC src)
target_link_libraries(bank_book PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2g'') Pure owned_manifest library — NO REAPER, NO SWELL. The owned-file manifest
# seam (Phase B B-cap): the set of project-relative files the capture path
# itself created, so Phase R prune can tell the bank system's own orphans from
# hand-dropped files. Deliberately DECOUPLED from bank_book — it tracks files
# CREATED, not index membership (sample-remove is not manifest-remove). Small
# pure type + JSON round-trip; mirror of wav_trim / tab_strip. B-cap writes +
# persists it; Phase R (R1/R2) consumes it — no prune logic here.
# ---------------------------------------------------------------------------
add_library(owned_manifest STATIC src/owned_manifest.cpp)
target_include_directories(owned_manifest PUBLIC src)
# ---------------------------------------------------------------------------
# 2g''') Pure prune_reconcile library — NO REAPER, NO SWELL, NO filesystem. The
# Phase R (Reclaim) Wave-1 safety-critical decision: given the files present
# in the bank folder, the union of files referenced across every bank, and the
# owned-file manifest, compute the orphan set (owned ∩ present) referenced.
# Mirror of view_mode_model::reconcile one level down (files, not GUIDs). Small
# pure function; R2/R3 wrap the two ends (folder enumeration + deletion) in the
# shell. Standalone — depends only on the standard library.
# ---------------------------------------------------------------------------
add_library(prune_reconcile STATIC src/prune_reconcile.cpp)
target_include_directories(prune_reconcile PUBLIC src)
# ---------------------------------------------------------------------------
# 2g'''') Pure prune_button layout — NO REAPER, NO SWELL. The Phase R (Reclaim)
# Wave-3 (R3, fork R-E) prune-button geometry: footer rect -> right-anchored
# button rect (suppressed when the footer is too narrow), and point -> in/out
# hit-test. Split out so the button's placement + hit-test math is unit-tested
# outside the DAW; the bank_panel footer that draws it and dispatches the
# "Prune bank folder" command is DAW-verified. Mirror of mode_switch / tab_strip.
# ---------------------------------------------------------------------------
add_library(prune_button STATIC src/prune_button.cpp)
target_include_directories(prune_button PUBLIC src)
# ---------------------------------------------------------------------------
# 2g) Pure realtime_record library — NO REAPER, NO SWELL. The M8 realtime-record
# logic: capture scope + FX-tap point -> I_RECMODE / I_RECMODE_FLAGS values,
# wet/dry -> tap point, and the recorded-file -> Sample mapping. Split out so
# the fiddly record-mode bit values + Sample population are unit-tested outside
# the DAW; the transport/temp-track/send/file-move recipe stays in capture.cpp.
# Depends on bank_model for the pure Sample / SourceMode types.
# ---------------------------------------------------------------------------
add_library(realtime_record STATIC src/realtime_record.cpp)
target_include_directories(realtime_record PUBLIC src)
target_link_libraries(realtime_record PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2h) Pure wav_trim library — NO REAPER, NO SWELL. The realtime tail's (T2) PCM
# decay-scan trim needs to TRUNCATE the recorded 32-bit-float WAV at a frame
# boundary without corrupting the RIFF container. This module holds the fiddly,
# easy-to-get-wrong part unit-tested outside the DAW: parse the WAV geometry
# (fmt/data chunk walk + 32-bit-float verification), extract the tail-region
# floats to scan, and compute the truncate plan (kept byte length + the two
# patched RIFF/data size fields). The file read/write/truncate I/O stays in the
# realtime shell. Depends on peaks for the AudioSample float alias.
# ---------------------------------------------------------------------------
add_library(wav_trim STATIC src/wav_trim.cpp)
target_include_directories(wav_trim PUBLIC src)
target_link_libraries(wav_trim PUBLIC peaks)
# ---------------------------------------------------------------------------
# 2i) Pure app_version library — NO REAPER, NO SWELL. The Phase V (V1) version-identity
# core: re-exports the ONE CMake-sourced version string (via the configure_file'd
# version_generated.h) and owns the pure parse/compare/classify logic — the semver
# ordering a within-channel forward migration needs, and the three-way writing-version
# classification (PreVersioning / Unknown / Stamped) persist reads back from ext state.
# Split out so the exact-string fidelity + parse/compare are unit-tested outside the
# DAW; the ext-state write/read (persist) and the show-version action (main) are shell.
# Depends on the generated header in the build tree (PUBLIC so every consumer sees it).
# ---------------------------------------------------------------------------
add_library(app_version STATIC src/app_version.cpp)
target_include_directories(app_version PUBLIC src ${CMAKE_CURRENT_BINARY_DIR}/generated)
# ---------------------------------------------------------------------------
# 2j) Pure provenance library — NO REAPER, NO SWELL. The Milestone 10 core: the
# recorded capture recipe (CaptureRecipe) + the thin drift-fingerprint that
# rides in Provenance.fxChainSnapshot (P1=a), its build/parse round-trip, the
# FX-chain identity fold, and the pure parent-detection decision (resample-from-
# sample by resolved file path). Split out so the encoding + decision logic are
# unit-tested outside the DAW; the FX-chain query, capture re-run, and action
# registration stay in the shell (main.cpp / actions.cpp). No dependency on
# bank_model — it takes plain strings/values at its boundary.
# ---------------------------------------------------------------------------
add_library(provenance STATIC src/provenance.cpp)
target_include_directories(provenance PUBLIC src)
# ---------------------------------------------------------------------------
# 2k) Pure action_buttons library — NO REAPER, NO SWELL. The Milestone 11
# action-trigger button strip: strip rect + N buttons at a minimum width ->
# per-button rects (equal tiling; overflow HIDES excess on a narrow panel
# rather than clipping), point -> button hit-test, and the button label format
# (action name + SDK binding string -> label, with the unbound/blank case
# degraded to an explicit marker and an over-long binding truncated). Split out
# so the layout + label math is unit-tested outside the DAW; the bank_panel
# draw + NamedCommandLookup/Main_OnCommand dispatch + kbd_getTextFromCmd query
# are DAW-verified. Mirror of mode_switch / tab_strip.
# ---------------------------------------------------------------------------
add_library(action_buttons STATIC src/action_buttons.cpp)
target_include_directories(action_buttons PUBLIC src)
# ---------------------------------------------------------------------------
# 2l) Pure drag_out library — NO REAPER, NO SWELL, NO OS/OLE. The Milestone 11
# native-OS-drag-out decision core: the gesture-boundary decision (drag state +
# pointer + panel rect -> internal drag / OS drag / none — the invariant-#4 seam
# that keeps the internal bank-to-bank drag byte-identical) and the drag path-list
# assembly (resolved sample paths -> de-duped, existing-only absolute path list with
# an explicit skip-missing / skip-unresolved policy). Split out so the boundary +
# set algebra are unit-tested outside the DAW; the OLE DoDragDrop / SWELL file-list
# initiation (drag_out_win) and the bank_panel gesture hook are DAW-verified. Mirror
# of action_buttons / mode_switch.
# ---------------------------------------------------------------------------
add_library(drag_out STATIC src/drag_out.cpp)
target_include_directories(drag_out PUBLIC src)
# ---------------------------------------------------------------------------
# 3) Standalone tests for the pure modules (run without launching REAPER).
# ---------------------------------------------------------------------------
enable_testing()
add_executable(bank_model_tests tests/test_bank_model.cpp)
target_link_libraries(bank_model_tests PRIVATE bank_model)
add_test(NAME bank_model_tests COMMAND bank_model_tests)
add_executable(peaks_tests tests/test_peaks.cpp)
target_link_libraries(peaks_tests PRIVATE peaks)
add_test(NAME peaks_tests COMMAND peaks_tests)
add_executable(capture_paths_tests tests/test_capture_paths.cpp)
target_link_libraries(capture_paths_tests PRIVATE capture_paths)
add_test(NAME capture_paths_tests COMMAND capture_paths_tests)
add_executable(bank_grid_tests tests/test_bank_grid.cpp)
target_link_libraries(bank_grid_tests PRIVATE bank_grid)
add_test(NAME bank_grid_tests COMMAND bank_grid_tests)
add_executable(mode_switch_tests tests/test_mode_switch.cpp)
target_link_libraries(mode_switch_tests PRIVATE mode_switch)
add_test(NAME mode_switch_tests COMMAND mode_switch_tests)
add_executable(tab_strip_tests tests/test_tab_strip.cpp)
target_link_libraries(tab_strip_tests PRIVATE tab_strip)
add_test(NAME tab_strip_tests COMMAND tab_strip_tests)
add_executable(view_mode_model_tests tests/test_view_mode_model.cpp)
target_link_libraries(view_mode_model_tests PRIVATE view_mode_model)
add_test(NAME view_mode_model_tests COMMAND view_mode_model_tests)
add_executable(view_tree_tests tests/test_view_tree.cpp)
target_link_libraries(view_tree_tests PRIVATE view_tree)
add_test(NAME view_tree_tests COMMAND view_tree_tests)
add_executable(guid_diff_tests tests/test_guid_diff.cpp)
target_link_libraries(guid_diff_tests PRIVATE guid_diff)
add_test(NAME guid_diff_tests COMMAND guid_diff_tests)
add_executable(lane_keys_tests tests/test_lane_keys.cpp)
target_link_libraries(lane_keys_tests PRIVATE lane_keys)
add_test(NAME lane_keys_tests COMMAND lane_keys_tests)
add_executable(insert_plan_tests tests/test_insert_plan.cpp)
target_link_libraries(insert_plan_tests PRIVATE insert_plan)
add_test(NAME insert_plan_tests COMMAND insert_plan_tests)
add_executable(render_settings_tests tests/test_render_settings.cpp)
target_link_libraries(render_settings_tests PRIVATE render_settings)
add_test(NAME render_settings_tests COMMAND render_settings_tests)
add_executable(batch_capture_tests tests/test_batch_capture.cpp)
target_link_libraries(batch_capture_tests PRIVATE batch_capture)
add_test(NAME batch_capture_tests COMMAND batch_capture_tests)
add_executable(tail_control_tests tests/test_tail_control.cpp)
target_link_libraries(tail_control_tests PRIVATE tail_control)
add_test(NAME tail_control_tests COMMAND tail_control_tests)
add_executable(realtime_record_tests tests/test_realtime_record.cpp)
target_link_libraries(realtime_record_tests PRIVATE realtime_record)
add_test(NAME realtime_record_tests COMMAND realtime_record_tests)
add_executable(bank_book_tests tests/test_bank_book.cpp)
target_link_libraries(bank_book_tests PRIVATE bank_book)
add_test(NAME bank_book_tests COMMAND bank_book_tests)
add_executable(wav_trim_tests tests/test_wav_trim.cpp)
target_link_libraries(wav_trim_tests PRIVATE wav_trim)
add_test(NAME wav_trim_tests COMMAND wav_trim_tests)
add_executable(owned_manifest_tests tests/test_owned_manifest.cpp)
target_link_libraries(owned_manifest_tests PRIVATE owned_manifest)
add_test(NAME owned_manifest_tests COMMAND owned_manifest_tests)
add_executable(prune_reconcile_tests tests/test_prune_reconcile.cpp)
target_link_libraries(prune_reconcile_tests PRIVATE prune_reconcile bank_book)
add_test(NAME prune_reconcile_tests COMMAND prune_reconcile_tests)
add_executable(prune_button_tests tests/test_prune_button.cpp)
target_link_libraries(prune_button_tests PRIVATE prune_button)
add_test(NAME prune_button_tests COMMAND prune_button_tests)
add_executable(app_version_tests tests/test_app_version.cpp)
target_link_libraries(app_version_tests PRIVATE app_version)
add_test(NAME app_version_tests COMMAND app_version_tests)
# The provenance test links bank_model too — it proves the recorded recipe survives
# the Sample-JSON round-trip (Provenance.fxChainSnapshot), the M1 seam M10 rides on.
add_executable(provenance_tests tests/test_provenance.cpp)
target_link_libraries(provenance_tests PRIVATE provenance bank_model)
add_test(NAME provenance_tests COMMAND provenance_tests)
add_executable(action_buttons_tests tests/test_action_buttons.cpp)
target_link_libraries(action_buttons_tests PRIVATE action_buttons)
add_test(NAME action_buttons_tests COMMAND action_buttons_tests)
add_executable(drag_out_tests tests/test_drag_out.cpp)
target_link_libraries(drag_out_tests PRIVATE drag_out)
add_test(NAME drag_out_tests COMMAND drag_out_tests)
# ---------------------------------------------------------------------------
# 4) The REAPER extension — a loadable module (dlopen'd by REAPER, not linked).
# ---------------------------------------------------------------------------
# LICE sources the bank_panel draws with: lice.cpp (LICE_SysBitmap, FillRect,
# Clear, Blit) + lice_line.cpp (Line, DrawRect). lice_line.cpp's bezier helpers
# call LICE_FillCircle from lice_arc.cpp, so that TU is required to link even
# though the panel draws no arcs. LICE routes GDI through native Win32 or, on
# mac/linux, the host SWELL (SWELL_PROVIDED_BY_APP).
set(LICE_SRC
${WDL_INC}/lice/lice.cpp
${WDL_INC}/lice/lice_line.cpp
${WDL_INC}/lice/lice_arc.cpp
)
add_library(reaper_reasampler MODULE
src/main.cpp
src/capture.cpp
src/capture_realtime.cpp
src/realtime_record.cpp
src/persist.cpp
src/bank_panel.cpp
src/mode_switch.cpp
src/tab_strip.cpp
src/insert.cpp
src/insert_plan.cpp
${LICE_SRC}
src/view_mode_model.cpp
src/view_tree.cpp
src/view.cpp
src/track_guid.cpp
src/provenance_shell.cpp
src/guid_diff.cpp
src/lane_keys.cpp
src/item_read.cpp
src/actions.cpp
src/bank_book.cpp
src/owned_manifest.cpp
src/drag_out_win.cpp
)
target_link_libraries(reaper_reasampler PRIVATE bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model insert_plan render_settings batch_capture tail_control realtime_record bank_book wav_trim owned_manifest prune_reconcile prune_button app_version provenance action_buttons drag_out)
target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC})
# OUTPUT_NAME is channel-derived (Phase V, V4): "reaper_reasampler" (stable, default) or
# "reaper_reasampler_beta" (beta). REAPER dlopen's any reaper_* module, so both channels'
# artifacts load side-by-side. The CMake TARGET name stays "reaper_reasampler" for both
# configs — one source tree, one target; only the emitted file name forks by channel.
set_target_properties(reaper_reasampler PROPERTIES PREFIX "" OUTPUT_NAME "${REASAMPLER_OUTPUT_NAME}")
if(WIN32)
# Native Win32. REAPER provides nothing extra to link. The bank_panel dialog
# template (M5) is compiled from src/resource.rc by the platform RC compiler.
target_sources(reaper_reasampler PRIVATE src/resource.rc)
elseif(APPLE)
# macOS: use REAPER's OWN SWELL at runtime via the modstub.
# Do NOT build full SWELL. SWELL_PROVIDED_BY_APP routes calls to the host.
target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub.mm)
target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
target_link_libraries(reaper_reasampler PRIVATE "-framework AppKit")
set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".dylib")
# bank_panel dialog (M5): SWELL can't read a Win32 .rc directly. Run resgen
# once to turn src/resource.rc into a C++ source, then add it here:
# php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
# target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h) # generated
else()
# Linux: REAPER's libSwell.so is used at runtime via the generic modstub.
# With SWELL_PROVIDED_BY_APP you can drop pkg-config / -lX11 entirely.
target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub-generic.cpp)
target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".so")
# bank_panel dialog (M5): reuse the macOS resgen output (see README /
# CLAUDE.md §SWELL dialog resources), then add the generated source:
# php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
# target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h) # generated
endif()