From 39cdbeef1d8ca52190250e49a2fa506b10333f51 Mon Sep 17 00:00:00 2001 From: Talon Date: Fri, 14 Aug 2026 20:39:01 +0200 Subject: [PATCH] Stop bar playback before the bar line, not on it Playing a single bar still triggered notes placed exactly on the next bar line. Two delays stack: the daemon polls at roughly frame rate, so it can notice up to ~33ms late, and REAPER renders audio ahead of the play position it reports, so the note has already reached the instrument before the stop lands. Stopping 60ms early clears both. The cost is a few milliseconds off the tail of the bar, which is inaudible, and the benefit is that the downbeat you were trying to exclude stays excluded. Tunable via the stoplead ExtState for setups with large audio buffers. --- MidiGrid_Daemon.lua | 9 ++++++++- README.md | 11 +++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/MidiGrid_Daemon.lua b/MidiGrid_Daemon.lua index a55a72f..58161da 100644 --- a/MidiGrid_Daemon.lua +++ b/MidiGrid_Daemon.lua @@ -53,7 +53,14 @@ local function loop() local stopAt = tonumber(G.getTemp("stopat", "")) if stopAt then local playing = (reaper.GetPlayState() % 2) == 1 - if playing and reaper.GetPlayPosition() >= stopAt then + -- Stop a little BEFORE the bar line, not on it. Two delays stack up + -- otherwise: this loop only runs at about frame rate, and REAPER renders + -- audio ahead of the play position it reports -- so a note sitting exactly + -- on the next bar line has already been sent to the instrument by the time + -- we notice. Leading by more than both delays keeps that note silent. + -- Costs a few ms off the tail of the bar, which is inaudible. + local lead = G.getNum("stoplead", 0.06) + if playing and reaper.GetPlayPosition() >= stopAt - lead then -- Stopping can move the edit cursor depending on preferences, and the -- edit cursor is the grid cursor, so put it back. local cur = reaper.GetCursorPosition() diff --git a/README.md b/README.md index c27913b..512bb8c 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,16 @@ script — a script that stayed alive waiting for the bar to end would trigger REAPER's "already running" prompt on the next press. Stopping can move the edit cursor depending on your preferences, so the daemon puts it back. +It stops **60 ms before** the bar line rather than on it. Two delays stack up +otherwise: the daemon runs at about frame rate, and REAPER renders audio ahead +of the play position it reports, so a note sitting exactly on the next bar line +has already reached the instrument by the time the stop lands — and you hear +the downbeat you were trying to exclude. Leading by more than both delays keeps +it silent, at the cost of a few inaudible milliseconds off the tail. + +If a next-bar note still sneaks through — a large audio buffer will do it — +raise `stoplead` in `ExtState`. + ## Shifting notes in time If a whole clip landed a couple of cells off the beat, `Ctrl+Shift+Left` and @@ -268,6 +278,7 @@ In `ExtState` section `midigrid`: |---|---|---| | `vel` | 96 | Velocity of inserted notes | | `velstep` | 8 | Velocity change per keypress | +| `stoplead` | 0.06 | How early to stop, in seconds, when playing one bar | | `chan` | 0 | MIDI channel (0-based) | | `previewdur` | 0.4 | Preview note length, seconds |