Files
midigrid/MidiGrid_Daemon.lua
T

76 lines
2.4 KiB
Lua
Raw Normal View History

--[[
MIDI Grid: preview daemon.
Runs quietly in the background and owns every preview note-on/note-off.
The action scripts never defer, so they always exit instantly and Reaper
never shows its "already running" prompt no matter how fast keys repeat.
Started automatically by the action scripts; you never need to run it.
]]
local dir = ({ reaper.get_action_context() })[2]:match("@?(.*[\\/])")
local G = dofile(dir .. "midigrid_lib.lua")
-- Refuse to start a second copy.
local hb = tonumber(G.getTemp("hb", "0")) or 0
if os.time() - hb <= 3 then return end
local sounding = {}
local releaseAt = 0
local lastSeq = tonumber(G.getTemp("seq", "0")) or 0
local function allOff()
for _, p in ipairs(sounding) do
reaper.StuffMIDIMessage(0, 0x80, p, 0)
end
sounding = {}
end
local function loop()
G.setTemp("hb", os.time())
local seq = tonumber(G.getTemp("seq", "0")) or 0
if seq ~= lastSeq then
lastSeq = seq
-- A new request cuts whatever is still sounding, so fast arrowing
-- retriggers cleanly instead of piling notes up.
allOff()
local vel = math.floor(G.getNum("vel", 96))
for s in tostring(G.getTemp("pitches", "")):gmatch("%d+") do
local p = tonumber(s)
if p and p >= 0 and p <= 127 then
sounding[#sounding + 1] = p
reaper.StuffMIDIMessage(0, 0x90, p, vel)
end
end
releaseAt = reaper.time_precise() + (tonumber(G.getTemp("dur", "0.4")) or 0.4)
end
if #sounding > 0 and reaper.time_precise() >= releaseAt then
allOff()
end
2026-08-14 20:04:20 +02:00
-- Pending "stop at end of bar" request, posted by the play-one-bar action.
local stopAt = tonumber(G.getTemp("stopat", ""))
if stopAt then
local playing = (reaper.GetPlayState() % 2) == 1
if playing and reaper.GetPlayPosition() >= stopAt 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()
reaper.CSurf_OnStop()
reaper.SetEditCurPos(cur, false, false)
G.setTemp("stopat", "")
elseif not playing
and reaper.time_precise() > (tonumber(G.getTemp("stoparm", "0")) or 0) then
-- Transport stopped by other means; drop the pending request.
G.setTemp("stopat", "")
end
end
reaper.defer(loop)
end
-- Never leave a note hanging if the daemon is terminated or Reaper quits.
reaper.atexit(allOff)
loop()