From 8fd1b4755f1bfcb1d2bad1f937bd028353798d0c Mon Sep 17 00:00:00 2001 From: Talon Date: Fri, 14 Aug 2026 19:57:55 +0200 Subject: [PATCH] Add play-from-start-of-bar Alt+Space plays from the downbeat of the bar the cursor is in. Auditioning a cell says what a note is; playing from the bar line says whether it is in the right place, which is the question that matters at 16ths and 32nds and cannot be answered from a note in isolation. REAPER can almost do this by chaining a go-to-measure action with play, but that leaves the edit cursor at the bar line -- and the edit cursor is the grid cursor, so you would lose your editing position every time you listened. Here the cursor is moved just long enough to start playback and then restored with seekplay=false so the restore cannot drag playback with it. Works regardless of grid mode, being a listening aid rather than an edit. --- MidiGrid_PlayFromBar.lua | 12 ++++++++++++ README.md | 17 +++++++++++++++++ install.ps1 | 6 ++++-- midigrid_lib.lua | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 MidiGrid_PlayFromBar.lua diff --git a/MidiGrid_PlayFromBar.lua b/MidiGrid_PlayFromBar.lua new file mode 100644 index 0000000..c87f31b --- /dev/null +++ b/MidiGrid_PlayFromBar.lua @@ -0,0 +1,12 @@ +--[[ + MIDI Grid: play from the start of the bar the cursor is in. + + Deliberately works whether or not grid mode is on -- it is a listening aid, + not an editing action, and it is just as useful while navigating with OSARA + normally. Stop with Space as usual. +]] +local dir = ({ reaper.get_action_context() })[2]:match("@?(.*[\\/])") +local G = dofile(dir .. "midigrid_lib.lua") + +local bar = G.playFromBar() +G.say("Playing from bar " .. bar) diff --git a/README.md b/README.md index dbef4a7..0efd734 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ actions by hand in Actions → Show action list. That always works. | `Alt+Shift+Up` / `Alt+Shift+Down` | Velocity up / down | — | | `Alt+G` | **Toggle grid mode on/off** | — | | `Alt+H` | Toggle hold mode | — | +| `Alt+Space` | Play from start of the current bar | works in both modes | | `Alt+A` | Repeat current cell (speak + sound) | — | | `Alt+S` | Set root and scale | — | | `1`–`9` | Grid size — REAPER's own grid actions | same | @@ -149,6 +150,22 @@ survive. They also need no mode: `L` behaves identically whether hold is on or off, so there is no state to set up beforehand and none to remember to turn off afterwards. +## Hearing it in context + +`Alt+Space` plays from the **top of the bar the cursor is in**, and says which +bar. Stop with `Space` as usual. + +Auditioning a cell tells you what a note *is*; playing from the downbeat tells +you whether it is in the right *place*. At 16ths or 32nds that difference is +the whole question, and it cannot be judged from a note in isolation. + +Your position is preserved. The edit cursor doubles as the grid cursor, so it +is moved to the bar line only long enough to start playback and then put +straight back — you carry on editing exactly where you were. + +This one works whether or not grid mode is on, since it is a listening aid +rather than an editing action. + ## Shifting notes in time If a whole clip landed a couple of cells off the beat, `Ctrl+Shift+Left` and diff --git a/install.ps1 b/install.ps1 index 8c32e0a..d74f718 100644 --- a/install.ps1 +++ b/install.ps1 @@ -59,7 +59,8 @@ $actions = @( @('RSmidigrid_shl', 32060, 'MIDI Grid: Shift all notes one cell left', 'MidiGrid_ShiftLeft.lua'), @('RSmidigrid_shr', 32060, 'MIDI Grid: Shift all notes one cell right', 'MidiGrid_ShiftRight.lua'), @('RSmidigrid_shlf', 32060, 'MIDI Grid: Shift all notes left (force)', 'MidiGrid_ShiftLeftForce.lua'), - @('RSmidigrid_shrf', 32060, 'MIDI Grid: Shift all notes right (force)', 'MidiGrid_ShiftRightForce.lua') + @('RSmidigrid_shrf', 32060, 'MIDI Grid: Shift all notes right (force)', 'MidiGrid_ShiftRightForce.lua'), + @('RSmidigrid_playbar',32060, 'MIDI Grid: Play from start of current bar', 'MidiGrid_PlayFromBar.lua') ) # flags, keycode, section, id @@ -86,7 +87,8 @@ $keys = @( @(13, 32805, 32060, 'RSmidigrid_shl'), @(13, 32807, 32060, 'RSmidigrid_shr'), @(29, 32805, 32060, 'RSmidigrid_shlf'), - @(29, 32807, 32060, 'RSmidigrid_shrf') + @(29, 32807, 32060, 'RSmidigrid_shrf'), + @(17, 32, 32060, 'RSmidigrid_playbar') ) $backup = "$kb.midigrid-backup" diff --git a/midigrid_lib.lua b/midigrid_lib.lua index a331fb3..79463d2 100644 --- a/midigrid_lib.lua +++ b/midigrid_lib.lua @@ -352,6 +352,41 @@ function M.toggleCell(take, pitch) return result, detail end +------------------------------------------------------------------ playback + +-- Start of the bar containing time t, plus the 1-based bar number. +function M.barStart(t) + local _, measures = reaper.TimeMap2_timeToBeats(0, t) + return reaper.TimeMap2_beatsToTime(0, 0, measures), measures + 1 +end + +--[[ + Play from the top of the bar the cursor is in, without losing your place. + + The edit cursor doubles as the grid cursor, so it is moved to the bar line + only long enough to start playback and then put straight back. Restoring it + passes seekplay=false so the restore cannot drag playback along with it. + + Playing from the bar line rather than the cursor is what makes fine + subdivisions checkable: you hear the note in relation to the downbeat, + which is the thing you are actually trying to judge. +]] +function M.playFromBar() + local here = reaper.GetCursorPosition() + local barPos, barNum = M.barStart(here) + + reaper.PreventUIRefresh(1) + reaper.SetEditCurPos(barPos, false, true) + -- GetPlayState bit 0 is "playing"; avoid bitwise ops for portability. + if (reaper.GetPlayState() % 2) == 0 then + reaper.CSurf_OnPlay() + end + reaper.SetEditCurPos(here, false, false) + reaper.PreventUIRefresh(-1) + + return barNum +end + ---------------------------------------------------------------- time shift --[[