Play preview through the edited track's instrument
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>
This commit is contained in:
@@ -84,4 +84,49 @@ eq(table.concat(G.chordPitches(69, 3), ","), "69,72,76", "A minor triad")
|
||||
ext.root, ext.scale = "0", "1"
|
||||
eq(G.chordPitches(127, 3), nil, "chord past top of range")
|
||||
|
||||
-- Preview routing: the edited track takes over arm/monitor so preview sounds
|
||||
-- through its instrument, any other armed track stands down so it cannot
|
||||
-- answer as well, and restore puts every one of them back.
|
||||
local tracks = {
|
||||
{ guid = "{A}", arm = 0, mon = 0, input = 0 },
|
||||
{ guid = "{B}", arm = 0, mon = 0, input = 0 }, -- the track being edited
|
||||
{ guid = "{C}", arm = 1, mon = 1, input = 6112 }, -- somebody else's armed track
|
||||
}
|
||||
local FIELD = { I_RECARM = "arm", I_RECMON = "mon", I_RECINPUT = "input" }
|
||||
reaper.CountTracks = function() return #tracks end
|
||||
reaper.GetTrack = function(_, i) return tracks[i + 1] end
|
||||
reaper.GetTrackGUID = function(t) return t.guid end
|
||||
reaper.GetMediaTrackInfo_Value = function(t, k) return t[FIELD[k]] end
|
||||
reaper.SetMediaTrackInfo_Value = function(t, k, v) t[FIELD[k]] = v end
|
||||
reaper.GetMediaItemTake_Track = function(tk) return tk.track end
|
||||
|
||||
local take = { track = tracks[2] }
|
||||
G.routePreview(take)
|
||||
eq(tracks[2].arm, 1, "edited track armed")
|
||||
eq(tracks[2].mon, 1, "edited track monitoring")
|
||||
eq(tracks[2].input, 6112, "edited track takes MIDI input")
|
||||
eq(tracks[3].arm, 0, "other armed track stood down")
|
||||
eq(tracks[1].arm, 0, "unarmed bystander untouched")
|
||||
|
||||
-- Re-pointing at the same track must not re-save the borrowed state as if it
|
||||
-- were the original, or restore would hand back grid mode's own settings.
|
||||
G.routePreview(take)
|
||||
G.restoreRouting()
|
||||
eq(tracks[2].arm, 0, "edited track disarmed again")
|
||||
eq(tracks[2].mon, 0, "edited track monitoring restored")
|
||||
eq(tracks[2].input, 0, "edited track input restored")
|
||||
eq(tracks[3].arm, 1, "other track re-armed")
|
||||
eq(tracks[3].mon, 1, "other track monitoring restored")
|
||||
|
||||
-- Restoring twice is harmless, and switching to a take on another track
|
||||
-- returns the first one before borrowing the second.
|
||||
eq(G.restoreRouting(), false, "restore with nothing borrowed")
|
||||
G.routePreview(take)
|
||||
G.routePreview({ track = tracks[1] })
|
||||
eq(tracks[1].arm, 1, "second track armed")
|
||||
eq(tracks[2].arm, 0, "first track handed back on switch")
|
||||
G.restoreRouting()
|
||||
eq(tracks[1].arm, 0, "second track handed back")
|
||||
eq(tracks[3].arm, 1, "bystander still armed at the end")
|
||||
|
||||
print(fails == 0 and "ALL PASS" or (fails .. " FAILURES"))
|
||||
|
||||
Reference in New Issue
Block a user