Created
April 14, 2021 18:06
-
-
Save adalinesimonian/95117229c9fb85e299288f2a3723ffa4 to your computer and use it in GitHub Desktop.
ReaScript to create instrument tracks for multi-channel VST tracks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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) |
Author
adalinesimonian
commented
Apr 15, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment