feat(S8): ingest through the bank — capture/import/drop into bank + assign to active instance
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
// ingest — the S8 "ingest through the bank" shell (EXTENSION side).
|
||||
//
|
||||
// Compiled into the reaper_reasampler MODULE. REAPER-facing (PCM_Source metadata reads,
|
||||
// Media-Explorer query, ext-state assignment write, action registration), so it is
|
||||
// DAW-verified, not unit-tested; the pure serialization it drives lives in
|
||||
// assignment_request (tested in CTest).
|
||||
//
|
||||
// -- The one gesture (CONTEXT.md §Ingest through the bank) --------------------
|
||||
//
|
||||
// Loading a sample into the sampler is ONE gesture: capture/import-into-bank AND
|
||||
// auto-assign to the active sampler instance. The EXTENSION owns ingest (it has arrange
|
||||
// access, Media-Explorer access, and the drop-target surface on its own panels); the
|
||||
// instrument stays a READ-ONLY bank consumer. Three ingest surfaces:
|
||||
//
|
||||
// 1. Arrange capture -> bank -> assign (a bindable action; reuses the capture path).
|
||||
// 2. Media-Explorer import -> bank -> assign (a bindable action; single-file, pull-on-
|
||||
// action via MediaExplorerGetLastPlayedFileInfo).
|
||||
// 3. Drop-onto-panel -> bank -> assign (an OS file drop on the docked bank_panel HWND;
|
||||
// multi-file: import all, assign the first).
|
||||
//
|
||||
// -- The load-bearing principle (restated) -----------------------------------
|
||||
//
|
||||
// Ingest NEVER inserts a timeline item. Capture writes a file + an index entry; import
|
||||
// copies a file + adds an index entry; assignment is a bank-index + instance-selection
|
||||
// act, not a placement. Any path here that calls InsertMedia would be a bug.
|
||||
//
|
||||
// -- Import semantics ---------------------------------------------------------
|
||||
//
|
||||
// A Media-Explorer/drop import is a FILE COPY into the project-relative bank folder +
|
||||
// an index add, mirroring how a capture lands (relative-paths-only, hash-dedup). If the
|
||||
// active bank already holds the imported content (by content hash), the import collapses
|
||||
// onto the existing sample and assigns THAT sample's id — no redundant on-disk copy.
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations keep this header REAPER-free at its own boundary (the .cpp pulls
|
||||
// the SDK). reaper_plugin_info_t is REAPER's dispatch struct; ReaSamplerSession owns the
|
||||
// book + persist bridge the ingest paths mutate.
|
||||
struct reaper_plugin_info_t;
|
||||
|
||||
namespace reasampler {
|
||||
|
||||
class ReaSamplerSession;
|
||||
|
||||
// Registers the S8 ingest action family (command_id/gaccel per the house contract),
|
||||
// mirror of bankRegisterActions. `session` is the live session the ingest paths mutate
|
||||
// (shared with the capture / bank / Design-View families). The single hookcommand in
|
||||
// main.cpp routes fired ids here via ingestHandleCommand.
|
||||
void ingestRegisterActions(reaper_plugin_info_t* rec, ReaSamplerSession* session);
|
||||
|
||||
// Routes a fired command id to its ingest action. Returns true iff it was one of ours
|
||||
// (claim-only, per the hookcommand contract); false otherwise so the hook keeps looking.
|
||||
bool ingestHandleCommand(int command);
|
||||
|
||||
// Mirror-unregisters the ingest action family on unload (the '-'-prefixed strings).
|
||||
void ingestUnregisterActions(reaper_plugin_info_t* rec);
|
||||
|
||||
// Write the S8 assignment request for a just-ingested sample: "the active sampler
|
||||
// instance should now play (bankId, sampleId)." Encodes the pure assignment_request value
|
||||
// (with a fresh monotonic generation stamp) and routes it to ext state via the session.
|
||||
// Called by EVERY ingest surface after the sample lands in the bank — the arrange
|
||||
// capture+assign action (main.cpp, alongside the capture machinery it reuses), the ME
|
||||
// import action, and the drop path. A no-op-safe write: if there is no saved/active
|
||||
// project the request is silently dropped (nothing to signal into), matching the
|
||||
// book/manifest quiet-persist idiom. `sampleId` empty -> no write (nothing to assign).
|
||||
void ingestAssignActiveInstance(const std::string& bankId, const std::string& sampleId);
|
||||
|
||||
// Ingest OS-dropped files onto a ReaSampler surface (S8 drop path). Called by the
|
||||
// bank_panel's WM_DROPFILES handler with the dropped file paths (absolute, OS-native).
|
||||
// Imports EVERY file into the active bank (copy + index add, hash-dedup) and assigns the
|
||||
// FIRST successfully-imported sample to the active instance. A no-op on an empty list or
|
||||
// an unsaved/no-active project (nothing to import into). Reports outcomes to the console.
|
||||
void ingestDroppedFiles(const std::vector<std::string>& absolutePaths);
|
||||
|
||||
} // namespace reasampler
|
||||
Reference in New Issue
Block a user