Skip to content

Instantly share code, notes, and snippets.

@mthines
Last active January 30, 2024 09:38
Show Gist options
  • Select an option

  • Save mthines/c5ae921df6f35eb6b322932a820d0f5a to your computer and use it in GitHub Desktop.

Select an option

Save mthines/c5ae921df6f35eb6b322932a820d0f5a to your computer and use it in GitHub Desktop.
Merge MIDI & to selected tracks - Reaper JSFX

These scripts makes it possible to merge MIDI in Reaper.

Explaination

  • Merge MIDI.lua: Merges MIDI of selected items
  • Render tracks as MIDI Output (obeying time selection).lua: Renders all of the MIDI data of the selected tracks (including the nested child tracks) to new MIDI items (obeying time selection).

Installation

  1. Open Reaper resource path and place the scripts in the Scripts directory (e.g. REAPER\Scripts).
-- @name Merge MIDI
-- @description Merged the selected items into a single MIDI item
-- @author Mads Thines Coello ([email protected])
-- @reference https://www.reapertips.com/post/how-to-merge-midi-in-reaper
-- @version 0.1.0
function mergeMIDI()
-- Item: Set item mix behavior to always mix
reaper.Main_OnCommand(40919, 0);
-- Item: Implode items across tracks into items on one track
reaper.Main_OnCommand(40644, 0);
-- Item: Glue items, ignoring time selection
reaper.Main_OnCommand(40362, 0);
-- Item: Set item mix behavior to project default
reaper.Main_OnCommand(40922, 0);
end
-- Run the main function
function main()
-- Begin a new undo block
reaper.Undo_BeginBlock()
-- Unselect all items
mergeMIDI();
-- End the undo block without registering any changes
reaper.Undo_EndBlock("Merge MIDI", -1)
end
-- Disable UI refresh to prevent flickering
reaper.PreventUIRefresh(1)
main();
-- Enable UI refresh
reaper.PreventUIRefresh(-1)
reaper.UpdateArrange()
-- @name Render tracks as MIDI Output (obeying time selection)
-- @author Mads Thines Coello ([email protected])
-- @version 0.1.0
function saveSelectedTracks()
local selectedTracks = {}
for i = 0, reaper.CountSelectedTracks(0) - 1 do
local selectedTrack = reaper.GetSelectedTrack(0, i)
table.insert(selectedTracks, selectedTrack)
end
return selectedTracks
end
function setTracksAsSelected(tracks)
-- Unselect all tracks
reaper.Main_OnCommand(40297, 0)
for _, track in ipairs(tracks) do
reaper.SetTrackSelected(track, true)
end
reaper.UpdateArrange()
end
-- Insert empty MIDI item in the time selection and select it
function insertEmptyMIDIItemsInTimeSelection()
local startTime, endTime = reaper.GetSet_LoopTimeRange(false, false, 0, 0, false)
if startTime == endTime then
reaper.MB("Error: No time selection set.", "Error", 0)
return
end
local numSelectedTracks = reaper.CountSelectedTracks(0)
if numSelectedTracks == 0 then
reaper.MB("Error: No tracks selected.", "Error", 0)
return
end
local newItems = {}
-- Loop through selected tracks
for i = 0, numSelectedTracks - 1 do
local track = reaper.GetSelectedTrack(0, i)
-- Insert a new MIDI item within the time selection
local newItem = reaper.CreateNewMIDIItemInProj(track, startTime, endTime, false)
-- Select the new MIDI item
reaper.SetMediaItemSelected(newItem, true)
table.insert(newItems, newItem)
end
return newItems
end
-- Recursively select child tracks
function selectAllChildTracks(track)
local numChildTracks = reaper.CountTracks(0)
for i = 0, numChildTracks - 1 do
local childTrack = reaper.GetTrack(0, i)
local parentTrack = reaper.GetParentTrack(childTrack)
if parentTrack and parentTrack == track then
reaper.SetTrackSelected(childTrack, true)
selectAllChildTracks(childTrack) -- Recursively select child tracks of the current child track
end
end
end
function clearSelection()
-- Unselect all items
reaper.Main_OnCommand(40289, 0);
-- Unselect all tracks
reaper.Main_OnCommand(40297, 0);
end
function mergeMIDI()
-- Item: Set item mix behavior to always mix
reaper.Main_OnCommand(40919, 0);
-- Item: Implode items across tracks into items on one track
reaper.Main_OnCommand(40644, 0);
-- Item: Glue items, ignoring time selection
reaper.Main_OnCommand(40362, 0);
-- Item: Set item mix behavior to project default
reaper.Main_OnCommand(40922, 0);
end
function renderNestedMIDIToTrack(selectedTrack)
-- Make sure the selected track is selected
reaper.SetTrackSelected(selectedTrack, true)
-- Recursively select all child tracks
selectAllChildTracks(selectedTrack)
-- Create new empty MIDI items for all tracks so we can apply the MIDI to them
local newItems = insertEmptyMIDIItemsInTimeSelection(track)
-- Apply track/take FX To MIDI items (MIDI Output)
reaper.Main_OnCommand(40436, 0);
-- Crop to Active Take
reaper.Main_OnCommand(40131, 0);
-- Merge the MIDI together into the first selected
mergeMIDI()
-- Rename the merged MIDI item to the name of the Track
local selectedItem = reaper.GetSelectedMediaItem(0, 0)
local track = reaper.GetMediaItem_Track(selectedItem)
local _, trackName = reaper.GetSetMediaTrackInfo_String(track, "P_NAME", "", false)
reaper.GetSetMediaItemTakeInfo_String(reaper.GetActiveTake(selectedItem), "P_NAME", trackName, true)
-- Clear the selection
clearSelection()
end
-- Run the main function
function main()
-- Begin a new undo block
reaper.Undo_BeginBlock()
-- Unselect all items
reaper.Main_OnCommand(40289, 0);
local numSelectedTracks = reaper.CountSelectedTracks(0)
if numSelectedTracks == 0 then
reaper.MB("Error: No tracks selected.", "Error", 0)
return
end
-- Save selected tracks for iteration and restoration later
local selectedTracks = saveSelectedTracks()
-- Iterate over the selected tracks and render them individually to MIDI
for _, selectedTrack in ipairs(selectedTracks) do
renderNestedMIDIToTrack(selectedTrack);
end
-- Clear the selection
clearSelection()
-- Restore the initially selected tracks to the selection
setTracksAsSelected(selectedTracks)
-- End the undo block without registering any changes
reaper.Undo_EndBlock("Render tracks as MIDI Output (obeying time selection)", -1)
end
-- Disable UI refresh to prevent flickering
reaper.PreventUIRefresh(1)
main();
-- Enable UI refresh
reaper.PreventUIRefresh(-1)
reaper.UpdateArrange()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment