Widen the deck row block to 1028 so the filter tie-line is exact, and accumulate the meter's block peaks instead of sampling one in 47
This commit is contained in:
@@ -128,16 +128,17 @@ public:
|
||||
Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID iid,
|
||||
void** obj) override;
|
||||
|
||||
// The embedded-strip activity level (0..1) for the embed shell, UI thread. The loudest of
|
||||
// the two published bus peaks — one publication serves the strip and the meter.
|
||||
// The embedded-strip activity level (0..1) for the embed shell, UI thread. The last block's
|
||||
// loudest channel — a non-consuming read, so it stays correct however often the editor's
|
||||
// meter drains its own accumulators (or never does, with no editor open).
|
||||
double embedActivityLevel() const {
|
||||
const float l = meterPeakL_.load(std::memory_order_relaxed);
|
||||
const float r = meterPeakR_.load(std::memory_order_relaxed);
|
||||
return static_cast<double>(l > r ? l : r);
|
||||
return static_cast<double>(advisoryPeak_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
// What the audio thread published about the output bus last block. UI thread.
|
||||
MasterBusMeter masterBusMeter() const;
|
||||
// What the audio thread published since the LAST call: peaks maxed and minGain minimised
|
||||
// across every block in that window. CONSUMING — it resets the accumulators as it reads, so
|
||||
// exactly one reader may call it, and that reader is the editor's meter tick. UI thread.
|
||||
MasterBusMeter masterBusMeter();
|
||||
void clearMasterBusClip();
|
||||
|
||||
// Resolves the selection against the instance-owned SampleRefs, decodes its WAV
|
||||
@@ -284,13 +285,28 @@ private:
|
||||
// Requires reloadMutex_ held — shared by reloadInstrument and rebuildVoiceEngine.
|
||||
void publishBuiltLocked(std::unique_ptr<LoadedInstrument> built);
|
||||
|
||||
// Publishes a silent block to the meter. EVERY process() path that emits no audio calls
|
||||
// this, or the bar freezes at the last peak it saw. The clip latch is deliberately not
|
||||
// touched — it survives silence until the user clears it.
|
||||
// Folds one block's reading into the accumulator it belongs to — a running max for a peak,
|
||||
// a running min for the limiter's gain. Read-modify-write rather than a bare store, so the
|
||||
// ~47 blocks that elapse between two 500 ms UI frames at 48 kHz/512 all reach the meter
|
||||
// instead of the one it happened to sample. Relaxed throughout: the accumulators are
|
||||
// advisory, and no other state is ordered against them. Block rate, never per frame.
|
||||
static void foldPeak(std::atomic<float>& acc, float blockPeak) {
|
||||
if (blockPeak > acc.load(std::memory_order_relaxed)) {
|
||||
acc.store(blockPeak, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
static void foldMinGain(std::atomic<float>& acc, float blockMinGain) {
|
||||
if (blockMinGain < acc.load(std::memory_order_relaxed)) {
|
||||
acc.store(blockMinGain, std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
// Publishes a silent block. EVERY process() path that emits no audio calls this. It clears
|
||||
// only the ADVISORY level, which is a last-block reading: the meter accumulators need
|
||||
// nothing here, because a block that emitted no audio contributes no peak and no gain
|
||||
// reduction, and the UI's own read is what resets them.
|
||||
void publishSilentMeterBlock() {
|
||||
meterPeakL_.store(0.f, std::memory_order_relaxed);
|
||||
meterPeakR_.store(0.f, std::memory_order_relaxed);
|
||||
meterMinGain_.store(1.f, std::memory_order_relaxed);
|
||||
advisoryPeak_.store(0.f, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Mirrors the persisted limiter enable onto the audio thread and the latency reader. Called
|
||||
@@ -456,13 +472,21 @@ private:
|
||||
instrument::engine::Limiter limiter_;
|
||||
std::atomic<bool> limiterEnabled_{false};
|
||||
|
||||
// What the audio thread publishes about the output bus each block, relaxed — peaks, the
|
||||
// latched clip, and the limiter's smallest gain. No dB, no ballistics, no hold timer here;
|
||||
// What the audio thread publishes about the output bus each block, relaxed. The peaks and
|
||||
// minGain ACCUMULATE (max / min) across every block since the UI last read, and
|
||||
// masterBusMeter() resets them as it reads — the fix for a bar that displayed roughly one
|
||||
// block in fifty. No dB, no ballistics, no hold timer here;
|
||||
// the UI runs those off these values and its own elapsed time.
|
||||
std::atomic<float> meterPeakL_{0.f};
|
||||
std::atomic<float> meterPeakR_{0.f};
|
||||
std::atomic<float> meterMinGain_{1.f};
|
||||
std::atomic<bool> meterClip_{false};
|
||||
|
||||
// The embed strip's activity level: the LAST block's loudest channel, plainly overwritten.
|
||||
// Separate from the accumulators above because it answers a different question ("how loud
|
||||
// is it now") and has a different reader — sharing one would make each reader's reset
|
||||
// silently truncate the other's window.
|
||||
std::atomic<float> advisoryPeak_{0.f};
|
||||
};
|
||||
|
||||
} // namespace reasampler::vst
|
||||
|
||||
Reference in New Issue
Block a user