Retire MPE scaffold; stand up reaper_reasampler pure-core skeleton

Rename CMake project/module to reaper_reasampler, delete mpe_model/mpe_view,
add minimal pure bank_model lib + placeholder CTest. main.cpp loads, logs to
console, keeps the action-registration seam commented with the forever-stable
CEREBELLUM_REASAMPLER_ action-id prefix.
This commit is contained in:
2026-07-21 21:18:51 -04:00
parent bbc0b2c19e
commit acfc9daabc
5 changed files with 196 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
cmake_minimum_required(VERSION 3.19)
project(reaper_reasampler LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# ---------------------------------------------------------------------------
# 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) Standalone tests for the model (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)
# ---------------------------------------------------------------------------
# 3) The REAPER extension — a loadable module (dlopen'd by REAPER, not linked).
# ---------------------------------------------------------------------------
add_library(reaper_reasampler MODULE
src/main.cpp
)
target_link_libraries(reaper_reasampler PRIVATE bank_model)
target_include_directories(reaper_reasampler PRIVATE ${SDK_INC} ${WDL_INC})
set_target_properties(reaper_reasampler PROPERTIES PREFIX "" OUTPUT_NAME "reaper_reasampler")
if(WIN32)
# Native Win32. REAPER provides nothing extra to link.
# Dialog resources return with the docked bank_panel (Milestone 5).
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")
# Dialog: run SWELL resgen once (see README) and add the generated source.
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")
# Dialog: run SWELL resgen once (see README) and add the generated source.
endif()
+10
View File
@@ -0,0 +1,10 @@
#include "bank_model.h"
namespace reasampler {
int bankModelVersion()
{
return 1;
}
} // namespace reasampler
+17
View File
@@ -0,0 +1,17 @@
#pragma once
// bank_model — the HEART of ReaSampler, deliberately free of any REAPER type so
// it compiles and unit-tests OUTSIDE the DAW. It owns the per-project sample
// bank: the `Sample` metadata struct and the `BankIndex` (add / remove / query /
// tier moves / dedup-by-hash + JSON round-trip).
//
// Milestone 0 placeholder: this is a minimal compiling stub sufficient to stand
// up the pure static lib and its CTest. The full data model (Sample field set,
// BankIndex operations, JSON) is Milestone 1 — see PLAN.md / CONTEXT.md §Data model.
namespace reasampler {
// M0 placeholder — replaced by the real `Sample` / `BankIndex` in Milestone 1.
// Returns the on-disk schema version the bank_model serializes to.
int bankModelVersion();
} // namespace reasampler
+83
View File
@@ -0,0 +1,83 @@
// main.cpp — the SINGLE translation unit that OWNS the REAPER API pointers.
//
// This file is the entire contract between REAPER and the extension:
// * At startup REAPER scans UserPlugins/ for reaper_*.dll|dylib|so and
// dlopen()s each one, then looks up ONE exported symbol: ReaperPluginEntry
// (that name is produced by the REAPER_PLUGIN_ENTRYPOINT macro).
// * REAPER calls it, handing over `rec` — a small dispatch struct.
// - rec->GetFunc(name) resolves any REAPER API function to a pointer
// - rec->Register(what,ptr) plugs OUR callbacks into REAPER
// * REAPERAPI_LoadAPI(rec->GetFunc) walks reaper_plugin_functions.h and
// fills in every global function pointer (ShowConsoleMsg, InsertMedia...).
//
// Exactly ONE .cpp defines REAPERAPI_IMPLEMENT (this one) — that allocates
// storage for those global pointers. Every other .cpp includes
// reaper_plugin_functions.h WITHOUT the define and gets `extern` declarations.
#define REAPERAPI_IMPLEMENT
#include "reaper_plugin.h"
#include "reaper_plugin_functions.h"
// Persistent action-id prefix for the ReaSampler action family.
// Every bindable action (capture / insert / slot / verify) mints its command id
// from a string beginning with this prefix, e.g. "CEREBELLUM_REASAMPLER_CAPTURE_MASTER".
// FOREVER-STABLE once shipped: user keybindings key off these strings, so the
// prefix and any minted id must never change after release.
#define REASAMPLER_ACTION_PREFIX "CEREBELLUM_REASAMPLER_"
// Globals other files reference via `extern`.
REAPER_PLUGIN_HINSTANCE g_hInst = nullptr; // this module's instance handle
reaper_plugin_info_t* g_rec = nullptr; // REAPER's dispatch struct
// ---- Action registration seam (reusable pattern, no action wired yet) ------
// The capture/insert/slot action family (PLAN.md M3+) reinstates the pattern
// below. Kept as a commented template so the shape is not re-derived each time.
//
// static int g_cmdCaptureMaster = 0;
//
// // REAPER calls this for EVERY action fired anywhere; claim only your own id,
// // return false otherwise so REAPER keeps looking.
// static bool OnHookCommand(int command, int /*flag*/)
// {
// if (command == 0) return false;
// if (command == g_cmdCaptureMaster) { /* route to capture module */ return true; }
// return false;
// }
//
// Registration, inside the load branch below:
// 1) g_cmdCaptureMaster =
// rec->Register("command_id", (void*)(REASAMPLER_ACTION_PREFIX "CAPTURE_MASTER"));
// 2) static gaccel_register_t sAccel{};
// sAccel.accel.cmd = g_cmdCaptureMaster;
// sAccel.desc = "ReaSampler: capture master mix";
// rec->Register("gaccel", (void*)&sAccel);
// 3) rec->Register("hookcommand", (void*)&OnHookCommand);
// On unload (rec == nullptr), mirror-unregister with the same strings prefixed '-'.
extern "C" REAPER_PLUGIN_DLL_EXPORT int REAPER_PLUGIN_ENTRYPOINT(
REAPER_PLUGIN_HINSTANCE hInstance, reaper_plugin_info_t* rec)
{
if (!rec)
{
// rec == nullptr => REAPER is UNLOADING us. Mirror-unregister every
// callback here (same strings prefixed with '-') once actions are wired.
g_rec = nullptr;
return 0;
}
// ABI guard: the struct layout we compiled against must match this REAPER.
if (rec->caller_version != REAPER_PLUGIN_VERSION)
return 0;
// Resolve every REAPER API function pointer. Returns the number that FAILED
// to load; 0 == success. Non-zero usually means REAPER is older than our SDK.
if (REAPERAPI_LoadAPI(rec->GetFunc) != 0)
return 0;
g_hInst = hInstance;
g_rec = rec;
ShowConsoleMsg("ReaSampler loaded.\n");
return 1; // success — REAPER keeps us loaded
}
+24
View File
@@ -0,0 +1,24 @@
// Standalone tests for reasampler::bank_model — no REAPER, no test framework.
// This is the point of splitting the model out: iterate the hard logic here with
// a fast build/run loop instead of restarting REAPER.
//
// Milestone 0 placeholder: a single assertion proving the pure lib links and
// runs under CTest. The real round-trip / dedup / tier / relative-path tests
// arrive with the Milestone 1 data model (see TODO.md, PLAN.md).
#include "../src/bank_model.h"
#include <cstdio>
using namespace reasampler;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
int main()
{
CHECK(bankModelVersion() == 1);
if (g_fail == 0) std::printf("All tests passed.\n");
return g_fail ? 1 : 0;
}