// import_bank.cpp — see import_bank.h for the contract. The REAPER-facing half of the // import: the project directory, the minted bank id, the birth records, and the one // undo-batched persist. Every decision it makes is in import_landing / import_plan. // // main.cpp owns the API pointers; this TU gets them extern. DAW-verified, not unit tested. #include "shell/package/import_bank.h" #include #include #include #include #include "core/capture/capture_paths.h" // projectDirOfRpp #include "shell/bank_ops/bank_ops.h" // persistBankOp — one bank op is one Ctrl-Z #include "shell/persist/session.h" #define REAPERAPI_MINIMAL #define REAPERAPI_WANT_EnumProjects #define REAPERAPI_WANT_genGuid #define REAPERAPI_WANT_guidToString #include "reaper_plugin_functions.h" namespace reasampler { namespace { std::string activeProjectDir() { std::vector buf(4096, '\0'); EnumProjects(-1, buf.data(), static_cast(buf.size())); return capture::projectDirOfRpp(std::string(buf.data())); } // The model mints no ids (it stays pure and deterministic), so the shell does — the // same GUID pair bankOpCreate uses. std::string mintBankId() { GUID g{}; genGuid(&g); char buf[64] = {0}; // guidToString needs >=64 chars (SDK contract) guidToString(&g, buf); return std::string(buf); } void fillPlanCounts(ImportBankResult& out, const package::ImportPlan& plan) { out.bankDisplayName = plan.bankDisplayName; out.seedBankName = plan.seedBankName; out.bankNameAdjusted = plan.bankNameAdjusted; out.landedCount = plan.landCount; out.collisionRenameCount = plan.collisionRenameCount; out.sanitizeRenameCount = plan.sanitizeRenameCount; out.collapsedCount = plan.collapseCount; } } // namespace ImportBankResult importBankPackage(ReaSamplerSession& session, const std::string& packageAbsPath) { ImportBankResult out; // A per-import disambiguator, the same shape capture and ingest file under. const std::string uniqueTag = std::to_string(static_cast(std::time(nullptr))); LandedFileJournal journal; const ImportLanding landing = landPackage(packageAbsPath, activeProjectDir(), session.book(), uniqueTag, journal); out.outcome = landing.outcome; out.header = landing.header; out.failedEntryName = landing.failedEntryName; out.rollback = landing.rollback; fillPlanCounts(out, landing.plan); if (landing.outcome != ImportOutcome::Landed) return out; const std::string bankId = mintBankId(); const bool applied = applyImportedBank( session.book(), bankId, landing.plan, [&session](const model::Sample& s) { session.recordCreated(s, tracking::OriginKind::PackageImport); }); if (!applied) { out.outcome = ImportOutcome::IndexRejected; out.rollback = journal.rollback(); return out; } out.bankId = bankId; // Generation bump + persist ride inside one undo block, so a Ctrl-Z takes the whole // import back out of the index. It does NOT un-write the files — the summary says so. persistBankOp(session, "ReaSampler: import bank package", /*bumpGeneration=*/true); // Only now: the files are referenced, so prune's self-cleanup carve-out no longer // covers them (see package_rollback.h). journal.markIndexCommitted(); return out; } } // namespace reasampler