StuffMIDIMessage feeds the virtual MIDI keyboard, which only reaches tracks that are armed and monitoring -- normally not the track whose item you are editing. Opening an item in grid mode therefore sounded every preview through whatever instrument happened to be armed, which is confusing when the notes you are writing come back in the wrong voice. Grid mode now borrows the record routing: the edited take's track is armed and monitoring with all MIDI inputs (anything narrower can exclude the virtual keyboard), and every other armed track is stood down so it cannot answer as well. The prior arm, monitor and input of each track touched is saved by GUID in transient ExtState. routePreview re-points lazily, so moving the editor to an item on another track costs nothing until the target actually changes. The daemon hands the routing back when grid mode goes off, when the editor closes, or on exit -- the same way it already restores the loop and repeat state the loop-bar action borrows -- so the project is put back even if grid mode is never toggled off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
40 lines
1.1 KiB
Lua
40 lines
1.1 KiB
Lua
-- MIDI Grid: toggle grid entry mode on/off
|
|
local dir = ({ reaper.get_action_context() })[2]:match("@?(.*[\\/])")
|
|
local G = dofile(dir .. "midigrid_lib.lua")
|
|
|
|
local now = not G.isActive()
|
|
G.set("active", now and 1 or 0)
|
|
|
|
if not now then
|
|
-- Hand back the record arm/monitor state grid mode borrowed for preview.
|
|
G.restoreRouting()
|
|
G.say("Grid mode off")
|
|
return
|
|
end
|
|
|
|
local hwnd, take, err = G.editor()
|
|
if not take then
|
|
-- Mode is still armed; it simply has nothing to act on yet.
|
|
G.say("Grid mode on, " .. err)
|
|
return
|
|
end
|
|
|
|
-- Preview must sound through the instrument of the track being edited.
|
|
G.routePreview(take)
|
|
|
|
-- Park the pitch cursor on a scale tone so the very first up/down press
|
|
-- moves by a sensible degree rather than off a foreign note.
|
|
local p = G.getPitch(hwnd)
|
|
if not G.inScale(p) then
|
|
local up = G.scaleStep(p, 1)
|
|
if up then p = up ; G.setPitch(hwnd, p) end
|
|
end
|
|
|
|
local g = G.gridQN(take)
|
|
G.say(("Grid mode on, %s, grid %s, %s, %s, %s"):format(
|
|
G.scaleName(),
|
|
G.gridLabel(g),
|
|
G.isHold() and "hold on" or "hold off",
|
|
G.noteName(p),
|
|
G.cellPosText(take)))
|