feat(version): V4 beta-in-isolation channel via -DREASAMPLER_CHANNEL
Compile-time channel flag forks a fully isolated reaper_reasampler_beta (namespace, command-id prefix, action names, dock ident, -beta render) from one auditable app_version definition. Stable identity byte-unchanged.
This commit is contained in:
+108
-79
@@ -21,9 +21,12 @@
|
||||
|
||||
#include "actions.h"
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app_version.h" // channelCommandId / channelActionName — one channel-identity point
|
||||
|
||||
#include "bank_book.h" // BankBook, nextBankId, TransferResult, kPoolBankId (B1)
|
||||
#include "bank_panel.h" // selection seam + full-height toggles (B3/B4)
|
||||
#include "item_read.h" // shared MediaItem* -> GUID + fixed-lane-name reads (D2 W3-B)
|
||||
@@ -57,22 +60,23 @@ namespace reasampler {
|
||||
|
||||
namespace {
|
||||
|
||||
// FOREVER-STABLE action-id strings. Same family prefix as main.cpp's capture/panel
|
||||
// actions; each full string is minted into a persistent command id and user
|
||||
// keybindings key off it — NEVER change these after ship.
|
||||
constexpr const char* kIdToggleMode = "CEREBELLUM_REASAMPLER_VIEW_TOGGLE_MODE";
|
||||
constexpr const char* kIdActivateArrange = "CEREBELLUM_REASAMPLER_VIEW_ACTIVATE_ARRANGE";
|
||||
constexpr const char* kIdActivateDesign = "CEREBELLUM_REASAMPLER_VIEW_ACTIVATE_DESIGN";
|
||||
constexpr const char* kIdTagDesign = "CEREBELLUM_REASAMPLER_VIEW_TAG_DESIGN";
|
||||
constexpr const char* kIdTagArrange = "CEREBELLUM_REASAMPLER_VIEW_TAG_ARRANGE";
|
||||
constexpr const char* kIdUntag = "CEREBELLUM_REASAMPLER_VIEW_UNTAG";
|
||||
constexpr const char* kIdShowBoth = "CEREBELLUM_REASAMPLER_VIEW_SHOW_BOTH";
|
||||
// FOREVER-STABLE action-id SUFFIXES (Phase V, V4). The channel family prefix is prepended
|
||||
// at register time via channelCommandId (app_version), so stable rebuilds the exact shipped
|
||||
// id ("CEREBELLUM_REASAMPLER_VIEW_TOGGLE_MODE") and beta yields the isolated forever-family
|
||||
// id ("CEREBELLUM_REASAMPLER_BETA_VIEW_TOGGLE_MODE"). Each composed id is minted into a
|
||||
// persistent command id user keybindings key off — NEVER change a shipped suffix after ship.
|
||||
constexpr const char* kIdToggleMode = "VIEW_TOGGLE_MODE";
|
||||
constexpr const char* kIdActivateArrange = "VIEW_ACTIVATE_ARRANGE";
|
||||
constexpr const char* kIdActivateDesign = "VIEW_ACTIVATE_DESIGN";
|
||||
constexpr const char* kIdTagDesign = "VIEW_TAG_DESIGN";
|
||||
constexpr const char* kIdTagArrange = "VIEW_TAG_ARRANGE";
|
||||
constexpr const char* kIdUntag = "VIEW_UNTAG";
|
||||
constexpr const char* kIdShowBoth = "VIEW_SHOW_BOTH";
|
||||
// D2 Wave 3-B item-level mode moves — the item analog of the track tag family. Same
|
||||
// FOREVER-STABLE contract: minted into a persistent command id, user keybindings key off
|
||||
// each — NEVER change these strings after ship.
|
||||
constexpr const char* kIdMoveItemsDesign = "CEREBELLUM_REASAMPLER_VIEW_MOVE_ITEMS_DESIGN";
|
||||
constexpr const char* kIdMoveItemsArrange = "CEREBELLUM_REASAMPLER_VIEW_MOVE_ITEMS_ARRANGE";
|
||||
constexpr const char* kIdUntagItems = "CEREBELLUM_REASAMPLER_VIEW_UNTAG_ITEMS";
|
||||
// FOREVER-STABLE contract (suffix composed with the channel prefix) — NEVER change these.
|
||||
constexpr const char* kIdMoveItemsDesign = "VIEW_MOVE_ITEMS_DESIGN";
|
||||
constexpr const char* kIdMoveItemsArrange = "VIEW_MOVE_ITEMS_ARRANGE";
|
||||
constexpr const char* kIdUntagItems = "VIEW_UNTAG_ITEMS";
|
||||
|
||||
// The live session the actions mutate. Set once by designViewRegisterActions and
|
||||
// read by the hookcommand handler. Not owned here (main.cpp owns g_session).
|
||||
@@ -103,15 +107,35 @@ gaccel_register_t g_accelMoveItemsDesign{};
|
||||
gaccel_register_t g_accelMoveItemsArrange{};
|
||||
gaccel_register_t g_accelUntagItems{};
|
||||
|
||||
// Mints a command id from a stable string and registers its gaccel (Actions-list
|
||||
// entry with `desc`). Returns the command id (0 on failure). The gaccel storage is
|
||||
// caller-owned and must outlive the module (the file-scope g_accel* above).
|
||||
int registerAction(reaper_plugin_info_t* rec, const char* stableId,
|
||||
gaccel_register_t& accel, const char* desc) {
|
||||
const int cmd = rec->Register("command_id", (void*)stableId);
|
||||
// Durable store of composed, channel-qualified strings (ids + labels). A std::deque never
|
||||
// invalidates references on push_back, so a c_str() handed to REAPER (a command_id at
|
||||
// register, a gaccel desc for its lifetime) stays valid until process exit. Memoized by
|
||||
// suffix so register and the mirror-unregister get the SAME id pointer for a given action.
|
||||
std::deque<std::string> g_strStore;
|
||||
|
||||
// Returns the channel-qualified command id for `suffix`, interning it once. Called by BOTH
|
||||
// registerAction and the unregister path, so a '-command_id' presents the identical string.
|
||||
const char* channelIdFor(const char* suffix) {
|
||||
const std::string composed = channelCommandId(suffix);
|
||||
for (const std::string& s : g_strStore)
|
||||
if (s == composed) return s.c_str();
|
||||
g_strStore.push_back(composed);
|
||||
return g_strStore.back().c_str();
|
||||
}
|
||||
|
||||
// Mints a command id from a channel-qualified SUFFIX and registers its gaccel (Actions-list
|
||||
// entry with a channel-qualified label PHRASE). Returns the command id (0 on failure). Both
|
||||
// the composed id and label are interned durably (g_strStore) — REAPER holds the desc
|
||||
// pointer, and the id must survive to the mirror-unregister. The gaccel storage itself is
|
||||
// caller-owned (the file-scope g_accel* above).
|
||||
int registerAction(reaper_plugin_info_t* rec, const char* suffix,
|
||||
gaccel_register_t& accel, const char* phrase) {
|
||||
const char* id = channelIdFor(suffix);
|
||||
const int cmd = rec->Register("command_id", (void*)id);
|
||||
if (cmd) {
|
||||
g_strStore.push_back(channelActionName(phrase));
|
||||
accel.accel.cmd = cmd;
|
||||
accel.desc = desc;
|
||||
accel.desc = g_strStore.back().c_str();
|
||||
rec->Register("gaccel", (void*)&accel);
|
||||
}
|
||||
return cmd;
|
||||
@@ -319,27 +343,27 @@ void designViewRegisterActions(reaper_plugin_info_t* rec, ReaSamplerSession* ses
|
||||
// command_id -> gaccel for each. The single hookcommand that routes these lives
|
||||
// in main.cpp (one hook per extension); designViewHandleCommand services them.
|
||||
g_cmdToggleMode = registerAction(rec, kIdToggleMode, g_accelToggleMode,
|
||||
"ReaSampler: toggle Design View mode");
|
||||
"toggle Design View mode");
|
||||
g_cmdActivateArrange = registerAction(rec, kIdActivateArrange, g_accelActivateArrange,
|
||||
"ReaSampler: activate mode Arrange");
|
||||
"activate mode Arrange");
|
||||
g_cmdActivateDesign = registerAction(rec, kIdActivateDesign, g_accelActivateDesign,
|
||||
"ReaSampler: activate mode Design");
|
||||
"activate mode Design");
|
||||
g_cmdTagDesign = registerAction(rec, kIdTagDesign, g_accelTagDesign,
|
||||
"ReaSampler: tag selected tracks -> Design");
|
||||
"tag selected tracks -> Design");
|
||||
g_cmdTagArrange = registerAction(rec, kIdTagArrange, g_accelTagArrange,
|
||||
"ReaSampler: tag selected tracks -> Arrange");
|
||||
"tag selected tracks -> Arrange");
|
||||
g_cmdUntag = registerAction(rec, kIdUntag, g_accelUntag,
|
||||
"ReaSampler: untag selected tracks");
|
||||
"untag selected tracks");
|
||||
g_cmdShowBoth = registerAction(rec, kIdShowBoth, g_accelShowBoth,
|
||||
"ReaSampler: show both for selected tracks");
|
||||
"show both for selected tracks");
|
||||
|
||||
// Item-level mode moves (D2 W3-B): the item analog of the track tag family.
|
||||
g_cmdMoveItemsDesign = registerAction(rec, kIdMoveItemsDesign, g_accelMoveItemsDesign,
|
||||
"ReaSampler: move selected items -> Design");
|
||||
"move selected items -> Design");
|
||||
g_cmdMoveItemsArrange = registerAction(rec, kIdMoveItemsArrange, g_accelMoveItemsArrange,
|
||||
"ReaSampler: move selected items -> Arrange");
|
||||
"move selected items -> Arrange");
|
||||
g_cmdUntagItems = registerAction(rec, kIdUntagItems, g_accelUntagItems,
|
||||
"ReaSampler: untag selected items");
|
||||
"untag selected items");
|
||||
}
|
||||
|
||||
bool designViewHandleCommand(int command) {
|
||||
@@ -367,26 +391,28 @@ void designViewUnregisterActions(reaper_plugin_info_t* rec) {
|
||||
// Mirror-unregister with '-'-prefixed strings, per the contract's unload rule.
|
||||
// gaccel first, then the command_id string (reverse of registration order — the item
|
||||
// moves registered last, so they tear down first).
|
||||
// Each '-command_id' re-presents the SAME interned, channel-qualified id (channelIdFor
|
||||
// returns the memoized pointer registered above), so the unregister matches exactly.
|
||||
rec->Register("-gaccel", (void*)&g_accelUntagItems);
|
||||
rec->Register("-command_id", (void*)kIdUntagItems);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdUntagItems));
|
||||
rec->Register("-gaccel", (void*)&g_accelMoveItemsArrange);
|
||||
rec->Register("-command_id", (void*)kIdMoveItemsArrange);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdMoveItemsArrange));
|
||||
rec->Register("-gaccel", (void*)&g_accelMoveItemsDesign);
|
||||
rec->Register("-command_id", (void*)kIdMoveItemsDesign);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdMoveItemsDesign));
|
||||
rec->Register("-gaccel", (void*)&g_accelShowBoth);
|
||||
rec->Register("-command_id", (void*)kIdShowBoth);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdShowBoth));
|
||||
rec->Register("-gaccel", (void*)&g_accelUntag);
|
||||
rec->Register("-command_id", (void*)kIdUntag);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdUntag));
|
||||
rec->Register("-gaccel", (void*)&g_accelTagArrange);
|
||||
rec->Register("-command_id", (void*)kIdTagArrange);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdTagArrange));
|
||||
rec->Register("-gaccel", (void*)&g_accelTagDesign);
|
||||
rec->Register("-command_id", (void*)kIdTagDesign);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdTagDesign));
|
||||
rec->Register("-gaccel", (void*)&g_accelActivateDesign);
|
||||
rec->Register("-command_id", (void*)kIdActivateDesign);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdActivateDesign));
|
||||
rec->Register("-gaccel", (void*)&g_accelActivateArrange);
|
||||
rec->Register("-command_id", (void*)kIdActivateArrange);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdActivateArrange));
|
||||
rec->Register("-gaccel", (void*)&g_accelToggleMode);
|
||||
rec->Register("-command_id", (void*)kIdToggleMode);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdToggleMode));
|
||||
|
||||
g_session = nullptr;
|
||||
}
|
||||
@@ -409,20 +435,22 @@ void designViewUnregisterActions(reaper_plugin_info_t* rec) {
|
||||
|
||||
namespace {
|
||||
|
||||
// FOREVER-STABLE multi-bank action-id strings. Same CEREBELLUM_REASAMPLER_ family
|
||||
// prefix; each is minted into a persistent command id user keybindings key off —
|
||||
// NEVER change these after ship.
|
||||
constexpr const char* kIdBankCreate = "CEREBELLUM_REASAMPLER_BANK_CREATE";
|
||||
constexpr const char* kIdBankRename = "CEREBELLUM_REASAMPLER_BANK_RENAME";
|
||||
constexpr const char* kIdBankDelete = "CEREBELLUM_REASAMPLER_BANK_DELETE";
|
||||
constexpr const char* kIdBankEvacuate = "CEREBELLUM_REASAMPLER_BANK_EVACUATE";
|
||||
constexpr const char* kIdBankActivateNext = "CEREBELLUM_REASAMPLER_BANK_ACTIVATE_NEXT";
|
||||
constexpr const char* kIdBankActivatePool = "CEREBELLUM_REASAMPLER_BANK_ACTIVATE_POOL";
|
||||
constexpr const char* kIdBankMoveSel = "CEREBELLUM_REASAMPLER_BANK_MOVE_SELECTED";
|
||||
constexpr const char* kIdBankCopySel = "CEREBELLUM_REASAMPLER_BANK_COPY_SELECTED";
|
||||
constexpr const char* kIdBankRemoveSel = "CEREBELLUM_REASAMPLER_BANK_REMOVE_SELECTED";
|
||||
constexpr const char* kIdBankPoolFull = "CEREBELLUM_REASAMPLER_BANK_POOL_FULLHEIGHT";
|
||||
constexpr const char* kIdBankBanksFull = "CEREBELLUM_REASAMPLER_BANK_BANKS_FULLHEIGHT";
|
||||
// FOREVER-STABLE multi-bank action-id SUFFIXES (Phase V, V4). The channel family prefix is
|
||||
// prepended at register via channelCommandId (as with the Design View family above) —
|
||||
// stable rebuilds the shipped id, beta the isolated one. NEVER change a shipped suffix.
|
||||
// Each suffix + the stable prefix must byte-match the pre-V4 shipped literal exactly
|
||||
// (e.g. "BANK_REMOVE_SELECTED" -> "CEREBELLUM_REASAMPLER_BANK_REMOVE_SELECTED").
|
||||
constexpr const char* kIdBankCreate = "BANK_CREATE";
|
||||
constexpr const char* kIdBankRename = "BANK_RENAME";
|
||||
constexpr const char* kIdBankDelete = "BANK_DELETE";
|
||||
constexpr const char* kIdBankEvacuate = "BANK_EVACUATE";
|
||||
constexpr const char* kIdBankActivateNext = "BANK_ACTIVATE_NEXT";
|
||||
constexpr const char* kIdBankActivatePool = "BANK_ACTIVATE_POOL";
|
||||
constexpr const char* kIdBankMoveSel = "BANK_MOVE_SELECTED";
|
||||
constexpr const char* kIdBankCopySel = "BANK_COPY_SELECTED";
|
||||
constexpr const char* kIdBankRemoveSel = "BANK_REMOVE_SELECTED";
|
||||
constexpr const char* kIdBankPoolFull = "BANK_POOL_FULLHEIGHT";
|
||||
constexpr const char* kIdBankBanksFull = "BANK_BANKS_FULLHEIGHT";
|
||||
|
||||
int g_cmdBankCreate = 0;
|
||||
int g_cmdBankRename = 0;
|
||||
@@ -831,27 +859,27 @@ void bankRegisterActions(reaper_plugin_info_t* rec, ReaSamplerSession* session)
|
||||
g_session = session; // shared with the Design View family; same live session
|
||||
|
||||
g_cmdBankCreate = registerAction(rec, kIdBankCreate, g_accelBankCreate,
|
||||
"ReaSampler: create bank");
|
||||
"create bank");
|
||||
g_cmdBankRename = registerAction(rec, kIdBankRename, g_accelBankRename,
|
||||
"ReaSampler: rename bank");
|
||||
"rename bank");
|
||||
g_cmdBankDelete = registerAction(rec, kIdBankDelete, g_accelBankDelete,
|
||||
"ReaSampler: delete bank");
|
||||
"delete bank");
|
||||
g_cmdBankEvacuate = registerAction(rec, kIdBankEvacuate, g_accelBankEvacuate,
|
||||
"ReaSampler: evacuate bank to pool");
|
||||
"evacuate bank to pool");
|
||||
g_cmdBankActivateNext = registerAction(rec, kIdBankActivateNext, g_accelBankActivateNext,
|
||||
"ReaSampler: activate next bank (cycle)");
|
||||
"activate next bank (cycle)");
|
||||
g_cmdBankActivatePool = registerAction(rec, kIdBankActivatePool, g_accelBankActivatePool,
|
||||
"ReaSampler: activate pool");
|
||||
"activate pool");
|
||||
g_cmdBankMoveSel = registerAction(rec, kIdBankMoveSel, g_accelBankMoveSel,
|
||||
"ReaSampler: move selected samples to bank");
|
||||
"move selected samples to bank");
|
||||
g_cmdBankCopySel = registerAction(rec, kIdBankCopySel, g_accelBankCopySel,
|
||||
"ReaSampler: copy selected samples to bank");
|
||||
"copy selected samples to bank");
|
||||
g_cmdBankRemoveSel = registerAction(rec, kIdBankRemoveSel, g_accelBankRemoveSel,
|
||||
"ReaSampler: remove selected samples");
|
||||
"remove selected samples");
|
||||
g_cmdBankPoolFull = registerAction(rec, kIdBankPoolFull, g_accelBankPoolFull,
|
||||
"ReaSampler: toggle pool full-height");
|
||||
"toggle pool full-height");
|
||||
g_cmdBankBanksFull = registerAction(rec, kIdBankBanksFull, g_accelBankBanksFull,
|
||||
"ReaSampler: toggle banks full-height");
|
||||
"toggle banks full-height");
|
||||
}
|
||||
|
||||
bool bankHandleCommand(int command) {
|
||||
@@ -873,29 +901,30 @@ bool bankHandleCommand(int command) {
|
||||
}
|
||||
|
||||
void bankUnregisterActions(reaper_plugin_info_t* rec) {
|
||||
// Mirror-unregister with '-'-prefixed strings, reverse of registration order.
|
||||
// Mirror-unregister with '-'-prefixed strings, reverse of registration order. Each
|
||||
// '-command_id' re-presents the same interned channel-qualified id (channelIdFor).
|
||||
rec->Register("-gaccel", (void*)&g_accelBankBanksFull);
|
||||
rec->Register("-command_id", (void*)kIdBankBanksFull);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankBanksFull));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankPoolFull);
|
||||
rec->Register("-command_id", (void*)kIdBankPoolFull);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankPoolFull));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankRemoveSel);
|
||||
rec->Register("-command_id", (void*)kIdBankRemoveSel);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankRemoveSel));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankCopySel);
|
||||
rec->Register("-command_id", (void*)kIdBankCopySel);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankCopySel));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankMoveSel);
|
||||
rec->Register("-command_id", (void*)kIdBankMoveSel);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankMoveSel));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankActivatePool);
|
||||
rec->Register("-command_id", (void*)kIdBankActivatePool);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankActivatePool));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankActivateNext);
|
||||
rec->Register("-command_id", (void*)kIdBankActivateNext);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankActivateNext));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankEvacuate);
|
||||
rec->Register("-command_id", (void*)kIdBankEvacuate);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankEvacuate));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankDelete);
|
||||
rec->Register("-command_id", (void*)kIdBankDelete);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankDelete));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankRename);
|
||||
rec->Register("-command_id", (void*)kIdBankRename);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankRename));
|
||||
rec->Register("-gaccel", (void*)&g_accelBankCreate);
|
||||
rec->Register("-command_id", (void*)kIdBankCreate);
|
||||
rec->Register("-command_id", (void*)channelIdFor(kIdBankCreate));
|
||||
|
||||
// g_session is shared with the Design View family; designViewUnregisterActions
|
||||
// also nulls it. Nulling twice is harmless. Leave it to whichever runs last.
|
||||
|
||||
Reference in New Issue
Block a user