#include "capture_paths.h" namespace reasampler { std::string normalizeSlashes(const std::string& path) { std::string out = path; for (char& c : out) { if (c == '\\') c = '/'; } // Strip a single trailing slash so joins do not double up. Preserve a lone // "/" (root) — stripping it would turn root into empty. if (out.size() > 1 && out.back() == '/') { out.pop_back(); } return out; } std::string sanitizeStem(const std::string& baseName) { std::string out; out.reserve(baseName.size()); for (unsigned char c : baseName) { const bool keep = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '_' || c == '-'; out.push_back(keep ? static_cast(c) : '_'); } // Collapse to a stable default if nothing usable survived (e.g. all spaces). // A stem of only separators ('.', '_', '-') is also unhelpful as a name. bool hasAlnum = false; for (unsigned char c : out) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) { hasAlnum = true; break; } } if (out.empty() || !hasAlnum) { return "capture"; } return out; } BankPaths deriveBankPaths(const std::string& projectDir, const std::string& baseName, const std::string& uniqueTag) { const std::string dir = normalizeSlashes(projectDir); std::string stem = sanitizeStem(baseName); if (!uniqueTag.empty()) { stem += "_" + sanitizeStem(uniqueTag); } const std::string fileName = stem + ".wav"; BankPaths p; p.fileStem = stem; // stem only — REAPER appends extension p.fileName = fileName; p.relativePath = std::string(kBankSubfolder) + "/" + fileName; // absoluteDir intentionally omits a trailing slash (RENDER_FILE wants the // directory itself; RENDER_PATTERN supplies the file name separately). p.absoluteDir = dir.empty() ? std::string(kBankSubfolder) : dir + "/" + kBankSubfolder; return p; } } // namespace reasampler