--[[ * ReaScript Name: Import markers and regions from tab-delimited CSV file * Description: See title. * Instructions: Select a track. Run. * Author: X-Raym * Author URI: http://www.extremraym.com * Repository: GitHub > X-Raym > EEL Scripts for Cockos REAPER * Repository URI: https://github.com/X-Raym/REAPER-EEL-Scripts * Links Forum Thread https://forum.cockos.com/showthread.php?p=1670961 * Licence: GPL v3 * REAPER: 5.0 * Version: 1.0 --]] --[[ * Changelog: * v1.0 (2019-01-26) + Initial Release *** Modified for ReaTrak import chords from biab plugin --]] -- USER CONFIG AREA ----------------------------------------------------------- -- Duplicate and Rename the script if you want to modify this. -- Else, a script update will erase your mods. -- Display a message in the console for debugging function Msg(value) if console then reaper.ShowConsoleMsg(tostring(value) .. "\n") end end console = true -- true/false: display debug messages in the console sep = "," -- default sep --(1)pattern,(2)type,(3)A verse B chorus,(4)weight,(5)mask,(6)duration,(7)bar --(1)shot,(2)0 shot 1 hold,(3)bar,(4)ticks,(5)duration ticks,weight,volume col_part = 1 -- col_bar = 2 -- bar col_beat = 3 -- beat col_name = 4 -- chord name --col_len = 6 -- Length column index in the CSV --col_color = 5 --col_pattern = 7 --col_ticks = 8 bpm, beat_per_measure = reaper.GetProjectTimeSignature2(0) ------------------------------------------------------- END OF USER CONFIG AREA function ColorHexToInt(hex) hex = hex:gsub("#", "") local R = tonumber("0x"..hex:sub(1,2)) local G = tonumber("0x"..hex:sub(3,4)) local B = tonumber("0x"..hex:sub(5,6)) return reaper.ColorToNative(R, G, B) end -- Optimization local reaper = reaper -- CSV to Table -- http://lua-users.org/wiki/LuaCsv function ParseCSVLine (line,sep) --[[ local line = string.gsub(line, "{.*}", "") -- remove { } and text between them local line = string.gsub(line, ";.*", "") -- remove ; and text after it local line = string.gsub(line, "pattern,PreFill.*", "") -- remove pattern,PreFill line --]] local line = string.gsub(line, "Chord=", "Chord,") -- replace = with , local line = string.gsub(line, "PartMarker=", "PartMarker,") -- replace = with , --if line == string.match(line, "Chord.*") then line = line --else line = "" --end --Msg("Line ".. line) local res = {} local pos = 1 sep = sep or ',' while true do local c = string.sub(line,pos,pos) if (c == "") then break end if (c == '"') then -- quoted value (ignore separator within) local txt = "" repeat local startp,endp = string.find(line,'^%b""',pos) txt = txt..string.sub(line,startp+1,endp-1) pos = endp + 1 c = string.sub(line,pos,pos) if (c == '"') then txt = txt..'"' end -- check first char AFTER quoted string, if it is another -- quoted string without separator, then append it -- this is the way to "escape" the quote char in a quote. example: -- value1,"blub""blip""boing",value3 will result in blub"blip"boing for the middle until (c ~= '"') table.insert(res,txt) assert(c == sep or c == "") pos = pos + 3 else -- no quotes used, just look for the first separator local startp,endp = string.find(line,sep,pos) if (startp) then table.insert(res,string.sub(line,pos,startp-1)) pos = endp + 1 else -- no separator found -> use rest of string and terminate table.insert(res,string.sub(line,pos)) break end end end return res end -- UTILITIES ------------------------------------------------------------- -- Display a message in the console for debugging function Msg(value) if console then reaper.ShowConsoleMsg(tostring(value) .. "\n") end end function ReverseTable(t) local reversedTable = {} local itemCount = #t for k, v in ipairs(t) do reversedTable[itemCount + 1 - k] = v end return reversedTable end --------------------------------------------------------- END OF UTILITIES function cursor_start() -- local (i, j, item, take, track) reaper.Undo_BeginBlock() -- Begining of the undo block. Leave it at the top of your main function. if reaper.GetPlayState() == 0 or reaper.GetPlayState == 2 then cursor_pos = reaper.GetCursorPosition() --msg_stl("proj time decimal", cursor_pos, 1) buf = reaper.format_timestr_pos(cursor_pos, "", 3) --msg_stl("proj time string", buf, 1) time = tonumber(buf) --msg_ftl("proj time decimal", time, 1) offset = cursor_pos - time --msg_ftl("offset", time, 1) reaper.SetEditCurPos(offset, 1, 0) end reaper.UpdateArrange() -- Update the arrangement (often needed) end function read_lines(filepath) lines = {} local f = io.input(filepath) repeat s = f:read ("*l") -- read one line if s then -- if not end of file (EOF) table.insert(lines, ParseCSVLine (s,sep)) end until not s -- until end of file f:close() end function get_song_values() vars = {} for line in io.lines(filetxt) do line = string.gsub(line, ";.*", "") -- remove ; and text after it --var, val = line:match('^([^=]+)=(.*)') var, bar_pos, a_b = line:match('(PartMarker=),(.*),(.*)') --if var then Msg("".. var .."=".. val) end if var == "wavename" then wavename1 = val end --Msg("wavename# ".. wavename) end if var == "TimeSig" then timesig = val end --Msg("TimeSig# ".. timesig) end if var == "Offset" then rd_offset = val end if var == "OFFSET" then rd_offset = val end if not line then end end end function set_part_markers() local count_markers_regions, count_markersOut, count_regionsOut = reaper.CountProjectMarkers(0) --Msg("bar start ".. bar) for i = bar, count_markersOut -1 do local retval, isrgn, rgnpos, rgnend, rgnname, markrgnindexnumber, rgncolor = reaper.EnumProjectMarkers3(0, count_markersOut -1) reaper.SetProjectMarker3( 0, markrgnindexnumber, false, rgnpos, rgnend, rgnname, part_marker_color ) end end function last_marker_to_region() bars_4 = ((((4) * beat_per_measure)/ bpm) * 60) --USES BARS BEATS NOW count_markers_regions, count_markersOut, count_regionsOut = reaper.CountProjectMarkers(0) retval, isrgn, rgnpos2, rgnend, rgnname2, markrgnindexnumber2, rgncolor2 = reaper.EnumProjectMarkers3(0, count_markers_regions -1) --reaper.DeleteProjectMarker( 0, markrgnindexnumber2 +1, true ) reaper.DeleteProjectMarkerByIndex( 0, markrgnindexnumber2 -1 ) reaper.SetEditCurPos2( 0, rgnpos2, 0, 0 ) reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure cur_pos = reaper.GetCursorPosition() --reaper.DeleteProjectMarkerByIndex( 0, markrgnindexnumber2 ) reaper.AddProjectMarker2(0, true, rgnpos2, cur_pos, rgnname2, -1, rgncolor2) end function snap_all_regions_to_grid() --NOT NEEDED reaper.SnapToGrid is used in other functions --commandID1 = reaper.NamedCommandLookup("_RS76d8155a5e6dec780974821d3f81a4da6e92e5bf") --reaper.Main_OnCommand(commandID1, 0) -- Script: ReaTrak snap all regions to grid.lua --[[ reaper.Main_OnCommand(40754, 0) -- Enable snap region_count , num_markersOut, num_regionsOut = reaper.CountProjectMarkers(0) for i=0, region_count -1 do --EnumProjectMarkers(i, is_region, region_start, region_end, #name, region_id) retval, isrgnOut, posOut, rgnendOut, region_name, markrgnindexnumberOut, colorOut = reaper.EnumProjectMarkers3(0, i) --if isrgnOut then region_snapped_start = reaper.SnapToGrid(0, posOut) region_snapped_end = reaper.SnapToGrid(0, rgnendOut) --SetProjectMarker(region_id, 1, region_snapped_start, region_snapped_end, #name) reaper.SetProjectMarker3( 0, markrgnindexnumberOut, true, region_snapped_start, region_snapped_end, region_name , colorOut ) reaper.SetProjectMarker3( 0, markrgnindexnumberOut, false, region_snapped_start, region_snapped_end, region_name , colorOut ) end --]] end -- Main function function main() --convert bar location and length from bars to time for i, line in ipairs( lines ) do --if line[col_part] == "Chord" then if i > 1 and line[col_part] == "Chord" then --or line[col_part] == "PartMarker" then -- Name Variables local part = line[col_part] local bar = line[col_bar] local beat = line[col_beat] local bar_beat = (line[col_bar] +1 ) + ( (line[col_beat] -1) / beat_per_measure) local name = line[col_name] --local color = 0 pos = ((((bar_beat) * beat_per_measure)/ bpm) * 60) --USING BAR BEAT POSITION NOW reaper.Main_OnCommand(40042, 0) -- Transport: Go to start of projectp reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure set_cur = 0 --while (set_cur < tonumber(bar)) do for i = 1, tonumber(bar) do reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure --reaper.MB("Select Item", "Select an Item", 0) cur_pos1 = reaper.GetCursorPosition() cur_pos = reaper.SnapToGrid(0, cur_pos1) --Msg("set_cur ".. set_cur .." bar ".. tonumber(bar)) set_cur = set_cur +1 end if set_cur == tonumber(bar) and tonumber(beat) > 1 then for i = 2, tonumber(beat) do cur_pos1 = reaper.GetCursorPosition() cur_pos = reaper.SnapToGrid(0, cur_pos1) retval, measures, cml, fullbeats, cdenom = reaper.TimeMap2_timeToBeats(0, cur_pos) current_measure = reaper.TimeMap2_beatsToTime(0, fullbeats +1) reaper.SetEditCurPos2( 0, current_measure, 0, 0 ) end -- For swing beat pos https://forum.cockos.com/showthread.php?t=220305 function unswingbeats(proj, beatpos) -- TimeMap2_timetoBeats() local retval, division, swing, swingamt = reaper.GetSetProjectGrid(proj,false) if swing and swingamt ~= 0 and division > 0 then beatpos = beatpos / (division*4) swingamt = swingamt*.5 local fullb = math.floor(beatpos/2)*2 beatpos = beatpos - fullb -- beatpos is [0..2), map 1+swingamt to 1 local div = 1+swingamt if beatpos <= div then beatpos = beatpos / div else beatpos = 1.0 + (beatpos - div) / (2 - div) end beatpos = (fullb + beatpos) * division * 4 end return beatpos end function swingbeats(proj, beatpos) -- TimeMap2_beatsToTime() local retval, division, swing, swingamt = reaper.GetSetProjectGrid(proj,false) if swing and swingamt ~= 0 and division > 0 then beatpos = beatpos / (division*4) local fullb = math.floor(beatpos/2)*2 beatpos = beatpos - fullb -- beatpos is [0..2), swingamt is -1..1, map 1 to 1+swingamt*.5 beatpos = beatpos + (swingamt*.5)*(1-math.abs(beatpos-1)) beatpos = (fullb + beatpos) * division * 4 end return beatpos end end cur_pos1 = reaper.GetCursorPosition() cur_pos = reaper.SnapToGrid(0, cur_pos1) color = ColorHexToInt("#3776EB")|0x1000000 count_in = ColorHexToInt("#FF80C0")|0x1000000 reaper.AddProjectMarker2(0, false, cur_pos, 0, name, -1, color) end end retval, isrgn, pos, rgnend, first_chord, markrgnindexnumber, color = reaper.EnumProjectMarkers3( 0, 0 ) reaper.AddProjectMarker2(0, false, 0, 0, first_chord, -1, count_in) end -- Main function 2 function main2() folder = filetxt:match[[^@?(.*[\/])[^\/]-$]] --Msg("folder ".. folder) --convert bar location and length from bars to time for i, line in ipairs( lines ) do --if line[col_part] == "Chord" then if i > 1 and line[col_part] == "PartMarker" then --or line[col_part] == "PartMarker" then -- Name Variables local part = line[col_part] local bar = line[col_bar] local beat = line[col_beat] --local bar_beat = (line[col_bar] ) + ( (line[col_beat] -1) / beat_per_measure) local name = line[col_name] if beat == "1" then part_marker_color = ColorHexToInt("#3776EB")|0x1000000 end if beat == "2" then part_marker_color = ColorHexToInt("#11AE3B")|0x1000000 end --Msg("beat= ".. beat) --bar = bar --Msg("bar ".. bar) --pos = ((((bar_beat) * beat_per_measure)/ bpm) * 60) --bar_pos = ((((bar+1) * beat_per_measure)/ bpm) * 60) --USES BARS BEATS NOW reaper.Main_OnCommand(40042, 0) -- Transport: Go to start of projectp reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure set_cur = 1 while (set_cur < tonumber(bar)+1) do reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure cur_pos = reaper.GetCursorPosition() set_cur = set_cur +1 end --Msg("Bar pos ".. set_cur .." @ ".. cur_pos) bar_pos = cur_pos reaper.SetEditCurPos2( 0, bar_pos, 0, 0 ) --set_part_markers() local count_markers_regions, count_markersOut, count_regionsOut = reaper.CountProjectMarkers(0) for i = 0 , count_markersOut -1 do local retval, isrgn, rgnpos, rgnend, rgnname, markrgnindexnumber, rgncolor = reaper.EnumProjectMarkers3(0, i) if bar_pos == rgnpos then i_pos = i break end --reaper.SetProjectMarker3( 0, markrgnindexnumber, false, rgnpos, rgnend, rgnname, part_marker_color ) end local count_markers_regions, count_markersOut, count_regionsOut = reaper.CountProjectMarkers(0) for s = i_pos , count_markersOut -1 do local retval, isrgn, rgnpos, rgnend, rgnname, markrgnindexnumber, rgncolor = reaper.EnumProjectMarkers3(0, s) reaper.SetProjectMarker3( 0, markrgnindexnumber, false, rgnpos, rgnend, rgnname, part_marker_color ) end end end end function split_region() local retval, num_markers, num_regionsOut = reaper.CountProjectMarkers(0) local desired_region_id = num_regionsOut local time1 = reaper.GetCursorPosition() local time = reaper.SnapToGrid(0, time1) local markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, time) local retval, isrgn, pos, rgnend, name, markrgnindexnumber, color = reaper.EnumProjectMarkers3(0, regionidx) if time == pos then goto finish end if time < rgnend then reaper.SetProjectMarker3( 0, markrgnindexnumber, 1, pos, time, name, color ) reaper.AddProjectMarker2(0, true, time, rgnend, name, desired_region_id, color) end ::finish:: end function pre_post_fill_regions() folder = filetxt:match[[^@?(.*[\/])[^\/]-$]] --Msg("folder ".. folder) --convert bar location and length from bars to time for i, line in ipairs( lines ) do --if line[col_part] == "Chord" then if i > 1 and line[col_part] == "PartMarker" then --or line[col_part] == "PartMarker" then -- Name Variables local part = line[col_part] local bar = line[col_bar] local beat = line[col_beat] --local bar_beat = (line[col_bar] ) + ( (line[col_beat] -1) / beat_per_measure) local name = line[col_name] --if beat == "1" then part_marker_color = ColorHexToInt("#3776EB")|0x1000000 end --if beat == "2" then part_marker_color = ColorHexToInt("#11AE3B")|0x1000000 end --bar = bar --Msg("bar ".. bar) --pos = ((((bar_beat) * beat_per_measure)/ bpm) * 60) bar_pos = ((((bar+1) * beat_per_measure)/ bpm) * 60) reaper.Main_OnCommand(40042, 0) -- Transport: Go to start of projectp reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure set_cur = 0 while (set_cur < tonumber(bar)) do reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure cur_pos1 = reaper.GetCursorPosition() cur_pos = reaper.SnapToGrid(0, cur_pos1) set_cur = set_cur +1 end --reaper.SetEditCurPos2( 0, bar_pos, 0, 0 ) bar_pos = cur_pos if tonumber(bar) > 1 then reaper.Main_OnCommand(41043, 0) -- Move edit cursor back one measure time = reaper.GetCursorPosition() grid_pos = reaper.SnapToGrid(0, time) reaper.SetEditCurPos2(0, grid_pos, false, false) split_region() time = reaper.GetCursorPosition() markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, time) retval, isrgn, pos, rgnend, name, markrgnindexnumber, color = reaper.EnumProjectMarkers3(0, regionidx) if color == ColorHexToInt("#3776EB")|0x1000000 then part_marker_color = ColorHexToInt("#71BEF1")|0x1000000 end -- verse fill if color == ColorHexToInt("#11AE3B")|0x1000000 then part_marker_color = ColorHexToInt("#50ED7B")|0x1000000 end -- chorus fill time = reaper.GetCursorPosition() markrgnindexnumber, rgnendOut = reaper.GetLastMarkerAndCurRegion(0, time) retval, isrgnOut, posOut, rgnendOut, nameOut, markrgnindexnumberOut = reaper.EnumProjectMarkers(rgnendOut) reaper.SetProjectMarker3( 0, markrgnindexnumberOut, true, posOut, rgnendOut, nameOut, part_marker_color ) reaper.Main_OnCommand(41042, 0) -- Move edit cursor forward one measure time = reaper.GetCursorPosition() grid_pos = reaper.SnapToGrid(0, time) reaper.SetEditCurPos2(0, grid_pos, false, false) end reaper.Main_OnCommand(41042, 0) -- Move edit cursor forward one measure time = reaper.GetCursorPosition() grid_pos = reaper.SnapToGrid(0, time) reaper.SetEditCurPos2(0, grid_pos, false, false) split_region() reaper.Main_OnCommand(41043, 0) -- Move edit cursor back one measure time = reaper.GetCursorPosition() grid_pos = reaper.SnapToGrid(0, time) reaper.SetEditCurPos2(0, grid_pos, false, false) time = reaper.GetCursorPosition() markeridx, regionidx = reaper.GetLastMarkerAndCurRegion(0, time) retval, isrgn, pos, rgnend, name, markrgnindexnumber, color = reaper.EnumProjectMarkers3(0, regionidx) if color == ColorHexToInt("#3776EB")|0x1000000 then part_marker_color = ColorHexToInt("#1127AE")|0x1000000 end -- verse post fill if color == ColorHexToInt("#11AE3B")|0x1000000 then part_marker_color = ColorHexToInt("#0B7427")|0x1000000 end -- chorus post fill time = reaper.GetCursorPosition() markrgnindexnumber, rgnendOut = reaper.GetLastMarkerAndCurRegion(0, time) retval, isrgnOut, posOut, rgnendOut, nameOut, markrgnindexnumberOut = reaper.EnumProjectMarkers(rgnendOut) reaper.SetProjectMarker3( 0, markrgnindexnumberOut, true, posOut, rgnendOut, nameOut, part_marker_color ) end end bars_4 = ((((4) * beat_per_measure)/ bpm) * 60) --USING BAR BEATS NOW retval, num_markers, num_regions = reaper.CountProjectMarkers(0) reaper.DeleteProjectMarker( 0, num_regions, true ) time = reaper.GetCursorPosition() markrgnindexnumber, rgnendOut = reaper.GetLastMarkerAndCurRegion(0, time) reaper.SetEditCurPos2( 0, time, 0, 0 ) reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure reaper.Main_OnCommand(41040, 0) -- Move edit cursor to start of next measure ending_end1 = reaper.GetCursorPosition() ending_end = reaper.SnapToGrid(0, ending_end1) retval, isrgn, pos, rgnend, name, markrgnindexnumber, color = reaper.EnumProjectMarkers3(0, rgnendOut) --if color == ColorHexToInt("#3776EB")|0x1000000 then part_marker_color = ColorHexToInt("#1127AE")|0x1000000 end -- verse post fill --if color == ColorHexToInt("#11AE3B")|0x1000000 then part_marker_color = ColorHexToInt("#0B7427")|0x1000000 end -- chorus post fill if color == ColorHexToInt("#1127AE")|0x1000000 then part_marker_color = ColorHexToInt("#97D0FE")|0x1000000 end -- verse ending if color == ColorHexToInt("#0B7427")|0x1000000 then part_marker_color = ColorHexToInt("#9EF5B6")|0x1000000 end -- chorus ending reaper.SetProjectMarker3( 0, markrgnindexnumberOut, true, pos, ending_end, name, part_marker_color ) end -- OS BASED SEPARATOR if reaper.GetOS() == "Win32" or reaper.GetOS() == "Win64" then -- user_folder = buf --"C:\\Users\\[username]" -- need to be test separator = "\\" else -- user_folder = "/USERS/[username]" -- Mac OS. Not tested on Linux. separator = "/" end --retval, filetxt = reaper.GetUserFileNameForRead("", "Import Song.txt in bb folder", "txt") inipath = reaper.get_ini_file() retval_folder, bb_folder = reaper.BR_Win32_GetPrivateProfileString("reaper", "reatrak_bb_folder", "", inipath) --Msg("bb_folder in ini= ".. bb_folder) --Msg("retval_folder ".. retval) --bb_folder = "C:".. separator .."bb" --_.. separator if retval_folder > 0 then --bb_folder = string.gsub(bb_folder, [[\]], separator ) --Msg("ini val= ".. bb_folder) filetxt = bb_folder .. "Song.txt" end if retval_folder == 0 then reaper.MB("Browse to the bb folder and select Song.txt", "Import Song.txt in bb folder", 0) retval, filetxt = reaper.GetUserFileNameForRead("Song.txt", "Import Song.txt in bb folder", "txt") end if retval == true then --Msg("File Manually Opened") bb_dir = filetxt:match[[^@?(.*[\/])[^\/]-$]] --Msg("bb_dir ".. bb_dir) reaper.BR_Win32_WritePrivateProfileString( "reaper", "reatrak_bb_folder", bb_dir, inipath ) end if retval == false then reaper.defer(function () end) return end curpos = reaper.GetCursorPosition() reaper.PreventUIRefresh(1) reaper.Undo_BeginBlock() -- Begining of the undo block. Leave it at the top of your main function. reaper.ClearConsole() read_lines(filetxt) -- reaper.Main_OnCommand( reaper.NamedCommandLookup( "_SWSMARKERLIST10" ), -1) -- SWS: Delete all regions main() --snap_all_regions_to_grid() main2() --snap_all_regions_to_grid() reaper.Main_OnCommand(40898, 0) -- Markers: Renumber all markers in timeline order snap_all_regions_to_grid() commandID1 = reaper.NamedCommandLookup("_SWSMARKERLIST13") reaper.Main_OnCommand(commandID1, 0) -- SWS: Convert markers to regions snap_all_regions_to_grid() last_marker_to_region() snap_all_regions_to_grid() --retval, input = reaper.GetUserInputs("Color Pre & Post Fill Regions", 1, "Color Pre-Post Fills ? no cancel", "yes") Fill_Info = [[ Color the Pre & Post Fills ? ]] overwrite = reaper.MB(Fill_Info, "Color Pre & Post Fill Regions", 4) if overwrite == 6 then pre_post_fill_regions() end --if overwrite == 7 then --style_exists = 1 goto skip --end --if retval then --pre_post_fill_regions() --end snap_all_regions_to_grid() reaper.Undo_EndBlock("ReaTrak import chords from biab plugin", -1) -- End of the undo block. Leave it at the bottom of your main function. reaper.UpdateArrange() reaper.PreventUIRefresh(-1) reaper.defer(function () end) --reaper.SetEditCurPos( curpos, 0, 0 ) --commandID10 = reaper.NamedCommandLookup("_RS8271ddb3a652d6fe57b7abc7efadff407c8da2d0") --reaper.Main_OnCommand(commandID10, 0) -- Script: ReaTrak move edit cursor to start of project.lua cursor_start() commandID11 = reaper.NamedCommandLookup("_SWSMARKERLIST8") reaper.Main_OnCommand(commandID11, 0) -- SWS: Renumber region IDs --end