Files
reasampler/CMakeLists.txt
T
daniel 26e2bf2fc6 S17 drop-and-load onto track FX button; S13 editor drop-accept (relay degraded)
S17: drag_out InstrumentDrop gesture + instrument_drop blob reusing the
instrument's own serializer; bank_panel FX hover-track + add-VST/vst_chunk
inject. S13 relay deferred (read-only bridge) — editor shows drop affordance.
2026-07-27 04:34:01 -04:00

1028 lines
63 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
cmake_minimum_required(VERSION 3.19)
# ---------------------------------------------------------------------------
# Version — SINGLE SOURCE OF TRUTH (Phase V, V1). Edit REASAMPLER_VERSION here and
# nowhere else: it flows to the binary constant, the ext-state writing-version stamp,
# and the "show version" action via a configure_file'd header (below). The string is
# authoritative verbatim — leading zero preserved (Daniel-fixed: exactly "0.9.01",
# two-digit zero-padded patch). We deliberately do NOT reconstruct the display string
# from project(VERSION)'s numeric components, since CMake may normalize a numeric patch
# field; the string variable is what renders. project(VERSION ...) is still set (with a
# normalized 0.9.1 triple) for CMake hygiene / any downstream numeric use, but it is NOT
# the rendered source of truth.
set(REASAMPLER_VERSION "0.9.01")
project(reaper_reasampler VERSION 0.9.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# ---------------------------------------------------------------------------
# Channel — SINGLE SOURCE OF TRUTH for beta-in-isolation (Phase V, V4). One flag,
# `-DREASAMPLER_CHANNEL=beta`, forks the whole channel identity from one build tree:
# absent (or `stable`) = today's build with BYTE-IDENTICAL identity (binary name,
# ext-state namespace, command-id strings, version render); `beta` = a fully isolated
# `reaper_reasampler_beta` that coexists with stable in one REAPER. The flag reduces to
# ONE bit (REASAMPLER_CHANNEL_IS_BETA) threaded through the SAME configure_file'd header
# as the version string, so the pure app_version module derives every channel-qualified
# identity from it — no scattered #ifdefs. Any value other than exactly `beta` is treated
# as stable (a typo must not silently produce a half-forked build), and we hard-error on
# an unrecognized non-empty value so a misspelled `-DREASAMPLER_CHANNEL=betaa` is caught
# at configure time rather than shipping stable identity under a beta intent.
set(REASAMPLER_CHANNEL "stable" CACHE STRING "Build channel: stable (default) or beta")
if(REASAMPLER_CHANNEL STREQUAL "beta")
set(REASAMPLER_CHANNEL_IS_BETA 1)
set(REASAMPLER_OUTPUT_NAME "reaper_reasampler_beta")
# 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.
set(REASAMPLER_VST_OUTPUT_NAME "reasampler_9000_beta")
elseif(REASAMPLER_CHANNEL STREQUAL "stable")
set(REASAMPLER_CHANNEL_IS_BETA 0)
set(REASAMPLER_OUTPUT_NAME "reaper_reasampler")
set(REASAMPLER_VST_OUTPUT_NAME "reasampler_9000")
else()
message(FATAL_ERROR
"REASAMPLER_CHANNEL must be 'stable' or 'beta' (got '${REASAMPLER_CHANNEL}')")
endif()
# Generate version_generated.h from the one REASAMPLER_VERSION variable + the channel bit.
# Regenerated at configure time whenever either changes; the exact string is substituted
# verbatim and the channel bit fans out through app_version.
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/src/version_generated.h.in
${CMAKE_CURRENT_BINARY_DIR}/generated/version_generated.h
@ONLY)
# ---------------------------------------------------------------------------
# Vendored dependencies — add as git submodules (see README):
# git submodule add https://github.com/justinfrankel/reaper-sdk vendor/reaper-sdk
# git submodule add https://github.com/justinfrankel/WDL vendor/WDL
# ---------------------------------------------------------------------------
set(SDK_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/reaper-sdk/sdk)
set(WDL_INC ${CMAKE_CURRENT_SOURCE_DIR}/vendor/WDL/WDL)
set(SWELL ${WDL_INC}/swell)
# ---------------------------------------------------------------------------
# 1) Pure model library — NO REAPER, NO SWELL. Builds & tests anywhere.
# The sampler's heart: Sample metadata + BankIndex (Milestone 1).
# ---------------------------------------------------------------------------
add_library(bank_model STATIC src/bank_model.cpp)
target_include_directories(bank_model PUBLIC src)
# ---------------------------------------------------------------------------
# 2) Pure peaks library — NO REAPER, NO SWELL. Waveform min/max thumbnails from
# raw PCM (Milestone 2). A sibling pure lib, kept distinct from bank_model.
# ---------------------------------------------------------------------------
add_library(peaks STATIC src/peaks.cpp)
target_include_directories(peaks PUBLIC src)
# ---------------------------------------------------------------------------
# 2b) Pure capture-path arithmetic — NO REAPER, NO SWELL. Bank-folder / unique
# file-name / project-relative path derivation for the capture shell (M3).
# Split out so the fiddly path logic is unit-tested outside the DAW.
# ---------------------------------------------------------------------------
add_library(capture_paths STATIC src/capture_paths.cpp)
target_include_directories(capture_paths PUBLIC src)
# ---------------------------------------------------------------------------
# 2c) Pure bank-grid layout — NO REAPER, NO SWELL. Grid tiling math (panel WxH +
# cell size + N -> cell rects, wrapping, partial last row) and the thumbnail
# cache key for the docked bank_panel (M5). Split out so the layout logic is
# unit-tested outside the DAW; the panel shell (SWELL/LICE/PCM) is DAW-verified.
# ---------------------------------------------------------------------------
add_library(bank_grid STATIC src/bank_grid.cpp)
target_include_directories(bank_grid PUBLIC src)
# ---------------------------------------------------------------------------
# 2c') Pure mode_switch layout — NO REAPER, NO SWELL. The Design-View mode-switch
# geometry (D5): header rect + N modes -> N equal segment rects (exact tiling),
# and point -> segment hit-test. Split out so the switch's layout math is
# unit-tested outside the DAW; the bank_panel header strip that draws it and
# routes clicks to view::applyMode is DAW-verified. Mirror of bank_grid.
# ---------------------------------------------------------------------------
add_library(mode_switch STATIC src/mode_switch.cpp)
target_include_directories(mode_switch PUBLIC src)
# ---------------------------------------------------------------------------
# 2c'') Pure tab_strip layout — NO REAPER, NO SWELL. The named-banks tab-strip
# geometry (B4): strip rect + N tabs at a fixed tab width + scroll offset ->
# per-tab rects (overflow-clipped), overflow chevron reservation + maxScroll,
# and point -> tab / chevron hit-test. Split out so the strip's layout +
# overflow/scroll math is unit-tested outside the DAW; the bank_panel region
# that draws it and routes clicks is DAW-verified. Mirror of mode_switch.
# ---------------------------------------------------------------------------
add_library(tab_strip STATIC src/tab_strip.cpp)
target_include_directories(tab_strip PUBLIC src)
# ---------------------------------------------------------------------------
# 2d) Pure view_mode_model library — NO REAPER, NO SWELL. The Design View heart
# (Phase D1): mode registry + GUID-keyed membership index + folder-tree-aware
# visibility derivation + parking/restore planner + JSON round-trip. Mirror of
# bank_model; the folder tree is an INPUT supplied by the D2 shell.
# ---------------------------------------------------------------------------
add_library(view_mode_model STATIC src/view_mode_model.cpp)
target_include_directories(view_mode_model PUBLIC src)
# The pure lane-minting decision (planLaneMinting) names managed lanes via the ONE
# durable-key convention in lane_keys (laneNameForMode), so the model depends on that
# pure sibling. PUBLIC so every consumer (tests + module) resolves the symbol.
target_link_libraries(view_mode_model PUBLIC lane_keys)
# ---------------------------------------------------------------------------
# 2d) Pure view_tree library — NO REAPER, NO SWELL. The one testable-outside-DAW
# piece of the D2 view shell: turning REAPER's linear I_FOLDERDEPTH stream into
# the parent<->child FolderTree the model consumes. The REAPER reads stay in
# view.cpp; this fiddly folder-depth walk is unit-tested here (mirrors
# capture_paths splitting the path math out of the capture shell).
# ---------------------------------------------------------------------------
add_library(view_tree STATIC src/view_tree.cpp)
target_include_directories(view_tree PUBLIC src)
target_link_libraries(view_tree PUBLIC view_mode_model)
# ---------------------------------------------------------------------------
# 2d'') Pure guid_diff library — NO REAPER, NO SWELL. The D2 Wave-2 new-content
# detection core: current \ previous GUID diff + the first-poll-after-open
# baseline guard (and per-project reset). Split out so the fiddly baseline/diff
# logic is unit-tested outside the DAW; the bank_panel timer that reads REAPER's
# live track/item GUID set and applies the tags is DAW-verified. Mirror of
# view_tree splitting the folder-depth walk out of view.cpp.
# ---------------------------------------------------------------------------
add_library(guid_diff STATIC src/guid_diff.cpp)
target_include_directories(guid_diff PUBLIC src)
# ---------------------------------------------------------------------------
# 2d''') Pure lane_keys library — NO REAPER, NO SWELL. The managed/manual fixed-lane
# heuristic (D2 Wave-2): a lane whose durable P_LANENAME:n carries the
# "reasampler:" prefix is tool-managed and keyed by that stable name; any other
# lane is user-minted manual and off-limits. Resolves design point #1 (auto-tag
# exemption) and #2 (name-keyed identity survives ordinal renumber). Split out
# so the prefix rule is unit-tested; view.cpp reads the names from REAPER.
# ---------------------------------------------------------------------------
add_library(lane_keys STATIC src/lane_keys.cpp)
target_include_directories(lane_keys PUBLIC src)
# ---------------------------------------------------------------------------
# 2e) Pure insert_plan library — NO REAPER, NO SWELL. The InsertMedia `mode`
# bitmask arithmetic behind the `insert` shell (M6). Split out so the
# load-bearing bit computation (no silent stretch, opt-in conform) is
# unit-tested outside the DAW; the InsertMedia call itself is DAW-verified.
# ---------------------------------------------------------------------------
add_library(insert_plan STATIC src/insert_plan.cpp)
target_include_directories(insert_plan PUBLIC src)
# ---------------------------------------------------------------------------
# 2f) Pure render_settings library — NO REAPER, NO SWELL. The M7 capture-family
# logic: source-mode + wet/dry -> RENDER_SETTINGS bit value, P_RAZOREDITS
# string -> time ranges + union bound, and the capture-action taxonomy table.
# Split out so the fiddly bit-mapping / razor-parsing is unit-tested outside
# the DAW; the render-driving + selection reads stay in capture.cpp / main.cpp.
# Depends on bank_model for the pure SourceMode enum.
# ---------------------------------------------------------------------------
add_library(render_settings STATIC src/render_settings.cpp)
target_include_directories(render_settings PUBLIC src)
target_link_libraries(render_settings PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2f'') Pure batch_capture library — NO REAPER, NO SWELL. The M11 batch-capture
# logic: an ordered list of source ranges (one per selected item / per razor
# area) -> validated, ordinal-assigned capture units (empty/inverted dropped),
# plus order-preserving per-unit result aggregation into a mixed-result summary
# line. Split out so the plan/aggregate/summary is unit-tested outside the DAW;
# the selection read, transient re-selection, and render loop stay in main.cpp.
# No dependency on bank_model — it takes plain ranges/values at its boundary.
# ---------------------------------------------------------------------------
add_library(batch_capture STATIC src/batch_capture.cpp)
target_include_directories(batch_capture PUBLIC src)
# ---------------------------------------------------------------------------
# 2f') Pure tail_control library — NO REAPER, NO SWELL. The docked bank_panel's
# tail-mode toggle logic (T1 exposure): TailSetting state, cycle order
# (None->Auto->Manual->None), the manual-length clamp to the 8 s cap, and the
# toggle label text. Split out so the toggle's cycle/clamp/label is unit-tested
# outside the DAW; the bank_panel footer that draws it + routes clicks is
# DAW-verified. Depends on render_settings for the pure TailMode enum + caps.
# ---------------------------------------------------------------------------
add_library(tail_control STATIC src/tail_control.cpp)
target_include_directories(tail_control PUBLIC src)
target_link_libraries(tail_control PUBLIC render_settings)
# ---------------------------------------------------------------------------
# 2g') Pure bank_book library — NO REAPER, NO SWELL. The multi-bank phase heart
# (Phase B1): an ordered registry of banks (pool seeded as bank-zero + named
# banks), each wrapping a BankIndex; create/rename/reorder/delete named banks,
# pool privileges enforced in-model, active-bank id, index-only move/copy of a
# sample between banks, JSON round-trip + legacy-bank_index→pool migration.
# Mirror of bank_model / view_mode_model; wraps BankIndex (bank_model untouched).
# ---------------------------------------------------------------------------
add_library(bank_book STATIC src/bank_book.cpp)
target_include_directories(bank_book PUBLIC src)
target_link_libraries(bank_book PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2g'') Pure owned_manifest library — NO REAPER, NO SWELL. The owned-file manifest
# seam (Phase B B-cap): the set of project-relative files the capture path
# itself created, so Phase R prune can tell the bank system's own orphans from
# hand-dropped files. Deliberately DECOUPLED from bank_book — it tracks files
# CREATED, not index membership (sample-remove is not manifest-remove). Small
# pure type + JSON round-trip; mirror of wav_trim / tab_strip. B-cap writes +
# persists it; Phase R (R1/R2) consumes it — no prune logic here.
# ---------------------------------------------------------------------------
add_library(owned_manifest STATIC src/owned_manifest.cpp)
target_include_directories(owned_manifest PUBLIC src)
# ---------------------------------------------------------------------------
# 2g''') Pure prune_reconcile library — NO REAPER, NO SWELL, NO filesystem. The
# Phase R (Reclaim) Wave-1 safety-critical decision: given the files present
# in the bank folder, the union of files referenced across every bank, and the
# owned-file manifest, compute the orphan set (owned ∩ present) referenced.
# Mirror of view_mode_model::reconcile one level down (files, not GUIDs). Small
# pure function; R2/R3 wrap the two ends (folder enumeration + deletion) in the
# shell. Standalone — depends only on the standard library.
# ---------------------------------------------------------------------------
add_library(prune_reconcile STATIC src/prune_reconcile.cpp)
target_include_directories(prune_reconcile PUBLIC src)
# ---------------------------------------------------------------------------
# 2g'''') Pure prune_button layout — NO REAPER, NO SWELL. The Phase R (Reclaim)
# Wave-3 (R3, fork R-E) prune-button geometry: footer rect -> right-anchored
# button rect (suppressed when the footer is too narrow), and point -> in/out
# hit-test. Split out so the button's placement + hit-test math is unit-tested
# outside the DAW; the bank_panel footer that draws it and dispatches the
# "Prune bank folder" command is DAW-verified. Mirror of mode_switch / tab_strip.
# ---------------------------------------------------------------------------
add_library(prune_button STATIC src/prune_button.cpp)
target_include_directories(prune_button PUBLIC src)
# ---------------------------------------------------------------------------
# 2g) Pure realtime_record library — NO REAPER, NO SWELL. The M8 realtime-record
# logic: capture scope + FX-tap point -> I_RECMODE / I_RECMODE_FLAGS values,
# wet/dry -> tap point, and the recorded-file -> Sample mapping. Split out so
# the fiddly record-mode bit values + Sample population are unit-tested outside
# the DAW; the transport/temp-track/send/file-move recipe stays in capture.cpp.
# Depends on bank_model for the pure Sample / SourceMode types.
# ---------------------------------------------------------------------------
add_library(realtime_record STATIC src/realtime_record.cpp)
target_include_directories(realtime_record PUBLIC src)
target_link_libraries(realtime_record PUBLIC bank_model)
# ---------------------------------------------------------------------------
# 2h) Pure wav_trim library — NO REAPER, NO SWELL. The realtime tail's (T2) PCM
# decay-scan trim needs to TRUNCATE the recorded 32-bit-float WAV at a frame
# boundary without corrupting the RIFF container. This module holds the fiddly,
# easy-to-get-wrong part unit-tested outside the DAW: parse the WAV geometry
# (fmt/data chunk walk + 32-bit-float verification), extract the tail-region
# floats to scan, and compute the truncate plan (kept byte length + the two
# patched RIFF/data size fields). The file read/write/truncate I/O stays in the
# realtime shell. Depends on peaks for the AudioSample float alias.
# ---------------------------------------------------------------------------
add_library(wav_trim STATIC src/wav_trim.cpp)
target_include_directories(wav_trim PUBLIC src)
target_link_libraries(wav_trim PUBLIC peaks)
# ---------------------------------------------------------------------------
# 2i) Pure app_version library — NO REAPER, NO SWELL. The Phase V (V1) version-identity
# core: re-exports the ONE CMake-sourced version string (via the configure_file'd
# version_generated.h) and owns the pure parse/compare/classify logic — the semver
# ordering a within-channel forward migration needs, and the three-way writing-version
# classification (PreVersioning / Unknown / Stamped) persist reads back from ext state.
# Split out so the exact-string fidelity + parse/compare are unit-tested outside the
# DAW; the ext-state write/read (persist) and the show-version action (main) are shell.
# Depends on the generated header in the build tree (PUBLIC so every consumer sees it).
# ---------------------------------------------------------------------------
add_library(app_version STATIC src/app_version.cpp)
target_include_directories(app_version PUBLIC src ${CMAKE_CURRENT_BINARY_DIR}/generated)
# ---------------------------------------------------------------------------
# 2j) Pure provenance library — NO REAPER, NO SWELL. The Milestone 10 core: the
# recorded capture recipe (CaptureRecipe) + the thin drift-fingerprint that
# rides in Provenance.fxChainSnapshot (P1=a), its build/parse round-trip, the
# FX-chain identity fold, and the pure parent-detection decision (resample-from-
# sample by resolved file path). Split out so the encoding + decision logic are
# unit-tested outside the DAW; the FX-chain query, capture re-run, and action
# registration stay in the shell (main.cpp / actions.cpp). No dependency on
# bank_model — it takes plain strings/values at its boundary.
# ---------------------------------------------------------------------------
add_library(provenance STATIC src/provenance.cpp)
target_include_directories(provenance PUBLIC src)
# ---------------------------------------------------------------------------
# 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/assignment_request.cpp)
target_include_directories(assignment_request PUBLIC src)
# ---------------------------------------------------------------------------
# 2k) Pure action_buttons library — NO REAPER, NO SWELL. The Milestone 11
# action-trigger button strip: strip rect + N buttons at a minimum width ->
# per-button rects (equal tiling; overflow HIDES excess on a narrow panel
# rather than clipping), point -> button hit-test, and the button label format
# (action name + SDK binding string -> label, with the unbound/blank case
# degraded to an explicit marker and an over-long binding truncated). Split out
# so the layout + label math is unit-tested outside the DAW; the bank_panel
# draw + NamedCommandLookup/Main_OnCommand dispatch + kbd_getTextFromCmd query
# are DAW-verified. Mirror of mode_switch / tab_strip.
# ---------------------------------------------------------------------------
add_library(action_buttons STATIC src/action_buttons.cpp)
target_include_directories(action_buttons PUBLIC src)
# ---------------------------------------------------------------------------
# 2l) Pure drag_out library — NO REAPER, NO SWELL, NO OS/OLE. The Milestone 11
# native-OS-drag-out decision core: the gesture-boundary decision (drag state +
# pointer + panel rect -> internal drag / OS drag / none — the invariant-#4 seam
# that keeps the internal bank-to-bank drag byte-identical) and the drag path-list
# assembly (resolved sample paths -> de-duped, existing-only absolute path list with
# an explicit skip-missing / skip-unresolved policy). Split out so the boundary +
# set algebra are unit-tested outside the DAW; the OLE DoDragDrop / SWELL file-list
# initiation (drag_out_win) and the bank_panel gesture hook are DAW-verified. Mirror
# of action_buttons / mode_switch.
# ---------------------------------------------------------------------------
add_library(drag_out STATIC src/drag_out.cpp)
target_include_directories(drag_out PUBLIC src)
# ---------------------------------------------------------------------------
# 2l') Pure instrument_drop library — NO REAPER, NO SWELL, NO VST3 SDK. The S17
# drop-and-load blob-construction core: turn the dragged capture id into the
# base64 "vst_chunk" the extension injects via TrackFX_SetNamedConfigParm so a
# freshly-added ReaSampler 9000 plays that capture. Reuses the instrument's OWN
# serializer (sample_map::serializeComponentState) — NOT a parallel byte writer —
# so the cross-artifact blob contract cannot drift; links sample_map (which pulls
# bank_book/wav_trim/sampler_core transitively) and NEITHER SDK. The round-trip
# test decodes back through the instrument's own reader. Mirror of assignment_request.
# ---------------------------------------------------------------------------
add_library(instrument_drop STATIC src/instrument_drop.cpp)
target_include_directories(instrument_drop PUBLIC src src/vst)
target_link_libraries(instrument_drop PUBLIC sample_map)
# ---------------------------------------------------------------------------
# 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/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/action_buttons/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/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 that
# supersedes the flat M11 action_buttons strip 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 / action_buttons / prune_button.
# ---------------------------------------------------------------------------
add_library(action_bar STATIC src/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/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/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/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/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/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/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
# Phase S MIDI-playback instrument (S3 / D3): polyphonic voice allocation with
# bounded stealing, an ADSR amplitude envelope, a key/velocity keymap with
# (note, velocity) -> zone resolution, and repitch/interpolation from a root note
# with loop-point-aware sustain. The mirror of bank_model / peaks / bank_book,
# tested hard outside any host. Lives under src/vst/ (it is instrument code) 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_trim also relies on). The VST3 shell (src/vst/
# 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 <windows.h> (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/vst/pitch_shift.cpp)
target_include_directories(pitch_shift PUBLIC src src/vst)
target_link_libraries(pitch_shift PUBLIC peaks)
add_library(sampler_core STATIC src/vst/sampler_core.cpp)
target_include_directories(sampler_core PUBLIC src src/vst)
target_link_libraries(sampler_core PUBLIC peaks pitch_shift)
# ---------------------------------------------------------------------------
# 3) Standalone tests for the pure modules (run without launching REAPER).
# ---------------------------------------------------------------------------
enable_testing()
add_executable(bank_model_tests tests/test_bank_model.cpp)
target_link_libraries(bank_model_tests PRIVATE bank_model)
add_test(NAME bank_model_tests COMMAND bank_model_tests)
add_executable(peaks_tests tests/test_peaks.cpp)
target_link_libraries(peaks_tests PRIVATE peaks)
add_test(NAME peaks_tests COMMAND peaks_tests)
add_executable(capture_paths_tests tests/test_capture_paths.cpp)
target_link_libraries(capture_paths_tests PRIVATE capture_paths)
add_test(NAME capture_paths_tests COMMAND capture_paths_tests)
add_executable(bank_grid_tests tests/test_bank_grid.cpp)
target_link_libraries(bank_grid_tests PRIVATE bank_grid)
add_test(NAME bank_grid_tests COMMAND bank_grid_tests)
add_executable(mode_switch_tests tests/test_mode_switch.cpp)
target_link_libraries(mode_switch_tests PRIVATE mode_switch)
add_test(NAME mode_switch_tests COMMAND mode_switch_tests)
add_executable(tab_strip_tests tests/test_tab_strip.cpp)
target_link_libraries(tab_strip_tests PRIVATE tab_strip)
add_test(NAME tab_strip_tests COMMAND tab_strip_tests)
add_executable(view_mode_model_tests tests/test_view_mode_model.cpp)
target_link_libraries(view_mode_model_tests PRIVATE view_mode_model)
add_test(NAME view_mode_model_tests COMMAND view_mode_model_tests)
add_executable(view_tree_tests tests/test_view_tree.cpp)
target_link_libraries(view_tree_tests PRIVATE view_tree)
add_test(NAME view_tree_tests COMMAND view_tree_tests)
add_executable(guid_diff_tests tests/test_guid_diff.cpp)
target_link_libraries(guid_diff_tests PRIVATE guid_diff)
add_test(NAME guid_diff_tests COMMAND guid_diff_tests)
add_executable(lane_keys_tests tests/test_lane_keys.cpp)
target_link_libraries(lane_keys_tests PRIVATE lane_keys)
add_test(NAME lane_keys_tests COMMAND lane_keys_tests)
add_executable(insert_plan_tests tests/test_insert_plan.cpp)
target_link_libraries(insert_plan_tests PRIVATE insert_plan)
add_test(NAME insert_plan_tests COMMAND insert_plan_tests)
add_executable(render_settings_tests tests/test_render_settings.cpp)
target_link_libraries(render_settings_tests PRIVATE render_settings)
add_test(NAME render_settings_tests COMMAND render_settings_tests)
add_executable(batch_capture_tests tests/test_batch_capture.cpp)
target_link_libraries(batch_capture_tests PRIVATE batch_capture)
add_test(NAME batch_capture_tests COMMAND batch_capture_tests)
add_executable(tail_control_tests tests/test_tail_control.cpp)
target_link_libraries(tail_control_tests PRIVATE tail_control)
add_test(NAME tail_control_tests COMMAND tail_control_tests)
add_executable(realtime_record_tests tests/test_realtime_record.cpp)
target_link_libraries(realtime_record_tests PRIVATE realtime_record)
add_test(NAME realtime_record_tests COMMAND realtime_record_tests)
add_executable(bank_book_tests tests/test_bank_book.cpp)
target_link_libraries(bank_book_tests PRIVATE bank_book)
add_test(NAME bank_book_tests COMMAND bank_book_tests)
add_executable(wav_trim_tests tests/test_wav_trim.cpp)
target_link_libraries(wav_trim_tests PRIVATE wav_trim)
add_test(NAME wav_trim_tests COMMAND wav_trim_tests)
add_executable(owned_manifest_tests tests/test_owned_manifest.cpp)
target_link_libraries(owned_manifest_tests PRIVATE owned_manifest)
add_test(NAME owned_manifest_tests COMMAND owned_manifest_tests)
add_executable(prune_reconcile_tests tests/test_prune_reconcile.cpp)
target_link_libraries(prune_reconcile_tests PRIVATE prune_reconcile bank_book)
add_test(NAME prune_reconcile_tests COMMAND prune_reconcile_tests)
add_executable(prune_button_tests tests/test_prune_button.cpp)
target_link_libraries(prune_button_tests PRIVATE prune_button)
add_test(NAME prune_button_tests COMMAND prune_button_tests)
add_executable(app_version_tests tests/test_app_version.cpp)
target_link_libraries(app_version_tests PRIVATE app_version)
add_test(NAME app_version_tests COMMAND app_version_tests)
# The provenance test links bank_model too — it proves the recorded recipe survives
# the Sample-JSON round-trip (Provenance.fxChainSnapshot), the M1 seam M10 rides on.
add_executable(provenance_tests tests/test_provenance.cpp)
target_link_libraries(provenance_tests PRIVATE provenance bank_model)
add_test(NAME provenance_tests COMMAND provenance_tests)
add_executable(action_buttons_tests tests/test_action_buttons.cpp)
target_link_libraries(action_buttons_tests PRIVATE action_buttons)
add_test(NAME action_buttons_tests COMMAND action_buttons_tests)
add_executable(drag_out_tests tests/test_drag_out.cpp)
target_link_libraries(drag_out_tests PRIVATE drag_out)
add_test(NAME drag_out_tests COMMAND drag_out_tests)
# instrument_drop (S17): the drop-and-load vst_chunk blob builder. The round-trip test
# decodes the base64 back through the instrument's OWN reader (deserializeComponentState) to
# prove the extension injects exactly what setState 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)
# 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 <windows.h> 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)
# ---------------------------------------------------------------------------
# 2i) Pure VST3-instrument helpers (Phase S1) — NO VST3, NO REAPER, NO SWELL/LICE.
# editor_geometry: the IPlugView LICE editor's rectangle layout + hit-test math
# (mirror of mode_switch/bank_grid). bridge_marshal: the REAPER VST-host bridge
# read marshalling — GetProjExtState result decode + a small JSON string-field
# reader (mirror of capture_paths/wav_trim). Both are unit-tested outside the DAW;
# the VST3 shell (src/vst/*) that draws/routes/invokes is DAW-verified.
# ---------------------------------------------------------------------------
add_library(editor_geometry STATIC src/vst/editor_geometry.cpp)
target_include_directories(editor_geometry PUBLIC src/vst)
add_library(bridge_marshal STATIC src/vst/bridge_marshal.cpp)
target_include_directories(bridge_marshal PUBLIC src/vst)
# embed_strip (Phase S6) — PURE layout + hit-test for the embedded TCP/MCP strip: the
# 128-key span -> zone-segment rects, point -> zone selection, and the level-band fill.
# The mirror of editor_geometry (whose Rect + contains() it reuses); unit-tested outside
# the DAW, while the embed shell (src/vst/reasampler_embed.cpp) marshals REAPER's embed
# messages (paint bitmap + mouse coords) into it. Links editor_geometry for the shared Rect.
add_library(embed_strip STATIC src/vst/embed_strip.cpp)
target_include_directories(embed_strip PUBLIC src/vst)
target_link_libraries(embed_strip PUBLIC editor_geometry)
# sample_map (Phase S4) — PURE mapping logic for the Tier-0 instrument: the live bank
# blob -> selected sample (via the SHARED bank_book JSON parse, NOT a second parser),
# interleaved->mono downmix (the Tier-0 channel policy), the Tier-0 chromatic keymap
# build, and the selected-sample instance-state (de)serialization. Links the three pure
# modules it composes — bank_book (shared JSON), wav_trim (shared WAV parse), and
# sampler_core (the Keymap/SampleData it yields) — and NEITHER SDK. The VST3 shell
# (reasampler_processor.cpp) does the bridge read + file I/O off the audio thread, then
# calls these; the process callback stays allocation-free.
add_library(sample_map STATIC src/vst/sample_map.cpp)
target_include_directories(sample_map PUBLIC src/vst src)
target_link_libraries(sample_map PUBLIC bank_book wav_trim sampler_core)
# 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/vst/capture_browser.cpp)
target_include_directories(capture_browser PUBLIC src/vst)
target_link_libraries(capture_browser PUBLIC editor_geometry)
# keyboard_strip (Phase S10) — PURE key-span<->pixel mapping, root marker, zone-bar rects +
# edge-grab hit regions, and the drag-delta note resolver for the capture-first editor's
# keyboard strip (single-capture root-set) and the opt-in Zones panel (S10-Z). The mirror of
# embed_strip; links editor_geometry for the shared Rect. NEITHER SDK.
add_library(keyboard_strip STATIC src/vst/keyboard_strip.cpp)
target_include_directories(keyboard_strip PUBLIC src/vst)
target_link_libraries(keyboard_strip PUBLIC editor_geometry)
# waveform_view (Phase S11) — PURE frame<->pixel mapping, marker grab regions, drag-delta
# frame resolver, and the zero-crossing snap for the capture-first editor's waveform surface
# (draggable start + loop markers over the picked capture's decoded PCM). The mirror of
# keyboard_strip; links editor_geometry for the shared Rect and peaks for the AudioSample
# alias the snap scans. NEITHER SDK.
add_library(waveform_view STATIC src/vst/waveform_view.cpp)
target_include_directories(waveform_view PUBLIC src/vst src)
target_link_libraries(waveform_view PUBLIC editor_geometry peaks)
# 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/vst/bank_sync.cpp)
target_include_directories(bank_sync PUBLIC src/vst src)
target_link_libraries(bank_sync PUBLIC assignment_request)
# 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/vst/browser_scroll.cpp)
target_include_directories(browser_scroll PUBLIC src/vst)
target_link_libraries(browser_scroll PUBLIC capture_browser)
# note_entry (Phase S12) — PURE text->clamped-MIDI-note parse for the direct numeric entry of
# a zone's low/high/root (decimal integer OR note name under the C4==60 convention, clamped to
# [0,127]). No dependency beyond the standard library. NEITHER SDK.
add_library(note_entry STATIC src/vst/note_entry.cpp)
target_include_directories(note_entry PUBLIC src/vst)
# 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/vst/param_slider.cpp)
target_include_directories(param_slider PUBLIC src/vst)
target_link_libraries(param_slider PUBLIC editor_geometry)
add_executable(editor_geometry_tests tests/test_editor_geometry.cpp)
target_link_libraries(editor_geometry_tests PRIVATE editor_geometry)
add_test(NAME editor_geometry_tests COMMAND editor_geometry_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 (+ its pure deps) — NEITHER
# the VST3 SDK nor the REAPER SDK — the same structural plain-data-boundary proof the
# sampler_core test enforces.
add_executable(sample_map_tests tests/test_sample_map.cpp)
target_link_libraries(sample_map_tests PRIVATE sample_map)
add_test(NAME sample_map_tests COMMAND sample_map_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)
add_test(NAME keyboard_strip_tests COMMAND keyboard_strip_tests)
# waveform_view (S11): the pure marker geometry + zero-crossing snap. Links ONLY waveform_view
# (+ its pure editor_geometry/peaks deps) — NEITHER SDK — the same plain-data-boundary proof.
add_executable(waveform_view_tests tests/test_waveform_view.cpp)
target_link_libraries(waveform_view_tests PRIVATE waveform_view)
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)
# note_entry (S12): the pure text->clamped-MIDI-note parse for direct numeric entry.
add_executable(note_entry_tests tests/test_note_entry.cpp)
target_link_libraries(note_entry_tests PRIVATE note_entry)
add_test(NAME note_entry_tests COMMAND note_entry_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)
# ---------------------------------------------------------------------------
# 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).
set(LICE_SRC
${WDL_INC}/lice/lice.cpp
${WDL_INC}/lice/lice_line.cpp
${WDL_INC}/lice/lice_arc.cpp
${WDL_INC}/lice/lice_textnew.cpp
)
add_library(reaper_reasampler MODULE
src/main.cpp
src/capture.cpp
src/capture_realtime.cpp
src/realtime_record.cpp
src/persist.cpp
src/bank_panel.cpp
src/draw_kit.cpp
src/mode_switch.cpp
src/tab_strip.cpp
src/insert.cpp
src/insert_plan.cpp
${LICE_SRC}
src/view_mode_model.cpp
src/view_tree.cpp
src/view.cpp
src/track_guid.cpp
src/provenance_shell.cpp
src/guid_diff.cpp
src/lane_keys.cpp
src/item_read.cpp
src/actions.cpp
src/ingest.cpp
src/bank_book.cpp
src/owned_manifest.cpp
src/drag_out_win.cpp
src/instrument_drop_win.cpp
src/action_bar.cpp
src/footer_bar.cpp
src/overflow_menu.cpp
src/mode_enable.cpp
src/tooltip.cpp
src/card_meta.cpp
src/card_drag.cpp
)
target_link_libraries(reaper_reasampler PRIVATE bank_model capture_paths peaks bank_grid mode_switch tab_strip view_mode_model insert_plan render_settings batch_capture tail_control realtime_record bank_book wav_trim owned_manifest prune_reconcile prune_button app_version provenance action_buttons drag_out instrument_drop theme component_geometry action_bar footer_bar overflow_menu mode_enable tooltip card_meta card_drag assignment_request bank_sync)
target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC})
# OUTPUT_NAME is channel-derived (Phase V, V4): "reaper_reasampler" (stable, default) or
# "reaper_reasampler_beta" (beta). REAPER dlopen's any reaper_* module, so both channels'
# artifacts load side-by-side. The CMake TARGET name stays "reaper_reasampler" for both
# configs — one source tree, one target; only the emitted file name forks by channel.
set_target_properties(reaper_reasampler PROPERTIES PREFIX "" OUTPUT_NAME "${REASAMPLER_OUTPUT_NAME}")
if(WIN32)
# Native Win32. REAPER provides nothing extra to link. The bank_panel dialog
# template (M5) is compiled from src/resource.rc by the platform RC compiler.
target_sources(reaper_reasampler PRIVATE src/resource.rc)
elseif(APPLE)
# macOS: use REAPER's OWN SWELL at runtime via the modstub.
# Do NOT build full SWELL. SWELL_PROVIDED_BY_APP routes calls to the host.
target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub.mm)
target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
target_link_libraries(reaper_reasampler PRIVATE "-framework AppKit")
set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".dylib")
# bank_panel dialog (M5): SWELL can't read a Win32 .rc directly. Run resgen
# once to turn src/resource.rc into a C++ source, then add it here:
# php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
# target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h) # generated
else()
# Linux: REAPER's libSwell.so is used at runtime via the generic modstub.
# With SWELL_PROVIDED_BY_APP you can drop pkg-config / -lX11 entirely.
target_sources(reaper_reasampler PRIVATE ${SWELL}/swell-modstub-generic.cpp)
target_compile_definitions(reaper_reasampler PRIVATE SWELL_PROVIDED_BY_APP)
set_target_properties(reaper_reasampler PROPERTIES SUFFIX ".so")
# bank_panel dialog (M5): reuse the macOS resgen output (see README /
# CLAUDE.md §SWELL dialog resources), then add the generated source:
# php ${WDL_INC}/swell/mac_resgen.php src/resource.rc
# target_sources(reaper_reasampler PRIVATE src/resource.rc_mac_dlg.h) # generated
endif()
# ===========================================================================
# 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 $<IF:$<CONFIG:Debug>,DEVELOPMENT=1,RELEASE=1>)
# --- 5b) The VST3 module (loadable .vst3 DLL). -------------------------------
add_library(reasampler_vst MODULE
src/vst/vst_entry.cpp
src/vst/reasampler_processor.cpp
src/vst/reasampler_editor.cpp
src/vst/reasampler_embed.cpp
src/vst/reaper_bridge.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->keymap mapping + state (de)ser the processor drives off the audio thread;
# linking it pulls its pure deps (bank_book, wav_trim, sampler_core, bank_model,
# peaks) transitively. capture_paths: the shared M4 path resolution (resolveBankFile /
# projectDirOfRpp) the bridge + processor use. Its PUBLIC include dirs (src, src/vst)
# give the shell TUs their headers (ext_keys.h, bank_book.h, sampler_core.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.
# 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 + note_entry + param_slider (S12 + S15/S16 control surfaces): the pure
# scroll/search geometry over the capture browser, the numeric-note-entry parse, 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 +
# note_entry link editor_geometry / the stdlib only. All engine-free, DAW-verified in the shell.
target_link_libraries(reasampler_vst PRIVATE vst3_sdk editor_geometry bridge_marshal
sample_map capture_paths embed_strip app_version capture_browser keyboard_strip
waveform_view bank_sync browser_scroll note_entry param_slider)
# 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.
target_include_directories(reasampler_vst PRIVATE ${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()