Tidy reasampler_processor.h ceiling, restamp contour publish, tighten pitch-shift test bound
Splits BuiltCapture/sourceRateRefusalText into processor_snapshot.h; fixes stale lock-nesting notes; restamp now also publishes liveContours_ like reload; tightens a slack test bound and one drifted comment.
This commit is contained in:
@@ -247,8 +247,9 @@ against a performance budget — they are there because `VoiceEngine::applyLiveT
|
||||
`LoadedInstrument`) and the automation lane's own state. All three are split out —
|
||||
`processor_snapshot.h` and `automation_channel.h`, on the same grounds `editor_interaction.h`
|
||||
was split out of `reasampler_editor.h` in this directory: neither is behaviour. What remains is
|
||||
the class declaration itself, a handful of lines over the ceiling since the live-contour block
|
||||
(`liveContours_` + `publishLiveContours`) landed beside `liveParams_` under the same ordering
|
||||
the class declaration itself, 630 lines (measured post-split) — over the ceiling since the
|
||||
live-contour block (`liveContours_` + `publishLiveContours`) landed beside `liveParams_` under
|
||||
the same ordering
|
||||
constraint. No further seam exists that isn't behaviour: every remaining aggregate-shaped chunk
|
||||
(the preview mailbox, the drain-slot triple) is read and written inline by `process()` on the
|
||||
audio thread, so splitting it into its own header would either duplicate the RT-discipline
|
||||
|
||||
@@ -128,7 +128,7 @@ BakeChainResult runBake(ReaSamplerProcessor& processor) {
|
||||
|
||||
// The snapshot comes first: the default program's window is derived from the sound it
|
||||
// carries (a Gate release, a Trigger play span), not from a constant.
|
||||
ReaSamplerProcessor::BuiltCapture built = processor.bakeSnapshot(sampleRate);
|
||||
BuiltCapture built = processor.bakeSnapshot(sampleRate);
|
||||
if (built.rateRefused) return fail("cannot render: " + sourceRateRefusalText());
|
||||
if (!built.sample) return fail("the loaded capture could not be decoded for the render");
|
||||
SampleData& snapshot = *built.sample;
|
||||
|
||||
@@ -80,10 +80,10 @@ std::optional<DecodedPcm> decodeRelative(const std::string& projectDir,
|
||||
|
||||
// The ONE decode + build the reload and the bake snapshot share, so a baked render can
|
||||
// never be built from a different fold than the one the user is hearing.
|
||||
ReaSamplerProcessor::BuiltCapture buildFromRef(const SelectedSample& sel,
|
||||
const InstrumentParams& params,
|
||||
const std::string& projectDir,
|
||||
ChannelMode mode, int renderRate) {
|
||||
BuiltCapture buildFromRef(const SelectedSample& sel,
|
||||
const InstrumentParams& params,
|
||||
const std::string& projectDir,
|
||||
ChannelMode mode, int renderRate) {
|
||||
std::optional<DecodedPcm> pcm = decodeRelative(projectDir, sel.relativePath, mode);
|
||||
if (!pcm) return {};
|
||||
if (!sourceRateSupported(pcm->sampleRate, renderRate)) return {std::nullopt, true};
|
||||
@@ -172,8 +172,9 @@ std::string ReaSamplerProcessor::reloadInstrument() {
|
||||
// collapses every automated envelope stage to zero frames.
|
||||
builtSampleRate_.store(sample.outputRate(), std::memory_order_relaxed);
|
||||
{
|
||||
// reloadMutex_ (held for this whole function) nests livePublishMutex_ here;
|
||||
// publishLiveParams never holds reloadMutex_, so this is the only nesting.
|
||||
// reloadMutex_ (held for this whole function) nests livePublishMutex_ here, the
|
||||
// same nesting restampHostRateLocked takes under its own reloadMutex_-held
|
||||
// callers; publishLiveParams never holds reloadMutex_.
|
||||
std::lock_guard<std::mutex> lp(livePublishMutex_);
|
||||
liveParams_.publish(instrument::engine::foldLive(sample.play, sample.keyTrack));
|
||||
// The model's contours, so a reload-tier contour edit (a point added, deleted or
|
||||
@@ -206,7 +207,7 @@ std::string ReaSamplerProcessor::usageInstanceGuid() {
|
||||
return instanceGuid_;
|
||||
}
|
||||
|
||||
ReaSamplerProcessor::BuiltCapture ReaSamplerProcessor::bakeSnapshot(int renderRate) {
|
||||
BuiltCapture ReaSamplerProcessor::bakeSnapshot(int renderRate) {
|
||||
const std::string selId = selectedSampleId();
|
||||
if (selId.empty()) return {};
|
||||
const InstrumentParams params = instrumentParams();
|
||||
@@ -443,6 +444,9 @@ bool ReaSamplerProcessor::restampHostRateLocked(SampleData& sample, int renderRa
|
||||
builtSampleRate_.store(sample.outputRate(), std::memory_order_relaxed);
|
||||
std::lock_guard<std::mutex> lp(livePublishMutex_);
|
||||
liveParams_.publish(instrument::engine::foldLive(sample.play, sample.keyTrack));
|
||||
// Symmetric with reloadInstrument's own publish pair: a re-stamp is a rebuild too, so the
|
||||
// drain's sounding voices need the model's contours refreshed beside the live params.
|
||||
liveContours_.publish(instrument::engine::foldContours(sample.play));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,27 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "core/instrument/engine/voice_engine.h"
|
||||
|
||||
namespace reasampler::vst {
|
||||
|
||||
// What the editor and the bake print for a refused file rate (sourceRateSupported), so the
|
||||
// limit is spelled in one place.
|
||||
std::string sourceRateRefusalText();
|
||||
|
||||
// The dialed sound as plain data for the offline bake (ReaSamplerProcessor::bakeSnapshot):
|
||||
// empty when nothing is loaded or the WAV is unreadable; `rateRefused` distinguishes a
|
||||
// decoded file whose rate is refused against the host's from that plain no-play.
|
||||
struct BuiltCapture {
|
||||
std::optional<SampleData> sample;
|
||||
// The file decoded, but sourceRateSupported (play_params.h) refuses its rate against
|
||||
// the host's — a distinct failure the user is told about, not an unreadable file.
|
||||
bool rateRefused = false;
|
||||
};
|
||||
|
||||
// What the audio thread publishes about the OUTPUT BUS, post-limiter, once per block. Raw
|
||||
// magnitudes only — the UI converts to dB and runs the ballistics (engine/meter_ballistics),
|
||||
// because a hold timer or a log on the audio thread would be per-block work that buys nothing.
|
||||
|
||||
@@ -39,10 +39,6 @@ using instrument::map::kPreviewVelocityDefault;
|
||||
|
||||
class ReaSamplerEmbed; // embedded TCP/MCP UI shell (owned below; see queryInterface)
|
||||
|
||||
// What the editor and the bake print for a refused file rate (sourceRateSupported), so the
|
||||
// limit is spelled in one place.
|
||||
std::string sourceRateRefusalText();
|
||||
|
||||
class ReaSamplerProcessor : public Steinberg::Vst::SingleComponentEffect {
|
||||
public:
|
||||
ReaSamplerProcessor() = default;
|
||||
@@ -157,13 +153,8 @@ public:
|
||||
// rather than copied off the live snapshot because a tier-3 live edit leaves that
|
||||
// snapshot's own play params stale on purpose — copying it would bake the pre-drag values.
|
||||
// Empty when nothing is loaded, the WAV is unreadable, or its rate is refused (then
|
||||
// `rateRefused` says so). Off the audio thread (file I/O).
|
||||
struct BuiltCapture {
|
||||
std::optional<SampleData> sample;
|
||||
// The file decoded, but sourceRateSupported (play_params.h) refuses its rate against
|
||||
// the host's — a distinct failure the user is told about, not an unreadable file.
|
||||
bool rateRefused = false;
|
||||
};
|
||||
// `rateRefused` says so). Off the audio thread (file I/O). See BuiltCapture
|
||||
// (processor_snapshot.h).
|
||||
BuiltCapture bakeSnapshot(int renderRate);
|
||||
|
||||
// Adopt a landed bake in ONE act: the new capture becomes this instance's ref and
|
||||
@@ -442,9 +433,10 @@ private:
|
||||
// The host lane's state and its release protocol; automation_channel.h owns the mechanism and
|
||||
// this directory's CLAUDE.md the authority model it enforces.
|
||||
AutomationChannel automation_;
|
||||
// Serializes the writer sites of liveParams_ (reloadInstrument, publishLiveParams) and of
|
||||
// liveContours_ (reloadInstrument, publishLiveContours) only — separate from reloadMutex_ so
|
||||
// a drag's publish never blocks behind a reload's WAV decode. The audio thread never takes
|
||||
// Serializes the writer sites of liveParams_ (reloadInstrument, publishLiveParams,
|
||||
// restampHostRateLocked) and of liveContours_ (reloadInstrument, publishLiveContours,
|
||||
// restampHostRateLocked) only — separate from reloadMutex_ so a drag's publish never blocks
|
||||
// behind a reload's WAV decode. The audio thread never takes
|
||||
// this; it only reads via the seqlock's lock-free retry.
|
||||
std::mutex livePublishMutex_;
|
||||
// The output rate the loaded capture's play params were resolved at (SampleData::
|
||||
|
||||
Reference in New Issue
Block a user