Skip to content

Instantly share code, notes, and snippets.

@adalinesimonian
Created April 14, 2021 18:06
Show Gist options
  • Save adalinesimonian/95117229c9fb85e299288f2a3723ffa4 to your computer and use it in GitHub Desktop.
Save adalinesimonian/95117229c9fb85e299288f2a3723ffa4 to your computer and use it in GitHub Desktop.
ReaScript to create instrument tracks for multi-channel VST tracks
-- instrument_track.lua fork v0.1 by Adaline Simonian
-- (@adaline on reaper forums, @adalinesimonian on github)
-- forked from instrument_track.lua v0.2 by Christian Fillion (cfillion)
--
-- use this script while selecting a multi-channel vst track.
--
-- it creates instrument tracks that both send midi and receive audio
-- so make sure that you have feedback in routing enabled (found in
-- project settings -> advanced).
--
-- this script will add tracks after the selection, so if you want
-- new tracks to go after the last created track, just shift+select
-- the next track after you create it. it only looks at the first
-- selected track when routing.
MAX_CHANNEL_COUNT = 64 -- set this to 32 if you only need to use one MIDI busses
MAX_MIDI_BUS = MAX_CHANNEL_COUNT / (16 * 2)
local dbScale = math.log(10.0) * 0.05
---@return table<number, table<integer, integer>>
function GetTrackMidiReceives(track)
---@type table<number, table<integer, integer>>
local list
local index, recvIndex, recvCount
list, index, recvIndex = {}, 0, 0
recvCount = reaper.GetTrackNumSends(track, -1)
while recvIndex < recvCount do
local dstBus, dstChan
dstBus = reaper.BR_GetSetTrackSendInfo(
track, -1, recvIndex, "I_MIDI_DSTBUS", false, 0)
dstChan = reaper.BR_GetSetTrackSendInfo(
track, -1, recvIndex, "I_MIDI_DSTCHAN", false, 0)
if dstBus + dstChan > -1 then
if dstBus == 0 then dstBus = 1 end
list[index] = {BUS=dstBus, CHAN=dstChan}
index = index + 1
end
recvIndex = recvIndex + 1
end
return list
end
---@param sends table<number, table<integer, integer>>
---@return number, number
function GetUnusedMidiChannel(sends)
local index
---@type table<number, number>
local busses
busses = {}
index = 1
while index <= MAX_MIDI_BUS do
busses[index] = 0
index = index + 1
end
for _,send in pairs(sends) do
local bus = math.floor(send["BUS"])
local chan = math.floor(send["CHAN"])
if busses[bus] ~= nil and busses[bus] < chan then
busses[bus] = chan
end
end
for i,chan in pairs(busses) do
if chan <= 15 then
return i,chan+1
end
end
return -1, -1
end
---@return number, number
function GetUnusedSlot(sampler)
local sends = GetTrackMidiReceives(sampler)
return GetUnusedMidiChannel(sends)
end
---@param bus number
---@param chan number
function MidiToAudioChannel(bus, chan)
if bus == 1 then bus = 0 end
return (bus * 16) + (chan - 1) * 2
end
---@return integer
function GetInsertionPoint()
local selectionSize = reaper.CountSelectedTracks(0)
if selectionSize == 0 then
return reaper.GetNumTracks()
end
track = reaper.GetSelectedTrack(0, selectionSize - 1)
return reaper.GetMediaTrackInfo_Value(track, "IP_TRACKNUMBER")
end
reaper.PreventUIRefresh(1)
reaper.Undo_BeginBlock()
local sampler = reaper.GetSelectedTrack(0, 0)
local _, samplerName = reaper.GetSetMediaTrackInfo_String(sampler, "P_NAME", "", 0)
local bus, chan = GetUnusedSlot(sampler)
local audioChan = MidiToAudioChannel(bus, chan)
local insertPos = GetInsertionPoint()
reaper.InsertTrackAtIndex(insertPos, true)
comboTrack = reaper.GetTrack(0, insertPos)
reaper.SetMediaTrackInfo_Value(comboTrack, "I_RECMON", 1)
reaper.SetMediaTrackInfo_Value(comboTrack, "I_RECINPUT", 4096 | 0 | (63 << 5))
reaper.GetSetMediaTrackInfo_String(comboTrack, "P_NAME",
string.format("-> %s %d-%d %d/%d", samplerName, bus, chan, audioChan + 1, audioChan + 2), true)
reaper.SNM_AddReceive(sampler, comboTrack, -1)
reaper.BR_GetSetTrackSendInfo(
comboTrack, -1, 0, "I_SRCCHAN", true, audioChan)
reaper.BR_GetSetTrackSendInfo(
comboTrack, -1, 0, "I_DSTCHAN", true, 0)
reaper.BR_GetSetTrackSendInfo(
comboTrack, -1, 0, "I_MIDI_SRCCHAN", true, -1)
reaper.BR_GetSetTrackSendInfo(
comboTrack, -1, 0, "I_SENDMODE", true, 3)
reaper.SNM_AddReceive(comboTrack, sampler, 0)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "D_VOL", true, math.exp(-2.41 * dbScale))
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_MIDI_LINK_VOLPAN", true, 1)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_SRCCHAN", true, -1)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_MIDI_SRCBUS", true, 0)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_MIDI_SRCCHAN", true, 0)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_MIDI_DSTBUS", true, bus)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_MIDI_DSTCHAN", true, chan)
reaper.BR_GetSetTrackSendInfo(
comboTrack, 0, 0, "I_SENDMODE", true, 3)
reaper.Undo_EndBlock("Create Instrument Track", 1)
reaper.PreventUIRefresh(-1)
reaper.TrackList_AdjustWindows(false)
@adalinesimonian
Copy link
Author

screen capture of script in use

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment