Fall back to focused tab when getReaperParent(3) is null
REAPER may not expose the parent project pointer during plugin creation/setState, so the instrument would silently resolve no sample roots. Only that null-parent case now falls back to EnumProjects(-1); a resolved-but-unlisted or unsaved project still resolves nothing.
This commit is contained in:
@@ -320,12 +320,15 @@ against a performance budget — they are there because `VoiceEngine::applyLiveT
|
||||
ordered root list; every instrument-side sample read (`reloadInstrument`, `bakeSnapshot`,
|
||||
the editor's `channelPcmFor`/`monoPcmFor`) goes through `readFromFirstRoot` over it. The old
|
||||
`EnumProjects(-1)` lookup resolved a background tab's instance against the FOCUSED project's
|
||||
folder — do not reintroduce it, not even as a fallback. A null parent, an unlisted project
|
||||
or an unsaved one yields no roots, which plays nothing, exactly as an unsaved project always
|
||||
did. The ordered list is one element today; a later root is added after the project
|
||||
directory, in `sampleRootCandidates`. `[verify — DAW]`: that `getReaperParent(3)` is non-null
|
||||
and enumerable during `setState` on project load, and that a background-tab instance and
|
||||
two open projects each with an instance play their own project's sample.
|
||||
folder — do not reintroduce it as the PRIMARY resolve. It survives ONE sanctioned use: when
|
||||
`getReaperParent(3)` itself comes back null (REAPER may not expose the parent during plugin
|
||||
creation/setState), `ownProjectDir` falls back to the focused tab — because at that point there
|
||||
is no "own project" identity to prefer a wrong answer over. A NON-NULL parent that is an
|
||||
unlisted project or an unsaved one still yields no roots, which plays nothing, exactly as an
|
||||
unsaved project always did. The ordered list is one element today; a later root is added after
|
||||
the project directory, in `sampleRootCandidates`. `[verify — DAW]`: that `getReaperParent(3)` is
|
||||
non-null and enumerable during `setState` on project load, and that a background-tab instance
|
||||
and two open projects each with an instance play their own project's sample.
|
||||
- The bake's availability probe runs on the SAME tick that paints the button, so the
|
||||
control can never be enabled on one tick and refuse on the next. The bake Hold control's
|
||||
applicability (`resolveBakeHoldNeeded`) rides the same tick for the same reason, and
|
||||
|
||||
@@ -94,8 +94,8 @@ bool ReaperBridge::connect(Steinberg::FUnknown* context) {
|
||||
std::optional<std::string> ReaperBridge::readReasamplerExtState(const std::string& key) {
|
||||
if (!getProjExtState_ || !hostApp_) return std::nullopt;
|
||||
|
||||
// getReaperParent(3) reads the live "reasampler" ext-state against the active project
|
||||
// the instrument was instantiated in, so it follows project switches for free. A null
|
||||
// getReaperParent(3) reads the live "reasampler" ext-state against the project the
|
||||
// instrument was instantiated in, so it follows project switches for free. A null
|
||||
// project is legitimate (REAPER treats it as the current project) — pass it through
|
||||
// rather than bailing; a fruitless read still yields nullopt to the caller.
|
||||
auto* reaper = static_cast<Steinberg::IReaperHostApplication*>(hostApp_);
|
||||
@@ -204,7 +204,6 @@ std::vector<std::string> ReaperBridge::sampleRoots() {
|
||||
if (!enumProjects_ || !hostApp_) return {};
|
||||
auto* reaper = static_cast<Steinberg::IReaperHostApplication*>(hostApp_);
|
||||
const void* own = reaper->getReaperParent(3);
|
||||
if (!own) return {};
|
||||
|
||||
std::vector<ProjectTab> open;
|
||||
std::vector<char> buf(4096, '\0');
|
||||
@@ -220,7 +219,15 @@ std::vector<std::string> ReaperBridge::sampleRoots() {
|
||||
// A duplicate of a listed tab is harmless: the first identity match wins.
|
||||
constexpr int kRenderingProject = 0x40000000;
|
||||
enumerate(kRenderingProject);
|
||||
return sampleRootCandidates(ownProjectDir(own, open));
|
||||
|
||||
// getReaperParent(3) can come back null while REAPER has not yet exposed the parent
|
||||
// (plugin creation/setState) — the focused tab is the one sanctioned fallback, used
|
||||
// ONLY then; see ownProjectDir. A non-null own that isn't in `open`, or is unsaved,
|
||||
// still resolves nothing.
|
||||
const void* activeFallback =
|
||||
own ? nullptr
|
||||
: enumProjects_(-1, buf.data(), static_cast<int>(buf.size()));
|
||||
return sampleRootCandidates(ownProjectDir(own, open, activeFallback));
|
||||
}
|
||||
|
||||
} // namespace reasampler::vst
|
||||
|
||||
@@ -32,8 +32,9 @@ public:
|
||||
|
||||
bool isConnected() const { return getProjExtState_ != nullptr; }
|
||||
|
||||
// Reads a "reasampler" ext-state value by key from the host's active project.
|
||||
// Returns nullopt when unconnected, unresolvable, or the key is absent.
|
||||
// Reads a "reasampler" ext-state value by key from this instance's own project
|
||||
// (getReaperParent(3)). Returns nullopt when unconnected, unresolvable, or the key is
|
||||
// absent.
|
||||
//
|
||||
// NOT REAL-TIME SAFE (allocates + calls into REAPER): audio-thread callers MUST NOT
|
||||
// invoke this. The instrument reads on the main/UI thread and hands a snapshot to
|
||||
@@ -42,8 +43,11 @@ public:
|
||||
|
||||
// The ordered roots this instance's bank-relative sample paths resolve against — its OWN
|
||||
// project's directory (getReaperParent(3) matched among EnumProjects' open projects),
|
||||
// never the focused tab's; see core/instrument/map/sample_roots. Empty when unconnected,
|
||||
// when the own project is not found, or when it was never saved. Not RT-safe.
|
||||
// never the focused tab's; see core/instrument/map/sample_roots. When getReaperParent(3)
|
||||
// is null (REAPER may not expose it yet during plugin creation/setState), falls back to
|
||||
// the focused tab (EnumProjects(-1)) — the one sanctioned use of it. Empty when
|
||||
// unconnected, when neither resolves to an open project, or when it was never saved.
|
||||
// Not RT-safe.
|
||||
std::vector<std::string> sampleRoots();
|
||||
|
||||
// The instrument's TWO sanctioned ext-state write surfaces, each accepting exactly one
|
||||
@@ -110,8 +114,9 @@ private:
|
||||
char* keyOut, int keyOut_sz, char* valOut,
|
||||
int valOut_sz);
|
||||
// EnumProjects(idx, projfnOut, sz) -> the idx'th open project + its .rpp path, null past
|
||||
// the last. Walked by index only: idx=-1 (the focused tab) is the wrong-project lookup
|
||||
// sampleRoots replaced.
|
||||
// the last. Walked by index for the open-tabs list; idx=-1 (the focused tab) was the
|
||||
// wrong-project lookup sampleRoots replaced as the PRIMARY resolve — it survives only as
|
||||
// the fallback used when getReaperParent(3) is null (see sampleRoots).
|
||||
using EnumProjectsFn = void* (*)(int idx, char* projfnOut, int projfnOut_sz);
|
||||
// Used ONLY by the two prefix-guarded writers — see the read-only-bank note there.
|
||||
using SetProjExtStateFn = int (*)(void* proj, const char* extname, const char* key,
|
||||
|
||||
Reference in New Issue
Block a user