From d04045be692cd65822d221d29d4d1ec016808d48 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Thu, 30 Jul 2026 12:19:18 -0400 Subject: [PATCH 1/3] build: split the 1423-line root CMakeLists into per-directory files with shared target helpers --- CLAUDE.md | 4 +- CMakeLists.txt | 1424 +---------------- cmake/reasampler_targets.cmake | 24 + src/app/CMakeLists.txt | 105 ++ src/core/CMakeLists.txt | 17 + src/core/audio/CMakeLists.txt | 2 + src/core/capture/CMakeLists.txt | 22 + src/core/instrument/CMakeLists.txt | 3 + src/core/instrument/engine/CMakeLists.txt | 26 + .../instrument/engine/filter/CMakeLists.txt | 15 + src/core/instrument/map/CMakeLists.txt | 31 + src/core/instrument/ui/CMakeLists.txt | 48 + src/core/json/CMakeLists.txt | 2 + src/core/model/CMakeLists.txt | 17 + src/core/reclaim/CMakeLists.txt | 3 + src/core/ui/CMakeLists.txt | 40 + src/core/util/CMakeLists.txt | 2 + src/core/version/CMakeLists.txt | 42 + src/core/view/CMakeLists.txt | 18 + src/core/wire/CMakeLists.txt | 18 + src/shell/instrument/CMakeLists.txt | 106 ++ 21 files changed, 591 insertions(+), 1378 deletions(-) create mode 100644 cmake/reasampler_targets.cmake create mode 100644 src/app/CMakeLists.txt create mode 100644 src/core/CMakeLists.txt create mode 100644 src/core/audio/CMakeLists.txt create mode 100644 src/core/capture/CMakeLists.txt create mode 100644 src/core/instrument/CMakeLists.txt create mode 100644 src/core/instrument/engine/CMakeLists.txt create mode 100644 src/core/instrument/engine/filter/CMakeLists.txt create mode 100644 src/core/instrument/map/CMakeLists.txt create mode 100644 src/core/instrument/ui/CMakeLists.txt create mode 100644 src/core/json/CMakeLists.txt create mode 100644 src/core/model/CMakeLists.txt create mode 100644 src/core/reclaim/CMakeLists.txt create mode 100644 src/core/ui/CMakeLists.txt create mode 100644 src/core/util/CMakeLists.txt create mode 100644 src/core/version/CMakeLists.txt create mode 100644 src/core/view/CMakeLists.txt create mode 100644 src/core/wire/CMakeLists.txt create mode 100644 src/shell/instrument/CMakeLists.txt diff --git a/CLAUDE.md b/CLAUDE.md index d17fbe1..b7a27e9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,7 +42,7 @@ Vendors three submodules (see `.gitmodules`): cmake --build build ctest --test-dir build -Every pure module has a corresponding `_tests` executable target that runs without REAPER or a DAW. `CMakeLists.txt` is the authoritative target list. The two loadable-module targets are `reaper_reasampler` (the REAPER extension `.dll`/`.dylib`/`.so`) and `reasampler_vst` (the VST3 instrument; Windows-only, omitted if the `vendor/vst3sdk` slice is absent). The `sample_usage_tests` executable target runs the pure unit tests for `sample_usage` (no REAPER, no DAW). +Every pure module has a corresponding `_tests` executable target that runs without REAPER or a DAW. Targets are declared per directory: each `src/**/CMakeLists.txt` owns its own libraries and their test targets, added via `add_subdirectory` from the root, which keeps only repo-global settings (version, channel, vendor paths). `cmake/reasampler_targets.cmake` holds the two shared declaration helpers. The two loadable-module targets are `reaper_reasampler` (the REAPER extension `.dll`/`.dylib`/`.so`) and `reasampler_vst` (the VST3 instrument; Windows-only, omitted if the `vendor/vst3sdk` slice is absent). The `sample_usage_tests` executable target runs the pure unit tests for `sample_usage` (no REAPER, no DAW). ### Beta channel build @@ -61,7 +61,7 @@ The VST3 target forks identically: `REASAMPLER_CHANNEL=beta` produces `reasample php vendor/WDL/WDL/swell/swell_resgen.php src/resource.rc # macOS; Linux reuses the output -Add the generated file to the appropriate `APPLE` / Linux `target_sources` block in CMakeLists.txt. The SWS extension build is the canonical reference for this step. +Add the generated file to the appropriate `APPLE` / Linux `target_sources` block in `src/app/CMakeLists.txt`. The SWS extension build is the canonical reference for this step. ### Install / reload diff --git a/CMakeLists.txt b/CMakeLists.txt index b99d138..8afb675 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,26 @@ 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 — any leading zeros are preserved exactly as written (Daniel's -# ruling: padded and unpadded versions are BOTH legitimate — "0.9.8" and "0.9.80" are -# different versions, and the system must never force zero-padding). 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 for CMake hygiene / any downstream numeric use, but -# it is NOT the rendered source of truth. +# Version — SINGLE SOURCE OF TRUTH. Edit REASAMPLER_VERSION here and nowhere else: it flows +# to the binary constant, the ext-state writing-version stamp, and the "show version" action +# through the configured header below. The string is authoritative verbatim, leading zeros +# included — padded and unpadded versions are BOTH legitimate ("0.9.8" and "0.9.80" are +# different versions), so nothing may force zero-padding. # # *** INVARIANT — DO NOT COLLAPSE OR DERIVE *** -# The set(REASAMPLER_VERSION ...) line below MUST remain a verbatim string literal, -# even when it is textually identical to the project(VERSION ...) line. It must NEVER -# become +# The set(REASAMPLER_VERSION ...) line below MUST stay a verbatim string literal, even when +# it is textually identical to the project(VERSION ...) line. It must NEVER become # set(REASAMPLER_VERSION "${PROJECT_VERSION}") # set(REASAMPLER_VERSION "${CMAKE_PROJECT_VERSION}") -# or any other form that derives the string from project(). CMake normalizes numeric -# patch fields: a padded "0.9.01" would silently round-trip to "0.9.1" and break the -# displayed version string. The verbatim-threading invariant is guarded at build time -# by app_version_padding_tests (a synthetic zero-padded canary; see the padding-canary -# block after app_version_tests). That guard detects reconstruct-from-components -# regressions in app_version.cpp but does NOT guard against this line being changed to -# a CMake variable derivation — that is this comment's job. +# or any other form derived from project(): CMake normalizes numeric patch fields, so a +# padded "0.9.01" would silently round-trip to "0.9.1" and break the displayed version. +# project(VERSION ...) is kept for CMake hygiene and downstream numeric use, but it is NOT +# the rendered source of truth. # -# There is a SECOND set(REASAMPLER_VERSION ...) inside the padding-canary function -# further down. That one is a permanent test fixture ("0.9.01") and must NEVER be -# bumped on release. +# The padding canary in src/core/version/CMakeLists.txt guards the other half of this +# invariant (reconstruct-from-components inside app_version.cpp) via a permanent synthetic +# "0.9.01" fixture there that must NEVER be bumped on release. It cannot see this line +# becoming a CMake derivation — that is this comment's job. set(REASAMPLER_VERSION "1.0.0") project(reaper_reasampler VERSION 1.0.0 LANGUAGES CXX) @@ -38,23 +30,19 @@ 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. +# Channel — SINGLE SOURCE OF TRUTH for beta-in-isolation. One flag forks the whole channel +# identity from one build tree: absent (or `stable`) is today's build with byte-identical +# identity; `beta` is a fully isolated artifact that coexists with stable in one REAPER. The +# flag reduces to ONE bit threaded through the SAME generated header as the version string, +# so app_version derives every channel-qualified identity from it and no #ifdefs scatter. +# An unrecognized non-empty value hard-errors at configure time: a misspelled +# -DREASAMPLER_CHANNEL=betaa must not silently ship 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") - # The VST3 instrument's on-disk name forks the same way (S18) — must match - # app_version::vstOutputName() so the artifact name and the in-binary self-id agree. + # Must match app_version::vstOutputName() so the artifact name and the in-binary + # self-id agree. set(REASAMPLER_VST_OUTPUT_NAME "reasampler_9000_beta") elseif(REASAMPLER_CHANNEL STREQUAL "stable") set(REASAMPLER_CHANNEL_IS_BETA 0) @@ -65,1089 +53,28 @@ else() "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. +# Regenerated at configure time whenever the version string or the channel bit changes; the +# string is substituted verbatim. configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/src/core/version/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) - -# --------------------------------------------------------------------------- -# 0) core/ — the Q-W1 shared pure substrate. NO REAPER, NO SWELL, NO VST3. -# json: the ONE JSON lexical layer (reader + writer) behind the five -# persisted-blob (de)serializers (bank_model / bank_book / -# view_mode_model / owned_manifest / tail_control). T2-02 / §2. -# wire: the ONE length-prefixed ext-state wire codec (putField + Cursor + -# the guarded decimal accumulate) behind provenance / -# assignment_request / sample_usage / bank_sync. T2-01(b). -# file_bytes: the ONE whole-file byte loader both artifacts link. T2-03. -# Headers are included as "core/json/json.h" etc. (rooted at src/), so the -# include paths survive the Q-W1 part-2 directory relocation unchanged. -# --------------------------------------------------------------------------- -add_library(json STATIC src/core/json/json.cpp) -target_include_directories(json PUBLIC src) - -add_library(wire STATIC src/core/wire/wire.cpp) -target_include_directories(wire PUBLIC src) - -add_library(file_bytes STATIC src/core/util/file_bytes.cpp) -target_include_directories(file_bytes PUBLIC src) - -# --------------------------------------------------------------------------- -# 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/core/model/bank_model.cpp) -target_include_directories(bank_model PUBLIC src) -target_link_libraries(bank_model PRIVATE json) - -# --------------------------------------------------------------------------- -# 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/core/audio/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/core/capture/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/core/ui/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/core/view/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/core/ui/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/core/view/view_mode_model.cpp) -target_include_directories(view_mode_model PUBLIC src) -target_link_libraries(view_mode_model PRIVATE json) -# 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/core/view/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/core/view/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/core/view/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/core/capture/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/core/capture/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/core/capture/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/core/capture/tail_control.cpp) -target_include_directories(tail_control PUBLIC src) -target_link_libraries(tail_control PUBLIC render_settings) -target_link_libraries(tail_control PRIVATE json) - -# --------------------------------------------------------------------------- -# 2g''') Pure slot_map library — NO REAPER, NO SWELL. The L7 gap-preserving -# display-position carrier for one bank (extracted from bank_book, Q-W1 -# T4-05): sample id -> slot, gap-preserving append/remove/reorder/reconcile, -# JSON round-trip. Mirror of bank_model; wrapped (not merged) by bank_book. -# --------------------------------------------------------------------------- -add_library(slot_map STATIC src/core/model/slot_map.cpp) -target_include_directories(slot_map PUBLIC src) -target_link_libraries(slot_map PRIVATE json) - -# --------------------------------------------------------------------------- -# 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/core/model/bank_book.cpp - src/core/model/bank_book_json.cpp) -target_include_directories(bank_book PUBLIC src) -target_link_libraries(bank_book PUBLIC bank_model) -target_link_libraries(bank_book PUBLIC slot_map) -target_link_libraries(bank_book PRIVATE json) - -# --------------------------------------------------------------------------- -# 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_codec / tab_strip. B-cap writes + -# persists it; Phase R (R1/R2) consumes it — no prune logic here. -# --------------------------------------------------------------------------- -add_library(owned_manifest STATIC src/core/model/owned_manifest.cpp) -target_include_directories(owned_manifest PUBLIC src) -target_link_libraries(owned_manifest PRIVATE json) - -# --------------------------------------------------------------------------- -# 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/core/reclaim/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/core/ui/prune_button.cpp) -target_include_directories(prune_button PUBLIC src) - -# --------------------------------------------------------------------------- -# 2g) Pure capture_realtime library — NO REAPER, NO SWELL. (Renamed from -# realtime_record in Q-W3 — the Q-9 naming rider: pure module takes the stem, -# the shell takes the suffix, matching drag_out <-> drag_out_win.) The M8 -# realtime-record logic: capture scope + FX-tap point -> I_RECMODE / -# I_RECMODE_FLAGS values, wet/dry -> tap point, the recorded-file -> Sample -# mapping, and the async record-phase state machine. Split out so the fiddly -# record-mode bit values + Sample population + phase transitions are -# unit-tested outside the DAW; the transport/temp-track/send recipe stays in -# capture_realtime_shell.cpp (+ the file-side capture_realtime_finalize.cpp). -# Depends on bank_model for the pure Sample / SourceMode types. -# --------------------------------------------------------------------------- -add_library(capture_realtime STATIC src/core/capture/capture_realtime.cpp) -target_include_directories(capture_realtime PUBLIC src) -target_link_libraries(capture_realtime PUBLIC bank_model) - -# --------------------------------------------------------------------------- -# 2h) Pure wav_codec library — NO REAPER, NO SWELL. The ONE owner of the WAV/RIFF -# byte format (Q-W3, audit §4e: T2-08 / T4-10 / T4-23 consolidation): the RIFF -# chunk walker + layout parse (formerly wav_trim), the tail-trim truncate plan + -# size-field patch (formerly duplicated in capture_realtime), the float32 WAV -# build (formerly hand-rolled in ingest), and the WAV-aware content hashes -# (formerly in capture_paths). The dedup-by-hash and null-test invariants rest -# on this one implementation. File I/O stays in the shells. Depends on peaks -# for the AudioSample float alias. (The transitional `wav_trim` alias was -# retired in Q-W6 — every includer points here directly.) -# --------------------------------------------------------------------------- -add_library(wav_codec STATIC src/core/capture/wav_codec.cpp) -target_include_directories(wav_codec PUBLIC src) -target_link_libraries(wav_codec 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/core/version/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 / shell/actions/). No dependency on -# bank_model — it takes plain strings/values at its boundary. -# --------------------------------------------------------------------------- -add_library(provenance STATIC src/core/model/provenance.cpp) -target_include_directories(provenance PUBLIC src) -target_link_libraries(provenance PRIVATE wire) - -# --------------------------------------------------------------------------- -# 2j') Pure assignment_request library — NO REAPER, NO SWELL, NO VST3. The S8 ingest -# assignment-request wire format: the (bankId, sampleId, generation) value the -# EXTENSION writes to "reasampler" ext-state after an ingest-with-assign, decoded by -# the VST3 instrument in a later dispatch. Only the wire (build/parse round-trip) -# lives here — writing it is the persist shell's job, reading it the instrument's. -# Split out (mirror of provenance / owned_manifest) so the format both artifacts -# depend on is unit-tested outside the DAW; the reader lands in a separate artifact, -# so the round-trip test is the contract guard. No dependency — plain strings + int64. -# --------------------------------------------------------------------------- -add_library(assignment_request STATIC src/core/wire/assignment_request.cpp) -target_include_directories(assignment_request PUBLIC src) -target_link_libraries(assignment_request PRIVATE wire) - -# --------------------------------------------------------------------------- -# 2j'') Pure sample_usage library — NO REAPER, NO SWELL, NO VST3. The pS-usage seam: -# the per-instance usage record the INSTRUMENT writes ("rsusage_" ext-state, -# the one sanctioned VST-side write) and the EXTENSION reads at prune time. Owns -# the wire round-trip, the publish plan (copy-collision fail-safe resolution), -# the liveness fold (which records count against the live FX enumeration, -# protect-all when zero identified, abort on unreadable), and the FX identity -# matcher. -# Linked by BOTH artifacts — the mirror of assignment_request, reversed direction. -# --------------------------------------------------------------------------- -add_library(sample_usage STATIC src/core/wire/sample_usage.cpp) -target_include_directories(sample_usage PUBLIC src) -target_link_libraries(sample_usage PRIVATE wire) - -# --------------------------------------------------------------------------- -# 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 mode_switch. -# --------------------------------------------------------------------------- -add_library(drag_out STATIC src/core/ui/drag_out.cpp) -target_include_directories(drag_out PUBLIC src) - -# --------------------------------------------------------------------------- -# 2l') Pure instrument_drop library — NO REAPER, NO SWELL, NO VST3 SDK. The S17 -# drop-and-load payload-construction core (S-GA-DropFX revision): turn the dragged -# capture id into a Steinberg-format .vstpreset image the shell applies via -# TrackFX_SetPreset so a freshly-added ReaSampler 9000 plays that capture (the -# former "vst_chunk" named-config-parm write fed REAPER raw component bytes its -# VST3 wrapper framing cannot apply — the blank-on-drop regression). Reuses the -# instrument's OWN serializer (component_state_io::serializeComponentState) — NOT -# a parallel byte writer — so the cross-artifact contract cannot drift; links -# component_state_io (Q-W2v codec split, T4-13 ≡ T2-07: the extension no longer -# links sampler_core/pitch_shift object code to serialize one preset blob) and -# NEITHER SDK. The class-ID string derives from the FROZEN UID macros -# (src/core/wire/reasampler_uid.h, SDK-free), channel-selected via the generated -# version header — hence the generated include dir. The round-trip test parses -# the container and decodes back through the instrument's own reader. Mirror of -# assignment_request. -# --------------------------------------------------------------------------- -add_library(instrument_drop STATIC src/core/wire/instrument_drop.cpp) -target_include_directories(instrument_drop PUBLIC src ${CMAKE_CURRENT_BINARY_DIR}/generated) -target_link_libraries(instrument_drop PUBLIC component_state_io) - -# --------------------------------------------------------------------------- -# 2m) Pure theme library — NO REAPER, NO SWELL, NO LICE. The Phase L (L1) palette -# core of the shared drawing kit: a ROLE-based color model (bg/base..warn), the -# interaction-state transform (rest/hover/active/pressed/dragging/focus/disabled), -# the Direction C spectral hue ramp, and the WCAG contrast math that lets a unit -# test prove every text-on-surface pair clears its floor ("punch to the floor"). -# THE SINGLE POINT OF CHANGE (DS-2): one direction constants block feeds roleColor; -# switching the visual direction is a one-file edit. The draw shell (draw_kit) turns -# a KitColor into a LICE_pixel at the boundary. Mirror of mode_switch — pure. -# --------------------------------------------------------------------------- -add_library(theme STATIC src/core/ui/theme.cpp) -target_include_directories(theme PUBLIC src) - -# --------------------------------------------------------------------------- -# 2n) Pure component_geometry library — NO REAPER, NO SWELL, NO LICE. The Phase L (L1) -# generic component geometry the kit draws against: button box (inset + graceful -# suppression), horizontal slider track/handle/filled geometry + value<->px inverse, -# and list-row rect + hover hit-test. The kit-level primitives that don't already -# have a pure owner (bank_grid/mode_switch/tab_strip/prune_button -# stay the source of truth for THEIR surfaces). Names KitBox/KitButtonBox/ -# SliderGeometry/ListRowBox avoid the existing ButtonRect/CellRect collisions. -# Mirror of prune_button — pure, CTest-covered. -# --------------------------------------------------------------------------- -add_library(component_geometry STATIC src/core/ui/component_geometry.cpp) -target_include_directories(component_geometry PUBLIC src) - -# --------------------------------------------------------------------------- -# 2o) Pure action_bar library — NO REAPER, NO SWELL, NO LICE. The Phase L (L2) -# dock-panel layout redesign core: the TASK-GROUPED action bar geometry for the -# panel's action inventory — clusters (capture / placement / maintenance) tile the -# bar at a fixed button -# width with intra/inter-cluster gaps, each button carrying a label + keybinding -# micro sub-rect, whole trailing buttons dropped (never clipped) on a narrow panel, -# and point -> flat action index hit-test. Split out so the layout + hit-test math -# is unit-tested outside the DAW; the bank_panel L1-kit draw + NamedCommandLookup/ -# Main_OnCommand dispatch + kbd_getTextFromCmd query are DAW-verified. Mirror of -# mode_switch / prune_button. -# --------------------------------------------------------------------------- -add_library(action_bar STATIC src/core/ui/action_bar.cpp) -target_include_directories(action_bar PUBLIC src) - -# --------------------------------------------------------------------------- -# 2p) Pure footer_bar layout — NO REAPER, NO SWELL, NO LICE. The Phase L (L4) -# dock-panel button-layout enhancement's footer LEFT group: the narrowed -# [Arrange|Design] mode toggle, its compact per-mode count label, and the Tail -# button, laid out left-to-right with greedy right-reserve suppression (the RIGHT -# Prune button stays owned by prune_button). Point -> Toggle/Tail/None hit-test. -# Split out so the footer's new multi-affordance row math is unit-tested outside -# the DAW; the bank_panel L1-kit draw + tail-cycle/mode-activate dispatch are -# DAW-verified. Reuses prune_button's FooterRect input type. Mirror of action_bar / -# mode_switch / prune_button. -# --------------------------------------------------------------------------- -add_library(footer_bar STATIC src/core/ui/footer_bar.cpp) -target_include_directories(footer_bar PUBLIC src) -target_link_libraries(footer_bar PUBLIC prune_button) - -# --------------------------------------------------------------------------- -# 2q) Pure overflow_menu layout — NO REAPER, NO SWELL, NO LICE. The Phase L (L5, -# refinement 1) top-toolbar "⋯" More-button geometry: band rect -> right-anchored -# menu-button rect (suppressed when the band is too narrow) + the horizontal reserve -# the action_bar must leave for it, and point -> in/out hit-test. Split out so the -# button placement + reserve math is unit-tested outside the DAW; the bank_panel -# L1-kit draw + TrackPopupMenu popup + NamedCommandLookup/Main_OnCommand dispatch are -# DAW-verified. Mirror of prune_button / mode_switch. -# --------------------------------------------------------------------------- -add_library(overflow_menu STATIC src/core/ui/overflow_menu.cpp) -target_include_directories(overflow_menu PUBLIC src) - -# --------------------------------------------------------------------------- -# 2r) Pure mode_enable predicate — NO REAPER, NO SWELL, NO LICE. The Phase L (L5, -# refinement 3) opposite-mode tag-button enablement: (active mode id, button target -# mode) -> live/disabled, so only the buttons for the OPPOSITE of the active mode are -# clickable. Split out so both active modes are covered by CTest (not only whichever a -# DAW pass sat in); the bank_panel reads the active mode from view().activeModeId() and -# draws disabled buttons in the kit Disabled state. Depends on view_mode_model for the -# seed mode-id constants (kArrangeModeId / kDesignModeId — ONE home for the ids). -# --------------------------------------------------------------------------- -add_library(mode_enable STATIC src/core/ui/mode_enable.cpp) -target_include_directories(mode_enable PUBLIC src) -target_link_libraries(mode_enable PUBLIC view_mode_model) - -# --------------------------------------------------------------------------- -# 2s) Pure tooltip layout — NO REAPER, NO SWELL, NO LICE. The Phase L (L5, refinement 2) -# custom hover-delay tooltip's placement geometry (anchor rect + text extent + client -# bounds -> tooltip box, preferring below, flipping above near the bottom edge, clamped -# to the client) + the action DISPLAY-PREFIX strip helper. Split out so placement + the -# prefix strip are unit-tested outside the DAW; the bank_panel hover timer + LICE overlay -# draw are DAW-verified. Mirror of prune_button / component_geometry. -# --------------------------------------------------------------------------- -add_library(tooltip STATIC src/core/ui/tooltip.cpp) -target_include_directories(tooltip PUBLIC src) - -# --------------------------------------------------------------------------- -# 2t) Pure card_meta formatters — NO REAPER, NO SWELL, NO LICE. The Phase L (L7) -# decorative card metadata overlay's formatting: bars.beats.subdivisions from a -# capture-time tempo + meter stamp (F1) and seconds.milliseconds from length. Split -# out so the musical/wall-clock string derivation (with its bar-boundary + unstamped -# edge cases) is unit-tested outside the DAW; the bank_panel kit-text overlay draw is -# DAW-verified. Mirror of tooltip's prefix-strip helper — pure, CTest-covered. -# --------------------------------------------------------------------------- -add_library(card_meta STATIC src/core/ui/card_meta.cpp) -target_include_directories(card_meta PUBLIC src) - -# --------------------------------------------------------------------------- -# 2u) Pure card_drag gesture — NO REAPER, NO SWELL, NO LICE, NO OS. The Phase L (L7) -# in-grid reorder drag decision logic: the F3 gesture precedence (leave-client -> -# OS-drag; else other-bank -> move/copy; else same-bank grid -> reorder/replace), -# the resolved-gesture -> cursor-cue map, and the sparse-aware slot rect layout + -# point -> slot hit-test (empties included). Split out so the precedence + slot math -# is unit-tested outside the DAW; the SWELL wiring + SetCursor call + drop-target draw -# are DAW-verified. Reuses drag_out's PanelClientRect/DragState + bank_grid's CellRect/ -# GridSpec. Mirror of drag_out::decideGesture / bank_grid. -# --------------------------------------------------------------------------- -add_library(card_drag STATIC src/core/ui/card_drag.cpp) -target_include_directories(card_drag PUBLIC src) -target_link_libraries(card_drag PUBLIC drag_out bank_grid) - -# --------------------------------------------------------------------------- -# 2v) Pure sampler_core library — NO VST3, NO REAPER, NO SWELL. The HEART of the -# MIDI-playback instrument (D3): polyphonic voice allocation with bounded stealing, -# the three envelope evaluators, and repitch/interpolation from a root note with -# loop-point-aware sustain over ONE loaded capture. The mirror of bank_model / peaks / -# bank_book, tested hard outside any host. Lives under core/instrument/engine/ but -# links NEITHER SDK — the plain-data boundary is enforced structurally: the test -# target below links only sampler_core (+ its peaks dep for the AudioSample alias, -# the one house precedent wav_codec also relies on). The VST3 shell (shell/instrument/ -# reasampler_processor.cpp) marshals MIDI/audio to/from it and is DAW-verified. -# --------------------------------------------------------------------------- -# pitch_shift (S16) — the pure duration-preserving PitchShifter (Preserve-engine DSP core). -# NO VST3/REAPER/SWELL/vendor: a hand-rolled OLA shifter chosen over WDL_SimplePitchShifter -# because that header drags (via wdltypes.h) into any TU that includes it, which -# cannot enter the pure sampler_core. Links only peaks (the AudioSample alias). sampler_core -# depends on it (Voice owns two PitchShifters). -add_library(pitch_shift STATIC src/core/instrument/engine/pitch_shift.cpp) -target_include_directories(pitch_shift PUBLIC src) -target_link_libraries(pitch_shift PUBLIC peaks) - -# velocity_curve (S-VIEW-9) — the pure velocity->amp transfer curve (eval + editing/clamp/inverse -# map). NO VST3/REAPER/SWELL/vendor and DELIBERATELY no editor_geometry (its hit-test takes an -# explicit pixel box, not a Rect) so the engine can depend on it WITHOUT gaining a transitive -# dependency on the editor's layout types. play_params.h carries one (SampleData holds the -# curve; Voice::start eval's it). Mirror of pitch_shift's role, one layer below the engine. -add_library(velocity_curve STATIC src/core/instrument/engine/velocity_curve.cpp) -target_include_directories(velocity_curve PUBLIC src) - -# Two TUs on the engine's own responsibility seam: voice.cpp is the per-NOTE half (note-on -# setup, the Preserve ring prime, legato retune), voice_engine.cpp the note routing / -# allocation / stealing / mono stack / panic / block render. The per-SAMPLE render half is -# inline in voice.h (with the envelope evaluators in envelopes.h) precisely so this TU -# boundary costs the hot path nothing — see voice.h's header. -add_library(sampler_core STATIC - src/core/instrument/engine/voice.cpp - src/core/instrument/engine/voice_engine.cpp) -target_include_directories(sampler_core PUBLIC src) -target_link_libraries(sampler_core PUBLIC peaks pitch_shift velocity_curve) - -# --------------------------------------------------------------------------- -# 3) Standalone tests for the pure modules (run without launching REAPER). -# --------------------------------------------------------------------------- -enable_testing() - -# core/ (Q-W1): the shared JSON lexical layer, wire codec, and file loader. -add_executable(json_tests tests/test_json.cpp) -target_link_libraries(json_tests PRIVATE json) -add_test(NAME json_tests COMMAND json_tests) - -add_executable(wire_tests tests/test_wire.cpp) -target_link_libraries(wire_tests PRIVATE wire) -add_test(NAME wire_tests COMMAND wire_tests) - -add_executable(file_bytes_tests tests/test_file_bytes.cpp) -target_link_libraries(file_bytes_tests PRIVATE file_bytes) -add_test(NAME file_bytes_tests COMMAND file_bytes_tests) - -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(capture_realtime_tests tests/test_capture_realtime.cpp) -target_link_libraries(capture_realtime_tests PRIVATE capture_realtime) -add_test(NAME capture_realtime_tests COMMAND capture_realtime_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(slot_map_tests tests/test_slot_map.cpp) -target_link_libraries(slot_map_tests PRIVATE slot_map json) -add_test(NAME slot_map_tests COMMAND slot_map_tests) - -add_executable(wav_codec_tests tests/test_wav_codec.cpp) -target_link_libraries(wav_codec_tests PRIVATE wav_codec) -add_test(NAME wav_codec_tests COMMAND wav_codec_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) - -# Anti-normalization padding canary (see tests/test_app_version_padding.cpp for the full -# rationale). The live-version assertions in app_version_tests are version-shape-blind: -# relative checks (e.g. appVersion() == stampVersion()) hold whether the string was -# threaded verbatim or reconstructed from numeric components, at any version, padded or -# not — the live suite cannot detect a reconstruct-from-components regression at all. -# So: run the SAME version_generated.h.in template through configure_file a second time -# with a SYNTHETIC padded version, and compile the SAME src/core/version/app_version.cpp against that -# header (include-dir substitution — the canary target never sees the live generated/ -# dir). The "0.9.01" here is a permanent test fixture, NOT the shipped version (see also -# the source-of-truth comment at the top of this file for the live-version invariant); it -# must match the literals in test_app_version_padding.cpp and must never be bumped on -# release. -# -# COVERAGE BOUNDARY: the canary detects "reconstruct-from-numeric-components" -# regressions inside app_version.cpp. It does NOT detect the live source-of-truth line -# becoming a CMake variable derivation; that case is separately guarded by the comment -# block at the top of this file. -function(_configure_padding_canary) - # set() inside a function is function-scoped — the clobber cannot leak into the - # parent scope, so no save/restore/unset dance is needed. REASAMPLER_CHANNEL_IS_BETA - # and CMAKE_CURRENT_SOURCE_DIR / CMAKE_CURRENT_BINARY_DIR are inherited read-only. - set(REASAMPLER_VERSION "0.9.01") - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/src/core/version/version_generated.h.in - ${CMAKE_CURRENT_BINARY_DIR}/generated_padding_canary/version_generated.h - @ONLY) -endfunction() -_configure_padding_canary() - -# NOTE: app_version_padding_tests deliberately recompiles src/core/version/app_version.cpp rather -# than linking the app_version library target. This is required for the include-dir -# substitution to work — the canary needs to see generated_padding_canary/ instead of -# the live generated/ dir. If app_version ever gains a link dependency (e.g. a new -# pure-module link), the canary target_link_libraries must mirror it here. -add_executable(app_version_padding_tests - tests/test_app_version_padding.cpp - src/core/version/app_version.cpp) -target_include_directories(app_version_padding_tests PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/generated_padding_canary src) -add_test(NAME app_version_padding_tests COMMAND app_version_padding_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(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) - -# instrument_drop (S17): the drop-and-load .vstpreset payload builder. The round-trip test -# parses the preset container and decodes its Comp chunk back through the instrument's OWN -# reader (deserializeComponentState) to prove the extension feeds setState exactly what it -# accepts — the cross-artifact contract guard. -add_executable(instrument_drop_tests tests/test_instrument_drop.cpp) -target_link_libraries(instrument_drop_tests PRIVATE instrument_drop) -add_test(NAME instrument_drop_tests COMMAND instrument_drop_tests) - -add_executable(theme_tests tests/test_theme.cpp) -target_link_libraries(theme_tests PRIVATE theme) -add_test(NAME theme_tests COMMAND theme_tests) - -add_executable(component_geometry_tests tests/test_component_geometry.cpp) -target_link_libraries(component_geometry_tests PRIVATE component_geometry) -add_test(NAME component_geometry_tests COMMAND component_geometry_tests) - -add_executable(action_bar_tests tests/test_action_bar.cpp) -target_link_libraries(action_bar_tests PRIVATE action_bar) -add_test(NAME action_bar_tests COMMAND action_bar_tests) - -add_executable(footer_bar_tests tests/test_footer_bar.cpp) -target_link_libraries(footer_bar_tests PRIVATE footer_bar) -add_test(NAME footer_bar_tests COMMAND footer_bar_tests) - -add_executable(overflow_menu_tests tests/test_overflow_menu.cpp) -target_link_libraries(overflow_menu_tests PRIVATE overflow_menu) -add_test(NAME overflow_menu_tests COMMAND overflow_menu_tests) - -add_executable(mode_enable_tests tests/test_mode_enable.cpp) -target_link_libraries(mode_enable_tests PRIVATE mode_enable) -add_test(NAME mode_enable_tests COMMAND mode_enable_tests) - -add_executable(tooltip_tests tests/test_tooltip.cpp) -target_link_libraries(tooltip_tests PRIVATE tooltip) -add_test(NAME tooltip_tests COMMAND tooltip_tests) - -add_executable(card_meta_tests tests/test_card_meta.cpp) -target_link_libraries(card_meta_tests PRIVATE card_meta) -add_test(NAME card_meta_tests COMMAND card_meta_tests) - -add_executable(card_drag_tests tests/test_card_drag.cpp) -target_link_libraries(card_drag_tests PRIVATE card_drag) -add_test(NAME card_drag_tests COMMAND card_drag_tests) - -add_executable(assignment_request_tests tests/test_assignment_request.cpp) -target_link_libraries(assignment_request_tests PRIVATE assignment_request) -add_test(NAME assignment_request_tests COMMAND assignment_request_tests) - -# sample_usage (pS-usage): the instance-usage wire + publish plan + liveness fold. The -# tests are the prune-protection proof at the pure layer: a capture held by a live -# instance lands in the referenced union and pruneOrphans can never emit it (links -# prune_reconcile for the composed proof). -add_executable(sample_usage_tests tests/test_sample_usage.cpp) -target_link_libraries(sample_usage_tests PRIVATE sample_usage prune_reconcile) -add_test(NAME sample_usage_tests COMMAND sample_usage_tests) - -# sampler_core: the S3 heart. Links ONLY sampler_core (+ its peaks dep) — NEITHER the -# VST3 SDK nor the REAPER SDK — which is the structural proof of the plain-data -# boundary (a VST3/REAPER type in the core would fail to compile/link here). -# pitch_shift (S16): the pure Preserve-engine OLA shifter. Links ONLY pitch_shift (+ peaks) — -# NEITHER SDK — the same plain-data-boundary proof, and specifically the compile-time proof it -# does NOT drag in the WDL chain the built-in WDL shifter would. -add_executable(pitch_shift_tests tests/test_pitch_shift.cpp) -target_link_libraries(pitch_shift_tests PRIVATE pitch_shift) -add_test(NAME pitch_shift_tests COMMAND pitch_shift_tests) - -add_executable(sampler_core_tests tests/test_sampler_core.cpp) -target_link_libraries(sampler_core_tests PRIVATE sampler_core) -add_test(NAME sampler_core_tests COMMAND sampler_core_tests) - -# velocity_curve (S-VIEW-9): the pure velocity->amp transfer curve. Links ONLY velocity_curve — -# NEITHER SDK, and specifically not editor_geometry — the plain-data-boundary + engine-clean proof. -add_executable(velocity_curve_tests tests/test_velocity_curve.cpp) -target_link_libraries(velocity_curve_tests PRIVATE velocity_curve) -add_test(NAME velocity_curve_tests COMMAND velocity_curve_tests) - -# --------------------------------------------------------------------------- -# 2i) Pure VST3-instrument helpers (Phase S1) — NO VST3, NO REAPER, NO SWELL/LICE. -# editor_geometry: the shared geometry vocabulary every instrument UI module speaks -# (the `Rect` alias + contains()) — header-only, hence INTERFACE; the Sample face's -# own layout lives in sample_bands/sample_chrome below. bridge_marshal: the REAPER -# VST-host bridge read marshalling — GetProjExtState result decode + the ONE -# grow-loop retry policy (readProjExtStateGrowing, Q-W5 rider T2-04) shared by the -# VST bridge read AND the extension's persist/usage_scan ext-state reads (hence -# linked into reaper_reasampler too); unit-tested outside the DAW, while the VST3 -# shell (shell/instrument/*) that draws/routes/invokes is DAW-verified. -# --------------------------------------------------------------------------- -add_library(editor_geometry INTERFACE) -target_include_directories(editor_geometry INTERFACE src) - -# sample_bands — THE band-stack allocator: the ONE module that owns the Sample face's -# vertical inventory (chrome / two-lane waveform / decks) plus the waveform band's lane -# split. A shared READ-ONLY surface for every band owner; a band's interior module lays out -# inside the rect it is handed and never re-allocates the stack. NEITHER SDK. -add_library(sample_bands STATIC src/core/instrument/ui/sample_bands.cpp) -target_include_directories(sample_bands PUBLIC src) -target_link_libraries(sample_bands PUBLIC editor_geometry) - -# sample_chrome — the CHROME band's interior: the toolbar row (title + Browse) over the -# control row (root strip, preview, velocity knob cell, curve button, channel toggle). Reads -# the band rect from sample_bands; owns no vertical inventory of its own. NEITHER SDK. -add_library(sample_chrome STATIC src/core/instrument/ui/sample_chrome.cpp) -target_include_directories(sample_chrome PUBLIC src) -target_link_libraries(sample_chrome PUBLIC sample_bands) - -add_library(bridge_marshal STATIC src/core/instrument/map/bridge_marshal.cpp) -target_include_directories(bridge_marshal PUBLIC src) - -# embed_strip (Phase S6) — PURE layout for the embedded TCP/MCP strip: the 128-key span -> -# key-span rects (the loaded capture's full span, and its root marker) and the level-band -# fill. Read-only, so no hit-test. Unit-tested outside the DAW, while the embed shell -# (src/shell/instrument/reasampler_embed.cpp) marshals REAPER's embed messages (the paint -# bitmap) into it. Links editor_geometry for the shared Rect. -add_library(embed_strip STATIC src/core/instrument/ui/embed_strip.cpp) -target_include_directories(embed_strip PUBLIC src) -target_link_libraries(embed_strip PUBLIC editor_geometry) - -# sample_map (Phase S4; RESOLUTION half since Q-W2v) — PURE mapping logic for the -# instrument: the live bank blob -> selected sample (via the SHARED bank_book JSON parse, -# NOT a second parser), interleaved->mono downmix (the channel policy), the one parameter -# set's override-beats-intrinsic fold, and the SampleData build. Links the pure modules it -# composes — bank_book (shared JSON), wav_codec (shared WAV parse), velocity_curve (the -# curve field play_params.h carries) — and NEITHER SDK. NOT the voice engine: since the -# build's product is plain SampleData, the engine's object code is no longer a dependency. -# The VST3 shell (reasampler_processor) does the bridge read + file I/O off the audio -# thread, then calls these; the process callback stays allocation-free. The ComponentState -# codec is component_state_io below. -add_library(sample_map STATIC src/core/instrument/map/sample_map.cpp) -target_include_directories(sample_map PUBLIC src) -target_link_libraries(sample_map PUBLIC bank_book wav_codec velocity_curve peaks) - -# component_state_io (Q-W2v split of sample_map, T4-13 ≡ T2-07) — the ComponentState -# ENVELOPE + params-payload binary codec (envelope v1..v11, params payload v1..v8, every -# lift preserved byte-identically; v1..v7 are the retired zone lists, read via the -# adopt-zone-one migration). Split so the codec — which grows on every envelope bump and is -# shared with the EXTENSION's preset-blob path (instrument_drop) — links WITHOUT the voice -# engine: its deps are velocity_curve (the curve field) and master_gain (the v8 wire cap) -# only; sampler_core/pitch_shift object code never enters the extension binary. Its own test -# target linking exactly these is the structural proof. -add_library(component_state_io STATIC src/core/instrument/map/component_state_io.cpp) -target_include_directories(component_state_io PUBLIC src) -target_link_libraries(component_state_io PUBLIC velocity_curve master_gain) - -# capture_browser (Phase S10) — PURE card-grid + bank-filter-tab layout + hit-test for the -# capture-first editor's default face. The mirror of mode_switch/editor_geometry: the fiddly -# grid/tab arithmetic lives here, unit-tested outside the DAW; the editor shell draws each -# card's peak thumbnail + name + badge and routes clicks into it. Links editor_geometry for -# the shared Rect + contains(). NEITHER SDK. -add_library(capture_browser STATIC src/core/instrument/ui/capture_browser.cpp) -target_include_directories(capture_browser PUBLIC src) -target_link_libraries(capture_browser PUBLIC editor_geometry) - -# keyboard_strip (Phase S10) — PURE piano-key geometry, hit-test, root marker, drag -# resolver, and note naming for the editor's keyboard strip (root display + root-set). The -# mirror of embed_strip; links editor_geometry for the shared Rect. NEITHER SDK. -add_library(keyboard_strip STATIC src/core/instrument/ui/keyboard_strip.cpp) -target_include_directories(keyboard_strip PUBLIC src) -target_link_libraries(keyboard_strip PUBLIC editor_geometry) - -# waveform_view (Phase S11) — PURE frame<->pixel mapping, marker grab regions, drag-delta -# frame resolver, the zero-crossing snap, and the WAVEFORM band's drawn surface (channel -# lanes + the overlay area — see waveform_view.h) for the capture-first editor. The mirror of -# keyboard_strip; links editor_geometry for the shared Rect/OverlayArea, peaks for the -# AudioSample alias the snap scans + the per-lane Envelope split. sample_bands is a PRIVATE -# implementation dep (waveformLanes, used internally) — nothing in the public header needs it. -# NEITHER SDK. -add_library(waveform_view STATIC src/core/instrument/ui/waveform_view.cpp) -target_include_directories(waveform_view PUBLIC src) -target_link_libraries(waveform_view PUBLIC editor_geometry peaks) -target_link_libraries(waveform_view PRIVATE sample_bands) - -# bank_sync (Phase S9/S8 reader) — PURE decision logic for the instrument's off-audio-thread -# poll: parse/compare the S9 bank-generation stamp, and the S8 assignment-request CONSUME -# decision (new-and-resolvable-and-target -> apply; unresolvable -> drop-and-mark; non-target -# -> stay eligible). The shell owns the timer cadence + side effects (reloadFromBank, -# setSelectedSampleId, component-state marker); this owns only the yes/no maths, unit-tested -# outside the DAW. Links assignment_request for the decoded AssignmentRequest it consumes. -# NEITHER SDK. -add_library(bank_sync STATIC src/core/instrument/map/bank_sync.cpp) -target_include_directories(bank_sync PUBLIC src) -target_link_libraries(bank_sync PUBLIC assignment_request) -target_link_libraries(bank_sync PRIVATE wire) - -# browser_scroll (Phase S12) — PURE scroll-window + scrollbar-thumb + type-to-filter-search -# geometry LAYERED over the S10 capture_browser: the visible-card window, thumb rect + -# thumb-drag<->offset mapping, and the name-substring filter that composes with the bank -# filter. The mirror of capture_browser; links capture_browser (for BrowserLayout + the card -# metrics/cell rect) which pulls editor_geometry transitively. NEITHER SDK. -add_library(browser_scroll STATIC src/core/instrument/ui/browser_scroll.cpp) -target_include_directories(browser_scroll PUBLIC src) -target_link_libraries(browser_scroll PUBLIC capture_browser sample_chrome) - -# param_slider (Phase S12 + the S15/S16 control surfaces deferred here) — PURE control-surface -# layout + hit-test + normalized value<->pixel mapping for the editor parameter panel (the -# Gate|Trigger + Varispeed|Preserve toggles and the AHDSR / Trigger / pitch-env sliders). The -# mirror of keyboard_strip; links editor_geometry for the shared Rect. Deliberately engine-free -# (no sampler_core types) — the shell owns the control-id -> param binding + the value DOMAIN -# mapping. NEITHER SDK. -add_library(param_slider STATIC src/core/instrument/ui/param_slider.cpp) -target_include_directories(param_slider PUBLIC src) -target_link_libraries(param_slider PUBLIC editor_geometry) - -# trigger_seam (Phase S-VIEW-3) — PURE Trigger-mode frames<->fraction converter for the TRIGGER -# SEAM documented in envelope_overlay.h: triggerPlayLength / framesToFadeFraction / -# fadeFractionToFrames. Owns the one formula so pack (draw) and unpack (commit) are provably -# consistent. No shell/LICE/REAPER types — only . NEITHER SDK. -add_library(trigger_seam STATIC src/core/instrument/map/trigger_seam.cpp) -target_include_directories(trigger_seam PUBLIC src) - -# envelope_overlay (Phase S-VIEW-3) — PURE amp-envelope -> polyline geometry for the Sample-view -# envelope overlay: AHDSR (Gate) / fade+%-length (Trigger) params + the sample's wall-clock -# duration -> a breakpoint polyline in the waveform rect, at the same time base waveform_view maps. -# The mirror of waveform_view / param_slider; links editor_geometry for the shared Rect. -# Deliberately engine-free (no sample_map / sampler_core) — the shell packs the one parameter -# set's stored AdsrSeconds / TriggerParams into the small AmpEnvelope view struct. NEITHER SDK. -add_library(envelope_overlay STATIC src/core/instrument/ui/envelope_overlay.cpp) -target_include_directories(envelope_overlay PUBLIC src) -target_link_libraries(envelope_overlay PUBLIC editor_geometry) - -# envelope_edit (Phase S-VIEW-3) — PURE node hit-test + pixel-delta -> clamped-param inverse map -# for the draggable envelope nodes: monotonic-in-time + range-clamped (against caller-supplied -# slider maxima) so a drag can never produce a param a slider couldn't. The mirror of card_drag; -# links envelope_overlay for the shared node vocabulary + the timeToX/levelToY maps. NEITHER SDK. -add_library(envelope_edit STATIC src/core/instrument/ui/envelope_edit.cpp) -target_include_directories(envelope_edit PUBLIC src) -target_link_libraries(envelope_edit PUBLIC envelope_overlay) - -# knob_deck (Wave B FB1, r11) — PURE knob-deck layout + hit-test for the recomposed Sample face: -# fenced groups (caption row + compact caption toggles + fixed 48x58 knob cells + optional row -# toggle), deterministic whole-group wrap, point -> control-id hit-test. The mirror of -# action_bar / param_slider; links editor_geometry for the shared Rect. Engine-free — cells and -# toggles carry opaque shell-owned control ids. NEITHER SDK. -add_library(knob_deck STATIC src/core/instrument/ui/knob_deck.cpp) -target_include_directories(knob_deck PUBLIC src) -target_link_libraries(knob_deck PUBLIC editor_geometry) - -# curve_popup (Wave B FB1, r11) — PURE centered-sheet geometry for the velocity-curve popup -# editor: size clamps (60%/55% of window, 360..520 x 260..380), title row + close button, the -# curve-box border rect, and the outside-sheet dismissal test. The mirror of overflow_menu; -# links editor_geometry for the shared Rect. NEITHER SDK. -add_library(curve_popup STATIC src/core/instrument/ui/curve_popup.cpp) -target_include_directories(curve_popup PUBLIC src) -target_link_libraries(curve_popup PUBLIC editor_geometry) - -# master_gain (Wave B FB1) — PURE dB<->linear<->knob-taper math for the post-mixer master gain -# (-inf..+24 dB; norm 0 = TRUE zero linear). One formula shared by the editor's Gain knob, the -# v8 component-state wire cap, and the processor's applied gain. Standard library only. NEITHER SDK. -add_library(master_gain STATIC src/core/instrument/engine/master_gain.cpp) -target_include_directories(master_gain PUBLIC src) - -# filter — the per-voice TPT/SVF with a continuous morph (HP->BP->LP or HP->notch->LP, selected -# at prepare() time) and an in-loop drive stage. -# The Cortex-M4 source's virtual FilterBase/Filter/Biquad hierarchy dispatched per channel per -# sample, which the per-voice per-sample path forbids, so none of it came across. Control -# mapping, SVF coefficients, morph weights, and the filter type each get their own file; -# VoiceFilter::process is header-inline so the kernel still inlines at the call site. Standard -# library only. NEITHER SDK. -add_library(filter STATIC - src/core/instrument/engine/filter/filter_params.cpp - src/core/instrument/engine/filter/filter_coeffs.cpp - src/core/instrument/engine/filter/filter_morph.cpp - src/core/instrument/engine/filter/voice_filter.cpp) -target_include_directories(filter PUBLIC src) - -# sample_bands: the band-stack allocator's vertical inventory, asserted as pure geometry -# (chrome / two-lane waveform / deck row) independent of any paint call — the contract the -# band owners downstream read. -add_executable(sample_bands_tests tests/test_sample_bands.cpp) -target_link_libraries(sample_bands_tests PRIVATE sample_bands) -add_test(NAME sample_bands_tests COMMAND sample_bands_tests) - -add_executable(sample_chrome_tests tests/test_sample_chrome.cpp) -target_link_libraries(sample_chrome_tests PRIVATE sample_chrome) -add_test(NAME sample_chrome_tests COMMAND sample_chrome_tests) - -add_executable(bridge_marshal_tests tests/test_bridge_marshal.cpp) -target_link_libraries(bridge_marshal_tests PRIVATE bridge_marshal) -add_test(NAME bridge_marshal_tests COMMAND bridge_marshal_tests) - -add_executable(embed_strip_tests tests/test_embed_strip.cpp) -target_link_libraries(embed_strip_tests PRIVATE embed_strip) -add_test(NAME embed_strip_tests COMMAND embed_strip_tests) - -# sample_map: the S4 mapping heart. Links ONLY sample_map + component_state_io (+ their -# pure deps) — NEITHER the VST3 SDK nor the REAPER SDK — the same structural -# plain-data-boundary proof the sampler_core test enforces. (The historical suite spans -# both halves of the Q-W2v split; the frozen-format assertions live here unmodified.) -add_executable(sample_map_tests tests/test_sample_map.cpp) -target_link_libraries(sample_map_tests PRIVATE sample_map component_state_io) -add_test(NAME sample_map_tests COMMAND sample_map_tests) - -# component_state_io (Q-W2v): the ComponentState codec's OWN target. Links ONLY -# component_state_io (velocity_curve + master_gain transitively) — deliberately NO -# sampler_core/pitch_shift — the structural proof the codec is engine-free (T2-07). -add_executable(component_state_io_tests tests/test_component_state_io.cpp) -target_link_libraries(component_state_io_tests PRIVATE component_state_io) -add_test(NAME component_state_io_tests COMMAND component_state_io_tests) - -add_executable(capture_browser_tests tests/test_capture_browser.cpp) -target_link_libraries(capture_browser_tests PRIVATE capture_browser) -add_test(NAME capture_browser_tests COMMAND capture_browser_tests) - -add_executable(keyboard_strip_tests tests/test_keyboard_strip.cpp) -target_link_libraries(keyboard_strip_tests PRIVATE keyboard_strip sample_bands sample_chrome) -add_test(NAME keyboard_strip_tests COMMAND keyboard_strip_tests) - -# waveform_view (S11): the pure marker geometry + zero-crossing snap. Links waveform_view (+ -# its pure editor_geometry/peaks deps) plus sample_bands directly, since the test exercises -# waveformLanes/kWaveformMinHeight/kLaneGap, which waveform_view no longer re-exports. NEITHER SDK. -add_executable(waveform_view_tests tests/test_waveform_view.cpp) -target_link_libraries(waveform_view_tests PRIVATE waveform_view sample_bands) -add_test(NAME waveform_view_tests COMMAND waveform_view_tests) - -# bank_sync (S9/S8 reader): the pure generation-parse + assignment-consume decision. Links -# ONLY bank_sync (+ its assignment_request dep) — NEITHER SDK — the plain-data-boundary proof. -add_executable(bank_sync_tests tests/test_bank_sync.cpp) -target_link_libraries(bank_sync_tests PRIVATE bank_sync) -add_test(NAME bank_sync_tests COMMAND bank_sync_tests) - -# browser_scroll (S12): the pure scroll-window/thumb + search geometry over capture_browser. -add_executable(browser_scroll_tests tests/test_browser_scroll.cpp) -target_link_libraries(browser_scroll_tests PRIVATE browser_scroll) -add_test(NAME browser_scroll_tests COMMAND browser_scroll_tests) - -# param_slider (S12 + S15/S16 control surfaces): the pure control-panel layout + slider/toggle -# value<->pixel mapping the editor parameter surface draws + routes against. -add_executable(param_slider_tests tests/test_param_slider.cpp) -target_link_libraries(param_slider_tests PRIVATE param_slider) -add_test(NAME param_slider_tests COMMAND param_slider_tests) - -# trigger_seam (S-VIEW-3): the pure Trigger-mode frames<->fraction converter. -# Links ONLY trigger_seam — no editor_geometry dep, the plainest data-boundary proof possible. -add_executable(trigger_seam_tests tests/test_trigger_seam.cpp) -target_link_libraries(trigger_seam_tests PRIVATE trigger_seam) -add_test(NAME trigger_seam_tests COMMAND trigger_seam_tests) - -# envelope_overlay (S-VIEW-3): the pure amp-envelope -> polyline geometry (Gate AHDSR + Trigger -# fade/%-length) at the waveform time base. Links ONLY envelope_overlay (+ its editor_geometry -# dep) — NEITHER SDK — the plain-data-boundary proof. -add_executable(envelope_overlay_tests tests/test_envelope_overlay.cpp) -target_link_libraries(envelope_overlay_tests PRIVATE envelope_overlay) -add_test(NAME envelope_overlay_tests COMMAND envelope_overlay_tests) - -# envelope_edit (S-VIEW-3): the pure node hit-test + clamped/monotonic pixel->param inverse map. -# Links ONLY envelope_edit (+ its envelope_overlay dep) — NEITHER SDK. -add_executable(envelope_edit_tests tests/test_envelope_edit.cpp) -target_link_libraries(envelope_edit_tests PRIVATE envelope_edit) -add_test(NAME envelope_edit_tests COMMAND envelope_edit_tests) - -# knob_deck (Wave B FB1): the pure r11 deck layout/wrap/hit-test. Links ONLY knob_deck — NEITHER SDK. -add_executable(knob_deck_tests tests/test_knob_deck.cpp) -target_link_libraries(knob_deck_tests PRIVATE knob_deck) -add_test(NAME knob_deck_tests COMMAND knob_deck_tests) - -# curve_popup (Wave B FB1): the pure r11 popup-sheet geometry at the size clamps. NEITHER SDK. -add_executable(curve_popup_tests tests/test_curve_popup.cpp) -target_link_libraries(curve_popup_tests PRIVATE curve_popup) -add_test(NAME curve_popup_tests COMMAND curve_popup_tests) - -# master_gain (Wave B FB1): the pure dB<->linear<->knob taper. NEITHER SDK. -add_executable(master_gain_tests tests/test_master_gain.cpp) -target_link_libraries(master_gain_tests PRIVATE master_gain) -add_test(NAME master_gain_tests COMMAND master_gain_tests) - -# filter: four targets along the module's own seams, so each asserts one domain. -# filter_params_tests — the rate-free control mappings (cutoff/Q/drive) and their inverses. -# filter_morph_tests — the pure morph-weight algebra under both morph laws; no DSP is run. -# filter_state_tests — numerical stability, the denormal flush, bounded-output/self-oscillation -# under full drive, and the state lifecycle — none of it needs the measurement harness below. -# filter_tests — the frequency response: pins the SVF coefficients against an independent -# derivation, holds the morph endpoints to the analytic 2-pole targets, and measures the -# HP-BP-LP corner flatness, the HP-notch-LP null, and rate/level invariance and drive -# stability by driving real sines. The seams above were chosen so this file alone owns the -# analytic reference and the steady-state gain measurement — a forked copy of a measurement -# reference is a worse defect than a long file. -# NEITHER SDK. -add_executable(filter_params_tests tests/test_filter_params.cpp) -target_link_libraries(filter_params_tests PRIVATE filter) -add_test(NAME filter_params_tests COMMAND filter_params_tests) - -add_executable(filter_morph_tests tests/test_filter_morph.cpp) -target_link_libraries(filter_morph_tests PRIVATE filter) -add_test(NAME filter_morph_tests COMMAND filter_morph_tests) - -add_executable(filter_state_tests tests/test_filter_state.cpp) -target_link_libraries(filter_state_tests PRIVATE filter) -add_test(NAME filter_state_tests COMMAND filter_state_tests) - -add_executable(filter_tests tests/test_filter.cpp) -target_link_libraries(filter_tests PRIVATE filter) -add_test(NAME filter_tests COMMAND filter_tests) - -# --------------------------------------------------------------------------- -# 4) The REAPER extension — a loadable module (dlopen'd by REAPER, not linked). -# --------------------------------------------------------------------------- -# LICE sources the bank_panel + draw_kit draw with: lice.cpp (LICE_SysBitmap, FillRect, -# GradRect, Clear, Blit) + lice_line.cpp (Line, DrawRect, RoundRect). lice_line.cpp's -# bezier helpers call LICE_FillCircle from lice_arc.cpp, so that TU is required to link. -# lice_textnew.cpp provides LICE_CachedFont (the kit's AA cached-font engine, Phase L L1 — -# the "temple os -> modern" text lever; see draw_kit.cpp). NOTE the "new" variant: it is the -# TU that implements the LICE_CachedFont CLASS (lice_text.cpp is the legacy bitmap-font -# renderer with no class and would not resolve the symbols). LICE routes GDI through native -# Win32 or, on mac/linux, the host SWELL (SWELL_PROVIDED_BY_APP). +# Vendored dependencies (git submodules — see CLAUDE.md for the one-time init). +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) +set(VST3_SDK ${CMAKE_CURRENT_SOURCE_DIR}/vendor/vst3sdk) + +# The LICE TUs both loadable modules draw with. lice_line.cpp's bezier helpers call +# LICE_FillCircle from lice_arc.cpp, so that TU is required to link. NOTE the "new" text +# variant: lice_textnew.cpp is the TU implementing the LICE_CachedFont CLASS the draw kit +# uses — lice_text.cpp is the legacy bitmap-font renderer with no class and would leave the +# symbols unresolved. LICE routes GDI through native Win32 or, on mac/linux, the host SWELL. +# draw_kit.cpp is compiled directly into each module rather than being a static library: +# it is the only kit TU that touches LICE, so it needs these LICE_SRC TUs linked into the +# same artifact, and both modules draw with it. set(LICE_SRC ${WDL_INC}/lice/lice.cpp ${WDL_INC}/lice/lice_line.cpp @@ -1155,268 +82,13 @@ set(LICE_SRC ${WDL_INC}/lice/lice_textnew.cpp ) -add_library(reaper_reasampler MODULE - src/app/main.cpp - src/shell/capture/capture.cpp - src/shell/capture/capture_orchestrator.cpp - src/shell/capture/capture_batch.cpp - src/shell/capture/scope_resolve.cpp - src/shell/capture/realtime_lifecycle.cpp - src/shell/capture/capture_realtime_shell.cpp - src/shell/capture/capture_realtime_finalize.cpp - src/core/capture/capture_realtime.cpp - src/shell/persist/session.cpp - src/shell/persist/ext_state_io.cpp - src/shell/persist/prune_fs.cpp - src/shell/bank_ops/bank_ops.cpp - src/shell/panel/panel_audition.cpp - src/shell/panel/panel_bank_ops.cpp - src/shell/panel/panel_drag.cpp - src/shell/panel/panel_input.cpp - src/shell/panel/panel_layout.cpp - src/shell/panel/panel_render.cpp - src/shell/panel/panel_thumbnails.cpp - src/shell/panel/panel_window.cpp - src/shell/panel/draw_kit.cpp - src/core/view/mode_switch.cpp - src/core/ui/tab_strip.cpp - src/shell/capture/insert.cpp - src/core/capture/insert_plan.cpp - ${LICE_SRC} - src/core/view/view_mode_model.cpp - src/core/view/view_tree.cpp - src/shell/view/view.cpp - src/shell/capture/track_guid.cpp - src/shell/capture/provenance_shell.cpp - src/core/view/guid_diff.cpp - src/core/view/lane_keys.cpp - src/shell/capture/item_read.cpp - src/shell/actions/action_registry.cpp - src/shell/actions/design_view_actions.cpp - src/shell/actions/bank_actions.cpp - src/shell/actions/prune_action.cpp - src/shell/actions/ingest.cpp - src/core/model/bank_book.cpp - src/core/model/bank_book_json.cpp - src/core/model/owned_manifest.cpp - src/shell/actions/drag_out_win.cpp - src/shell/actions/instrument_drop_win.cpp - src/core/ui/action_bar.cpp - src/core/ui/footer_bar.cpp - src/core/ui/overflow_menu.cpp - src/core/ui/mode_enable.cpp - src/core/ui/tooltip.cpp - src/core/ui/card_meta.cpp - src/core/ui/card_drag.cpp - src/shell/persist/usage_scan.cpp -) -target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync bridge_marshal sample_usage) -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}") +# --------------------------------------------------------------------------- +set(REASAMPLER_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) +set(REASAMPLER_TESTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/tests) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/reasampler_targets.cmake) -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) +enable_testing() -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() - -# =========================================================================== -# 5) The ReaSampler VST3 instrument — the SECOND build artifact (Phase S1). -# -# Windows-only, VST3-only, REAPER-only (D5). A separate native VST3 plugin the user -# instantiates on an instrument track. Additive: the reaper_reasampler target above -# builds unchanged. This is the S1 opening spike — a silent-but-loading -# SingleComponentEffect skeleton, an IPlugView<->LICE editor, and the REAPER VST-host -# bridge read — not yet a sampler. -# -# ONE-TIME SDK SUBMODULE SETUP (see README / .gitmodules): the vst3sdk superproject is -# vendored pinned to tag v3.7.9_build_61; only three of its sub-submodules are needed -# (VSTGUI/examples/tests are NOT). After `git submodule update --init vendor/vst3sdk`: -# cd vendor/vst3sdk && git submodule update --init pluginterfaces base public.sdk -# =========================================================================== -set(VST3_SDK ${CMAKE_CURRENT_SOURCE_DIR}/vendor/vst3sdk) -# The VST3 module needs the nested vst3sdk slice (pluginterfaces / base / public.sdk) -# checked out — the one-time step documented above. When it is absent (a fresh clone -# that ran only the top-level `git submodule update --init`), skip the module rather than -# fail configure on missing sources: the pure geometry/mapping libraries + their CTest -# targets still build and test without the SDK. Probe one representative source file. -if(WIN32 AND EXISTS "${VST3_SDK}/public.sdk/source/main/pluginfactory.cpp") - - # --- 5a) The bounded slice of the Steinberg VST3 SDK this spike needs. -------- - # Enumerated (not add_subdirectory of the whole SDK) to keep the build hermetic and - # lean, matching the project's two-submodule discipline: no VSTGUI, no examples, no - # SDK-global CMake helpers/install machinery. Pinned to tag v3.7.9_build_61, so the - # list is fixed. If the SDK tag is bumped, re-verify this set. - add_library(vst3_sdk STATIC - # pluginterfaces/base — FUnknown, IIDs, string table, ustring. - ${VST3_SDK}/pluginterfaces/base/funknown.cpp - ${VST3_SDK}/pluginterfaces/base/coreiids.cpp - ${VST3_SDK}/pluginterfaces/base/conststringtable.cpp - ${VST3_SDK}/pluginterfaces/base/ustring.cpp - # base/source — FObject, strings, buffers, streamer, debug, IIDs, update handler. - ${VST3_SDK}/base/source/fobject.cpp - ${VST3_SDK}/base/source/fstring.cpp - ${VST3_SDK}/base/source/fbuffer.cpp - ${VST3_SDK}/base/source/fstreamer.cpp - ${VST3_SDK}/base/source/fdebug.cpp - ${VST3_SDK}/base/source/baseiids.cpp - ${VST3_SDK}/base/source/updatehandler.cpp - ${VST3_SDK}/base/thread/source/flock.cpp - # public.sdk/source/vst — the SingleComponentEffect base + its deps. NOTE: - # vstsinglecomponenteffect.cpp #includes vsteditcontroller.cpp (unity-style), so - # vsteditcontroller.cpp must NOT be listed separately (double definition). - ${VST3_SDK}/public.sdk/source/vst/vstsinglecomponenteffect.cpp - ${VST3_SDK}/public.sdk/source/vst/vstcomponentbase.cpp - ${VST3_SDK}/public.sdk/source/vst/vstbus.cpp - ${VST3_SDK}/public.sdk/source/vst/vstparameters.cpp - ${VST3_SDK}/public.sdk/source/vst/vstinitiids.cpp - # public.sdk/source/common — CPluginView (IPlugView base) + IIDs. - ${VST3_SDK}/public.sdk/source/common/pluginview.cpp - ${VST3_SDK}/public.sdk/source/common/commoniids.cpp - # public.sdk/source/main — the class-factory (GetPluginFactory) support. NOTE: - # dllmain.cpp + moduleinit.cpp (which carry the InitDll/ExitDll dll exports) are - # compiled into the MODULE target directly, NOT here: their SMTG_EXPORT_SYMBOL - # functions have no internal referrer, so the linker strips them from a static - # lib. Compiling them into the module keeps the exports. - ${VST3_SDK}/public.sdk/source/main/pluginfactory.cpp - ) - target_include_directories(vst3_sdk PUBLIC ${VST3_SDK}) - # The SDK requires exactly one of RELEASE / DEVELOPMENT (fdebug.cpp keys off it). - target_compile_definitions(vst3_sdk PUBLIC $,DEVELOPMENT=1,RELEASE=1>) - - # --- 5b) The VST3 module (loadable .vst3 DLL). ------------------------------- - add_library(reasampler_vst MODULE - src/shell/instrument/vst_entry.cpp - # The processor family (Q-W2v, T4-12): lifecycle + process() whole (T4-29), with - # component-state I/O and the off-thread reload/publish family in sibling TUs. - src/shell/instrument/reasampler_processor.cpp - src/shell/instrument/processor_state.cpp - src/shell/instrument/processor_reload.cpp - # The editor family, split on the Sample face's BAND axis: session/bridge state, - # param plumbing + the shared band-layout resolve, then paint and input in matching - # sets — dispatch, chrome, waveform, decks — plus the two band-independent surfaces - # (the Browse modal and the velocity-curve popup) and the platform/window TU. The - # layout math itself is PURE (core/instrument/ui/sample_bands + sample_chrome + - # browser_scroll). Shared internals: editor_internal.h (no TU). - src/shell/instrument/editor_session.cpp - src/shell/instrument/editor_controls.cpp - src/shell/instrument/editor_paint.cpp - src/shell/instrument/editor_paint_chrome.cpp - src/shell/instrument/editor_paint_waveform.cpp - src/shell/instrument/editor_paint_deck.cpp - src/shell/instrument/editor_paint_browse.cpp - src/shell/instrument/editor_paint_curve.cpp - src/shell/instrument/editor_input.cpp - src/shell/instrument/editor_input_chrome.cpp - src/shell/instrument/editor_input_waveform.cpp - src/shell/instrument/editor_input_deck.cpp - src/shell/instrument/editor_input_browse.cpp - src/shell/instrument/editor_input_curve.cpp - src/shell/instrument/editor_platform.cpp - src/shell/instrument/reasampler_embed.cpp - src/shell/instrument/reaper_bridge.cpp - # The Phase L (L1) draw kit — the ONE source of drawing the editor + embed shells - # now consume (L3). Compiled into the MODULE (not a static lib) for the same reason - # bank_panel does: it is the only kit TU touching LICE, and its cached-font engine - # (LICE_CachedFont) needs the LICE_SRC TUs below linked into this artifact. - src/shell/panel/draw_kit.cpp - # SDK module entry — compiled into the module (not the static lib) so the - # InitDll/ExitDll dll exports survive the link (see vst3_sdk note above). - ${VST3_SDK}/public.sdk/source/main/dllmain.cpp - ${VST3_SDK}/public.sdk/source/main/moduleinit.cpp - ${LICE_SRC} - ) - # editor_geometry + bridge_marshal: the pure spike helpers. sample_map (S4): the pure - # bank -> one-capture resolve + SampleData build the processor drives off the audio - # thread; linking it pulls its pure deps (bank_book, wav_codec, velocity_curve, peaks) - # transitively — deliberately NOT sampler_core (the voice engine). capture_paths: the - # shared M4 path resolution (resolveBankFile / projectDirOfRpp) the bridge + processor - # use. Its PUBLIC include dir (src) - # gives the shell TUs their headers (ext_keys.h, bank_book.h, voice_engine.h, ...). - # embed_strip (S6): the pure inline-strip layout + hit-test the embed shell marshals - # into; it links editor_geometry transitively (shared Rect). - # app_version: ext_keys.h's channel-derived namespace accessor (V4) delegates to it, so - # the instrument reads the SAME namespace the extension writes; its PUBLIC include dir - # (build/generated) carries version_generated.h for the channel bit. - # sampler_core: the voice engine the processor drives (sample_map no longer pulls it — - # its build yields plain SampleData — so the module links it directly.) - # sample_bands + sample_chrome: the band-stack allocator the Sample face's three band - # TUs read, and the chrome band's interior geometry. - # capture_browser + keyboard_strip (S10): the pure card-grid/tab + keyboard-strip - # geometry the capture-first editor draws + hit-tests against; both link editor_geometry - # transitively (shared Rect). - # waveform_view (S11): the pure frame<->pixel marker geometry + zero-crossing snap the - # editor's waveform surface draws + hit-tests against; links editor_geometry + peaks - # transitively (shared Rect + AudioSample). - # bank_sync (S9/S8 reader): the pure generation-compare + assignment-consume decision the - # processor's off-thread poll runs; links assignment_request transitively (the decoded - # request it consumes) — the same key the extension writes, shared via the pure module. - # browser_scroll + param_slider (S12 + S15/S16 control surfaces): the pure scroll/search - # geometry over the capture browser, and the control-panel layout + slider/toggle - # value<->pixel mapping the editor's parameter surface draws + routes against. - # browser_scroll pulls capture_browser transitively; param_slider links editor_geometry / - # the stdlib only. All engine-free, DAW-verified in the shell. - # tooltip: the pure placement math (anchor + text extent -> clamped box) the piano - # strip's note-name chip shares with the dock panel's hover tooltip. - # theme + component_geometry + bank_grid: the Phase L (L1) draw-kit's PURE deps (L3). The - # kit draws every editor/embed surface by palette ROLE via draw_kit.cpp (compiled into the - # module above): theme supplies role->KitColor + spectralColor, component_geometry the - # KitBox/button/slider geometry, bank_grid the shared dB display-compression the waveform - # primitive uses. All REAPER/SWELL-free. - # envelope_overlay + envelope_edit (S-VIEW-3): the pure amp-envelope -> polyline forward map - # and the node hit-test + pixel-delta -> clamped-param inverse map the Sample-view envelope - # overlay draws + drags against; envelope_edit links envelope_overlay transitively (shared - # node vocabulary + timeToX/levelToY). Both engine-free, DAW-verified in the shell. - # knob_deck + curve_popup + master_gain (Wave B FB1, r11): the pure deck layout/hit-test, - # the curve-popup sheet geometry, and the master-gain taper the recomposed Sample face - # draws + routes against (master_gain also rides in via sample_map for the v8 wire cap). - # sample_usage (pS-usage): the usage-record wire + publish plan the processor's - # reloadInstrument publishes through the bridge (the one sanctioned VST-side write). - target_link_libraries(reasampler_vst PRIVATE vst3_sdk editor_geometry bridge_marshal - sampler_core sample_map component_state_io capture_paths embed_strip app_version - capture_browser keyboard_strip sample_bands sample_chrome - waveform_view bank_sync browser_scroll param_slider tooltip - theme component_geometry bank_grid trigger_seam envelope_overlay envelope_edit - knob_deck curve_popup master_gain sample_usage file_bytes) - # SDK_INC gives reaper_vst3_interfaces.h + reaper_plugin_functions.h for the bridge; - # WDL_INC gives LICE for the editor. The VST3 SDK headers come from vst3_sdk PUBLIC. - # src: the Q-W1 rooted include convention ("core/..." / "shell/..."). src/vst is GONE - # (Q-W2v): the two former god TUs live split under shell/instrument/. - target_include_directories(reasampler_vst PRIVATE src ${SDK_INC} ${WDL_INC}) - # A .vst3 is a DLL with a .vst3 extension and no lib-prefix. OUTPUT_NAME is the on-disk - # product name, channel-forked (S18): reasampler_9000.vst3 (stable, byte-identical to - # pre-S18) / reasampler_9000_beta.vst3 (beta) — driven by REASAMPLER_VST_OUTPUT_NAME set - # from the ONE channel decision above, mirroring the extension's REASAMPLER_OUTPUT_NAME - # and matching app_version::vstOutputName(). The two channels install side-by-side; the - # per-channel VST3 class UID (reasampler_vst.h) keeps a saved instance rebinding to its - # own channel (save-rename-reopen is a DAW-verify). - set_target_properties(reasampler_vst PROPERTIES PREFIX "" SUFFIX ".vst3" - OUTPUT_NAME "${REASAMPLER_VST_OUTPUT_NAME}") -endif() +add_subdirectory(src/core) +add_subdirectory(src/app) +add_subdirectory(src/shell/instrument) diff --git a/cmake/reasampler_targets.cmake b/cmake/reasampler_targets.cmake new file mode 100644 index 0000000..74d9075 --- /dev/null +++ b/cmake/reasampler_targets.cmake @@ -0,0 +1,24 @@ +# The two shapes that repeat across src/: a pure static library and its CTest target. +# Both are thin pass-throughs — LINK is forwarded to target_link_libraries verbatim, so +# PUBLIC/PRIVATE keywords and link order stay visible at the call site rather than being +# invented by the helper. Targets that genuinely deviate are written out longhand. + +# Every pure library carries src/ as a PUBLIC include dir: headers are included rooted +# there ("core/json/json.h"), so a consumer needs only the link edge. +function(reasampler_pure_library name) + cmake_parse_arguments(ARG "" "" "SOURCES;LINK" ${ARGN}) + add_library(${name} STATIC ${ARG_SOURCES}) + target_include_directories(${name} PUBLIC ${REASAMPLER_SRC_DIR}) + if(ARG_LINK) + target_link_libraries(${name} ${ARG_LINK}) + endif() +endfunction() + +# Test naming is exceptionless: target _tests is built from tests/test_.cpp +# and registered under its own target name. +function(reasampler_test name) + cmake_parse_arguments(ARG "" "" "LINK" ${ARGN}) + add_executable(${name}_tests ${REASAMPLER_TESTS_DIR}/test_${name}.cpp) + target_link_libraries(${name}_tests PRIVATE ${ARG_LINK}) + add_test(NAME ${name}_tests COMMAND ${name}_tests) +endfunction() diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt new file mode 100644 index 0000000..e471a7d --- /dev/null +++ b/src/app/CMakeLists.txt @@ -0,0 +1,105 @@ +# The REAPER extension — a loadable module REAPER dlopen()s, never linked against. +# Its source list spans app/ + shell/ + the handful of core TUs compiled straight in, so +# the paths below are rooted at src/ rather than being relative to this directory. + +add_library(reaper_reasampler MODULE + ${REASAMPLER_SRC_DIR}/app/main.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/capture.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/capture_orchestrator.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/capture_batch.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/scope_resolve.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/realtime_lifecycle.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/capture_realtime_shell.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/capture_realtime_finalize.cpp + ${REASAMPLER_SRC_DIR}/core/capture/capture_realtime.cpp + ${REASAMPLER_SRC_DIR}/shell/persist/session.cpp + ${REASAMPLER_SRC_DIR}/shell/persist/ext_state_io.cpp + ${REASAMPLER_SRC_DIR}/shell/persist/prune_fs.cpp + ${REASAMPLER_SRC_DIR}/shell/bank_ops/bank_ops.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_audition.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_bank_ops.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_drag.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_input.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_layout.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_render.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_thumbnails.cpp + ${REASAMPLER_SRC_DIR}/shell/panel/panel_window.cpp + # draw_kit is compiled into each module rather than being a static library — see root + # CMakeLists.txt's LICE_SRC comment for why. + ${REASAMPLER_SRC_DIR}/shell/panel/draw_kit.cpp + ${REASAMPLER_SRC_DIR}/core/view/mode_switch.cpp + ${REASAMPLER_SRC_DIR}/core/ui/tab_strip.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/insert.cpp + ${REASAMPLER_SRC_DIR}/core/capture/insert_plan.cpp + ${LICE_SRC} + ${REASAMPLER_SRC_DIR}/core/view/view_mode_model.cpp + ${REASAMPLER_SRC_DIR}/core/view/view_tree.cpp + ${REASAMPLER_SRC_DIR}/shell/view/view.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/track_guid.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/provenance_shell.cpp + ${REASAMPLER_SRC_DIR}/core/view/guid_diff.cpp + ${REASAMPLER_SRC_DIR}/core/view/lane_keys.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/item_read.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/action_registry.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/design_view_actions.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/bank_actions.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/prune_action.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/ingest.cpp + ${REASAMPLER_SRC_DIR}/core/model/bank_book.cpp + ${REASAMPLER_SRC_DIR}/core/model/bank_book_json.cpp + ${REASAMPLER_SRC_DIR}/core/model/owned_manifest.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/drag_out_win.cpp + ${REASAMPLER_SRC_DIR}/shell/actions/instrument_drop_win.cpp + ${REASAMPLER_SRC_DIR}/core/ui/action_bar.cpp + ${REASAMPLER_SRC_DIR}/core/ui/footer_bar.cpp + ${REASAMPLER_SRC_DIR}/core/ui/overflow_menu.cpp + ${REASAMPLER_SRC_DIR}/core/ui/mode_enable.cpp + ${REASAMPLER_SRC_DIR}/core/ui/tooltip.cpp + ${REASAMPLER_SRC_DIR}/core/ui/card_meta.cpp + ${REASAMPLER_SRC_DIR}/core/ui/card_drag.cpp + ${REASAMPLER_SRC_DIR}/shell/persist/usage_scan.cpp +) +target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync bridge_marshal sample_usage) +target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC}) + +# OUTPUT_NAME is channel-derived; the CMake target name stays "reaper_reasampler" for both +# configs, since REAPER dlopen's any reaper_* module and the two channels' artifacts load +# side-by-side. LIBRARY_OUTPUT_DIRECTORY pins the module to the top of the build tree even +# though this target is declared in a subdirectory — the install step copies it from there. +# ARCHIVE_OUTPUT_DIRECTORY pins the same for MODULE targets: CMake emits an import-lib +# sidecar (.lib/.exp on MSVC) keyed off ARCHIVE_OUTPUT_DIRECTORY, not LIBRARY_OUTPUT_DIRECTORY, +# so it needs pinning too even though nothing links against this import lib. +set_target_properties(reaper_reasampler PROPERTIES + PREFIX "" + OUTPUT_NAME "${REASAMPLER_OUTPUT_NAME}" + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") + +if(WIN32) + # Native Win32; REAPER provides nothing extra to link. The bank-panel dialog template + # is compiled from resource.rc by the platform RC compiler. + target_sources(reaper_reasampler PRIVATE ${REASAMPLER_SRC_DIR}/resource.rc) + +elseif(APPLE) + # 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") + # SWELL can't read a Win32 .rc directly. Run resgen once to turn 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 ${REASAMPLER_SRC_DIR}/resource.rc_mac_dlg.h) + +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") + # Reuse the macOS resgen output (see 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 ${REASAMPLER_SRC_DIR}/resource.rc_mac_dlg.h) +endif() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000..efbd14a --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,17 @@ +# The pure substrate — see root CLAUDE.md's architecture section for the core/ purity invariant. +# +# Declaration order below runs base-first so the file reads as a dependency ladder; CMake +# itself does not require it (link names resolve at generate time), and a few edges do run +# backwards — core/wire's instrument_drop reuses the instrument's own state codec. + +add_subdirectory(json) +add_subdirectory(util) +add_subdirectory(wire) +add_subdirectory(audio) +add_subdirectory(model) +add_subdirectory(capture) +add_subdirectory(reclaim) +add_subdirectory(version) +add_subdirectory(view) +add_subdirectory(ui) +add_subdirectory(instrument) diff --git a/src/core/audio/CMakeLists.txt b/src/core/audio/CMakeLists.txt new file mode 100644 index 0000000..2b205b8 --- /dev/null +++ b/src/core/audio/CMakeLists.txt @@ -0,0 +1,2 @@ +reasampler_pure_library(peaks SOURCES peaks.cpp) +reasampler_test(peaks LINK peaks) diff --git a/src/core/capture/CMakeLists.txt b/src/core/capture/CMakeLists.txt new file mode 100644 index 0000000..3fc8590 --- /dev/null +++ b/src/core/capture/CMakeLists.txt @@ -0,0 +1,22 @@ +reasampler_pure_library(capture_paths SOURCES capture_paths.cpp) +reasampler_test(capture_paths LINK capture_paths) + +reasampler_pure_library(insert_plan SOURCES insert_plan.cpp) +reasampler_test(insert_plan LINK insert_plan) + +reasampler_pure_library(render_settings SOURCES render_settings.cpp LINK PUBLIC bank_model) +reasampler_test(render_settings LINK render_settings) + +reasampler_pure_library(batch_capture SOURCES batch_capture.cpp) +reasampler_test(batch_capture LINK batch_capture) + +reasampler_pure_library(tail_control + SOURCES tail_control.cpp + LINK PUBLIC render_settings PRIVATE json) +reasampler_test(tail_control LINK tail_control) + +reasampler_pure_library(capture_realtime SOURCES capture_realtime.cpp LINK PUBLIC bank_model) +reasampler_test(capture_realtime LINK capture_realtime) + +reasampler_pure_library(wav_codec SOURCES wav_codec.cpp LINK PUBLIC peaks) +reasampler_test(wav_codec LINK wav_codec) diff --git a/src/core/instrument/CMakeLists.txt b/src/core/instrument/CMakeLists.txt new file mode 100644 index 0000000..16d3af6 --- /dev/null +++ b/src/core/instrument/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(engine) +add_subdirectory(map) +add_subdirectory(ui) diff --git a/src/core/instrument/engine/CMakeLists.txt b/src/core/instrument/engine/CMakeLists.txt new file mode 100644 index 0000000..747f4c2 --- /dev/null +++ b/src/core/instrument/engine/CMakeLists.txt @@ -0,0 +1,26 @@ +# The shifter is hand-rolled rather than WDL_SimplePitchShifter because that header drags +# 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 chain. +reasampler_test(pitch_shift LINK pitch_shift) + +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) + +# 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) +# 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) + +add_subdirectory(filter) diff --git a/src/core/instrument/engine/filter/CMakeLists.txt b/src/core/instrument/engine/filter/CMakeLists.txt new file mode 100644 index 0000000..6765ad0 --- /dev/null +++ b/src/core/instrument/engine/filter/CMakeLists.txt @@ -0,0 +1,15 @@ +# Control mapping, SVF coefficients, morph weights, and the filter type each get their own +# TU; VoiceFilter::process stays header-inline so the kernel still inlines at the call site. +reasampler_pure_library(filter SOURCES + filter_params.cpp + filter_coeffs.cpp + filter_morph.cpp + voice_filter.cpp) + +# Four test targets along the module's own seams so each asserts one domain. filter_tests +# alone owns the analytic reference and the steady-state gain measurement — a forked copy of +# a measurement reference is a worse defect than a long file. +reasampler_test(filter_params LINK filter) +reasampler_test(filter_morph LINK filter) +reasampler_test(filter_state LINK filter) +reasampler_test(filter LINK filter) diff --git a/src/core/instrument/map/CMakeLists.txt b/src/core/instrument/map/CMakeLists.txt new file mode 100644 index 0000000..91836e9 --- /dev/null +++ b/src/core/instrument/map/CMakeLists.txt @@ -0,0 +1,31 @@ +reasampler_pure_library(bridge_marshal SOURCES bridge_marshal.cpp) +reasampler_test(bridge_marshal LINK bridge_marshal) + +reasampler_pure_library(trigger_seam SOURCES trigger_seam.cpp) +# Links only trigger_seam — not even editor_geometry — the plainest data-boundary proof +# available. +reasampler_test(trigger_seam LINK trigger_seam) + +reasampler_pure_library(bank_sync + SOURCES bank_sync.cpp + LINK PUBLIC assignment_request PRIVATE wire) +# Links only bank_sync (+ its assignment_request dep): linking more would break the +# plain-data-boundary proof. +reasampler_test(bank_sync LINK bank_sync) + +# The state codec is shared with the extension's preset-blob path, so it must link WITHOUT +# the voice engine: velocity_curve (the curve field) and master_gain (the wire gain cap) only. +reasampler_pure_library(component_state_io + SOURCES component_state_io.cpp + LINK PUBLIC velocity_curve master_gain) +# Links only component_state_io, deliberately no sampler_core/pitch_shift: the structural +# proof the codec is engine-free, which is what keeps engine object code out of the extension. +reasampler_test(component_state_io LINK component_state_io) + +# The mapping's product is plain SampleData, so the voice engine is not a dependency. +reasampler_pure_library(sample_map + SOURCES sample_map.cpp + LINK PUBLIC bank_book wav_codec velocity_curve peaks) +# Links only sample_map + component_state_io: the same plain-data-boundary proof, spanning +# both halves of the mapping/codec split where the frozen-format assertions live. +reasampler_test(sample_map LINK sample_map component_state_io) diff --git a/src/core/instrument/ui/CMakeLists.txt b/src/core/instrument/ui/CMakeLists.txt new file mode 100644 index 0000000..bda722a --- /dev/null +++ b/src/core/instrument/ui/CMakeLists.txt @@ -0,0 +1,48 @@ +# The geometry vocabulary every instrument UI module speaks (the Rect alias + contains()) +# is header-only, hence INTERFACE. +add_library(editor_geometry INTERFACE) +target_include_directories(editor_geometry INTERFACE ${REASAMPLER_SRC_DIR}) + +reasampler_pure_library(sample_bands SOURCES sample_bands.cpp LINK PUBLIC editor_geometry) +reasampler_test(sample_bands LINK sample_bands) + +reasampler_pure_library(sample_chrome SOURCES sample_chrome.cpp LINK PUBLIC sample_bands) +reasampler_test(sample_chrome LINK sample_chrome) + +reasampler_pure_library(embed_strip SOURCES embed_strip.cpp LINK PUBLIC editor_geometry) +reasampler_test(embed_strip LINK embed_strip) + +reasampler_pure_library(capture_browser SOURCES capture_browser.cpp LINK PUBLIC editor_geometry) +reasampler_test(capture_browser LINK capture_browser) + +reasampler_pure_library(keyboard_strip SOURCES keyboard_strip.cpp LINK PUBLIC editor_geometry) +reasampler_test(keyboard_strip LINK keyboard_strip sample_bands sample_chrome) + +# sample_bands is PRIVATE: the lane split is used internally and nothing in the public +# header needs it. +reasampler_pure_library(waveform_view + SOURCES waveform_view.cpp + LINK PUBLIC editor_geometry peaks PRIVATE sample_bands) +# sample_bands is linked directly here because the test exercises the lane metrics that +# waveform_view does not re-export. +reasampler_test(waveform_view LINK waveform_view sample_bands) + +reasampler_pure_library(browser_scroll + SOURCES browser_scroll.cpp + LINK PUBLIC capture_browser sample_chrome) +reasampler_test(browser_scroll LINK browser_scroll) + +reasampler_pure_library(param_slider SOURCES param_slider.cpp LINK PUBLIC editor_geometry) +reasampler_test(param_slider LINK param_slider) + +reasampler_pure_library(envelope_overlay SOURCES envelope_overlay.cpp LINK PUBLIC editor_geometry) +reasampler_test(envelope_overlay LINK envelope_overlay) + +reasampler_pure_library(envelope_edit SOURCES envelope_edit.cpp LINK PUBLIC envelope_overlay) +reasampler_test(envelope_edit LINK envelope_edit) + +reasampler_pure_library(knob_deck SOURCES knob_deck.cpp LINK PUBLIC editor_geometry) +reasampler_test(knob_deck LINK knob_deck) + +reasampler_pure_library(curve_popup SOURCES curve_popup.cpp LINK PUBLIC editor_geometry) +reasampler_test(curve_popup LINK curve_popup) diff --git a/src/core/json/CMakeLists.txt b/src/core/json/CMakeLists.txt new file mode 100644 index 0000000..8bf1079 --- /dev/null +++ b/src/core/json/CMakeLists.txt @@ -0,0 +1,2 @@ +reasampler_pure_library(json SOURCES json.cpp) +reasampler_test(json LINK json) diff --git a/src/core/model/CMakeLists.txt b/src/core/model/CMakeLists.txt new file mode 100644 index 0000000..b59c551 --- /dev/null +++ b/src/core/model/CMakeLists.txt @@ -0,0 +1,17 @@ +reasampler_pure_library(bank_model SOURCES bank_model.cpp LINK PRIVATE json) +reasampler_test(bank_model LINK bank_model) + +reasampler_pure_library(slot_map SOURCES slot_map.cpp LINK PRIVATE json) +reasampler_test(slot_map LINK slot_map json) + +reasampler_pure_library(bank_book + SOURCES bank_book.cpp bank_book_json.cpp + LINK PUBLIC bank_model slot_map PRIVATE json) +reasampler_test(bank_book LINK bank_book) + +reasampler_pure_library(owned_manifest SOURCES owned_manifest.cpp LINK PRIVATE json) +reasampler_test(owned_manifest LINK owned_manifest) + +reasampler_pure_library(provenance SOURCES provenance.cpp LINK PRIVATE wire) +# bank_model: the test proves the recorded recipe survives the Sample-JSON round-trip. +reasampler_test(provenance LINK provenance bank_model) diff --git a/src/core/reclaim/CMakeLists.txt b/src/core/reclaim/CMakeLists.txt new file mode 100644 index 0000000..1717dee --- /dev/null +++ b/src/core/reclaim/CMakeLists.txt @@ -0,0 +1,3 @@ +reasampler_pure_library(prune_reconcile SOURCES prune_reconcile.cpp) +# bank_book supplies the cross-bank referenced-file union the orphan set is computed against. +reasampler_test(prune_reconcile LINK prune_reconcile bank_book) diff --git a/src/core/ui/CMakeLists.txt b/src/core/ui/CMakeLists.txt new file mode 100644 index 0000000..8678d05 --- /dev/null +++ b/src/core/ui/CMakeLists.txt @@ -0,0 +1,40 @@ +reasampler_pure_library(bank_grid SOURCES bank_grid.cpp) +reasampler_test(bank_grid LINK bank_grid) + +reasampler_pure_library(tab_strip SOURCES tab_strip.cpp) +reasampler_test(tab_strip LINK tab_strip) + +reasampler_pure_library(prune_button SOURCES prune_button.cpp) +reasampler_test(prune_button LINK prune_button) + +reasampler_pure_library(drag_out SOURCES drag_out.cpp) +reasampler_test(drag_out LINK drag_out) + +reasampler_pure_library(theme SOURCES theme.cpp) +reasampler_test(theme LINK theme) + +reasampler_pure_library(component_geometry SOURCES component_geometry.cpp) +reasampler_test(component_geometry LINK component_geometry) + +reasampler_pure_library(action_bar SOURCES action_bar.cpp) +reasampler_test(action_bar LINK action_bar) + +# prune_button owns the FooterRect input type the footer layout reuses. +reasampler_pure_library(footer_bar SOURCES footer_bar.cpp LINK PUBLIC prune_button) +reasampler_test(footer_bar LINK footer_bar) + +reasampler_pure_library(overflow_menu SOURCES overflow_menu.cpp) +reasampler_test(overflow_menu LINK overflow_menu) + +# view_mode_model owns the seed mode ids the predicate compares against. +reasampler_pure_library(mode_enable SOURCES mode_enable.cpp LINK PUBLIC view_mode_model) +reasampler_test(mode_enable LINK mode_enable) + +reasampler_pure_library(tooltip SOURCES tooltip.cpp) +reasampler_test(tooltip LINK tooltip) + +reasampler_pure_library(card_meta SOURCES card_meta.cpp) +reasampler_test(card_meta LINK card_meta) + +reasampler_pure_library(card_drag SOURCES card_drag.cpp LINK PUBLIC drag_out bank_grid) +reasampler_test(card_drag LINK card_drag) diff --git a/src/core/util/CMakeLists.txt b/src/core/util/CMakeLists.txt new file mode 100644 index 0000000..897e2ba --- /dev/null +++ b/src/core/util/CMakeLists.txt @@ -0,0 +1,2 @@ +reasampler_pure_library(file_bytes SOURCES file_bytes.cpp) +reasampler_test(file_bytes LINK file_bytes) diff --git a/src/core/version/CMakeLists.txt b/src/core/version/CMakeLists.txt new file mode 100644 index 0000000..d8e06eb --- /dev/null +++ b/src/core/version/CMakeLists.txt @@ -0,0 +1,42 @@ +reasampler_pure_library(app_version SOURCES app_version.cpp) +# version_generated.h, configured at the root from the one REASAMPLER_VERSION string. +# PUBLIC so every consumer of the channel bit sees it. +target_include_directories(app_version PUBLIC ${PROJECT_BINARY_DIR}/generated) +reasampler_test(app_version LINK app_version) + +# Anti-normalization padding canary (rationale in tests/test_app_version_padding.cpp). The +# live-version assertions in app_version_tests are version-shape-blind — relative checks +# such as appVersion() == stampVersion() hold whether the string was threaded verbatim or +# reconstructed from numeric components — so that suite cannot detect a +# reconstruct-from-components regression at all. So: run the SAME template through +# configure_file a second time with a SYNTHETIC padded version, and compile the SAME +# app_version.cpp against it. +# +# "0.9.01" is a permanent test fixture, NOT the shipped version. It must match the literals +# in test_app_version_padding.cpp and must NEVER be bumped on release. +# +# Coverage boundary: this catches reconstruct-from-components inside app_version.cpp. It +# cannot see the live source-of-truth line becoming a CMake variable derivation — the +# comment block at the top of the root CMakeLists.txt guards that half. +function(_configure_padding_canary) + # set() inside a function is function-scoped, so this clobber cannot leak to the parent + # scope — no save/restore dance needed. REASAMPLER_CHANNEL_IS_BETA and the directory + # variables are inherited read-only. + set(REASAMPLER_VERSION "0.9.01") + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/version_generated.h.in + ${PROJECT_BINARY_DIR}/generated_padding_canary/version_generated.h + @ONLY) +endfunction() +_configure_padding_canary() + +# Longhand rather than reasampler_test: the canary RECOMPILES app_version.cpp instead of +# linking the library, which is what lets the include-dir substitution work — it must see +# generated_padding_canary/ in place of the live generated/ dir. If app_version ever gains +# a link dependency, mirror it here. +add_executable(app_version_padding_tests + ${REASAMPLER_TESTS_DIR}/test_app_version_padding.cpp + app_version.cpp) +target_include_directories(app_version_padding_tests PRIVATE + ${PROJECT_BINARY_DIR}/generated_padding_canary ${REASAMPLER_SRC_DIR}) +add_test(NAME app_version_padding_tests COMMAND app_version_padding_tests) diff --git a/src/core/view/CMakeLists.txt b/src/core/view/CMakeLists.txt new file mode 100644 index 0000000..5062b57 --- /dev/null +++ b/src/core/view/CMakeLists.txt @@ -0,0 +1,18 @@ +reasampler_pure_library(lane_keys SOURCES lane_keys.cpp) +reasampler_test(lane_keys LINK lane_keys) + +# lane_keys is PUBLIC: the lane-minting plan names managed lanes through the one durable-key +# convention, so every consumer has to resolve that symbol too. +reasampler_pure_library(view_mode_model + SOURCES view_mode_model.cpp + LINK PRIVATE json PUBLIC lane_keys) +reasampler_test(view_mode_model LINK view_mode_model) + +reasampler_pure_library(view_tree SOURCES view_tree.cpp LINK PUBLIC view_mode_model) +reasampler_test(view_tree LINK view_tree) + +reasampler_pure_library(guid_diff SOURCES guid_diff.cpp) +reasampler_test(guid_diff LINK guid_diff) + +reasampler_pure_library(mode_switch SOURCES mode_switch.cpp) +reasampler_test(mode_switch LINK mode_switch) diff --git a/src/core/wire/CMakeLists.txt b/src/core/wire/CMakeLists.txt new file mode 100644 index 0000000..766f820 --- /dev/null +++ b/src/core/wire/CMakeLists.txt @@ -0,0 +1,18 @@ +reasampler_pure_library(wire SOURCES wire.cpp) +reasampler_test(wire LINK wire) + +reasampler_pure_library(assignment_request SOURCES assignment_request.cpp LINK PRIVATE wire) +reasampler_test(assignment_request LINK assignment_request) + +reasampler_pure_library(sample_usage SOURCES sample_usage.cpp LINK PRIVATE wire) +# prune_reconcile composes the protection proof at the pure layer: a capture held by a live +# instance lands in the referenced union, so pruneOrphans can never emit it. +reasampler_test(sample_usage LINK sample_usage prune_reconcile) + +# The drop payload is built through the instrument's OWN state serializer rather than a +# parallel byte writer, so the cross-artifact contract cannot drift — hence the link to +# component_state_io, which stays engine-free. The class-ID string derives from the frozen +# UID macros, channel-selected via the generated version header, hence its include dir. +reasampler_pure_library(instrument_drop SOURCES instrument_drop.cpp LINK PUBLIC component_state_io) +target_include_directories(instrument_drop PUBLIC ${PROJECT_BINARY_DIR}/generated) +reasampler_test(instrument_drop LINK instrument_drop) diff --git a/src/shell/instrument/CMakeLists.txt b/src/shell/instrument/CMakeLists.txt new file mode 100644 index 0000000..791e169 --- /dev/null +++ b/src/shell/instrument/CMakeLists.txt @@ -0,0 +1,106 @@ +# ReaSampler 9000 — the second build artifact: a Windows-only VST3 instrument the user +# instantiates on an instrument track. Additive; the extension builds unchanged. +# +# The nested vst3sdk slice (pluginterfaces / base / public.sdk) is a one-time submodule +# step documented in CLAUDE.md. When it is absent — a fresh clone that ran only the +# top-level init — skip this module rather than fail configure on missing sources: the pure +# libraries and their CTest targets still build and test without the SDK. Probe one +# representative source file. +if(WIN32 AND EXISTS "${VST3_SDK}/public.sdk/source/main/pluginfactory.cpp") + + # The bounded slice of the Steinberg VST3 SDK this instrument needs. Enumerated rather + # than add_subdirectory of the whole SDK to keep the build hermetic and lean: no VSTGUI, + # no examples, no SDK-global CMake helpers or install machinery. The submodule is pinned + # to tag v3.7.9_build_61, so the list is fixed — re-verify this set if the tag is bumped. + add_library(vst3_sdk STATIC + ${VST3_SDK}/pluginterfaces/base/funknown.cpp + ${VST3_SDK}/pluginterfaces/base/coreiids.cpp + ${VST3_SDK}/pluginterfaces/base/conststringtable.cpp + ${VST3_SDK}/pluginterfaces/base/ustring.cpp + ${VST3_SDK}/base/source/fobject.cpp + ${VST3_SDK}/base/source/fstring.cpp + ${VST3_SDK}/base/source/fbuffer.cpp + ${VST3_SDK}/base/source/fstreamer.cpp + ${VST3_SDK}/base/source/fdebug.cpp + ${VST3_SDK}/base/source/baseiids.cpp + ${VST3_SDK}/base/source/updatehandler.cpp + ${VST3_SDK}/base/thread/source/flock.cpp + # vstsinglecomponenteffect.cpp #includes vsteditcontroller.cpp unity-style, so + # vsteditcontroller.cpp must NOT be listed separately (double definition). + ${VST3_SDK}/public.sdk/source/vst/vstsinglecomponenteffect.cpp + ${VST3_SDK}/public.sdk/source/vst/vstcomponentbase.cpp + ${VST3_SDK}/public.sdk/source/vst/vstbus.cpp + ${VST3_SDK}/public.sdk/source/vst/vstparameters.cpp + ${VST3_SDK}/public.sdk/source/vst/vstinitiids.cpp + ${VST3_SDK}/public.sdk/source/common/pluginview.cpp + ${VST3_SDK}/public.sdk/source/common/commoniids.cpp + # dllmain.cpp + moduleinit.cpp are NOT here — see the module target below. + ${VST3_SDK}/public.sdk/source/main/pluginfactory.cpp + ) + target_include_directories(vst3_sdk PUBLIC ${VST3_SDK}) + # The SDK requires exactly one of RELEASE / DEVELOPMENT (fdebug.cpp keys off it). + target_compile_definitions(vst3_sdk PUBLIC $,DEVELOPMENT=1,RELEASE=1>) + + add_library(reasampler_vst MODULE + vst_entry.cpp + reasampler_processor.cpp + processor_state.cpp + processor_reload.cpp + # The editor family is split on the Sample face's band axis: session/bridge state, + # param plumbing plus the shared band-layout resolve, then paint and input in + # matching sets, plus the two band-independent surfaces and the platform TU. + editor_session.cpp + editor_controls.cpp + editor_paint.cpp + editor_paint_chrome.cpp + editor_paint_waveform.cpp + editor_paint_deck.cpp + editor_paint_browse.cpp + editor_paint_curve.cpp + editor_input.cpp + editor_input_chrome.cpp + editor_input_waveform.cpp + editor_input_deck.cpp + editor_input_browse.cpp + editor_input_curve.cpp + editor_platform.cpp + reasampler_embed.cpp + reaper_bridge.cpp + # draw_kit is compiled into each module rather than being a static library — see root + # CMakeLists.txt's LICE_SRC comment for why. + ${REASAMPLER_SRC_DIR}/shell/panel/draw_kit.cpp + # Compiled into the module, NOT into vst3_sdk: their SMTG_EXPORT_SYMBOL functions + # (InitDll/ExitDll) have no internal referrer, so the linker strips them from a + # static library. Compiling them here keeps the exports. + ${VST3_SDK}/public.sdk/source/main/dllmain.cpp + ${VST3_SDK}/public.sdk/source/main/moduleinit.cpp + ${LICE_SRC} + ) + # sample_map's build yields plain SampleData, so it does NOT pull the voice engine — + # sampler_core is linked directly. app_version's PUBLIC include dir carries the + # generated version header, so the instrument reads the SAME channel-derived ext-state + # namespace the extension writes. + target_link_libraries(reasampler_vst PRIVATE vst3_sdk editor_geometry bridge_marshal + sampler_core sample_map component_state_io capture_paths embed_strip app_version + capture_browser keyboard_strip sample_bands sample_chrome + waveform_view bank_sync browser_scroll param_slider tooltip + theme component_geometry bank_grid trigger_seam envelope_overlay envelope_edit + knob_deck curve_popup master_gain sample_usage file_bytes) + # SDK_INC gives the REAPER VST3 interfaces + API header for the bridge; WDL_INC gives + # LICE for the editor. The VST3 SDK headers arrive via vst3_sdk PUBLIC. + target_include_directories(reasampler_vst PRIVATE ${REASAMPLER_SRC_DIR} ${SDK_INC} ${WDL_INC}) + + # A .vst3 is a DLL with a .vst3 extension and no lib prefix. OUTPUT_NAME is channel- + # forked from the one channel decision at the root and must match + # app_version::vstOutputName(); the two channels install side-by-side, and the + # per-channel VST3 class UID keeps a saved instance bound to its own channel. + # LIBRARY_OUTPUT_DIRECTORY / ARCHIVE_OUTPUT_DIRECTORY pin the module to the top of the + # build tree even though this target is declared in a subdirectory — see src/app/CMakeLists.txt's + # set_target_properties comment for why both properties are needed. + set_target_properties(reasampler_vst PROPERTIES + PREFIX "" + SUFFIX ".vst3" + OUTPUT_NAME "${REASAMPLER_VST_OUTPUT_NAME}" + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}" + ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}") +endif() From 68765da031a004fbbea6b55d9a99d220b9d57bff Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Thu, 30 Jul 2026 12:28:39 -0400 Subject: [PATCH 2/3] build: route every core/ TU into reaper_reasampler through exactly one static-library link edge, never a direct compile --- src/app/CMakeLists.txt | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index e471a7d..300f75a 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -1,6 +1,8 @@ # The REAPER extension — a loadable module REAPER dlopen()s, never linked against. -# Its source list spans app/ + shell/ + the handful of core TUs compiled straight in, so -# the paths below are rooted at src/ rather than being relative to this directory. +# Its source list is app/ + shell/ only, so the paths below are rooted at src/ rather than +# being relative to this directory. Every core/ TU enters through a link edge instead: a TU +# compiled here AND linked from its library would be built twice under two different sets of +# per-target compile definitions and include dirs — two definitions of one symbol in one link. add_library(reaper_reasampler MODULE ${REASAMPLER_SRC_DIR}/app/main.cpp @@ -11,7 +13,6 @@ add_library(reaper_reasampler MODULE ${REASAMPLER_SRC_DIR}/shell/capture/realtime_lifecycle.cpp ${REASAMPLER_SRC_DIR}/shell/capture/capture_realtime_shell.cpp ${REASAMPLER_SRC_DIR}/shell/capture/capture_realtime_finalize.cpp - ${REASAMPLER_SRC_DIR}/core/capture/capture_realtime.cpp ${REASAMPLER_SRC_DIR}/shell/persist/session.cpp ${REASAMPLER_SRC_DIR}/shell/persist/ext_state_io.cpp ${REASAMPLER_SRC_DIR}/shell/persist/prune_fs.cpp @@ -27,39 +28,22 @@ add_library(reaper_reasampler MODULE # draw_kit is compiled into each module rather than being a static library — see root # CMakeLists.txt's LICE_SRC comment for why. ${REASAMPLER_SRC_DIR}/shell/panel/draw_kit.cpp - ${REASAMPLER_SRC_DIR}/core/view/mode_switch.cpp - ${REASAMPLER_SRC_DIR}/core/ui/tab_strip.cpp - ${REASAMPLER_SRC_DIR}/shell/capture/insert.cpp - ${REASAMPLER_SRC_DIR}/core/capture/insert_plan.cpp ${LICE_SRC} - ${REASAMPLER_SRC_DIR}/core/view/view_mode_model.cpp - ${REASAMPLER_SRC_DIR}/core/view/view_tree.cpp + ${REASAMPLER_SRC_DIR}/shell/capture/insert.cpp ${REASAMPLER_SRC_DIR}/shell/view/view.cpp ${REASAMPLER_SRC_DIR}/shell/capture/track_guid.cpp ${REASAMPLER_SRC_DIR}/shell/capture/provenance_shell.cpp - ${REASAMPLER_SRC_DIR}/core/view/guid_diff.cpp - ${REASAMPLER_SRC_DIR}/core/view/lane_keys.cpp ${REASAMPLER_SRC_DIR}/shell/capture/item_read.cpp ${REASAMPLER_SRC_DIR}/shell/actions/action_registry.cpp ${REASAMPLER_SRC_DIR}/shell/actions/design_view_actions.cpp ${REASAMPLER_SRC_DIR}/shell/actions/bank_actions.cpp ${REASAMPLER_SRC_DIR}/shell/actions/prune_action.cpp ${REASAMPLER_SRC_DIR}/shell/actions/ingest.cpp - ${REASAMPLER_SRC_DIR}/core/model/bank_book.cpp - ${REASAMPLER_SRC_DIR}/core/model/bank_book_json.cpp - ${REASAMPLER_SRC_DIR}/core/model/owned_manifest.cpp ${REASAMPLER_SRC_DIR}/shell/actions/drag_out_win.cpp ${REASAMPLER_SRC_DIR}/shell/actions/instrument_drop_win.cpp - ${REASAMPLER_SRC_DIR}/core/ui/action_bar.cpp - ${REASAMPLER_SRC_DIR}/core/ui/footer_bar.cpp - ${REASAMPLER_SRC_DIR}/core/ui/overflow_menu.cpp - ${REASAMPLER_SRC_DIR}/core/ui/mode_enable.cpp - ${REASAMPLER_SRC_DIR}/core/ui/tooltip.cpp - ${REASAMPLER_SRC_DIR}/core/ui/card_meta.cpp - ${REASAMPLER_SRC_DIR}/core/ui/card_drag.cpp ${REASAMPLER_SRC_DIR}/shell/persist/usage_scan.cpp ) -target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync bridge_marshal sample_usage) +target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model view_tree guid_diff lane_keys insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync bridge_marshal sample_usage) target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC}) # OUTPUT_NAME is channel-derived; the CMake target name stays "reaper_reasampler" for both From 5420550ff37448d5b547394f88dbb2356247a55b Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Thu, 30 Jul 2026 12:40:37 -0400 Subject: [PATCH 3/3] fix: correct app CMakeLists comments, drop dead bridge_marshal link edge --- src/app/CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 300f75a..6688deb 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -1,8 +1,9 @@ -# The REAPER extension — a loadable module REAPER dlopen()s, never linked against. -# Its source list is app/ + shell/ only, so the paths below are rooted at src/ rather than -# being relative to this directory. Every core/ TU enters through a link edge instead: a TU -# compiled here AND linked from its library would be built twice under two different sets of -# per-target compile definitions and include dirs — two definitions of one symbol in one link. +# The REAPER extension — a loadable module REAPER dlopen()s, never linked against. Paths +# below are rooted at src/, not relative to this directory. +# No core/ TU is ever compiled into this source list; every core/ TU enters through a link edge +# instead. Compiling one here too would give it its own copy, built under this target's own +# compile definitions and include dirs — free to diverge from the library copy every other +# consumer (the _tests targets, reasampler_vst) links, with nothing to detect it. add_library(reaper_reasampler MODULE ${REASAMPLER_SRC_DIR}/app/main.cpp @@ -43,7 +44,7 @@ add_library(reaper_reasampler MODULE ${REASAMPLER_SRC_DIR}/shell/actions/instrument_drop_win.cpp ${REASAMPLER_SRC_DIR}/shell/persist/usage_scan.cpp ) -target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model view_tree guid_diff lane_keys insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync bridge_marshal sample_usage) +target_link_libraries(reaper_reasampler PRIVATE json wire file_bytes bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model view_tree guid_diff lane_keys insert_plan render_settings batch_capture tail_control capture_realtime bank_book wav_codec owned_manifest prune_reconcile prune_button app_version provenance drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync sample_usage) target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC}) # OUTPUT_NAME is channel-derived; the CMake target name stays "reaper_reasampler" for both