// render_settings.cpp — pure logic for the M7 capture action family. See header. // NO REAPER types; unit-tested by tests/test_render_settings.cpp. #include "render_settings.h" #include namespace reasampler { RenderSettingsChoice renderSettingsFor(SourceMode mode, double /*wetDry*/) { // All M7 actions are wet-only. `wetDry` is accepted so CaptureRequest.wetDry // remains the seam for future M10 dry work, but it does not affect the mapping. RenderSettingsChoice c; switch (mode) { case SourceMode::MasterMix: case SourceMode::TimeSelection: // Master IS the mix — wet-only; &(1|2)==0, no source bits. c.settings = kRenderMasterMix; c.supported = true; return c; case SourceMode::SelectedTracks: // Selected tracks via master (&128) — wet (post-FX). Header ~3041. c.settings = kRenderSelTracksViaMaster; c.supported = true; return c; case SourceMode::SelectedItems: // Selected media items, rendered to ONE file (single-file bit) so a // multi-item selection yields a single bank entry, not N wavs. c.settings = kRenderSelItems | kRenderSingleFile; c.supported = true; return c; case SourceMode::RazorArea: // Render razor edits to ONE file (same single-file rationale as items). c.settings = kRenderRazorEdits | kRenderSingleFile; c.supported = true; return c; case SourceMode::Realtime: // Not an offline-render source — the realtime backend (M8) owns it. c.settings = kRenderMasterMix; c.supported = false; return c; } // Unreachable for a valid enum; fail closed (unsupported) rather than render. c.supported = false; return c; } std::vector parseRazorEdits(const std::string& razorString) { std::vector ranges; std::istringstream in(razorString); // The string is space-separated TRIPLES: . // A track-audio area's third token is the literal two-char string `""`; an // envelope-lane area's is a GUID `{…}`. We keep only track-audio triples. std::string startTok, endTok, guidTok; while (in >> startTok >> endTok >> guidTok) { // Envelope-lane areas carry a real GUID; skip them (M7 = track audio). // A track-audio area's GUID token is the empty quoted string `""`. if (guidTok != "\"\"") continue; // Parse the two time tokens. std::stod throws on garbage — guard so one // malformed triple does not abort the whole parse. double start = 0.0, end = 0.0; try { std::size_t sp = 0, ep = 0; start = std::stod(startTok, &sp); end = std::stod(endTok, &ep); // Reject tokens with trailing garbage (e.g. "1.0x") — a partial parse // is a malformed area, not a valid range. if (sp != startTok.size() || ep != endTok.size()) continue; } catch (...) { continue; } if (end > start) ranges.push_back({start, end}); // drop empty/inverted } return ranges; } RazorRange razorUnionBounds(const std::vector& ranges) { if (ranges.empty()) return {0.0, 0.0}; RazorRange u = ranges.front(); for (const RazorRange& r : ranges) { if (r.startSeconds < u.startSeconds) u.startSeconds = r.startSeconds; if (r.endSeconds > u.endSeconds) u.endSeconds = r.endSeconds; } return u; } const std::vector& captureActionTable() { // Built once (function-local static): four wet-only actions. Tail OFF for all // (exact bounds). Ids are FOREVER-STABLE — never edit a shipped string. // Dry variants deferred to M10; see kRenderPreFaderStems note in the header. static const std::vector table = { // Master mix — wet only (master IS the mix; no pre-FX concept applies). {"CEREBELLUM_REASAMPLER_CAPTURE_MASTER", "ReaSampler: capture master mix", "master_mix", SourceMode::MasterMix, 1.0}, // Selected tracks — wet (via master, &128). {"CEREBELLUM_REASAMPLER_CAPTURE_TRACKS_WET", "ReaSampler: capture selected tracks", "tracks_wet", SourceMode::SelectedTracks, 1.0}, // Selected items — wet, single file (&32 | single-file). {"CEREBELLUM_REASAMPLER_CAPTURE_ITEMS_WET", "ReaSampler: capture selected items", "items_wet", SourceMode::SelectedItems, 1.0}, // Razor area — wet, single file (&4096 | single-file). {"CEREBELLUM_REASAMPLER_CAPTURE_RAZOR_WET", "ReaSampler: capture razor area", "razor_wet", SourceMode::RazorArea, 1.0}, }; return table; } } // namespace reasampler