├── .gitignore ├── .vscode └── tasks.json ├── Alpha ├── Sexan_Track_versions_core.lua └── Sexan_Track_versions_gui.lua ├── ApiParser ├── DefinitionsOutput │ ├── imgui_pre09_defs.lua │ └── reaper_defs.lua ├── ImGuiDefinitions.lua ├── ReaperDefinitionsGenerator.lua └── api_imgui_pre09.txt ├── Area51 ├── Area_51_RW.lua └── Modules │ ├── Area_51_class.lua │ ├── Area_51_functions.lua │ ├── Area_51_functions_code.lua │ ├── Area_51_ghosts.lua │ ├── Area_51_key_functions.lua │ ├── Area_51_keyboard.lua │ └── Area_51_mouse.lua ├── Debug ├── DBG_test.lua ├── LoadDebug.lua └── Modules │ ├── dkjson.lua │ ├── mobdebug.lua │ ├── socket.lua │ └── socket │ └── core.dll ├── Edit_Groups ├── Edit_groups.lua └── Utils │ └── Mouse.lua ├── FX ├── Sexan_FX_Browser_Parser.lua └── Sexan_FX_Browser_ParserV7.lua ├── ImGui_Tools ├── FX_Browser_Standalone.lua ├── FileManager.lua ├── PluginScreenShooter.lua └── Sexan_Chunk_Viewer.lua ├── Items ├── Sexan_Set Item and take volume of previous odd to next even items.lua ├── Sexan_SmartSplit items crossfade left or right.lua └── Sexan_select all other items on track.lua ├── Lil_Series ├── Lil_Item_Homie.lua └── Lil_Track_Homie.lua ├── Other ├── Sexan_ChordGun_Pad.lua ├── Sexan_Remove in order time selection items tracks.lua └── Sexan_Show midi note name in tooltip.lua ├── ParanormalFX ├── FXChains │ ├── 3BANDSTOCK.RfxChain │ ├── 4BANDSTOCK.RfxChain │ ├── 5BANDSTOCK.RfxChain │ ├── LEWLOIWC_2_4_MODE_SETUP.RfxChain │ ├── LEWLOIWC_2_BANDNOTCH_SETUP.RfxChain │ ├── LEWLOIWC_2_COMBPHASE_SETUP.RfxChain │ ├── LEWLOIWC_3_MIN_PHASE_SETUP.RfxChain │ ├── LEWLOIWC_ENVELOPE_SETUP.RfxChain │ ├── LEWLOIWC_GATE_SETUP.RfxChain │ ├── LEWLOIWC_TRANSIENT_SETUP.RfxChain │ ├── MS_SETUP.RfxChain │ ├── SAIKE_2_SETUP.RfxChain │ ├── SAIKE_3_SETUP.RfxChain │ ├── SAIKE_4_SETUP.RfxChain │ └── SAIKE_5_SETUP.RfxChain ├── Fonts │ ├── Icons.ttf │ └── ProggyClean.ttf ├── JSFX │ ├── MSMidFX.jsfx │ └── MSSideFX.jsfx ├── Modules │ ├── Canvas.lua │ ├── ContainerCode.lua │ ├── Drawing.lua │ ├── Functions.lua │ ├── Utils.lua │ └── flux.lua └── Sexan_ParaNormal_FX_Router.lua ├── Pie3000 ├── Common.lua ├── CustomImages │ └── Readme.txt ├── PieUtils.lua ├── PieXYZSetup.lua ├── Roboto-Medium.ttf ├── Sexan_Pie3000.lua ├── Sexan_Pie3000_Setup.lua ├── Sexan_Pie3000_Tracker_BG.lua ├── Sexan_PieCleanFiles.lua ├── easing.lua └── fontello1.ttf ├── PieMenu ├── Pie.lua ├── PieICONS.ttf ├── PieSetup.lua ├── PieUtils.lua ├── easing.lua └── pie_menus.txt ├── Project ├── Sexan_Multi_project_time_counter.lua └── Sexan_Project time counter with AFK mode.lua ├── README.md ├── ReaSpaghetti ├── Docs │ └── ReaSpaghetti.pdf ├── Examples │ ├── Envelopes_Increase_Points_Bellow_Threshold.reanodes │ ├── Function_Advance.reanodes │ ├── Functions_Basic.reanodes │ ├── IMGUI_ITEMS.reanodes │ ├── Imgui.reanodes │ ├── SCHWA │ │ ├── BG.png │ │ ├── Explosion.png │ │ ├── MENU.png │ │ ├── Schwa_ATTACK.png │ │ ├── Schwa_IDLE.png │ │ ├── invader.png │ │ ├── invader2.png │ │ └── squid.png │ ├── SCHWARMINATOR.reanodes │ ├── Toggle_Mute_Tracks.reanodes │ └── Track_volume_defer.reanodes ├── ExportedActions │ └── dummy.lua ├── Library │ ├── GetAllSelectedTracksItems.reanlib │ ├── GetSelectedTracks.reanlib │ ├── MUTE_TRACK_ITEMS.reanlib │ └── SET_VOLUME_ALL_TRACKS.reanlib ├── Modules │ ├── APIParser.lua │ ├── Canvas.lua │ ├── CustomFunctions.lua │ ├── Defaults.lua │ ├── ExportToAction.lua │ ├── FileManager.lua │ ├── Flow.lua │ ├── Library.lua │ ├── NodeDraw.lua │ ├── ProFi.lua │ ├── UI.lua │ ├── Undo.lua │ ├── Utils.lua │ ├── flux.lua │ ├── glue.lua │ ├── inspect.lua │ ├── json.lua │ ├── path2d_bezier3.lua │ ├── path2d_bezier3_hit.lua │ ├── path2d_bezier_length.lua │ ├── path2d_point.lua │ └── profiler.lua ├── Sexan_ReaSpaghetti.lua ├── api_file.txt └── ultra_api.txt ├── Theme └── V6_Button_organizer.lua ├── Track ├── Sexan_Create VCA master from selection.lua ├── Sexan_Folder record monitor arming childs.lua └── Sexan_Remove selected VCA master and its slaves with all flags.lua ├── Utils ├── Key_Intercept.lua └── PipeWireConfig.lua ├── VirtualTrack ├── Images │ ├── VT_icon_empty.png │ └── comp_test.png ├── Modules │ ├── Utils.lua │ └── VTCommon.lua ├── Shortcuts │ ├── VT_Activate_lane_under_mouse.lua │ ├── VT_Copy_to_Comp.lua │ ├── VT_CreateNew.lua │ ├── VT_Delete.lua │ ├── VT_Duplicate.lua │ ├── VT_New_COMP.lua │ ├── VT_Rename.lua │ ├── VT_SWIPE_to_Comp_HOLD.lua │ ├── VT_SWIPE_to_Comp_TOGGLE.lua │ ├── VT_ShowAll.lua │ ├── VT_Switch_DOWN.lua │ └── VT_Switch_UP.lua ├── Virtual_track_Mouse.lua └── Virtual_track_SelTrack.lua └── index.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/* 2 | 3 | 4 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Run Reaper Script", 6 | "type": "shell", 7 | "command": "C:/REAPER/reaper.exe", 8 | "args": [ 9 | "-nonewinst", 10 | "${file}" 11 | ], 12 | "problemMatcher": [], 13 | "presentation": { 14 | "reveal": "never" 15 | } 16 | }, 17 | { 18 | "label": "Debug Script", 19 | "command": "${command:workbench.action.debug.start}" 20 | }, 21 | { 22 | "label": "Debug and Run", 23 | "dependsOrder": "parallel", 24 | "dependsOn": [ 25 | "Debug Script", 26 | "Run Reaper Script" 27 | ], 28 | "problemMatcher": [] 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /Area51/Modules/Area_51_functions.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.07 5 | * NoIndex: true 6 | --]] 7 | local reaper = reaper 8 | local refresh_tracks, update, update_all 9 | 10 | function Delete(tr, src_tr, data, t_start, t_dur, t_offset, job) 11 | if not data then return end 12 | split_or_delete_items(tr, data.items, t_start, t_dur, job) 13 | --insert_edge_points(tr, t_start, t_dur, 0) 14 | del_env(tr, t_start, t_dur, 0) 15 | del_AI(tr, nil, t_start, t_dur, 0) 16 | update_all = true 17 | end 18 | 19 | function Split(tr, src_tr, data, t_start, t_dur, t_offset, job) 20 | if not data then return end 21 | split_or_delete_items(tr, data.items, t_start, t_dur, job) 22 | update_all = true 23 | end 24 | 25 | function Paste(tr, src_tr, data, t_start, t_dur, t_offset, job) 26 | if not data then return end 27 | local offset = t_offset - t_start 28 | create_item(tr, data.items, t_start, t_dur, offset, job) 29 | paste_env(tr, src_tr, data.env_points, t_start, t_dur, offset, job) 30 | Paste_AI(tr, src_tr, data.AI, t_start, t_dur, offset, job) 31 | refresh_tracks = true 32 | end 33 | 34 | function Duplicate(tr, src_tr, data, t_start, t_dur, t_offset, job) 35 | if not data then return end 36 | local offset = t_dur 37 | create_item(tr, data.items, t_start, t_dur, offset, job) 38 | paste_env(tr, src_tr, data.env_points, t_start, t_dur, offset, job) 39 | Paste_AI(tr, src_tr, data.AI, t_start, t_dur, offset, job) 40 | update = true 41 | end 42 | 43 | function Area_function(tbl,func) 44 | if not tbl then return end -- IF THERE IS NO TABLE OR TABLE HAS NO DATA RETURN 45 | local tr_offset = copy and Mouse_track_offset() or 0 46 | local BUFFER = Get_area_table("Copy") 47 | reaper.Undo_BeginBlock() 48 | reaper.PreventUIRefresh(1) 49 | 50 | for a = 1, #tbl do 51 | local tbl_t = tbl[a] 52 | local area_pos_offset = 0 53 | area_pos_offset = area_pos_offset + (tbl_t.time_start - lowest_start()) -- OFFSET BETWEEN AREAS 54 | local total_pos_offset = mouse.p + area_pos_offset 55 | 56 | for i = 1, #tbl_t.sel_info do -- LOOP THRU AREA DATA 57 | local sel_info_t = tbl_t.sel_info[i] 58 | local target_track = sel_info_t.track -- AREA TRACK 59 | local new_tr, under = Track_from_offset(target_track, tr_offset) 60 | new_tr = under and Insert_track(under) or new_tr 61 | new_tr = env_offset_new(tbl_t.sel_info, target_track, new_tr, tbl_t.sel_info[i].env_name) or new_tr 62 | 63 | if reaper.ValidatePtr(new_tr, "MediaTrack*") and reaper.ValidatePtr(target_track, "TrackEnvelope*") then 64 | new_tr = get_set_envelope_chunk(new_tr, target_track) 65 | end 66 | 67 | local off_tr = copy and new_tr or target_track -- OFFSET TRACK ONLY IF WE ARE IN COPY MODE 68 | local data = ((#BUFFER ~= 0 and BUFFER[a].sel_info[i]) and (BUFFER[a].guid == tbl[a].guid)) and BUFFER[a].sel_info[i] or sel_info_t 69 | _G[func](off_tr, target_track, data, tbl_t.time_start, tbl_t.time_dur, total_pos_offset, func) 70 | end 71 | 72 | if update then 73 | tbl_t.time_start = (func == "Duplicate") and tbl_t.time_start + tbl_t.time_dur or tbl_t.time_start 74 | tbl_t.sel_info = GetSelectionInfo(tbl_t) 75 | update = nil 76 | end 77 | 78 | if update_all then 79 | local areas_tbl = Get_area_table("Areas") 80 | Ghost_unlink_or_destroy(areas_tbl, "Delete") 81 | for i = 1, #areas_tbl do 82 | areas_tbl[i].sel_info = GetSelectionInfo(areas_tbl[i]) 83 | end 84 | update_all = nil 85 | end 86 | end 87 | 88 | reaper.Undo_EndBlock("A51 " .. func, 4) 89 | reaper.PreventUIRefresh(-1) 90 | --reaper.UpdateTimeline() 91 | reaper.UpdateArrange() 92 | if refresh_tracks then 93 | GetTracksXYH() -- CALL AFTER PreventUIRefresh SINCE TRACK COORDINATE DO NOT UPDATE 94 | refresh_tracks = false 95 | end 96 | end 97 | 98 | ------------------------------------------- D R A G ---------------------------------------------------- 99 | function Split_for_move(tbl) 100 | if not tbl then return end 101 | for i = 1, #tbl.sel_info do 102 | split_or_delete_items(tbl.sel_info[i].track, tbl.sel_info[i], tbl.time_start, tbl.time_dur, "Split_for_move") 103 | tbl.sel_info[i].items = get_items_in_as(tbl.sel_info[i].track, tbl.time_start, tbl.time_start + tbl.time_dur) 104 | end 105 | update_all = true 106 | end 107 | 108 | function Clean(dst_tbl, src_tbl, dst_t, src_t) 109 | for i = 1, #dst_tbl do 110 | local dst_tr = dst_tbl[i].track 111 | local src_tr = src_tbl[i].track 112 | del_env(src_tr, src_t[1], src_t[2], 0) 113 | del_env(dst_tr, dst_t[1], dst_t[2], 0) 114 | if dst_tr ~= src_tr then -- ONYLY MOVE AIS ON OTHER TRACKS IF DESTINATION AND SOURCE ARE DIFFERENT 115 | del_AI(src_tr, nil, src_t[1], src_t[2], 0) 116 | del_AI(dst_tr, nil, dst_t[1], dst_t[2], 0) 117 | end 118 | end 119 | end 120 | 121 | function C_move(new_tr, src_tr, src_data, src_time_start, src_time_dur, src_dst_offset) 122 | Move_items(new_tr, src_data.items, src_dst_offset) 123 | paste_env(new_tr, src_tr, src_data.env_points, src_time_start, src_time_dur, src_dst_offset) 124 | if new_tr ~= src_tr then -- ONYLY MOVE AIS ON OTHER TRACKS IF DESTINATION AND SOURCE ARE DIFFERENT 125 | Paste_AI(new_tr, src_tr, src_data.AI, src_time_start, src_time_dur, src_dst_offset) 126 | else 127 | Move_AIs(new_tr, src_data.AI, src_dst_offset) 128 | end 129 | end 130 | 131 | function C_drag_copy(new_tr, src_tr, src_data, src_time_start, src_time_dur, src_dst_offset) 132 | create_item(new_tr, src_data.items, src_time_start, src_time_dur, src_dst_offset) 133 | paste_env(new_tr, src_tr, src_data.env_points, src_time_start, src_time_dur, src_dst_offset) 134 | Paste_AI(new_tr, src_tr, src_data.AI, src_time_start, src_time_dur, src_dst_offset) 135 | end 136 | 137 | function Area_Drag(src_tbl, dst_tbl, src_time_tbl, dst_time_tbl, src_dst_offset, zone, action) 138 | local tr_offset = Mouse_track_offset(src_tbl.sel_info[1].track) 139 | reaper.Undo_BeginBlock() 140 | reaper.PreventUIRefresh(1) 141 | local func = zone .. "_" .. action 142 | local clean = (action == "move" and src_dst_offset ~= 0) and Clean(dst_tbl.sel_info, src_tbl.sel_info, dst_time_tbl, src_time_tbl) 143 | 144 | local new_area = {} 145 | 146 | for i = 1, #dst_tbl.sel_info do 147 | local dst_tr, src_tr = dst_tbl.sel_info[i].track, src_tbl.sel_info[i].track 148 | local src_time_start, src_time_dur = src_time_tbl[1], src_time_tbl[2] 149 | --local dst_time_start, dst_time_dur = dst_time_tbl[1], dst_time_tbl[2] 150 | 151 | local new_tr, under = Track_from_offset(src_tr, tr_offset) 152 | new_tr = under and Insert_track(under) or new_tr 153 | new_tr = env_offset_new(src_tbl.sel_info, src_tr, new_tr, src_tbl.sel_info[i].env_name) or new_tr 154 | 155 | if reaper.ValidatePtr(new_tr, "MediaTrack*") and reaper.ValidatePtr(src_tr, "TrackEnvelope*") then 156 | new_tr = get_set_envelope_chunk(new_tr, src_tr) 157 | end 158 | new_area[i] = {track = new_tr} 159 | 160 | _G[func](new_tr, src_tr, src_tbl.sel_info[i], src_time_start, src_time_dur, src_dst_offset) 161 | end 162 | if update_all then 163 | local areas_tbl = Get_area_table("Areas") 164 | Ghost_unlink_or_destroy(areas_tbl, "Delete") 165 | for i = 1, #areas_tbl do 166 | areas_tbl[i].sel_info = GetSelectionInfo(areas_tbl[i]) 167 | end 168 | update_all = nil 169 | end 170 | 171 | reaper.Undo_EndBlock("A51 " .. func, 4) 172 | reaper.PreventUIRefresh(-1) 173 | --reaper.UpdateTimeline() 174 | reaper.UpdateArrange() 175 | 176 | GetTracksXYH() 177 | local new_y, new_h = GetTrackTBH(new_area) -- SINCE WE ARE MOVING AREA, IF THERE ARE NEW ADDED TRACKS CHANGE AREA TO THAT LOCATION 178 | dst_tbl.y, dst_tbl.h = new_y, new_h 179 | end -------------------------------------------------------------------------------- /Area51/Modules/Area_51_key_functions.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.05 5 | * NoIndex: true 6 | --]] 7 | local reaper = reaper 8 | local prev_area 9 | 10 | function Remove() 11 | local tbl = Get_area_table("Areas") 12 | local CPY_TBL = Get_area_table("Copy") 13 | if copy then 14 | Copy_mode() 15 | return 16 | end -- DISABLE COPY MODE 17 | RemoveAsFromTable(tbl, "Delete", "~=") 18 | DeleteCopy(CPY_TBL) 19 | prev_area = nil 20 | BLOCK = nil 21 | Change_cursor() 22 | Set_active_as(nil) 23 | AREAS_UPDATE = 1 24 | end 25 | 26 | function Copy_mode() 27 | local tbl = Get_area_table("Areas") 28 | local CPY_TBL = Get_area_table("Copy") 29 | copy = next(tbl) ~= nil and not copy 30 | GHOST_UPDATE = copy and 1 or false 31 | if copy then 32 | Set_copy_tbl(copy3(tbl)) 33 | Buffer_copy(Get_area_table("Copy")) 34 | end 35 | if not copy then 36 | Ghost_unlink_or_destroy(tbl, "Unlink") 37 | DeleteCopy(CPY_TBL) 38 | prev_area = nil 39 | Set_active_as(nil) 40 | end 41 | AREAS_UPDATE = 1 42 | end 43 | 44 | function Copy_Paste() 45 | if copy then 46 | local tbl = Get_area_table() 47 | Area_function(tbl, "Paste") 48 | end 49 | end 50 | 51 | function Duplicate_area() 52 | if copy then return end -- DO NOT ALLOW DUPLICATE IN COPY MODE 53 | local tbl = Get_area_table() 54 | Area_function(tbl, "Duplicate") 55 | end 56 | 57 | function Del() 58 | local tbl = Get_area_table() 59 | Area_function(tbl, "Delete") 60 | end 61 | 62 | function As_split() 63 | local tbl = Get_area_table() 64 | Area_function(tbl, "Split") 65 | end 66 | 67 | 68 | function Select_as(num) 69 | if not copy then return end 70 | local tbl = Get_area_table("Areas") 71 | local CPY_TBL = Get_area_table("Copy") 72 | local active_as = tbl[num] and tbl[num] or nil 73 | 74 | if prev_area ~= active_as then 75 | if prev_area ~= nil then 76 | reaper.JS_LICE_AlterBitmapHSV( prev_area, 0, 0, -0.5) -- revert to original 77 | prev_area = nil 78 | end 79 | end 80 | 81 | if active_as and CPY_TBL[num].bm ~= prev_area then 82 | reaper.JS_LICE_AlterBitmapHSV( CPY_TBL[num].bm, 0, 0, 0.5) -- increase , high light 83 | prev_area = CPY_TBL[num].bm 84 | end 85 | Ghost_unlink_or_destroy(tbl, "Unlink", "area") 86 | Set_active_as(active_as) 87 | GHOST_UPDATE = 1 88 | AREAS_UPDATE = 1 89 | end 90 | 91 | -------------------------------------------------------------------------------- /Area51/Modules/Area_51_keyboard.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.05 5 | * NoIndex: true 6 | --]] 7 | local reaper = reaper 8 | local Key_TB = {} 9 | local key 10 | local key_state, last_key_state 11 | local intercept_keys = -1 12 | 13 | local startTime = reaper.time_precise() 14 | local thisCycleTime 15 | local Element = {} 16 | 17 | function modifier_name(mod) 18 | if mod == 4 then return "Ctrl" 19 | elseif mod == 8 then return"Shift" 20 | elseif mod == 16 then return "Alt" 21 | elseif mod == 24 then return "Alt_Shift" 22 | elseif mod == 12 then return "Ctrl_Shift" 23 | elseif mod == 20 then return "Ctrl_Alt" 24 | elseif mod == 28 then return "Ctrl_Shift_Alt" 25 | else return 26 | end 27 | end 28 | 29 | function Element:new(ID, name, func, m_key) 30 | local elm = {} 31 | elm.ID = ID 32 | elm.name = name 33 | elm.press = function() local start = true 34 | for i = 1, #elm.ID do 35 | if key_state:byte(elm.ID[i]) == 0 then start = false break end-- BREAK IF NOT BOTH KEYS ARE PRESSED 36 | end 37 | return start 38 | end 39 | elm.m_key = m_key 40 | elm.down_time = 0 41 | elm.last_key_down = false 42 | elm.last_key_hold = false 43 | elm.last_key_up = true 44 | elm.func = func 45 | elm.int = -1 46 | ---------------------- 47 | setmetatable(elm, self) 48 | self.__index = self 49 | return elm 50 | end 51 | 52 | function Extended(Child, Parent) 53 | setmetatable(Child,{__index = Parent}) 54 | end 55 | 56 | local Key = {} 57 | Extended(Key, Element) 58 | 59 | function Element:intercept(int) 60 | for i = 1, #self.ID do 61 | reaper.JS_VKeys_Intercept(self.ID[i], int) 62 | end 63 | end 64 | 65 | function Element:exec_func() 66 | local f_arr = type(tonumber(self.name)) == "number" and tonumber(self.name) or nil 67 | if self.func then 68 | _G[self.func](f_arr) 69 | end 70 | end 71 | 72 | function exec_func(tbl) 73 | local f_arr = type(tonumber(tbl.name)) == "number" and tonumber(tbl.name) or nil 74 | if tbl.func then--and AREA_ACTIVE then 75 | _G[tbl.func](f_arr) 76 | end 77 | -- if not tbl.m_key then 78 | -- reaper.JS_VKeys_Intercept(tbl.ID[1],1) 79 | -- _G[tbl.func](f_arr) 80 | -- else 81 | -- if tbl.mod == tbl.m_key then 82 | -- _G[tbl.func](f_arr) 83 | -- end 84 | -- end 85 | -- end 86 | --if AREA_ACTIVE then reaper.JS_VKeys_Intercept(tbl.ID[1],-1) end 87 | end 88 | 89 | function Element:onKeyDown(kd) 90 | if kd and self.last_key_down == false then 91 | self.down_time = os.clock() 92 | self.last_key_down = true 93 | self.last_key_up = false 94 | key["DOWN"] = self 95 | --exec_func(self) 96 | --end 97 | end 98 | end 99 | 100 | function Element:OnKeyUp(kd) 101 | if not kd and self.last_key_down == true and self.last_key_up == false then 102 | self.last_key_up = true 103 | self.last_key_down = false 104 | self.last_key_hold = false 105 | key["UP"] = self 106 | --self:exec_func() 107 | --end 108 | end 109 | end 110 | 111 | function Element:onKeyHold() 112 | self.last_key_hold = true 113 | --self.int = 1 114 | --reaper.JS_VKeys_Intercept(self.ID[1],1) 115 | key["HOLD"] = self 116 | --self:exec_func() 117 | --return self 118 | end 119 | 120 | function Element:GetKey() 121 | local KEY_DOWN = self.press() 122 | --self.mod = modifier_name(reaper.JS_Mouse_GetState(95)) 123 | 124 | if KEY_DOWN then 125 | if self.last_key_up == true and self.last_key_down == false then 126 | self:onKeyDown(KEY_DOWN) 127 | elseif self.last_key_up == false and self.last_key_down == true then 128 | if os.clock() - self.down_time > 0.15 then 129 | self:onKeyHold() 130 | end 131 | end 132 | elseif not KEY_DOWN and self.last_key_up == false and self.last_key_down == true then 133 | self:OnKeyUp(KEY_DOWN) 134 | end 135 | end 136 | 137 | function Track_keys() 138 | local prevCycleTime = thisCycleTime or startTime 139 | thisCycleTime = reaper.time_precise() 140 | key_state = reaper.JS_VKeys_GetState(startTime-2) 141 | key = {} 142 | 143 | if key_state ~= last_key_state then 144 | for i = 1, #Key_TB do Key_TB[i]:GetKey() end 145 | last_key_state = key_state 146 | end 147 | 148 | if key.DOWN then exec_func(key.DOWN) end 149 | FOLDER_MOD = ((key.HOLD) and (key.HOLD.name == "FOLDER")) and true or nil 150 | end 151 | 152 | function Intercept_reaper_key(tbl) 153 | local val = #tbl ~= 0 and 1 or -1 154 | if val ~= intercept_keys then 155 | for i = 1, #Key_TB do 156 | if Key_TB[i].func then 157 | Key_TB[i]:intercept(val) -- INTERCEPT OR RELEASE INTERCEPT 158 | end 159 | end 160 | intercept_keys = val 161 | end 162 | end 163 | 164 | function Release_reaper_keys() 165 | for i = 1, #Key_TB do 166 | if Key_TB[i].func then 167 | Key_TB[i]:intercept(-1) 168 | end 169 | end 170 | end 171 | 172 | for i = 1, 255 do 173 | local func 174 | local name = string.char(i) 175 | if type(tonumber(name)) == "number" then 176 | func = "Select_as" 177 | end 178 | if name == "S" then 179 | func = "As_split" 180 | end 181 | if i == 16 then 182 | name = "Shift" 183 | elseif i == 17 then 184 | name = "Ctrl" 185 | elseif i == 18 then 186 | name = "Alt" 187 | elseif i == 13 then 188 | name = "Return" 189 | elseif i == 8 then 190 | name = "Backspace" 191 | elseif i == 32 then 192 | name = "Space" 193 | elseif i == 20 then 194 | name = "Caps-Lock" 195 | elseif i == 27 then 196 | name = "ESC" 197 | func = "Remove" 198 | elseif i == 9 then 199 | name = "TAB" 200 | elseif i == 192 then 201 | name = "~" 202 | elseif i == 91 then 203 | name = "Win" 204 | elseif i == 45 then 205 | name = "Insert" 206 | elseif i == 46 then 207 | name = "Del" 208 | func = "Del" 209 | elseif i == 36 then 210 | name = "Home" 211 | elseif i == 35 then 212 | name = "End" 213 | elseif i == 33 then 214 | name = "PG-Up" 215 | elseif i == 34 then 216 | name = "PG-Down" 217 | end 218 | Key_TB[#Key_TB + 1] = Key:new({i}, name, func) 219 | 220 | Key_TB[#Key_TB + 1] = Key:new({17,67}, "COPY", "Copy_mode", "Ctrl") -- COPY (TOGGLE) 221 | Key_TB[#Key_TB + 1] = Key:new({17,86}, "PASTE", "Copy_Paste", "Ctrl") -- PASTE 222 | Key_TB[#Key_TB + 1] = Key:new({17,68}, "DUPLICATE", "Duplicate_area","Ctrl") -- PASTE 223 | Key_TB[#Key_TB + 1] = Key:new({89}, "FOLDER") -- PASTE 224 | end -------------------------------------------------------------------------------- /Area51/Modules/Area_51_mouse.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.06 5 | * NoIndex: true 6 | --]] 7 | local reaper = reaper 8 | local main_wnd = reaper.GetMainHwnd() -- GET MAIN WINDOW 9 | local track_window = reaper.JS_Window_FindChildByID(main_wnd, 0x3E8) -- GET TRACK VIEW 10 | 11 | local mouse = { 12 | LB = 1, 13 | RB = 2, 14 | Ctrl = function() return reaper.JS_Mouse_GetState(95) &4 == 4 end, 15 | Shift = function() return reaper.JS_Mouse_GetState(95) &8 == 8 end, 16 | Alt = function() return reaper.JS_Mouse_GetState(95) &16 == 16 end, 17 | Alt_Shift = function() return reaper.JS_Mouse_GetState(95) &24 == 24 end, 18 | Ctrl_Shift = function() return reaper.JS_Mouse_GetState(95) &12 == 12 end, 19 | Ctrl_Alt = function() return reaper.JS_Mouse_GetState(95) &20 == 20 end, 20 | Ctrl_Shift_Alt = function() return reaper.JS_Mouse_GetState(95) &28 == 28 end, 21 | cap = function (mask) 22 | if mask == nil then 23 | return reaper.JS_Mouse_GetState(95) end 24 | return reaper.JS_Mouse_GetState(95)&mask == mask 25 | end, 26 | 27 | lb_down = function() return reaper.JS_Mouse_GetState(95) &1 == 1 end, 28 | rb_down = function() return reaper.JS_Mouse_GetState(95) &2 == 2 end, 29 | uptime = 0, 30 | 31 | last_x = -1, 32 | last_y = -1, 33 | last_p = -1, 34 | 35 | last_tr = nil, 36 | last_r_t = nil, 37 | last_r_b = nil, 38 | 39 | dx = 0, 40 | dy = 0, 41 | dp = 0, 42 | 43 | ox = 0, 44 | oy = 0, 45 | op = 0, 46 | otr = nil, 47 | ort = 0, 48 | orb = 0, 49 | 50 | tr = nil, 51 | x = 0, 52 | y = 0, 53 | p = 0, 54 | r_t = 0, 55 | r_b = 0, 56 | 57 | detail = false, 58 | 59 | last_LMB_state = false, 60 | last_RMB_state = false, 61 | 62 | l_click = false, 63 | r_click = false, 64 | l_dclick = false, 65 | l_up = false, 66 | r_up = false, 67 | l_down = false, 68 | r_down = false 69 | } 70 | 71 | function OnMouseDown(lmb_down, rmb_down) 72 | if not rmb_down and lmb_down and mouse.last_LMB_state == false then 73 | mouse.last_LMB_state = true 74 | mouse.l_click = true 75 | end 76 | if not lmb_down and rmb_down and mouse.last_RMB_state == false then 77 | mouse.last_RMB_state = true 78 | mouse.r_click = true 79 | end 80 | 81 | mouse.ox, mouse.oy = mouse.x, mouse.y -- mouse click coordinates 82 | mouse.ort, mouse.orb, mouse.otr = mouse.r_t, mouse.r_b, mouse.tr 83 | mouse.op = mouse.p 84 | mouse.cap_count = 0 -- reset mouse capture count 85 | end 86 | 87 | function OnMouseUp(lmb_down, rmb_down) 88 | mouse.uptime = os.clock() 89 | mouse.dx = 0 90 | mouse.dy = 0 91 | mouse.detail = false 92 | if not lmb_down and mouse.last_LMB_state then mouse.last_LMB_state = false mouse.l_up = true end 93 | if not rmb_down and mouse.last_RMB_state then mouse.last_RMB_state = false mouse.r_up = true end 94 | end 95 | 96 | function OnMouseDoubleClick() 97 | mouse.l_dclick = true 98 | end 99 | 100 | function OnMouseHold(lmb_down, rmb_down) 101 | mouse.l_down = lmb_down and true 102 | mouse.r_down = rmb_down and true 103 | mouse.dx = mouse.x - mouse.ox 104 | mouse.dy = mouse.y - mouse.oy 105 | mouse.dp = mouse.p - mouse.op 106 | 107 | mouse.last_x, mouse.last_y, mouse.last_p = mouse.x, mouse.y, mouse.p 108 | if mouse.tr then 109 | mouse.last_r_t, mouse.last_r_b = mouse.r_t, mouse.r_b 110 | mouse.last_tr = mouse.tr 111 | end 112 | end 113 | 114 | function X_to_pos(x) 115 | local zoom_lvl = reaper.GetHZoomLevel() -- HORIZONTAL ZOOM LEVEL 116 | local Arr_start_time = reaper.GetSet_ArrangeView2(0, false, 0, 0) -- GET ARRANGE VIEW 117 | local cx, _ = reaper.JS_Window_ScreenToClient( track_window, x, 0) 118 | 119 | cx = cx >= 0 and cx or 0 120 | 121 | local p = (cx / zoom_lvl) + Arr_start_time 122 | p = reaper.GetToggleCommandState(1157) == 1 and reaper.SnapToGrid(0, p) or p 123 | return p 124 | end 125 | 126 | function MouseInfo(x,y,p) 127 | mouse.x, mouse.y = reaper.GetMousePosition() 128 | mouse.p = X_to_pos(mouse.x) 129 | if mouse.tr then mouse.last_tr = mouse.tr end 130 | 131 | local m_cx, m_cy = reaper.JS_Window_ScreenToClient( track_window, mouse.x, mouse.y ) 132 | 133 | --ARRANGE = ((mouse.l_down) and (mouse.ox >= sx and Check_val_for_os(mouse.oy, sy)) and mouse.otr) and true or false 134 | ARRANGE = ((mouse.l_down) and mouse.otr) and true or false--((mouse.l_down) and (m_cx >= 0 and m_cy >= 0) and mouse.otr) and true or false 135 | --ARRANGE = ((mouse.l_down) and (mouse.ox >= sx and mouse.oy >= sy) and mouse.otr) and true or false ------ FOR OSX OY NEEDS TO BE LESS THAN SCREEN Y (mouse.oy <= sy) ---------------------------------- 136 | mouse.DRAW_AREA = mouse.Ctrl_Shift() or mouse.Ctrl_Shift_Alt() and true or false 137 | mouse.l_click = false 138 | mouse.r_click = false 139 | mouse.l_dclick = false 140 | mouse.l_up = false 141 | mouse.r_up = false 142 | mouse.l_down = false 143 | mouse.r_down = false 144 | local LB_DOWN = mouse.lb_down() -- Get current left mouse button state 145 | local RB_DOWN = mouse.rb_down() -- Get current right mouse button state 146 | 147 | if (LB_DOWN and not RB_DOWN) or (RB_DOWN and not LB_DOWN) then -- LMB or RMB pressed down? 148 | if (mouse.last_LMB_state == false and not RB_DOWN) or (mouse.last_RMB_state == false and not LB_DOWN) then 149 | OnMouseDown(LB_DOWN, RB_DOWN) 150 | if mouse.uptime and os.clock() - mouse.uptime < 0.20 then 151 | OnMouseDoubleClick() 152 | end 153 | else 154 | OnMouseHold(LB_DOWN,RB_DOWN) 155 | end 156 | elseif not LB_DOWN and mouse.last_RMB_state or not RB_DOWN and mouse.last_LMB_state then 157 | OnMouseUp(LB_DOWN, RB_DOWN) 158 | end 159 | 160 | return mouse 161 | end 162 | 163 | local prevTime = 0 -- or script start time 164 | function Pass_thru() 165 | if mouse.l_down then 166 | if not BLOCK then 167 | if not mouse.Ctrl_Shift_Alt() and not mouse.Ctrl_Shift() then 168 | if WINDOW_IN_FRONT or check_window_in_front() then return end 169 | local pOK, pass, time, wLow, wHigh, lLow, lHigh = reaper.JS_WindowMessage_Peek(track_window, "WM_LBUTTONDOWN") 170 | local pOK1, pass1, time1, wLow1, wHigh1, lLow1, lHigh1 = reaper.JS_WindowMessage_Peek(track_window, "WM_LBUTTONDBLCLK") 171 | if pOK and time > prevTime then 172 | prevTime = time 173 | reaper.JS_WindowMessage_Post(track_window, "WM_LBUTTONDOWN", wLow, wHigh, lLow, lHigh) 174 | reaper.JS_WindowMessage_Post(track_window, "WM_LBUTTONDBLCLK", wLow1, wHigh1, lLow1, lHigh1) 175 | end 176 | end 177 | end 178 | end 179 | end -------------------------------------------------------------------------------- /Debug/DBG_test.lua: -------------------------------------------------------------------------------- 1 | local info = debug.getinfo(1, 'S'); 2 | local script_path = info.source:match [[^@?(.*[\/])[^\/]-$]]; 3 | 4 | dofile(script_path .. "/LoadDebug.lua") 5 | 6 | global_table = { "this", "is", "test", "table", "1", "2" } 7 | function Main() 8 | --DEBUG.console("HELLO VSCODE!") -- PRINTS IN VS Debug Console 9 | local variable = -1 10 | 11 | for i = 1, 10 do 12 | variable = i 13 | end 14 | --a = "ASB" + 1 15 | 16 | local new_variable = "RUNNING IN REAPER" 17 | DEBUG.defer(Main) 18 | end 19 | 20 | function exit() return end 21 | 22 | reaper.atexit(exit) 23 | DEBUG.defer(Main) 24 | -------------------------------------------------------------------------------- /Debug/LoadDebug.lua: -------------------------------------------------------------------------------- 1 | local info = debug.getinfo(1, 'S'); 2 | local script_path = info.source:match [[^@?(.*[\/])[^\/]-$]]; 3 | package.cpath = package.cpath .. 4 | ";" .. 5 | script_path .. 6 | "/Modules/?.dll" -- Add current folder/socket module for looking at .dll (need for loading basic luasocket) 7 | package.cpath = package.cpath .. 8 | ";" .. 9 | script_path .. 10 | "/Modules/?.so" -- Add current folder/socket module for looking at .so (need for loading basic luasocket) 11 | package.path = package.path .. 12 | ";" .. 13 | script_path .. 14 | "/Modules/?.lua" -- Add current folder/socket module for looking at sockets. 15 | 16 | -- INSTALL VSCODE EXSTENSION 17 | -- https://marketplace.visualstudio.com/items?itemName=AlexeyMelnichuk.lua-mobdebug 18 | 19 | -- .vscode/launch.json 20 | -- { 21 | -- // Use IntelliSense to learn about possible attributes. 22 | -- // Hover to view descriptions of existing attributes. 23 | -- // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 24 | -- "version": "0.2.0", 25 | -- "configurations": [ 26 | -- { 27 | -- "name": "Lua MobDebug: Listen", 28 | -- "type": "luaMobDebug", 29 | -- "request": "attach", 30 | -- "workingDirectory": "${workspaceFolder}", 31 | -- "sourceBasePath": "${workspaceFolder}", 32 | -- "listenPublicly": false, 33 | -- "listenPort": 8172, 34 | -- "stopOnEntry": false, 35 | -- "sourceEncoding": "UTF-8" 36 | -- } 37 | -- ] 38 | -- } 39 | 40 | 41 | -- .vscode/tasks.json 42 | -- { 43 | -- "version": "2.0.0", 44 | -- "tasks": [ 45 | -- { 46 | -- "label": "Run Reaper Script", 47 | -- "type": "shell", 48 | -- "command": "C:/REAPER/reaper.exe", 49 | -- "args": [ 50 | -- "-nonewinst", 51 | -- "${file}" 52 | -- ], 53 | -- "problemMatcher": [], 54 | -- "presentation": { 55 | -- "reveal": "never" 56 | -- } 57 | -- { 58 | -- "label": "Debug Script", 59 | -- "command": "${command:workbench.action.debug.start}" 60 | -- }, 61 | -- { 62 | -- "label": "Debug and Run", 63 | -- "dependsOrder": "parallel", 64 | -- "dependsOn": [ 65 | -- "Debug Script", 66 | -- "Run Reaper Script" 67 | -- ], 68 | -- "problemMatcher": [] 69 | -- } 70 | -- ] 71 | -- } 72 | 73 | local DEBUG = require("mobdebug") 74 | 75 | DEBUG.defer = function(func) 76 | reaper.defer(function() xpcall(func, DEBUG.crash) end) 77 | end 78 | 79 | DEBUG.start() 80 | 81 | function MobDebug() 82 | return DEBUG 83 | end 84 | -------------------------------------------------------------------------------- /Debug/Modules/socket.lua: -------------------------------------------------------------------------------- 1 | -- @metapackage 2 | -- @description Mavriq Lua Sockets 3 | -- @version 1.2 4 | -- @author Mavriq 5 | -- @about 6 | -- # Allows use of Lua Sockets in 'REAPER' 7 | -- Reaper is missing Lua Auxlib in it's embedded version of Lua. As such things such as the luasockets library etc will not work. If loaded they will throw an error for missing symbols when the library tries to access those in the missing AuxLib. 8 | -- 9 | -- Until the REAPER devs fix this, we have to work around the issue. This project does that for all all three REAPER platforms. 10 | -- 11 | -- This package is used by other scripts and doesn't do anything on its own. 12 | -- 13 | -- ### Thanks 14 | -- A huge thanks to Sexan and Daniel Lumertz for updating the packages to 5.4 in my absence. And cfillion for doing final testing on mac and linux as I had no access at that moment. 15 | -- @donation: https://www.paypal.com/paypalme/mavriqdev 16 | -- @links 17 | -- Forum Thread https://github.com/available_soon 18 | -- GitHub repository https://github.com/mavriq-dev/mavriq-lua-sockets 19 | -- @changelog 20 | -- V1.2 21 | -- + fix for Reaper 7/Lua 5.4 22 | -- V1.1.2 23 | -- + fix M1 24 | -- V1.1.1 25 | -- + fixed issue with mac silicon due to changes in Reapack 26 | -- V1.1.0 27 | -- + added support for mac silicon 28 | -- + added support for older macs (10.9+) 29 | -- v1.0.0 30 | -- + initial release 31 | -- v1.0.0pre3 32 | -- + linux fix 33 | -- v1.0.0pre2 34 | -- + fixed linux version 35 | -- v1.0.0pre1 36 | -- + initial release 37 | -- @provides 38 | -- /Various/Mavriq-Lua-Sockets/*.lua 39 | -- [win64] /Various/Mavriq-Lua-Sockets/socket/core.dll 40 | -- [darwin64] /Various/Mavriq-Lua-Sockets/socket/core.so 41 | -- [darwin-arm64] /Various/Mavriq-Lua-Sockets/socket/core.so 42 | -- [linux64] /Various/Mavriq-Lua-Sockets/socket/core.so.linux > socket/core.so 43 | 44 | 45 | ----------------------------------------------------------------------------- 46 | -- LuaSocket helper module 47 | -- Author: Diego Nehab 48 | ----------------------------------------------------------------------------- 49 | 50 | ----------------------------------------------------------------------------- 51 | -- Declare module and import dependencies 52 | ----------------------------------------------------------------------------- 53 | local base = _G 54 | local string = require("string") 55 | local math = require("math") 56 | local socket = require("socket.core") 57 | 58 | local _M = socket 59 | 60 | ----------------------------------------------------------------------------- 61 | -- Exported auxiliar functions 62 | ----------------------------------------------------------------------------- 63 | function _M.connect4(address, port, laddress, lport) 64 | return socket.connect(address, port, laddress, lport, "inet") 65 | end 66 | 67 | function _M.connect6(address, port, laddress, lport) 68 | return socket.connect(address, port, laddress, lport, "inet6") 69 | end 70 | 71 | function _M.bind(host, port, backlog) 72 | if host == "*" then host = "0.0.0.0" end 73 | local addrinfo, err = socket.dns.getaddrinfo(host); 74 | if not addrinfo then return nil, err end 75 | local sock, res 76 | err = "no info on address" 77 | for i, alt in base.ipairs(addrinfo) do 78 | if alt.family == "inet" then 79 | sock, err = socket.tcp4() 80 | else 81 | sock, err = socket.tcp6() 82 | end 83 | if not sock then return nil, err end 84 | sock:setoption("reuseaddr", true) 85 | res, err = sock:bind(alt.addr, port) 86 | if not res then 87 | sock:close() 88 | else 89 | res, err = sock:listen(backlog) 90 | if not res then 91 | sock:close() 92 | else 93 | return sock 94 | end 95 | end 96 | end 97 | return nil, err 98 | end 99 | 100 | _M.try = _M.newtry() 101 | 102 | function _M.choose(table) 103 | return function(name, opt1, opt2) 104 | if base.type(name) ~= "string" then 105 | name, opt1, opt2 = "default", name, opt1 106 | end 107 | local f = table[name or "nil"] 108 | if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) 109 | else return f(opt1, opt2) end 110 | end 111 | end 112 | 113 | ----------------------------------------------------------------------------- 114 | -- Socket sources and sinks, conforming to LTN12 115 | ----------------------------------------------------------------------------- 116 | -- create namespaces inside LuaSocket namespace 117 | local sourcet, sinkt = {}, {} 118 | _M.sourcet = sourcet 119 | _M.sinkt = sinkt 120 | 121 | _M.BLOCKSIZE = 2048 122 | 123 | sinkt["close-when-done"] = function(sock) 124 | return base.setmetatable({ 125 | getfd = function() return sock:getfd() end, 126 | dirty = function() return sock:dirty() end 127 | }, { 128 | __call = function(self, chunk, err) 129 | if not chunk then 130 | sock:close() 131 | return 1 132 | else return sock:send(chunk) end 133 | end 134 | }) 135 | end 136 | 137 | sinkt["keep-open"] = function(sock) 138 | return base.setmetatable({ 139 | getfd = function() return sock:getfd() end, 140 | dirty = function() return sock:dirty() end 141 | }, { 142 | __call = function(self, chunk, err) 143 | if chunk then return sock:send(chunk) 144 | else return 1 end 145 | end 146 | }) 147 | end 148 | 149 | sinkt["default"] = sinkt["keep-open"] 150 | 151 | _M.sink = _M.choose(sinkt) 152 | 153 | sourcet["by-length"] = function(sock, length) 154 | return base.setmetatable({ 155 | getfd = function() return sock:getfd() end, 156 | dirty = function() return sock:dirty() end 157 | }, { 158 | __call = function() 159 | if length <= 0 then return nil end 160 | local size = math.min(socket.BLOCKSIZE, length) 161 | local chunk, err = sock:receive(size) 162 | if err then return nil, err end 163 | length = length - string.len(chunk) 164 | return chunk 165 | end 166 | }) 167 | end 168 | 169 | sourcet["until-closed"] = function(sock) 170 | local done 171 | return base.setmetatable({ 172 | getfd = function() return sock:getfd() end, 173 | dirty = function() return sock:dirty() end 174 | }, { 175 | __call = function() 176 | if done then return nil end 177 | local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 178 | if not err then return chunk 179 | elseif err == "closed" then 180 | sock:close() 181 | done = 1 182 | return partial 183 | else return nil, err end 184 | end 185 | }) 186 | end 187 | 188 | 189 | sourcet["default"] = sourcet["until-closed"] 190 | 191 | _M.source = _M.choose(sourcet) 192 | 193 | return _M 194 | -------------------------------------------------------------------------------- /Debug/Modules/socket/core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/Debug/Modules/socket/core.dll -------------------------------------------------------------------------------- /Edit_Groups/Utils/Mouse.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | local reaper = reaper 9 | 10 | local crash = function(errObject) 11 | local byLine = "([^\r\n]*)\r?\n?" 12 | local trimPath = "[\\/]([^\\/]-:%d+:.+)$" 13 | local err = errObject and string.match(errObject, trimPath) or "Couldn't get error message." 14 | local trace = debug.traceback() 15 | local stack = {} 16 | for line in string.gmatch(trace, byLine) do 17 | local str = string.match(line, trimPath) or line 18 | stack[#stack + 1] = str 19 | end 20 | local name = ({ reaper.get_action_context() })[2]:match("([^/\\_]+)$") 21 | local ret = 22 | reaper.ShowMessageBox( 23 | name .. " has crashed!\n\n" .. "Would you like to have a crash report printed " .. "to the Reaper console?", 24 | "Oops", 25 | 4 26 | ) 27 | if ret == 6 then 28 | reaper.ShowConsoleMsg( 29 | "Error: " .. err .. "\n\n" .. 30 | "Stack traceback:\n\t" .. table.concat(stack, "\n\t", 2) .. "\n\n" .. 31 | "Reaper: \t" .. reaper.GetAppVersion() .. "\n" .. 32 | "Platform: \t" .. reaper.GetOS() 33 | ) 34 | end 35 | end 36 | 37 | function GetCrash() return crash end 38 | 39 | local main_wnd = reaper.GetMainHwnd() 40 | local track_window = reaper.JS_Window_FindChildByID(main_wnd, 0x3E8) 41 | local mouse = { 42 | Ctrl = function() return reaper.JS_Mouse_GetState(95) & 4 == 4 end, 43 | Shift = function() return reaper.JS_Mouse_GetState(95) & 8 == 8 end, 44 | Alt = function() return reaper.JS_Mouse_GetState(95) & 16 == 16 end, 45 | Alt_Shift = function() return reaper.JS_Mouse_GetState(95) & 24 == 24 end, 46 | Ctrl_Shift = function() return reaper.JS_Mouse_GetState(95) & 12 == 12 end, 47 | Ctrl_Alt = function() return reaper.JS_Mouse_GetState(95) & 20 == 20 end, 48 | Ctrl_Shift_Alt = function() return reaper.JS_Mouse_GetState(95) & 28 == 28 end, 49 | cap = function(mask) 50 | if mask == nil then 51 | return reaper.JS_Mouse_GetState(95) 52 | end 53 | return reaper.JS_Mouse_GetState(95) & mask == mask 54 | end, 55 | lb_down = function() return reaper.JS_Mouse_GetState(95) & 1 == 1 end, 56 | rb_down = function() return reaper.JS_Mouse_GetState(95) & 2 == 2 end, 57 | p = nil, op = nil, dp = nil, 58 | tr = nil, tr_num = nil, tr_info = nil, otr = nil, otr_num = nil, otr_info = nil, dtr = {}, 59 | env = nil, env_name = nil, oenv = nil, oenv_name = nil, 60 | track_range = {}, 61 | item = nil, oitem = nil, otake = nil, 62 | detail = nil, odetail = nil, 63 | x = 0, y = 0, 64 | ox = 0, oy = 0, 65 | dx = 0, dy = 0, 66 | last_LMB_state = false, 67 | last_RMB_state = false, 68 | l_click = false, r_click = false, 69 | l_dclick = false, 70 | l_up = false, r_up = false, 71 | l_down = false, r_down = false, 72 | } 73 | 74 | local function OnMouseDown(lmb_down, rmb_down) 75 | if not rmb_down and lmb_down and mouse.last_LMB_state == false then 76 | mouse.last_LMB_state = true 77 | mouse.l_click = true 78 | end 79 | if not lmb_down and rmb_down and mouse.last_RMB_state == false then 80 | mouse.last_RMB_state = true 81 | mouse.r_click = true 82 | end 83 | mouse.track_range = {} 84 | mouse.ox, mouse.oy = mouse.x, mouse.y -- mouse click coordinates 85 | mouse.odetail, mouse.otr, mouse.otr_num, mouse.oitem, mouse.otake = mouse.detail, mouse.tr, mouse.tr_num, mouse.item, mouse.take 86 | mouse.op = mouse.p 87 | mouse.oenv = mouse.env 88 | mouse.oenv_name = mouse.env_name 89 | end 90 | 91 | local function OnMouseUp(lmb_down, rmb_down) 92 | mouse.uptime = os.clock() 93 | mouse.dx, mouse.dy = 0, 0 94 | if not lmb_down and mouse.last_LMB_state then mouse.last_LMB_state = false 95 | mouse.l_up = true 96 | end 97 | if not rmb_down and mouse.last_RMB_state then mouse.last_RMB_state = false 98 | mouse.r_up = true 99 | end 100 | end 101 | 102 | local function OnMouseDoubleClick() 103 | mouse.l_dclick = true 104 | end 105 | 106 | local function OnMouseHold(lmb_down, rmb_down) 107 | mouse.l_down = lmb_down and true 108 | mouse.r_down = rmb_down and true 109 | 110 | mouse.dx = mouse.x - mouse.ox 111 | mouse.dy = mouse.y - mouse.oy 112 | mouse.dp = mouse.p - mouse.op 113 | 114 | if mouse.tr_num then -- ALWAYS CAPTURE TRACK (IF WE WENT OFFSCREEN REMEMBER LAST TRACK) 115 | mouse.dtr = { mouse.otr_num, mouse.tr_num } 116 | mouse.last_tr_num = mouse.tr_num 117 | end 118 | mouse.last_x, mouse.last_y = mouse.x, mouse.y 119 | mouse.last_p = mouse.p 120 | end 121 | 122 | function Mouse_X_to_pos(x) 123 | local zoom_lvl = reaper.GetHZoomLevel() 124 | local Arr_start_time = reaper.GetSet_ArrangeView2(0, false, 0, 0) 125 | local cx, _ = reaper.JS_Window_ScreenToClient(track_window, x, 0) 126 | cx = cx >= 0 and cx or 0 127 | local p = (cx / zoom_lvl) + Arr_start_time 128 | p = reaper.GetToggleCommandState(1157) == 1 and reaper.SnapToGrid(0, p) or p 129 | return p 130 | end 131 | 132 | function Mouse() 133 | mouse.x, mouse.y = reaper.GetMousePosition() 134 | mouse.tr, mouse.detail = reaper.GetThingFromPoint(mouse.x, mouse.y) 135 | if mouse.detail:match("envelope") then 136 | mouse.env = reaper.GetTrackEnvelope(mouse.tr, tonumber(mouse.detail:match("%d+"))) 137 | mouse.env_name = ({ reaper.GetEnvelopeName(mouse.env) })[2] 138 | else 139 | mouse.env, mouse.env_name = nil, nil 140 | end 141 | mouse.p = Mouse_X_to_pos(mouse.x) 142 | mouse.tr_num = mouse.tr and reaper.GetMediaTrackInfo_Value(mouse.tr, "IP_TRACKNUMBER") or nil 143 | mouse.item, mouse.take = reaper.GetItemFromPoint(mouse.x, mouse.y, true) 144 | mouse.l_click, mouse.r_click, mouse.l_dclick, mouse.l_up, mouse.r_up, mouse.l_down, mouse.r_down = false, false, false, false, false, false, false 145 | local LB_DOWN, RB_DOWN = mouse.lb_down(), mouse.rb_down() 146 | 147 | if (LB_DOWN and not RB_DOWN) or (RB_DOWN and not LB_DOWN) then 148 | if (mouse.last_LMB_state == false and not RB_DOWN) or (mouse.last_RMB_state == false and not LB_DOWN) then 149 | OnMouseDown(LB_DOWN, RB_DOWN) 150 | if mouse.uptime and os.clock() - mouse.uptime < 0.20 then 151 | OnMouseDoubleClick() 152 | end 153 | else 154 | OnMouseHold(LB_DOWN, RB_DOWN) 155 | end 156 | elseif not LB_DOWN and mouse.last_RMB_state or not RB_DOWN and mouse.last_LMB_state then 157 | OnMouseUp(LB_DOWN, RB_DOWN) 158 | end 159 | 160 | if #mouse.dtr > 1 then 161 | if mouse.dtr[1] and mouse.dtr[2] then 162 | mouse.track_range, mouse.razors = {}, {} 163 | local first = mouse.dtr[1] > mouse.dtr[2] and mouse.dtr[2] or mouse.dtr[1] 164 | local last = mouse.dtr[1] > mouse.dtr[2] and mouse.dtr[1] or mouse.dtr[2] 165 | for i = first, last do mouse.track_range[#mouse.track_range + 1] = reaper.CSurf_TrackFromID(i, false) end 166 | end 167 | end 168 | return mouse 169 | end 170 | -------------------------------------------------------------------------------- /ImGui_Tools/PluginScreenShooter.lua: -------------------------------------------------------------------------------- 1 | -- Credits nihilboy for idea 2 | 3 | local r = reaper 4 | package.path = r.ImGui_GetBuiltinPath() .. '/?.lua' 5 | local im = require 'imgui' '0.9.2' 6 | 7 | local platform = r.GetOS() 8 | 9 | local deps = {} 10 | local proc_delay = 0.5 11 | local SIZE_DATA = {} 12 | local osx, linux, win 13 | local linux_app 14 | if platform:match("OSX") or platform:match("macOS") then 15 | osx = true 16 | elseif platform:match("Other") then 17 | linux = true 18 | --AAA = reaper.ExecProcess('/bin/bash -c "which gnome-screenshot"',0) 19 | else 20 | win = true 21 | end 22 | 23 | if not im.GetVersion then 24 | deps[#deps + 1] = '"Dear Imgui"' 25 | end 26 | if not r.JS_ReaScriptAPI_Version then 27 | deps[#deps + 1] = '"js_ReaScriptAPI"' 28 | end 29 | 30 | if #deps ~= 0 then 31 | r.ShowMessageBox("Need Additional Packages.\nPlease Install it in next window", "MISSING DEPENDENCIES", 0) 32 | r.ReaPack_BrowsePackages(table.concat(deps, " OR ")) 33 | return true 34 | end 35 | 36 | local function PrintTraceback(err) 37 | local byLine = "([^\r\n]*)\r?\n?" 38 | local trimPath = "[\\/]([^\\/]-:%d+:.+)$" 39 | local stack = {} 40 | for line in string.gmatch(err, byLine) do 41 | local str = string.match(line, trimPath) or line 42 | stack[#stack + 1] = str 43 | end 44 | r.ShowConsoleMsg( 45 | "Error: " .. stack[1] .. "\n\n" .. 46 | "Stack traceback:\n\t" .. table.concat(stack, "\n\t", 3) .. "\n\n" .. 47 | "Reaper: \t" .. r.GetAppVersion() .. "\n" .. 48 | "Platform: \t" .. r.GetOS() 49 | ) 50 | end 51 | 52 | function PDefer(func) 53 | r.defer(function() 54 | local status, err = xpcall(func, debug.traceback) 55 | if not status then 56 | PrintTraceback(err) 57 | Exit() 58 | end 59 | end) 60 | end 61 | 62 | local ctx = im.CreateContext('FX SCREENSHOTER') 63 | 64 | local png_folder = "/Scripts/FX_PNG/" 65 | local folder = r.GetResourcePath() .. png_folder 66 | 67 | if not r.file_exists(folder) then 68 | reaper.RecursiveCreateDirectory(folder,0) 69 | end 70 | 71 | r.InsertTrackAtIndex(r.CountTracks(0), false) 72 | 73 | local track = r.GetTrack(r.CountTracks(0), 0) 74 | local fx_idx = 0 75 | 76 | local total_fx = 0 77 | for j = 1, math.huge do 78 | local retval = r.EnumInstalledFX(j) 79 | if not retval then break end 80 | total_fx = total_fx + 1 81 | end 82 | 83 | local function SerializeTable(val, name, skipnewlines, depth) 84 | skipnewlines = skipnewlines or false 85 | depth = depth or 0 86 | local tmp = string.rep(" ", depth) 87 | if name then 88 | if type(name) == "number" and math.floor(name) == name then 89 | name = "[" .. name .. "]" 90 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 91 | name = string.gsub(name, "'", "\\'") 92 | name = "['" .. name .. "']" 93 | end 94 | tmp = tmp .. name .. " = " 95 | end 96 | if type(val) == "table" then 97 | tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") 98 | for k, v in pairs(val) do 99 | tmp = tmp .. SerializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "") 100 | end 101 | tmp = tmp .. string.rep(" ", depth) .. "}" 102 | else 103 | val = type(val) ~= 'userdata' and val or nil 104 | tmp = tmp .. ('%q'):format(val) 105 | end 106 | return tmp 107 | end 108 | 109 | function TableToString(table) return SerializeTable(table) end 110 | 111 | function WriteToFile(path, data) 112 | local file_cat = io.open(path, "w") 113 | if file_cat then 114 | file_cat:write(data) 115 | file_cat:close() 116 | end 117 | end 118 | 119 | local function WriteFxData() 120 | local serialized = TableToString(SIZE_DATA) 121 | WriteToFile(folder .. "FX_SIZES.txt", serialized) 122 | end 123 | 124 | function Wait(startTime, callback) 125 | PROCESS = true 126 | if r.time_precise() - startTime > proc_delay then 127 | callback() 128 | fx_idx = fx_idx + 1 129 | PROCESS = nil 130 | else 131 | r.defer(function() Wait(startTime, callback) end) 132 | end 133 | end 134 | 135 | local function FxOffset() 136 | return pluginName:match("^JS") and 0 or 27 137 | end 138 | 139 | local function ScreenshotOSX(path, x, y, w, h) 140 | x, y = im.PointConvertNative(ctx, x, y, false) 141 | local command = 'screencapture -x -R %d,%d,%d,%d -t png "%s"' 142 | os.execute(command:format(x, y, w, h, path .. ".png")) 143 | end 144 | 145 | local function ScreenshotLinux(path, x, y, w, h) 146 | x, y = im.PointConvertNative(ctx, x, y, false) 147 | local command = 'shutter -s %d,%d,%d,%d -e -o "%s"' 148 | os.execute(command:format(x, y, w, h, path .. ".png")) 149 | end 150 | 151 | local function takeScreenshot(fxIndex, path) 152 | local window = r.TrackFX_GetFloatingWindow(track, fxIndex) 153 | local retval, left, top, right, bottom = r.JS_Window_GetClientRect( window ) 154 | if retval then 155 | local destBmp 156 | local w, h = right - left, bottom - top 157 | local off_y = FxOffset() 158 | if win or linux then 159 | local srcDC = r.JS_GDI_GetClientDC(window) 160 | destBmp = r.JS_LICE_CreateBitmap(true, w, h - off_y) 161 | local destDC = r.JS_LICE_GetDC(destBmp) 162 | r.JS_GDI_Blit(destDC, 0, -off_y, srcDC, 0, 0, w, h) 163 | r.JS_LICE_WritePNG(path .. ".png", destBmp, false) 164 | r.JS_GDI_ReleaseDC(window, srcDC) 165 | r.JS_LICE_DestroyBitmap(destBmp) 166 | elseif osx then 167 | h = top - bottom 168 | ScreenshotOSX(path, left, top - off_y, w, h - off_y) 169 | else 170 | -- ScreenshotLinux(path, left, top - off_y, w, h - off_y) 171 | end 172 | if r.ValidatePtr(track, "MediaTrack*") then 173 | r.TrackFX_Delete(track, fxIndex) 174 | end 175 | SIZE_DATA[pluginName] = { path = path .. ".png", w = w, h = h } 176 | end 177 | end 178 | 179 | local function BuildDatabase() 180 | SIZE_DATA = {} 181 | for j = 1, math.huge do 182 | local retval, pluginName = r.EnumInstalledFX(j) 183 | if not retval then break end 184 | local png_name = pluginName:gsub("[-:_/%s><]", "_") 185 | local path = folder .. png_name .. ".png" 186 | if r.file_exists(path) then 187 | local img = im.CreateImage(path) 188 | local w, h = im.Image_GetSize(img) 189 | SIZE_DATA[pluginName] = { path = png_folder .. png_name .. ".png", w = w, h = h } 190 | end 191 | end 192 | WriteFxData() 193 | end 194 | 195 | local function Process() 196 | if DONE then return end 197 | retval, pluginName = r.EnumInstalledFX(fx_idx) 198 | if not retval then 199 | START = false 200 | DONE = true 201 | BuildDatabase() 202 | return 203 | end 204 | if pluginName then 205 | local png_name = pluginName:gsub("[-:_/%s><]", "_") 206 | local path = folder .. png_name 207 | if not r.file_exists(path .. ".png") then 208 | if not PROCESS then 209 | local fxIndex = r.TrackFX_AddByName(track, pluginName, false, 1) 210 | r.TrackFX_Show(track, fxIndex, 3) 211 | Wait( 212 | r.time_precise(), 213 | function() 214 | takeScreenshot(fxIndex, path) 215 | end 216 | ) 217 | end 218 | else 219 | fx_idx = fx_idx + 1 220 | end 221 | else 222 | fx_idx = fx_idx + 1 223 | end 224 | end 225 | 226 | local function Main() 227 | local visible, open = im.Begin(ctx, 'FX SCREENSHOTER', true) 228 | if visible then 229 | if START then Process() end 230 | if im.Button(ctx, START and "STOP" or "START") then 231 | if not START then 232 | BuildDatabase() 233 | end 234 | START = not START 235 | if DONE then DONE = nil end 236 | end 237 | if fx_idx > 0 then 238 | im.SameLine(ctx) 239 | im.Text(ctx, fx_idx .. " of " .. total_fx) 240 | im.ProgressBar(ctx,fx_idx/total_fx) 241 | if START then 242 | im.Text(ctx, DONE and "FINISHED" or (START and "PROCESSING : " .. (pluginName or "") or "")) 243 | end 244 | end 245 | im.End(ctx) 246 | end 247 | 248 | if open then 249 | PDefer(Main) 250 | end 251 | end 252 | 253 | function Exit() 254 | if track and r.ValidatePtr(track, "MediaTrack*") then 255 | r.DeleteTrack(track) 256 | end 257 | end 258 | 259 | r.atexit(Exit) 260 | PDefer(Main) 261 | -------------------------------------------------------------------------------- /ImGui_Tools/Sexan_Chunk_Viewer.lua: -------------------------------------------------------------------------------- 1 | -- @description Sexan ChunkViewer Imgui 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 1.01 5 | -- @changelog 6 | -- cleanup 7 | local r = reaper 8 | local ctx = r.ImGui_CreateContext('ChunkyBoy') 9 | local contents = '' 10 | 11 | local function AddIdent(str) 12 | local t = {} 13 | local number_of_spaces = 2 14 | local indent = 0 15 | local add = false 16 | for line in str:gmatch("[^\n]+") do 17 | if add then 18 | indent = indent + 1 19 | add = false 20 | end 21 | if line:find("^<") then 22 | add = true 23 | elseif line == ">" then 24 | indent = indent - 1 25 | end 26 | t[#t + 1] = (string.rep(string.rep(" ", number_of_spaces), indent) or "") .. line 27 | end 28 | return table.concat(t, "\n") 29 | end 30 | 31 | local function Main() 32 | local visible, open = reaper.ImGui_Begin(ctx, 'CHUNKY BOY', true, flags) 33 | if visible then 34 | if r.ImGui_Button(ctx, 'GET TRACK') then 35 | local track = r.GetSelectedTrack2(0, 0, true) 36 | if track then 37 | LAST = "TRACK" 38 | LAST_PTR = track 39 | local retval, chunk = r.GetTrackStateChunk(track, "", false) 40 | contents = AddIdent(chunk) 41 | end 42 | end 43 | r.ImGui_SameLine(ctx) 44 | if r.ImGui_Button(ctx, 'GET ENVELOPE') then 45 | local env = r.GetSelectedEnvelope(0) 46 | if env then 47 | LAST = "ENV" 48 | LAST_PTR = env 49 | local retval, chunk = r.GetEnvelopeStateChunk(env, "", false) 50 | contents = AddIdent(chunk) 51 | end 52 | end 53 | r.ImGui_SameLine(ctx) 54 | if r.ImGui_Button(ctx, 'GET ITEM') then 55 | local item = r.GetSelectedMediaItem(0, 0) 56 | if item then 57 | LAST = "ITEM" 58 | LAST_PTR = item 59 | local retval, chunk = r.GetItemStateChunk(item, "", false) 60 | contents = AddIdent(chunk) 61 | end 62 | end 63 | r.ImGui_SameLine(ctx) 64 | if r.ImGui_Button(ctx, 'SET') then 65 | if LAST then 66 | if LAST == "TRACK" then 67 | r.SetTrackStateChunk(LAST_PTR, contents, false) 68 | elseif LAST == "ENV" then 69 | r.SetEnvelopeStateChunk(LAST_PTR, contents, false) 70 | elseif LAST == "ITEM" then 71 | r.SetItemStateChunk(LAST_PTR, contents, false) 72 | end 73 | end 74 | end 75 | RV, contents = r.ImGui_InputTextMultiline(ctx, '##source', contents, -1, -1) 76 | r.ImGui_End(ctx) 77 | end 78 | if open then r.defer(Main) end 79 | end 80 | reaper.defer(Main) 81 | -------------------------------------------------------------------------------- /Items/Sexan_Set Item and take volume of previous odd to next even items.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Set Item and take volume of odd to even items.lua 3 | * About: Script sets volume of item and take of previous odd item to next even item 4 | * Author: SeXan 5 | * Licence: GPL v3 6 | * REAPER: 5.0 7 | * Extensions: None 8 | * Version: 1.3 9 | --]] 10 | 11 | --[[ 12 | * Changelog: 13 | * v1.3 (2017-07-25) 14 | + Small modifications 15 | --]] 16 | 17 | -- Aquired from SPK77 Script - Copy take volume envelope from selected take to other takes in same group 18 | local function get_and_show_take_envelope(take, envelope_name) 19 | local env = reaper.GetTakeEnvelopeByName(take, envelope_name) 20 | local item 21 | 22 | if env == nil then 23 | item = reaper.GetMediaItemTake_Item(take) 24 | local sel = reaper.IsMediaItemSelected(item) 25 | if not sel then 26 | reaper.SetMediaItemSelected(item, true) 27 | end 28 | if envelope_name == "Volume" then reaper.Main_OnCommand(reaper.NamedCommandLookup("_S&M_TAKEENV1"), 0) -- show take volume envelope 29 | elseif envelope_name == "Pan" then reaper.Main_OnCommand(reaper.NamedCommandLookup("_S&M_TAKEENV2"), 0) -- show take pan envelope 30 | elseif envelope_name == "Mute" then reaper.Main_OnCommand(reaper.NamedCommandLookup("_S&M_TAKEENV3"), 0) -- show take mute envelope 31 | elseif envelope_name == "Pitch" then reaper.Main_OnCommand(reaper.NamedCommandLookup("_S&M_TAKEENV10"), 0) -- show take pitch envelope 32 | end 33 | if sel then 34 | reaper.SetMediaItemSelected(item, false) 35 | end 36 | env = reaper.GetTakeEnvelopeByName(take, envelope_name) 37 | end 38 | return env,item 39 | end 40 | 41 | local function Main() 42 | -- ALWAYS USE TRACK 3 43 | local tr = reaper.GetTrack(0,2) 44 | 45 | if not tr then return 0 end 46 | 47 | local cnt_items = reaper.CountTrackMediaItems( tr ) 48 | reaper.PreventUIRefresh(1) 49 | 50 | for i = 1, cnt_items, 2 do 51 | -- ODD 52 | local o_item = reaper.GetTrackMediaItem( tr, i-1 ) 53 | local o_item_v = reaper.GetMediaItemInfo_Value( o_item, "D_VOL" ) 54 | 55 | local o_take = reaper.GetActiveTake(o_item) 56 | local o_take_v = reaper.GetMediaItemTakeInfo_Value( o_take, "D_VOL" ) 57 | local o_take_e = get_and_show_take_envelope(o_take, "Volume") 58 | local retval, env_chunk = reaper.GetEnvelopeStateChunk( o_take_e, "", true ) 59 | 60 | i = i + 1 61 | 62 | -- EVEN 63 | local e_item = reaper.GetTrackMediaItem( tr, i-1 ) 64 | local e_item_v = reaper.SetMediaItemInfo_Value( e_item, "D_VOL", o_item_v ) 65 | 66 | local e_take = reaper.GetActiveTake(e_item) 67 | local e_take_v = reaper.SetMediaItemTakeInfo_Value( e_take, "D_VOL", o_take_v ) 68 | local env,item = get_and_show_take_envelope(e_take, "Volume") 69 | local set_env = reaper.SetEnvelopeStateChunk(env, env_chunk, true) 70 | 71 | if item then 72 | -- UNSELECT ITEMS 73 | reaper.SetMediaItemSelected(item, false) 74 | end 75 | 76 | end 77 | reaper.PreventUIRefresh(0) 78 | reaper.UpdateArrange() 79 | end 80 | Main() 81 | -------------------------------------------------------------------------------- /Items/Sexan_SmartSplit items crossfade left or right.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: SmartSplit items crossfade left or right 3 | * About: This is two action split script, normal split and time selection split.If time selection split already 4 | * exists then you can freely split anywhere while time selection is still active. 5 | * Normal split creates crossfade on the side where the mouse cursor is depending on edit cursor 6 | * Author: SeXan 7 | * Licence: GPL v3 8 | * REAPER: 5.0 9 | * Extensions: SWS 10 | * Version: 1.01 11 | --]] 12 | 13 | --[[ 14 | * Changelog: 15 | * v1.01 (2017-07-13) 16 | --]] 17 | 18 | local edit_cursor_pos = reaper.GetCursorPosition() 19 | local _, _, mouse_pos = reaper.BR_TrackAtMouseCursor() 20 | 21 | local function cross_fade_pos() 22 | if edit_cursor_pos > mouse_pos then 23 | reaper.Main_OnCommand(reaper.NamedCommandLookup("_SWS_AWSPLITXFADELEFT"), 0) 24 | else 25 | reaper.Main_OnCommand(40759,0) 26 | end 27 | end 28 | 29 | local function Main() 30 | local count_sel_items = reaper.CountSelectedMediaItems(0) 31 | if count_sel_items > 0 then 32 | SmartSplit() 33 | end 34 | end 35 | 36 | function SmartSplit() 37 | local item = reaper.GetSelectedMediaItem(0, 0) 38 | local item_start = reaper.GetMediaItemInfo_Value(item,"D_POSITION") 39 | local item_len = reaper.GetMediaItemInfo_Value(item,"D_LENGTH") 40 | local item_end = item_start + item_len 41 | local Tstart, Tend = reaper.GetSet_LoopTimeRange(0, 0, 0, 0, 0) 42 | 43 | --is item in TS 44 | if Tstart <= item_start and Tend >= item_end then cross_fade_pos() 45 | 46 | --is item outside TS (left side) 47 | elseif Tstart > item_start and Tstart >= item_end then cross_fade_pos() 48 | 49 | --is item outside TS (left side but end in TS) 50 | elseif Tstart > item_start and Tend > item_end then cross_fade_pos() 51 | 52 | --is item outside TS (right side) 53 | elseif Tend <= item_start and Tend < item_end then cross_fade_pos() 54 | 55 | --is item outside TS (right side but start in TS) 56 | elseif Tstart < item_start and Tend < item_end then cross_fade_pos() 57 | 58 | 59 | elseif Tstart == Tend then cross_fade_pos() 60 | 61 | --is item over TS 62 | elseif Tstart >= item_start and Tend <= item_end then 63 | reaper.Main_OnCommand(40061, 0) 64 | end 65 | 66 | end 67 | 68 | Main() 69 | -------------------------------------------------------------------------------- /Items/Sexan_select all other items on track.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Select all other items on track.lua 3 | * About: Script select all items on the track except selected one 4 | * Author: SeXan 5 | * Licence: GPL v3 6 | * REAPER: 5.0 7 | * Extensions: None 8 | * Version: 1.13 9 | --]] 10 | 11 | --[[ 12 | * Changelog: 13 | * v1.13 (2017-07-23) 14 | + wrong api used 15 | --]] 16 | 17 | function Main() 18 | sel_item = reaper.GetSelectedMediaItem( 0, 0 ) 19 | 20 | if not sel_item then return 0 end 21 | 22 | local tr = reaper.GetMediaItem_Track( sel_item ) 23 | reaper.SetMediaItemInfo_Value( sel_item, "B_UISEL", 0 ) 24 | 25 | cnt_items = reaper.CountTrackMediaItems( tr ) 26 | 27 | for i = 1, cnt_items do 28 | local item = reaper.GetTrackMediaItem( tr, i-1 ) 29 | if item ~= sel_item then 30 | reaper.SetMediaItemSelected( item, true ) 31 | end 32 | end 33 | reaper.UpdateArrange() 34 | end 35 | Main() 36 | -------------------------------------------------------------------------------- /Other/Sexan_Remove in order time selection items tracks.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Remove in order time selection,items,tracks 3 | * About: Script removes things in following order. If there is time selection, some selected items and tracks 4 | * First run of the script it removes time selection, second items and third tracks. 5 | * (I use it on "ESC" key) 6 | * Author: SeXan 7 | * Licence: GPL v3 8 | * REAPER: 5.0 9 | * Extensions: SWS 10 | * Version: 1.01 11 | --]] 12 | 13 | --[[ 14 | * Changelog: 15 | * v1.01 (2017-07-13) 16 | --]] 17 | 18 | local Tstart, Tend = reaper.GetSet_LoopTimeRange(0, 0, 0, 0, 0) 19 | 20 | function Main() 21 | -- First remove Time Selection 22 | if Tstart ~= Tend then 23 | reaper.Main_OnCommand(40020,0) 24 | -- Second deselect items 25 | elseif reaper.CountSelectedMediaItems(0) then 26 | reaper.Main_OnCommand(40289,0) 27 | -- Third deselect tracks 28 | elseif reaper.CountSelectedTracks(0) then 29 | reaper.Main_OnCommand(40297,0) 30 | end 31 | end 32 | Main() 33 | -------------------------------------------------------------------------------- /Other/Sexan_Show midi note name in tooltip.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Show midi note name in tooltip.lua 3 | * About: Show tooltip with note name and position under mouse cursor 4 | * Requested by nofish 5 | * Author: SeXan 6 | * Licence: GPL v3 7 | * REAPER: 5.0 8 | * Extensions: None 9 | * Version: 1.0 10 | --]] 11 | 12 | --[[ 13 | * Changelog: 14 | * v1.0 (2018-15-11) 15 | + Initial release 16 | --]] 17 | 18 | local oct_tbl = {"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"} 19 | 20 | function round(num, numDecimalPlaces) 21 | local mult = 10^(numDecimalPlaces or 0) 22 | return math.floor(num * mult + 0.5) / mult 23 | end 24 | 25 | function main() 26 | local x,y = reaper.GetMousePosition() 27 | local window, segment, details = reaper.BR_GetMouseCursorContext() 28 | if segment == "notes" and window == "midi_editor" then 29 | local retval, inlineEditor, noteRow, ccLane, ccLaneVal, ccLaneId = reaper.BR_GetMouseCursorContext_MIDI() 30 | local pos = reaper.BR_GetMouseCursorContext_Position() 31 | local retval, measures, cml, fullbeats, cdenom = reaper.TimeMap2_timeToBeats( 0, pos ) 32 | local beats = retval + 1 33 | local oct = math.floor(noteRow / 12) -- get OCTAVE (1,2,3,4....) 34 | local cur_oct = oct * 12 -- GET OCAVE RANGE (12,24,36...) 35 | local cur_oct_note = ((cur_oct - noteRow ) * -1) + 1 -- GET OCTAVE NOTE (1,2,3,4...) 36 | 37 | for i = 1,#oct_tbl do 38 | if i == cur_oct_note then 39 | local note = oct_tbl[i] .. oct - 1 .. " - " .. measures + 1 .. "." .. round(beats, 2) 40 | if last_x ~= x or last_y ~= y then -- DO NOT UPDATE ALL THE TIME, JUST IF MOUSE POSITION CHANGED 41 | reaper.TrackCtl_SetToolTip( note, x, y - 25, true ) 42 | last_x, last_y = x, y 43 | end 44 | end 45 | end 46 | end 47 | reaper.defer(main) 48 | end 49 | main() -------------------------------------------------------------------------------- /ParanormalFX/FXChains/3BANDSTOCK.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | 19 | WAK 0 0 20 | BYPASS 0 0 0 21 | 25 | 27 | SHOW 0 28 | LASTSEL 0 29 | DOCKED 0 30 | > 31 | WAK 0 0 32 | BYPASS 0 0 0 33 | 39 | 41 | SHOW 0 42 | LASTSEL 0 43 | DOCKED 0 44 | > 45 | WAK 0 0 46 | PARALLEL 2 47 | BYPASS 0 0 0 48 | 54 | 56 | SHOW 0 57 | LASTSEL 0 58 | DOCKED 0 59 | > 60 | WAK 0 0 61 | PARALLEL 2 62 | > 63 | WAK 0 0 64 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/4BANDSTOCK.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | 19 | WAK 0 0 20 | BYPASS 0 0 0 21 | 25 | 27 | SHOW 0 28 | LASTSEL 0 29 | DOCKED 0 30 | > 31 | WAK 0 0 32 | BYPASS 0 0 0 33 | 39 | 41 | SHOW 0 42 | LASTSEL 0 43 | DOCKED 0 44 | > 45 | WAK 0 0 46 | PARALLEL 2 47 | BYPASS 0 0 0 48 | 54 | 56 | SHOW 0 57 | LASTSEL 0 58 | DOCKED 0 59 | > 60 | WAK 0 0 61 | PARALLEL 2 62 | BYPASS 0 0 0 63 | 69 | 71 | SHOW 0 72 | LASTSEL 0 73 | DOCKED 0 74 | > 75 | WAK 0 0 76 | PARALLEL 2 77 | > 78 | WAK 0 0 79 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/5BANDSTOCK.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | 18 | WAK 0 0 19 | BYPASS 0 0 0 20 | 24 | 26 | SHOW 0 27 | LASTSEL 0 28 | DOCKED 0 29 | > 30 | WAK 0 0 31 | BYPASS 0 0 0 32 | 38 | 40 | SHOW 0 41 | LASTSEL 0 42 | DOCKED 0 43 | > 44 | WAK 0 0 45 | PARALLEL 2 46 | BYPASS 0 0 0 47 | 53 | 55 | SHOW 0 56 | LASTSEL 0 57 | DOCKED 0 58 | > 59 | WAK 0 0 60 | PARALLEL 2 61 | BYPASS 0 0 0 62 | 68 | 70 | SHOW 0 71 | LASTSEL 0 72 | DOCKED 0 73 | > 74 | WAK 0 0 75 | PARALLEL 2 76 | BYPASS 0 0 0 77 | 83 | 85 | SHOW 0 86 | LASTSEL 0 87 | DOCKED 0 88 | > 89 | WAK 0 0 90 | PARALLEL 2 91 | > 92 | WAK 0 0 93 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_2_4_MODE_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 12 | 20 | SHOW 0 21 | LASTSEL 2 22 | DOCKED 0 23 | BYPASS 0 0 0 24 | 27 | WAK 0 0 28 | BYPASS 0 0 0 29 | 33 | 35 | SHOW 0 36 | LASTSEL 0 37 | DOCKED 0 38 | > 39 | WAK 0 0 40 | BYPASS 0 0 0 41 | 47 | 49 | SHOW 0 50 | LASTSEL 0 51 | DOCKED 0 52 | > 53 | WAK 0 0 54 | PARALLEL 1 55 | BYPASS 0 0 0 56 | 62 | 64 | SHOW 0 65 | LASTSEL 0 66 | DOCKED 0 67 | > 68 | WAK 0 0 69 | PARALLEL 2 70 | BYPASS 0 0 0 71 | 77 | 79 | SHOW 0 80 | LASTSEL 0 81 | DOCKED 0 82 | > 83 | WAK 0 0 84 | PARALLEL 2 85 | > 86 | PRESETNAME "[Template] 3 Band" 87 | WAK 0 0 88 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_2_BANDNOTCH_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 10 | 16 | SHOW 0 17 | LASTSEL 3 18 | DOCKED 0 19 | BYPASS 0 0 0 20 | 23 | WAK 0 0 24 | BYPASS 0 0 0 25 | 31 | 33 | SHOW 0 34 | LASTSEL 0 35 | DOCKED 0 36 | > 37 | WAK 0 0 38 | BYPASS 0 0 0 39 | 43 | 45 | SHOW 0 46 | LASTSEL 0 47 | DOCKED 0 48 | > 49 | WAK 0 0 50 | PARALLEL 1 51 | > 52 | PRESETNAME "[Template] 3 Band" 53 | WAK 0 0 54 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_2_COMBPHASE_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 10 | 16 | SHOW 0 17 | LASTSEL 3 18 | DOCKED 0 19 | BYPASS 0 0 0 20 | 23 | WAK 0 0 24 | BYPASS 0 0 0 25 | 29 | 31 | SHOW 0 32 | LASTSEL 0 33 | DOCKED 0 34 | > 35 | WAK 0 0 36 | BYPASS 0 0 0 37 | 43 | 45 | SHOW 0 46 | LASTSEL 0 47 | DOCKED 0 48 | > 49 | WAK 0 0 50 | PARALLEL 1 51 | > 52 | PRESETNAME "[Template] 3 Band" 53 | WAK 0 0 54 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_3_MIN_PHASE_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 10 | 16 | SHOW 0 17 | LASTSEL 3 18 | DOCKED 0 19 | BYPASS 0 0 0 20 | 23 | 27 | WAK 0 0 28 | BYPASS 0 0 0 29 | 33 | 35 | SHOW 0 36 | LASTSEL 0 37 | DOCKED 0 38 | > 39 | WAK 0 0 40 | BYPASS 0 0 0 41 | 47 | 49 | SHOW 0 50 | LASTSEL 0 51 | DOCKED 0 52 | > 53 | WAK 0 0 54 | PARALLEL 1 55 | BYPASS 0 0 0 56 | 62 | 64 | SHOW 0 65 | LASTSEL 0 66 | DOCKED 0 67 | > 68 | WAK 0 0 69 | PARALLEL 1 70 | > 71 | PRESETNAME "[Template] 3 Band" 72 | WAK 0 0 73 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_ENVELOPE_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 8 | 12 | SHOW 0 13 | LASTSEL 2 14 | DOCKED 0 15 | BYPASS 0 0 0 16 | 19 | WAK 0 0 20 | BYPASS 0 0 0 21 | 25 | 27 | SHOW 0 28 | LASTSEL 0 29 | DOCKED 0 30 | > 31 | WAK 0 0 32 | BYPASS 0 0 0 33 | 39 | 41 | SHOW 0 42 | LASTSEL 0 43 | DOCKED 0 44 | > 45 | WAK 0 0 46 | PARALLEL 1 47 | > 48 | PRESETNAME "[Template] Envelope Follwer Split" 49 | WAK 0 0 50 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_GATE_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 8 | 12 | SHOW 0 13 | LASTSEL 2 14 | DOCKED 0 15 | BYPASS 0 0 0 16 | 19 | WAK 0 0 20 | BYPASS 0 0 0 21 | 25 | 27 | SHOW 0 28 | LASTSEL 0 29 | DOCKED 0 30 | > 31 | WAK 0 0 32 | BYPASS 0 0 0 33 | 39 | 41 | SHOW 0 42 | LASTSEL 0 43 | DOCKED 0 44 | > 45 | WAK 0 0 46 | PARALLEL 1 47 | > 48 | PRESETNAME "[Template] Gate Split" 49 | WAK 0 0 50 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/LEWLOIWC_TRANSIENT_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 8 | 12 | SHOW 0 13 | LASTSEL 0 14 | DOCKED 0 15 | BYPASS 0 0 0 16 | 19 | WAK 0 0 20 | BYPASS 0 0 0 21 | 25 | 27 | SHOW 0 28 | LASTSEL 0 29 | DOCKED 0 30 | > 31 | WAK 0 0 32 | BYPASS 0 0 0 33 | 39 | 41 | SHOW 0 42 | LASTSEL 0 43 | DOCKED 0 44 | > 45 | WAK 0 0 46 | PARALLEL 1 47 | > 48 | PRESETNAME "[Template] Transient Split" 49 | WAK 0 0 50 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/MS_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | WAK 0 0 16 | > 17 | WAK 0 0 18 | BYPASS 0 0 0 19 | 23 | 25 | SHOW 0 26 | LASTSEL 0 27 | DOCKED 0 28 | BYPASS 0 0 0 29 | 32 | WAK 0 0 33 | > 34 | WAK 0 0 35 | PARALLEL 2 36 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/SAIKE_2_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | 18 | 21 | WAK 0 0 22 | BYPASS 0 0 0 23 | 27 | 29 | SHOW 0 30 | LASTSEL 0 31 | DOCKED 0 32 | > 33 | WAK 0 0 34 | BYPASS 0 0 0 35 | 41 | 43 | SHOW 0 44 | LASTSEL 0 45 | DOCKED 0 46 | > 47 | WAK 0 0 48 | PARALLEL 2 49 | > 50 | WAK 0 0 51 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/SAIKE_3_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | JS_DIMS 745 266 16 | 19 | 22 | WAK 0 0 23 | BYPASS 0 0 0 24 | 28 | 30 | SHOW 0 31 | LASTSEL 0 32 | DOCKED 0 33 | > 34 | WAK 0 0 35 | BYPASS 0 0 0 36 | 42 | 44 | SHOW 0 45 | LASTSEL 0 46 | DOCKED 0 47 | > 48 | WAK 0 0 49 | PARALLEL 2 50 | BYPASS 0 0 0 51 | 57 | 59 | SHOW 0 60 | LASTSEL 0 61 | DOCKED 0 62 | > 63 | WAK 0 0 64 | PARALLEL 2 65 | > 66 | WAK 0 0 67 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/SAIKE_4_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | JS_DIMS 1073 340 16 | 19 | 22 | WAK 0 0 23 | BYPASS 0 0 0 24 | 28 | 30 | SHOW 0 31 | LASTSEL 0 32 | DOCKED 0 33 | > 34 | WAK 0 0 35 | BYPASS 0 0 0 36 | 42 | 44 | SHOW 0 45 | LASTSEL 0 46 | DOCKED 0 47 | > 48 | WAK 0 0 49 | PARALLEL 2 50 | BYPASS 0 0 0 51 | 57 | 59 | SHOW 0 60 | LASTSEL 0 61 | DOCKED 0 62 | > 63 | WAK 0 0 64 | PARALLEL 2 65 | BYPASS 0 0 0 66 | 72 | 74 | SHOW 0 75 | LASTSEL 0 76 | DOCKED 0 77 | > 78 | WAK 0 0 79 | PARALLEL 2 80 | > 81 | WAK 0 0 82 | > -------------------------------------------------------------------------------- /ParanormalFX/FXChains/SAIKE_5_SETUP.RfxChain: -------------------------------------------------------------------------------- 1 | BYPASS 0 0 0 2 | 6 | 8 | SHOW 0 9 | LASTSEL 0 10 | DOCKED 0 11 | BYPASS 0 0 0 12 | 15 | JS_DIMS 1105 370 16 | 19 | 22 | WAK 0 0 23 | BYPASS 0 0 0 24 | 28 | 30 | SHOW 0 31 | LASTSEL 0 32 | DOCKED 0 33 | > 34 | WAK 0 0 35 | BYPASS 0 0 0 36 | 42 | 44 | SHOW 0 45 | LASTSEL 0 46 | DOCKED 0 47 | > 48 | WAK 0 0 49 | PARALLEL 2 50 | BYPASS 0 0 0 51 | 57 | 59 | SHOW 0 60 | LASTSEL 0 61 | DOCKED 0 62 | > 63 | WAK 0 0 64 | PARALLEL 2 65 | BYPASS 0 0 0 66 | 72 | 74 | SHOW 0 75 | LASTSEL 0 76 | DOCKED 0 77 | > 78 | WAK 0 0 79 | PARALLEL 2 80 | BYPASS 0 0 0 81 | 87 | 89 | SHOW 0 90 | LASTSEL 0 91 | DOCKED 0 92 | > 93 | WAK 0 0 94 | PARALLEL 2 95 | > 96 | WAK 0 0 97 | > -------------------------------------------------------------------------------- /ParanormalFX/Fonts/Icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ParanormalFX/Fonts/Icons.ttf -------------------------------------------------------------------------------- /ParanormalFX/Fonts/ProggyClean.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ParanormalFX/Fonts/ProggyClean.ttf -------------------------------------------------------------------------------- /ParanormalFX/JSFX/MSMidFX.jsfx: -------------------------------------------------------------------------------- 1 | desc:MS Mid FX 2 | //tags: mid processing for parallel fx 3 | //author: Cockos/Sexan 4 | 5 | in_pin:left input 6 | in_pin:right input 7 | out_pin:left output 8 | out_pin:right output 9 | 10 | @init 11 | ext_tail_size = -2; 12 | 13 | @sample 14 | spl0orig=spl0; 15 | spl1orig=spl1; 16 | spl0 = (spl0orig+spl1orig) * 0.5; 17 | spl1 = (spl0orig+spl1orig) * 0.5; 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ParanormalFX/JSFX/MSSideFX.jsfx: -------------------------------------------------------------------------------- 1 | desc:MS Side FX 2 | //tags: side processing for parallel fx 3 | //author: Cockos/Sexan 4 | 5 | in_pin:left input 6 | in_pin:right input 7 | out_pin:left output 8 | out_pin:right output 9 | 10 | @init 11 | ext_tail_size = -2; 12 | vol = 2^(-180/6); 13 | 14 | @sample 15 | spl0orig=spl0; 16 | spl1orig=spl1; 17 | spl0 = (spl0orig*vol) + (spl0orig-spl1orig) * 0.5; 18 | spl1 = (spl1orig*vol) - (spl0orig-spl1orig) * 0.5; 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ParanormalFX/Modules/Utils.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | local r = reaper 5 | 6 | function Literalize(str) 7 | return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end) 8 | end 9 | 10 | function serializeTable(val, name, skipnewlines, depth) 11 | skipnewlines = skipnewlines or false 12 | depth = depth or 0 13 | local tmp = string.rep(" ", depth) 14 | if name then 15 | if type(name) == "number" and math.floor(name) == name then 16 | name = "[" .. name .. "]" 17 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 18 | name = string.gsub(name, "'", "\\'") 19 | name = "['" .. name .. "']" 20 | end 21 | tmp = tmp .. name .. " = " 22 | end 23 | if type(val) == "table" then 24 | tmp = tmp .. "{" 25 | for k, v in pairs(val) do 26 | tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," 27 | end 28 | tmp = tmp .. string.rep(" ", depth) .. "}" 29 | elseif type(val) == "number" then 30 | tmp = tmp .. tostring(val) 31 | elseif type(val) == "string" then 32 | tmp = tmp .. string.format("%q", val) 33 | elseif type(val) == "boolean" then 34 | tmp = tmp .. (val and "true" or "false") 35 | else 36 | tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" 37 | end 38 | return tmp 39 | end 40 | 41 | function tableToString(table) 42 | return serializeTable(table) 43 | end 44 | 45 | function stringToTable(str) 46 | local f, err = load("return " .. str) 47 | return f ~= nil and f() or nil 48 | end 49 | 50 | function OpenFile(file) 51 | local cmd 52 | if r.GetOS():sub(1, 3) == 'Win' then 53 | cmd = 'cmd.exe /C start ""' 54 | else 55 | cmd = '/bin/sh -c open ""' 56 | end 57 | r.ExecProcess(([[%s "%s"]]):format(cmd, file), 0) 58 | end 59 | 60 | local pearson_table = { 61 | 9, 159, 180, 252, 71, 6, 13, 164, 232, 35, 226, 155, 98, 120, 154, 69, 62 | 157, 24, 137, 29, 147, 78, 121, 85, 112, 8, 248, 130, 55, 117, 190, 160, 63 | 176, 131, 228, 64, 211, 106, 38, 27, 140, 30, 88, 210, 227, 104, 84, 77, 64 | 75, 107, 169, 138, 195, 184, 70, 90, 61, 166, 7, 244, 165, 108, 219, 51, 65 | 9, 139, 209, 40, 31, 202, 58, 179, 116, 33, 207, 146, 76, 60, 242, 124, 66 | 254, 197, 80, 167, 153, 145, 129, 233, 132, 48, 246, 86, 156, 177, 36, 187, 67 | 45, 1, 96, 18, 19, 62, 185, 234, 99, 16, 218, 95, 128, 224, 123, 253, 68 | 42, 109, 4, 247, 72, 5, 151, 136, 0, 152, 148, 127, 204, 133, 17, 14, 69 | 182, 217, 54, 199, 119, 174, 82, 57, 215, 41, 114, 208, 206, 110, 239, 23, 70 | 189, 15, 3, 22, 188, 79, 113, 172, 28, 2, 222, 21, 251, 225, 237, 105, 71 | 102, 32, 56, 181, 126, 83, 230, 53, 158, 52, 59, 213, 118, 100, 67, 142, 72 | 220, 170, 144, 115, 205, 26, 125, 168, 249, 66, 175, 97, 255, 92, 229, 91, 73 | 214, 236, 178, 243, 46, 44, 201, 250, 135, 186, 150, 221, 163, 216, 162, 43, 74 | 11, 101, 34, 37, 194, 25, 50, 12, 87, 198, 173, 240, 193, 171, 143, 231, 75 | 111, 141, 191, 103, 74, 245, 223, 20, 161, 235, 122, 63, 89, 149, 73, 238, 76 | 134, 68, 93, 183, 241, 81, 196, 49, 192, 65, 212, 94, 203, 10, 200, 47, 77 | } 78 | assert(#pearson_table == 0x100) 79 | 80 | function pearson8(str) 81 | local hash = 0 82 | for c in str:gmatch('.') do 83 | hash = pearson_table[(hash ~ c:byte()) + 1] 84 | end 85 | return hash 86 | end 87 | 88 | local tsort = table.sort 89 | function SortTable(tab, val1, val2) 90 | tsort(tab, function(a, b) 91 | if (a[val1] < b[val1]) then 92 | -- primary sort on position -> a before b 93 | return true 94 | elseif (a[val1] > b[val1]) then 95 | -- primary sort on position -> b before a 96 | return false 97 | else 98 | -- primary sort tied, resolve w secondary sort on rank 99 | return a[val2] < b[val2] 100 | end 101 | end) 102 | end 103 | 104 | function Lead_Trim_ws(s) return s:match '^%s*(.*)' end 105 | 106 | local old_t = {} 107 | local old_filter = "" 108 | function Filter_actions(filter_text, tbl) 109 | if old_filter == filter_text then return old_t end 110 | filter_text = Lead_Trim_ws(filter_text) 111 | local t = {} 112 | if filter_text == "" or not filter_text then return t end 113 | for i = 1, #tbl do 114 | local name = tbl[i]:lower() 115 | local found = true 116 | for word in filter_text:gmatch("%S+") do 117 | if not name:find(word:lower(), 1, true) then 118 | found = false 119 | break 120 | end 121 | end 122 | if found then t[#t + 1] = { score = tbl[i]:len() - filter_text:len(), name = tbl[i] } end 123 | end 124 | if #t >= 2 then 125 | SortTable(t, "score", "name") -- Sort by key priority 126 | end 127 | old_t = t 128 | old_filter = filter_text 129 | return t 130 | end 131 | 132 | function SetMinMax(Input, Min, Max) 133 | if Input >= Max then 134 | Input = Max 135 | elseif Input <= Min then 136 | Input = Min 137 | else 138 | Input = Input 139 | end 140 | return Input 141 | end 142 | 143 | function ClearExtState() 144 | r.DeleteExtState("PARANORMALFX2", "COPY_BUFFER", false) 145 | r.DeleteExtState("PARANORMALFX2", "COPY_BUFFER_ID", false) 146 | CLIPBOARD = {} 147 | end 148 | 149 | function Deepcopy(orig) 150 | local orig_type = type(orig) 151 | local copy 152 | if orig_type == 'table' then 153 | copy = {} 154 | for orig_key, orig_value in next, orig, nil do 155 | copy[Deepcopy(orig_key)] = Deepcopy(orig_value) 156 | end 157 | setmetatable(copy, Deepcopy(getmetatable(orig))) 158 | else -- number, string, boolean, etc 159 | copy = orig 160 | end 161 | return copy 162 | end 163 | 164 | function HasMultiple(tbl) 165 | local cnt = 0 166 | for _ in pairs(tbl) do 167 | cnt = cnt + 1 168 | if cnt == 2 then return true end 169 | end 170 | --return count 171 | end 172 | 173 | 174 | function M_CLICK() return r.JS_Mouse_GetState(95) &1 == 1 end 175 | 176 | function M_TEST() 177 | if not LAST_CLICK and M_CLICK() then 178 | LAST_CLICK = true 179 | end 180 | 181 | MOUSE_UP = not LAST_CLICK and true or false 182 | 183 | if LAST_CLICK and not M_CLICK() then 184 | LAST_CLICK = nil 185 | end 186 | end 187 | 188 | --profiler.attachToWorld() -- after all functions have been defined -------------------------------------------------------------------------------- /ParanormalFX/Modules/flux.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | -- 5 | -- flux 6 | -- 7 | -- Copyright (c) 2016 rxi 8 | -- 9 | -- This library is free software; you can redistribute it and/or modify it 10 | -- under the terms of the MIT license. See LICENSE for details. 11 | -- 12 | 13 | local flux = { _version = "0.1.5" } 14 | flux.__index = flux 15 | 16 | flux.tweens = {} 17 | flux.easing = { linear = function(p) return p end } 18 | 19 | local easing = { 20 | quad = "p * p", 21 | cubic = "p * p * p", 22 | quart = "p * p * p * p", 23 | quint = "p * p * p * p * p", 24 | expo = "2 ^ (10 * (p - 1))", 25 | sine = "-math.cos(p * (math.pi * .5)) + 1", 26 | circ = "-(math.sqrt(1 - (p * p)) - 1)", 27 | back = "p * p * (2.7 * p - 1.7)", 28 | elastic = "-(2^(10 * (p - 1)) * math.sin((p - 1.075) * (math.pi * 2) / .3))" 29 | } 30 | 31 | local makefunc = function(str, expr) 32 | local load = loadstring or load 33 | return load("return function(p) " .. str:gsub("%$e", expr) .. " end")() 34 | end 35 | 36 | for k, v in pairs(easing) do 37 | flux.easing[k .. "in"] = makefunc("return $e", v) 38 | flux.easing[k .. "out"] = makefunc([[ 39 | p = 1 - p 40 | return 1 - ($e) 41 | ]], v) 42 | flux.easing[k .. "inout"] = makefunc([[ 43 | p = p * 2 44 | if p < 1 then 45 | return .5 * ($e) 46 | else 47 | p = 2 - p 48 | return .5 * (1 - ($e)) + .5 49 | end 50 | ]], v) 51 | end 52 | 53 | local tween = {} 54 | tween.__index = tween 55 | 56 | local function makefsetter(field) 57 | return function(self, x) 58 | local mt = getmetatable(x) 59 | if type(x) ~= "function" and not (mt and mt.__call) then 60 | error("expected function or callable", 2) 61 | end 62 | local old = self[field] 63 | self[field] = old and function() 64 | old() 65 | x() 66 | end or x 67 | return self 68 | end 69 | end 70 | 71 | local function makesetter(field, checkfn, errmsg) 72 | return function(self, x) 73 | if checkfn and not checkfn(x) then 74 | error(errmsg:gsub("%$x", tostring(x)), 2) 75 | end 76 | self[field] = x 77 | return self 78 | end 79 | end 80 | 81 | tween.ease = makesetter("_ease", 82 | function(x) return flux.easing[x] end, 83 | "bad easing type '$x'") 84 | tween.delay = makesetter("_delay", 85 | function(x) return type(x) == "number" end, 86 | "bad delay time; expected number") 87 | tween.onstart = makefsetter("_onstart") 88 | tween.onupdate = makefsetter("_onupdate") 89 | tween.oncomplete = makefsetter("_oncomplete") 90 | 91 | 92 | function tween.new(obj, time, vars) 93 | local self = setmetatable({}, tween) 94 | self.obj = obj 95 | self.rate = time > 0 and 1 / time or 0 96 | self.progress = time > 0 and 0 or 1 97 | self._delay = 0 98 | self._ease = "quadout" 99 | self.vars = {} 100 | for k, v in pairs(vars) do 101 | if type(v) ~= "number" then 102 | error("bad value for key '" .. k .. "'; expected number") 103 | end 104 | self.vars[k] = v 105 | end 106 | return self 107 | end 108 | 109 | function tween:init() 110 | for k, v in pairs(self.vars) do 111 | local x = self.obj[k] 112 | if type(x) ~= "number" then 113 | error("bad value on object key '" .. k .. "'; expected number") 114 | end 115 | self.vars[k] = { start = x, diff = v - x } 116 | end 117 | self.inited = true 118 | end 119 | 120 | function tween:after(...) 121 | local t 122 | if select("#", ...) == 2 then 123 | t = tween.new(self.obj, ...) 124 | else 125 | t = tween.new(...) 126 | end 127 | t.parent = self.parent 128 | self:oncomplete(function() flux.add(self.parent, t) end) 129 | return t 130 | end 131 | 132 | function tween:stop() 133 | flux.remove(self.parent, self) 134 | end 135 | 136 | function flux.group() 137 | return setmetatable({}, flux) 138 | end 139 | 140 | function flux:to(obj, time, vars) 141 | return flux.add(self, tween.new(obj, time, vars)) 142 | end 143 | 144 | function flux:update(deltatime) 145 | for i = #self, 1, -1 do 146 | local t = self[i] 147 | if t._delay > 0 then 148 | t._delay = t._delay - deltatime 149 | else 150 | if not t.inited then 151 | flux.clear(self, t.obj, t.vars) 152 | t:init() 153 | end 154 | if t._onstart then 155 | t._onstart() 156 | t._onstart = nil 157 | end 158 | t.progress = t.progress + t.rate * deltatime 159 | local p = t.progress 160 | local x = p >= 1 and 1 or flux.easing[t._ease](p) 161 | for k, v in pairs(t.vars) do 162 | t.obj[k] = v.start + x * v.diff 163 | end 164 | if t._onupdate then t._onupdate() end 165 | if p >= 1 then 166 | flux.remove(self, i) 167 | if t._oncomplete then t._oncomplete() end 168 | end 169 | end 170 | end 171 | end 172 | 173 | function flux:clear(obj, vars) 174 | for t in pairs(self[obj]) do 175 | if t.inited then 176 | for k in pairs(vars) do t.vars[k] = nil end 177 | end 178 | end 179 | end 180 | 181 | function flux:add(tween) 182 | -- Add to object table, create table if it does not exist 183 | local obj = tween.obj 184 | self[obj] = self[obj] or {} 185 | self[obj][tween] = true 186 | -- Add to array 187 | table.insert(self, tween) 188 | tween.parent = self 189 | return tween 190 | end 191 | 192 | function flux:remove(x) 193 | if type(x) == "number" then 194 | -- Remove from object table, destroy table if it is empty 195 | local obj = self[x].obj 196 | self[obj][self[x]] = nil 197 | if not next(self[obj]) then self[obj] = nil end 198 | -- Remove from array 199 | self[x] = self[#self] 200 | return table.remove(self) 201 | end 202 | for i, v in ipairs(self) do 203 | if v == x then 204 | return flux.remove(self, i) 205 | end 206 | end 207 | end 208 | 209 | local bound = { 210 | to = function(...) return flux.to(flux.tweens, ...) end, 211 | update = function(...) return flux.update(flux.tweens, ...) end, 212 | remove = function(...) return flux.remove(flux.tweens, ...) end, 213 | } 214 | setmetatable(bound, flux) 215 | 216 | return bound 217 | -------------------------------------------------------------------------------- /Pie3000/CustomImages/Readme.txt: -------------------------------------------------------------------------------- 1 | Put here your custom png images/icons. -------------------------------------------------------------------------------- /Pie3000/PieUtils.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | local r = reaper 4 | 5 | local getinfo = debug.getinfo(1, 'S'); 6 | local script_path = getinfo.source:match [[^@?(.*[\/])[^\/]-$]]; 7 | package.path = script_path .. "?.lua;" .. package.path -- GET DIRECTORY FOR REQUIRE 8 | 9 | function CheckDeps() 10 | local deps = {} 11 | if not r.ImGui_GetVersion then 12 | deps[#deps + 1] = '"Dear Imgui"' 13 | end 14 | if not r.JS_VKeys_Intercept then 15 | deps[#deps + 1] = '"js_ReaScriptAPI"' 16 | end 17 | if not r.SNM_SetIntConfigVar then 18 | deps[#deps + 1] = '"SWS/S&M"' 19 | end 20 | 21 | if #deps ~= 0 then 22 | r.ShowMessageBox("Need Additional Packages.\nPlease Install it in next window", "MISSING DEPENDENCIES", 0) 23 | r.ReaPack_BrowsePackages(table.concat(deps, " OR ")) 24 | return true 25 | end 26 | end 27 | 28 | function SaveToFile(data, fn) 29 | local file 30 | file = io.open(fn, "w") 31 | if file then 32 | file:write(data) 33 | file:close() 34 | end 35 | end 36 | 37 | function InTbl(tbl, val) 38 | for i = 1, #tbl do 39 | if tbl[i].guid == val then 40 | return tbl[i], i 41 | end 42 | end 43 | end 44 | 45 | function PngToRelative(fn) 46 | local file = io.open(fn, "r") 47 | if not file then return end 48 | local content = file:read("a") 49 | if content == "" then return end 50 | content = content:gsub('png = "(.-)/Data', 'png = "/Data') 51 | file = io.open(fn, "w") 52 | if file then 53 | file:write(content) 54 | file:close() 55 | end 56 | end 57 | 58 | function Deepcopy(orig) 59 | local orig_type = type(orig) 60 | local copy 61 | if orig_type == 'table' then 62 | copy = {} 63 | for orig_key, orig_value in next, orig, nil do 64 | copy[Deepcopy(orig_key)] = Deepcopy(orig_value) 65 | end 66 | setmetatable(copy, Deepcopy(getmetatable(orig))) 67 | else -- number, string, boolean, etc 68 | copy = orig 69 | end 70 | return copy 71 | end 72 | 73 | function pow(x, p) return x ^ p end 74 | 75 | function ReadFromFile(fn) 76 | local file = io.open(fn, "r") 77 | if not file then return end 78 | local content = file:read("a") 79 | if content == "" then return end 80 | return StringToTable(content) 81 | end 82 | 83 | function StringToTable(str) 84 | local f, err = load("return " .. str) 85 | return f ~= nil and f() or nil 86 | end 87 | 88 | function serializeTable(val, name, skipnewlines, depth) 89 | skipnewlines = skipnewlines or false 90 | depth = depth or 0 91 | local tmp = string.rep(" ", depth) 92 | if name then 93 | if type(name) == "number" and math.floor(name) == name then 94 | name = "[" .. name .. "]" 95 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 96 | name = string.gsub(name, "'", "\\'") 97 | name = "['" .. name .. "']" 98 | end 99 | tmp = tmp .. name .. " = " 100 | end 101 | if type(val) == "table" then 102 | tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") 103 | for k, v in pairs(val) do 104 | if k ~= "selected" and k ~= "guid_list" and k ~= "img_obj" then 105 | tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "") 106 | end 107 | end 108 | tmp = tmp .. string.rep(" ", depth) .. "}" 109 | elseif type(val) == "number" then 110 | tmp = tmp .. tostring(val) 111 | elseif type(val) == "string" then 112 | tmp = tmp .. string.format("%q", val) 113 | elseif type(val) == "boolean" then 114 | tmp = tmp .. (val and "true" or "false") 115 | else 116 | tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" 117 | end 118 | return tmp 119 | end 120 | 121 | function TableToString(table, new_line) 122 | local str = serializeTable(table, nil, new_line) 123 | return str 124 | end 125 | 126 | if not r.HasExtState("PIE3000", "RELATIVE_PNG") then 127 | --! REMOVE THIS AFTER A WHILE (THIS IS CURRENT SILENT PNG RELATIVE PATH FIX) 128 | local menu_file = script_path .. "menu_file.txt" 129 | local pie_file = script_path .. "pie_file.txt" 130 | PngToRelative(pie_file) 131 | PngToRelative(menu_file) 132 | r.SetExtState("PIE3000", "RELATIVE_PNG", "fix", true) 133 | end 134 | -------------------------------------------------------------------------------- /Pie3000/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/Pie3000/Roboto-Medium.ttf -------------------------------------------------------------------------------- /Pie3000/Sexan_Pie3000_Tracker_BG.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | local r = reaper 4 | r.set_action_options(1|4) 5 | 6 | local WND = { 7 | ["Media Explorer"] = true 8 | } 9 | 10 | local SCRIPT_START_TIME = r.time_precise() 11 | local prev_wnd = r.JS_Window_FromPoint(r.GetMousePosition()) 12 | local PIE_KEY 13 | local pie_id = "_RS4d29f3707604c3725652ed7a634cf9a2f390a588" 14 | 15 | for k in io.lines(r.GetResourcePath() .. "/reaper-kb.ini") do 16 | if k:match(pie_id) then 17 | PIE_KEY = k:match("KEY %d+ (%d+)") 18 | end 19 | end 20 | 21 | local MAIN_HWND = r.GetMainHwnd() 22 | local function TriggerPie(parent, title, info) 23 | local MIDI_HWND = r.MIDIEditor_GetActive() 24 | if (WND[title] or info:match("^fx_")) and r.JS_Window_GetFocus() ~= MAIN_HWND then 25 | r.JS_Window_SetFocus(r.GetMainHwnd()) 26 | r.JS_WindowMessage_Post(MAIN_HWND, "WM_KEYDOWN", PIE_KEY, 0, 0, 0) 27 | elseif parent == MAIN_HWND then 28 | r.JS_Window_SetFocus(r.GetMainHwnd()) 29 | r.JS_WindowMessage_Post(MAIN_HWND, "WM_KEYDOWN", PIE_KEY, 0, 0, 0) 30 | elseif parent == MIDI_HWND then 31 | r.JS_Window_SetFocus(MIDI_HWND) 32 | r.JS_WindowMessage_Post(MAIN_HWND, "WM_KEYDOWN", PIE_KEY, 0, 0, 0) 33 | end 34 | end 35 | 36 | local parent_title, parent 37 | local function Main() 38 | local x, y = r.GetMousePosition() 39 | local wnd = r.JS_Window_FromPoint(x, y) 40 | local track, info = r.GetThingFromPoint(x, y) 41 | 42 | if prev_wnd ~= wnd then 43 | --local wnd_id = r.JS_Window_GetLongPtr(wnd, "ID") 44 | parent = r.JS_Window_GetParent(wnd) 45 | parent_title = r.JS_Window_GetTitle(parent) 46 | prev_wnd = wnd 47 | end 48 | 49 | if prev_wnd == wnd then 50 | local key_state = r.JS_VKeys_GetState(SCRIPT_START_TIME - 0.1) 51 | if key_state:byte(PIE_KEY) ~= 0 then 52 | SCRIPT_START_TIME = r.time_precise() + 0.1 53 | TriggerPie(parent, parent_title, info) 54 | end 55 | end 56 | r.defer(Main) 57 | end 58 | 59 | r.atexit(function() 60 | r.set_action_options(1|8) 61 | end) 62 | Main() 63 | -------------------------------------------------------------------------------- /Pie3000/Sexan_PieCleanFiles.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | local getinfo = debug.getinfo(1, 'S'); 5 | local script_path = getinfo.source:match [[^@?(.*[\/])[^\/]-$]]; 6 | package.path = script_path .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 7 | 8 | local pie_file = script_path .. "pie_file.txt" 9 | local menu_file = script_path .. "menu_file.txt" 10 | 11 | rv = reaper.ShowMessageBox( "Delete Pie script data?", "WARNING", 1 ) 12 | 13 | if rv == 1 then 14 | os.remove(pie_file) 15 | os.remove(menu_file) 16 | end -------------------------------------------------------------------------------- /Pie3000/fontello1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/Pie3000/fontello1.ttf -------------------------------------------------------------------------------- /PieMenu/PieICONS.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/PieMenu/PieICONS.ttf -------------------------------------------------------------------------------- /PieMenu/PieUtils.lua: -------------------------------------------------------------------------------- 1 | function Save_to_file(data, fn) 2 | local file 3 | file = io.open(fn, "w") 4 | file:write(data) 5 | file:close() 6 | end 7 | 8 | function Read_from_file(fn) 9 | local file = io.open(fn, "r") 10 | if not file then return end 11 | local content = file:read("a") 12 | if content == "" then return end 13 | return content 14 | end 15 | 16 | function StringToTable(str) 17 | local f, err = load("return " .. str) 18 | return f ~= nil and f() or nil 19 | end 20 | 21 | local function SerializeTable(val, name, skipnewlines, depth) 22 | skipnewlines = skipnewlines or false 23 | depth = depth or 0 24 | local tmp = string.rep(" ", depth) 25 | if name then 26 | if type(name) == "number" and math.floor(name) == name then 27 | name = "[" .. name .. "]" 28 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 29 | name = string.gsub(name, "'", "\\'") 30 | name = "['" .. name .. "']" 31 | end 32 | tmp = tmp .. name .. " = " 33 | end 34 | if type(val) == "table" then 35 | tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") 36 | for k, v in pairs(val) do 37 | tmp = tmp .. SerializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "") 38 | end 39 | tmp = tmp .. string.rep(" ", depth) .. "}" 40 | elseif type(val) == "number" then 41 | tmp = tmp .. tostring(val) 42 | elseif type(val) == "string" then 43 | tmp = tmp .. string.format("%q", val) 44 | elseif type(val) == "boolean" then 45 | tmp = tmp .. (val and "true" or "false") 46 | else 47 | tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" 48 | end 49 | return tmp 50 | end 51 | 52 | function TableToString(table) 53 | local str = SerializeTable(table) 54 | return str 55 | end 56 | -------------------------------------------------------------------------------- /PieMenu/pie_menus.txt: -------------------------------------------------------------------------------- 1 | { 2 | arrange = { 3 | [1] = { 4 | cmd = "", 5 | name = "FOR SETUP SCRIPT", 6 | icon = "E", 7 | }, 8 | [2] = { 9 | icon = "", 10 | name = "WHEN YOU GET TIME", 11 | }, 12 | [3] = { 13 | cmd = { 14 | [1] = { 15 | cmd = 2019, 16 | name = "THANK", 17 | }, 18 | [2] = { 19 | cmd = 2003, 20 | name = "YOU", 21 | }, 22 | [3] = { 23 | cmd = 42383, 24 | name = "VERY MUCH", 25 | }, 26 | }, 27 | name = "?", 28 | icon = "X", 29 | }, 30 | [4] = { 31 | icon = "O", 32 | name = "BIRDY", 33 | }, 34 | [5] = { 35 | cmd = "", 36 | name = "WILL YOU PLEASE", 37 | icon = "X", 38 | }, 39 | [6] = { 40 | cmd = "", 41 | name = "MAKE A SANE UI", 42 | icon = "L", 43 | }, 44 | [7] = { 45 | cmd = 65547, 46 | name = "Script: PieSetup.lua", 47 | icon = "", 48 | }, 49 | [8] = { 50 | cmd = { 51 | [2] = { 52 | cmd = 41738, 53 | name = "Edit: Delete notes of less than 1/128 note in length in selected MIDI items", 54 | }, 55 | [1] = { 56 | cmd = 40698, 57 | name = "Edit: Copy items", 58 | }, 59 | }, 60 | name = "EMPTY MENU7", 61 | icon = "", 62 | }, 63 | [9] = { 64 | cmd = 40858, 65 | name = "Automation lane: Decrease active fader a little bit", 66 | icon = "", 67 | }, 68 | }, 69 | mcp = { 70 | [8] = { 71 | cmd = { 72 | [1] = { 73 | cmd = 40406, 74 | name = "Toggle Volume", 75 | }, 76 | [2] = { 77 | cmd = 40407, 78 | name = "Toggle Pan", 79 | }, 80 | [3] = { 81 | cmd = 1007, 82 | name = "Yellow", 83 | }, 84 | [4] = { 85 | cmd = 1007, 86 | name = "Blue", 87 | }, 88 | [5] = { 89 | cmd = 1007, 90 | name = "Schwa", 91 | }, 92 | [6] = { 93 | cmd = 1007, 94 | name = "Justin", 95 | }, 96 | [7] = { 97 | cmd = 1007, 98 | name = "PLAY", 99 | }, 100 | }, 101 | name = "ENV Menu", 102 | icon = "E", 103 | }, 104 | [1] = { 105 | cmd = 1007, 106 | name = "Play", 107 | icon = "A", 108 | }, 109 | [2] = { 110 | cmd = 1013, 111 | name = "Record", 112 | icon = "B", 113 | }, 114 | [3] = { 115 | cmd = 1007, 116 | name = "Play", 117 | icon = "A", 118 | }, 119 | [4] = { 120 | cmd = 1013, 121 | name = "Record", 122 | icon = "B", 123 | }, 124 | [5] = { 125 | cmd = 1003, 126 | name = "Schwa", 127 | icon = "C", 128 | }, 129 | [6] = { 130 | cmd = 1003, 131 | name = "Justin", 132 | icon = "D", 133 | }, 134 | [7] = { 135 | cmd = "_RSaea4bc032a8e5652fe85818e22f6a1a1b38557f3", 136 | name = "Birdy TAG", 137 | icon = "E", 138 | }, 139 | }, 140 | envelope = { 141 | [8] = { 142 | cmd = { 143 | [1] = { 144 | cmd = 40406, 145 | name = "Toggle Volume", 146 | }, 147 | [2] = { 148 | cmd = 40407, 149 | name = "Toggle Pan", 150 | }, 151 | [3] = { 152 | cmd = 1007, 153 | name = "Yellow", 154 | }, 155 | [4] = { 156 | cmd = 1007, 157 | name = "Blue", 158 | }, 159 | [5] = { 160 | cmd = 1007, 161 | name = "Schwa", 162 | }, 163 | [6] = { 164 | cmd = 1007, 165 | name = "Justin", 166 | }, 167 | [7] = { 168 | cmd = 1007, 169 | name = "PLAY", 170 | }, 171 | }, 172 | name = "ENV Menu", 173 | icon = "E", 174 | }, 175 | [1] = { 176 | cmd = 1007, 177 | name = "Play", 178 | icon = "A", 179 | }, 180 | [2] = { 181 | cmd = 1013, 182 | name = "Record", 183 | icon = "B", 184 | }, 185 | [3] = { 186 | cmd = 1007, 187 | name = "Play", 188 | icon = "A", 189 | }, 190 | [4] = { 191 | cmd = 1013, 192 | name = "Record", 193 | icon = "B", 194 | }, 195 | [5] = { 196 | cmd = 1003, 197 | name = "Schwa", 198 | icon = "C", 199 | }, 200 | [6] = { 201 | cmd = 1003, 202 | name = "Justin", 203 | icon = "D", 204 | }, 205 | [7] = { 206 | cmd = "_RSaea4bc032a8e5652fe85818e22f6a1a1b38557f3", 207 | name = "Birdy TAG", 208 | icon = "E", 209 | }, 210 | }, 211 | tcp = { 212 | [8] = { 213 | cmd = { 214 | [1] = { 215 | cmd = 40406, 216 | name = "Toggle Volume", 217 | }, 218 | [2] = { 219 | cmd = 40407, 220 | name = "Toggle Pan", 221 | }, 222 | [3] = { 223 | cmd = 1007, 224 | name = "Yellow", 225 | }, 226 | [4] = { 227 | cmd = 1007, 228 | name = "Blue", 229 | }, 230 | [5] = { 231 | cmd = 1007, 232 | name = "Schwa", 233 | }, 234 | [6] = { 235 | cmd = 1007, 236 | name = "Justin", 237 | }, 238 | [7] = { 239 | cmd = 1007, 240 | name = "PLAY", 241 | }, 242 | }, 243 | name = "ENV Menu", 244 | icon = "E", 245 | }, 246 | [1] = { 247 | cmd = 1007, 248 | name = "Play", 249 | icon = "A", 250 | }, 251 | [2] = { 252 | cmd = 1013, 253 | name = "Record", 254 | icon = "B", 255 | }, 256 | [3] = { 257 | cmd = 1007, 258 | name = "Play", 259 | icon = "A", 260 | }, 261 | [4] = { 262 | cmd = 1013, 263 | name = "Record", 264 | icon = "B", 265 | }, 266 | [5] = { 267 | cmd = 1003, 268 | name = "Schwa", 269 | icon = "C", 270 | }, 271 | [6] = { 272 | cmd = 1003, 273 | name = "Justin", 274 | icon = "D", 275 | }, 276 | [7] = { 277 | cmd = "_RSaea4bc032a8e5652fe85818e22f6a1a1b38557f3", 278 | name = "Birdy TAG", 279 | icon = "E", 280 | }, 281 | }, 282 | item = { 283 | [1] = { 284 | cmd = 1007, 285 | name = "Play", 286 | icon = "A", 287 | }, 288 | [2] = { 289 | cmd = 1013, 290 | name = "Record", 291 | icon = "B", 292 | }, 293 | [3] = { 294 | cmd = 1007, 295 | name = "Play", 296 | icon = "A", 297 | }, 298 | [4] = { 299 | cmd = 1013, 300 | name = "Record", 301 | icon = "B", 302 | }, 303 | [5] = { 304 | cmd = 1003, 305 | name = "Schwa", 306 | icon = "C", 307 | }, 308 | [6] = { 309 | cmd = 1003, 310 | name = "Justin", 311 | icon = "D", 312 | }, 313 | [7] = { 314 | cmd = 40406, 315 | name = "envelope VISIBLE", 316 | icon = "E", 317 | }, 318 | [8] = { 319 | cmd = { 320 | [1] = { 321 | cmd = 40406, 322 | name = "Toggle Volume", 323 | }, 324 | [2] = { 325 | cmd = 40407, 326 | name = "Toggle Pan", 327 | }, 328 | [3] = { 329 | cmd = 1007, 330 | name = "Yellow", 331 | }, 332 | [4] = { 333 | cmd = 1007, 334 | name = "Blue", 335 | }, 336 | [5] = { 337 | cmd = 1007, 338 | name = "Schwa", 339 | }, 340 | [6] = { 341 | cmd = 1007, 342 | name = "Justin", 343 | }, 344 | [7] = { 345 | cmd = 1007, 346 | name = "PLAY", 347 | }, 348 | }, 349 | name = "ENV Menu", 350 | icon = "E", 351 | }, 352 | [9] = { 353 | action = "", 354 | name = "ADD MORE", 355 | icon = "C", 356 | }, 357 | [10] = { 358 | action = "", 359 | name = "BATTNS", 360 | icon = "C", 361 | }, 362 | }, 363 | } -------------------------------------------------------------------------------- /Project/Sexan_Multi_project_time_counter.lua: -------------------------------------------------------------------------------- 1 | -- @description Multi project time counter 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 1.45 5 | -- @changelog 6 | -- + cleanup 7 | 8 | local reaper = reaper 9 | --------------------------------------- 10 | local afk = 60 -- set afk treshold HERE 11 | --------------------------------------- 12 | local threshold = afk 13 | local last_time = 0 14 | local last_action_time = 0 15 | local last_proj_change_count = reaper.GetProjectStateChangeCount(0) 16 | local last_proj, last_proj_name = reaper.EnumProjects(-1, 0) 17 | local dock_pos = reaper.GetExtState("timer", "dock") 18 | 19 | local timer, timer2 20 | 21 | local function store_time() -- store time values to project 22 | reaper.SetProjExtState(0, "timer", "timer", timer) -- store seconds 23 | reaper.SetProjExtState(0, "timer", "timer2", timer2) -- store seconds 24 | end 25 | 26 | local function restore_time() -- restore time values from project 27 | local ret, load_timer = reaper.GetProjExtState(0, "timer", "timer") -- restore seconds 28 | local ret, load_timer2 = reaper.GetProjExtState(0, "timer", "timer2") -- restore seconds 29 | if load_timer ~= "" and load_timer2 ~= "" then 30 | timer = tonumber(load_timer) 31 | timer2 = tonumber(load_timer2) 32 | else 33 | timer = 0 34 | timer2 = 0 35 | end 36 | end 37 | 38 | local function count_time() 39 | if afk < threshold then 40 | if os.time() - last_action_time > 0 then -- interval of 1 second 41 | afk = afk + 1 42 | timer = timer + 1 43 | last_action_time = os.time() 44 | end 45 | end 46 | 47 | if os.time() - last_time > 0 then 48 | timer2 = timer2 + 1 49 | last_time = os.time() 50 | end 51 | 52 | store_time() 53 | end 54 | 55 | local function time(x) 56 | local days = math.floor(x / (60 * 60 * 24)) 57 | local hours = math.floor(x / (60 * 60) % 24) 58 | local minutes = math.floor(x / 60 % 60) 59 | local seconds = math.floor(x % 60) 60 | 61 | local time = string.format("%02d:%02d:%02d:%02d", days, hours, minutes, seconds) 62 | return time 63 | end 64 | 65 | local function main() 66 | local proj, proj_name = reaper.EnumProjects(-1, 0) 67 | local proj_change_count = reaper.GetProjectStateChangeCount(0) 68 | 69 | if last_proj ~= proj then 70 | restore_time() 71 | last_proj = proj 72 | end 73 | 74 | if proj_change_count > last_proj_change_count or reaper.GetPlayState() ~= 0 then 75 | afk = 0 76 | last_proj_change_count = proj_change_count 77 | end 78 | 79 | count_time() 80 | 81 | local project_time, afk_time = time(timer2), time(timer) 82 | local w_time = os.date("%X") 83 | 84 | gfx.x, gfx.y = 2, 8 85 | gfx.printf(" ") 86 | gfx.printf(w_time) 87 | gfx.printf(" - T") 88 | gfx.x, gfx.y = 2, 38 89 | gfx.printf(project_time) 90 | gfx.printf(" - P") 91 | gfx.x, gfx.y = 2, 68 92 | gfx.printf(afk_time) 93 | gfx.printf(" - A") 94 | gfx.update() 95 | 96 | if gfx.getchar() > -1 then -- defer while gfx window is open 97 | reaper.defer(main) 98 | end 99 | end 100 | 101 | local function store_settings() 102 | reaper.SetExtState("timer", "dock", gfx.dock(-1), true) 103 | store_time() 104 | end 105 | 106 | local function init() 107 | dock_pos = dock_pos or 513 108 | gfx.init("", 155, 100, dock_pos) 109 | gfx.setfont(1, "Arial", 24) 110 | gfx.clear = 3355443 111 | main() 112 | end 113 | 114 | restore_time() 115 | init() 116 | reaper.atexit(store_settings) 117 | -------------------------------------------------------------------------------- /Project/Sexan_Project time counter with AFK mode.lua: -------------------------------------------------------------------------------- 1 | -- @description Project Time Counter with AFK mode 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 1.40 5 | -- @changelog 6 | -- + cleanup 7 | 8 | local reaper = reaper 9 | --------------------------------------- 10 | local afk = 60 -- set afk treshold HERE 11 | --------------------------------------- 12 | local threshold = afk 13 | 14 | local last_action_time = 0 15 | local last_proj_change_count = reaper.GetProjectStateChangeCount(0) 16 | local last_proj, last_proj_name = reaper.EnumProjects(-1, 0) 17 | local dock_pos = reaper.GetExtState("timer", "dock") 18 | 19 | function store_time() -- store time values to project 20 | reaper.SetProjExtState(0, "timer", "timer", timer) -- store seconds 21 | end 22 | 23 | function restore_time() -- restore time values from project 24 | local ret, load_timer = reaper.GetProjExtState(0, "timer", "timer") -- restore seconds 25 | if load_timer ~= "" then 26 | timer = tonumber(load_timer) 27 | else 28 | timer = 0 29 | end 30 | end 31 | 32 | function count_time() 33 | if afk < threshold then 34 | if os.time() - last_action_time > 0 then -- interval of 1 second 35 | afk = afk + 1 36 | timer = timer + 1 37 | last_action_time = os.time() 38 | end 39 | end 40 | store_time() 41 | end 42 | 43 | function time() 44 | local days = math.floor(timer / (60 * 60 * 24)) 45 | local hours = math.floor(timer / (60 * 60) % 24) 46 | local minutes = math.floor(timer / 60 % 60) 47 | local seconds = math.floor(timer % 60) 48 | 49 | local format = string.format("%02d:%02d:%02d:%02d", days, hours, minutes, seconds) 50 | return format 51 | end 52 | 53 | function main() 54 | local proj, proj_name = reaper.EnumProjects(-1, 0) 55 | local proj_change_count = reaper.GetProjectStateChangeCount(0) 56 | 57 | if last_proj ~= proj then 58 | restore_time() 59 | last_proj = proj 60 | end 61 | 62 | if proj_change_count > last_proj_change_count or reaper.GetPlayState() ~= 0 then 63 | afk = 0 64 | last_proj_change_count = proj_change_count 65 | end 66 | 67 | count_time() 68 | 69 | gfx.x, gfx.y = 2, 15 70 | gfx.printf(time()) 71 | gfx.update() 72 | 73 | if gfx.getchar() > -1 then -- defer while gfx window is open 74 | reaper.defer(main) 75 | else 76 | 77 | end 78 | end 79 | 80 | function store_settings() 81 | reaper.SetExtState("timer", "dock", gfx.dock(-1), true) 82 | store_time() 83 | end 84 | 85 | function init() 86 | dock_pos = dock_pos or 513 87 | 88 | gfx.init("", 120, 50, dock_pos) 89 | gfx.setfont(1, "Arial", 24) 90 | gfx.clear = 3355443 91 | main() 92 | end 93 | 94 | restore_time() -- call function restore_time() to restore time values from project 95 | init() 96 | reaper.atexit(store_settings) 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReaScripts 2 | My ReaPack Repo : https://github.com/GoranKovac/ReaScripts/raw/master/index.xml 3 | 4 | Donation : https://www.paypal.me/GoranK101 5 | Kofi: https://ko-fi.com/goran52202 6 | -------------------------------------------------------------------------------- /ReaSpaghetti/Docs/ReaSpaghetti.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Docs/ReaSpaghetti.pdf -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/BG.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/Explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/Explosion.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/MENU.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/MENU.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/Schwa_ATTACK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/Schwa_ATTACK.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/Schwa_IDLE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/Schwa_IDLE.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/invader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/invader.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/invader2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/invader2.png -------------------------------------------------------------------------------- /ReaSpaghetti/Examples/SCHWA/squid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/ReaSpaghetti/Examples/SCHWA/squid.png -------------------------------------------------------------------------------- /ReaSpaghetti/ExportedActions/dummy.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/Defaults.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | WIDGETS_LIVE_UPDATE_SPEED = 10 -- FRAMES 5 | 6 | -- EDGE GRAG SCROLLING 7 | EDGE_SCROLLING_ZONE = 80 8 | EDGE_SCROLLING_SPEED = 5 9 | 10 | -- ENABLE GRID 11 | GRID = true 12 | 13 | -- THRESHOLD FOR NEW PROJECT SAVE PROMPT 14 | NEW_PROJECT_NODE_CONDITION = 1 15 | 16 | -- FONT SIZE FOR ZOOMING (UPDATES ON ZOOM - EVERYTHING IN NODE) 17 | FONT_SIZE = 16 18 | ORG_FONT_SIZE = FONT_SIZE 19 | 20 | -- STATIC FONT SIZE (WONT UPDATE ON ZOOM - TOOLTIPS) 21 | FONT_SIZE_STATIC = 15 22 | 23 | TOOLTIP = true 24 | DEBUG = false 25 | PROFILE_DEBUG = false 26 | 27 | PROJECT_NAME = 'Untitled Spaghetti' 28 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/ExportToAction.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | local r = reaper 5 | function ExportTest(name, proj_path, is_defer) 6 | name = name:match(".%reanodes") and name or name .. ".reanodes" 7 | local lua_string = {} 8 | 9 | table.insert(lua_string, 'package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\\/])[^\\/]-$]] .. "../?.lua;"') 10 | table.insert(lua_string, 'STANDALONE_RUN = true') 11 | if is_defer then 12 | table.insert(lua_string, 'DEFER = true') 13 | end 14 | table.insert(lua_string, 'require("Sexan_ReaSpaghetti")') 15 | table.insert(lua_string, 'local func_file = "' .. proj_path:gsub("\\", "/") .. name:gsub("\\", "/") .. '"') 16 | table.insert(lua_string, 'local file = io.open(func_file, "r")') 17 | table.insert(lua_string, 'if file then') 18 | table.insert(lua_string, ' local string = file:read("*all")') 19 | table.insert(lua_string, ' RestoreNodes(string)') 20 | table.insert(lua_string, ' file:close()') 21 | table.insert(lua_string, 'end') 22 | 23 | table.insert(lua_string, 'local function Main()') 24 | 25 | table.insert(lua_string, 'InitRunFlow()') 26 | if is_defer then 27 | table.insert(lua_string, 'if DEFERED_NODE and DEFER then reaper.defer(Main) end') 28 | end 29 | table.insert(lua_string, 'end') 30 | table.insert(lua_string, 'local function Exit()') 31 | if is_defer then 32 | table.insert(lua_string, 'DEFER = nil') 33 | end 34 | table.insert(lua_string, 'end') 35 | table.insert(lua_string, 'reaper.atexit(Exit)') 36 | if is_defer then 37 | table.insert(lua_string, 'reaper.defer(Main)') 38 | else 39 | table.insert(lua_string, 'Main()') 40 | end 41 | 42 | local path = PATH .. "ExportedActions/ReaSpaghetti_StandAlone_" .. name:gsub(".reanodes", "") .. ".lua" 43 | local file = io.open(path, "w") 44 | if file then 45 | file:write(table.concat(lua_string, "\n")) 46 | file:close() 47 | local ret = r.AddRemoveReaScript(true, 0, path, 1) 48 | if ret then 49 | ADDED_TO_ACTIONS = true 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/Library.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | local r = reaper 4 | 5 | local lib_path = PATH .. "Library" 6 | 7 | local LIBRARY = {} 8 | 9 | function InitLibrary() 10 | LIBRARY = {} 11 | for index = 0, math.huge do 12 | local lib_file = r.EnumerateFiles(lib_path, index) 13 | if not lib_file then break end 14 | local file = io.open(lib_path .. NATIVE_SEPARATOR .. lib_file, "r") 15 | if file then 16 | local string = file:read("*all") 17 | local store_function = StringToTable(string) 18 | if store_function ~= nil then 19 | LIBRARY[#LIBRARY + 1] = store_function 20 | end 21 | file:close() 22 | end 23 | end 24 | end 25 | 26 | function GetLibrary() 27 | return LIBRARY 28 | end 29 | 30 | function ExportFunction(id) 31 | local FUNCTIONS = GetFUNCTIONS() 32 | local function_to_export = FUNCTIONS[id] 33 | local serialized = TableToString(function_to_export) 34 | local save_path = PATH .. "Library" .. NATIVE_SEPARATOR .. function_to_export.label .. ".reanlib" 35 | 36 | local file = io.open(save_path, "w") 37 | if file then 38 | file:write(serialized) 39 | file:close() 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/Undo.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | local UNDO = {} 5 | local UNDO_LIMIT = 10 6 | 7 | local function RelinkMetatables(node) 8 | local FUNCTIONS = GetFUNCTIONS() 9 | --local node = func_tbl.NODES[n] 10 | if node.type == "func" then 11 | -- NODE HAS PARRENT FUNCTION 12 | if node.FID then 13 | -- RELINK FUNCTION NODES METATABLE 14 | node.NODES = {} 15 | setmetatable(node.NODES, 16 | { 17 | __index = FUNCTIONS[node.FID].NODES, 18 | __len = function() return #FUNCTIONS[node.FID].NODES end 19 | } 20 | ) 21 | end 22 | end 23 | 24 | -- RELINK INPUT METATABLE 25 | for o = 1, #node.inputs do 26 | if next(node.inputs[o].connection) then 27 | local connected_node = GetNodeInfo(node.inputs[o].connection[1].node) 28 | setmetatable(node.inputs[o], { 29 | __index = connected_node.outputs[node.inputs[o].connection[1].pin] 30 | }) 31 | end 32 | end 33 | 34 | -- RELINK MATH METATABLE 35 | if node.fname and node.fname:lower():find("math") then 36 | setmetatable(node.outputs[1], { 37 | __index = function(t, k) 38 | if k == "o_val" then return DoMath(node.inputs[2].i_val, node) end 39 | end, 40 | }) 41 | elseif node.fname and node.fname:lower():find("std_") then 42 | setmetatable(node.outputs[1], { 43 | __index = function(t, k) 44 | if k == "o_val" then return DoStd(node.inputs[2].i_val, node) end 45 | end, 46 | }) 47 | end 48 | 49 | -- RELINK GETTERS METATABLE 50 | if node.get then 51 | local source_node = GetNodeInfo(node.get) 52 | setmetatable(node.outputs[1], { 53 | __index = source_node.outputs[1], 54 | }) 55 | end 56 | 57 | 58 | if node.set then 59 | -- RELINK API SETTER 60 | if node.set.api then 61 | local source_node = GetNodeInfo(node.set.guid) 62 | setmetatable(node.inputs[1], { 63 | __index = source_node.outputs[node.set.pin], 64 | }) 65 | else 66 | -- RELINK VARIABLE SETTER 67 | local source_node = GetNodeInfo(node.set.guid) 68 | setmetatable(node.outputs[1], { 69 | __index = function(t, k) 70 | if k == "get" then rawset(node.outputs[1], "o_val", source_node.outputs[1].o_val) end 71 | end, 72 | __newindex = function(t, k, v) if k == "set" then source_node.outputs[1].o_val = v end end 73 | }) 74 | end 75 | end 76 | end 77 | 78 | function AddUndo(node, operation) 79 | if #UNDO == UNDO_LIMIT then 80 | table.remove(UNDO, 1) 81 | else 82 | UNDO[#UNDO + 1] = { node = Deepcopy(node), op_tbl = operation } 83 | end 84 | end 85 | 86 | local function RevertWires(node, wire_link) 87 | for i = 0, #node.inputs do 88 | if #node.inputs[i].connection ~= 0 then 89 | if node.inputs[i].connection[1].link == wire_link then 90 | local target_node = GetNodeInfo(node.inputs[i].connection[1].node) 91 | local target_pin = node.inputs[i].connection[1].pin 92 | 93 | target_node.outputs[target_pin].connection[#target_node.outputs[target_pin].connection + 1] = { 94 | link = wire_link, 95 | node = node.guid, 96 | pin = i, 97 | } 98 | end 99 | end 100 | end 101 | end 102 | 103 | function DoUndo() 104 | if #UNDO == 0 then return end 105 | local last_node = UNDO[#UNDO].node 106 | local last_operation = UNDO[#UNDO].op_tbl 107 | if last_node then 108 | local FUNCTIONS = GetFUNCTIONS() 109 | if last_operation.op == "DELETE_WIRE" then 110 | RevertWires(last_node, last_operation.link) 111 | end 112 | 113 | local source_node, f, n = GetNodeInfo(last_node.guid) 114 | if source_node then 115 | FUNCTIONS[f].NODES[n] = last_node 116 | RelinkMetatables(FUNCTIONS[f].NODES[n]) 117 | end 118 | table.remove(UNDO, #UNDO) 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/Utils.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | local r = reaper 5 | 6 | function Literalize(str) 7 | return str:gsub( 8 | "[%(%)%.%%%+%-%*%?%[%]%^%$]", 9 | function(c) 10 | return "%" .. c 11 | end 12 | ) 13 | end 14 | 15 | function Ltrim(s) 16 | if s == nil then return end 17 | return (s:gsub("^%s*", "")) 18 | end 19 | 20 | function OpenFile(file) 21 | local cmd 22 | if r.GetOS():sub(1, 3) == 'Win' then 23 | cmd = 'cmd.exe /C start ""' 24 | else 25 | cmd = '/bin/sh -c open ""' 26 | end 27 | r.ExecProcess(([[%s "%s"]]):format(cmd, file), 0) 28 | end 29 | 30 | function OpenUrlHelp(api) 31 | local cmd 32 | if r.GetOS():sub(1, 3) == 'Win' then 33 | cmd = 'cmd.exe /C start ""' 34 | else 35 | cmd = '/bin/sh -c open ""' 36 | end 37 | r.ExecProcess(([[%s "https://www.extremraym.com/cloud/reascript-doc/#%s"]]):format(cmd, api), 0) 38 | end 39 | 40 | function OpenUrl(api) 41 | local cmd 42 | if r.GetOS():sub(1, 3) == 'Win' then 43 | cmd = 'cmd.exe /C start ""' 44 | else 45 | cmd = '/bin/sh -c open ""' 46 | end 47 | r.ExecProcess(([[%s %s"]]):format(cmd, api), 0) 48 | end 49 | 50 | function ShallowCopy(t) 51 | local t2 = {} 52 | for k, v in pairs(t) do 53 | t2[k] = v 54 | end 55 | return t2 56 | end 57 | 58 | function Deepcopy(orig) 59 | local orig_type = type(orig) 60 | local copy 61 | if orig_type == 'table' then 62 | copy = {} 63 | for orig_key, orig_value in next, orig, nil do 64 | copy[Deepcopy(orig_key)] = Deepcopy(orig_value) 65 | end 66 | setmetatable(copy, Deepcopy(getmetatable(orig))) 67 | else -- number, string, boolean, etc 68 | copy = orig 69 | end 70 | return copy 71 | end 72 | 73 | function Palette(t) 74 | local a = { r = 0.5, g = 0.5, b = 0.5 } 75 | local b = { r = 0.5, g = 0.5, b = 0.5 } 76 | local c = { r = 1, g = 1, b = 1 } 77 | local d = { r = 0, g = 0.33, b = 0.67 } 78 | 79 | local brightness = 0.2 80 | 81 | local col = {} 82 | col.r = math.min(a.r + brightness + math.cos((c.r * t + d.r) * 6.28318) * b.r, 1) 83 | col.g = math.min(a.g + brightness + math.cos((c.g * t + d.g) * 6.28318) * b.g, 1) 84 | col.b = math.min(a.b + brightness + math.cos((c.b * t + d.b) * 6.28318) * b.b, 1) 85 | return col 86 | end 87 | 88 | function SerializeTable(val, name, skipnewlines, depth) 89 | skipnewlines = skipnewlines or false 90 | depth = depth or 0 91 | local tmp = string.rep(" ", depth) 92 | if name then 93 | if type(name) == "number" and math.floor(name) == name then 94 | name = "[" .. name .. "]" 95 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 96 | name = string.gsub(name, "'", "\\'") 97 | name = "['" .. name .. "']" 98 | end 99 | tmp = tmp .. name .. " = " 100 | end 101 | if type(val) == "table" then 102 | tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") 103 | for k, v in pairs(val) do 104 | tmp = tmp .. SerializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "") 105 | end 106 | tmp = tmp .. string.rep(" ", depth) .. "}" 107 | else 108 | val = type(val) ~= 'userdata' and val or nil 109 | tmp = tmp .. ('%q'):format(val) 110 | end 111 | return tmp 112 | end 113 | 114 | function SerializeTableEXTSTATE(val, name, skipnewlines, depth) 115 | skipnewlines = skipnewlines or false 116 | depth = depth or 0 117 | local tmp = string.rep(" ", depth) 118 | if name then 119 | if type(name) == "number" and math.floor(name) == name then 120 | name = "[" .. name .. "]" 121 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 122 | name = string.gsub(name, "'", "\\'") 123 | name = "['" .. name .. "']" 124 | end 125 | tmp = tmp .. name .. " = " 126 | end 127 | if type(val) == "table" then 128 | tmp = tmp .. "{" -- .. (not skipnewlines and "\n" or "") 129 | for k, v in pairs(val) do 130 | tmp = tmp .. SerializeTable(v, k, skipnewlines, depth + 1) --.. "," .. (not skipnewlines and "\n" or "") 131 | end 132 | tmp = tmp .. string.rep(" ", depth) .. "}" 133 | else 134 | -- HOPE TO FIX INF, -INF, NAN 135 | val = type(val) ~= 'userdata' and val or nil 136 | tmp = tmp .. ('%q'):format(val) 137 | -- elseif type(val) == "number" then 138 | -- tmp = tmp .. tostring(val) 139 | -- elseif type(val) == "string" then 140 | -- tmp = tmp .. string.format("%q", val) 141 | -- elseif type(val) == "boolean" then 142 | -- tmp = tmp .. (val and "true" or "false") 143 | -- else 144 | -- --! THIS IS MODIFICATION FOR THIS SCRIPT 145 | -- --! POINTERS GET RECALCULATED ON RUN SO WE NIL HERE (MEDIATRACKS, MEDIAITEMS... ) 146 | -- tmp = tmp .. "nil" 147 | -- --tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" 148 | end 149 | return tmp 150 | end 151 | 152 | function TableToString(table) return SerializeTable(table) end 153 | 154 | function StringToTable(str) 155 | local f, err = load("return " .. str) 156 | if err then 157 | reaper.ShowConsoleMsg("\nerror" .. err) 158 | end 159 | return f ~= nil and f() or nil 160 | end 161 | 162 | function Unbackslashed(s) 163 | local str = tostring(s) 164 | local ch = { 165 | ["\\a"] = '\\007', --'\a' alarm Ctrl+G BEL 166 | ["\\b"] = '\\008', --'\b' backspace Ctrl+H BS 167 | ["\\f"] = '\\012', --'\f' formfeed Ctrl+L FF 168 | ["\\n"] = '\\010', --'\n' newline Ctrl+J LF 169 | ["\\r"] = '\\013', --'\r' carriage return Ctrl+M CR 170 | ["\\t"] = '\\009', --'\t' horizontal tab Ctrl+I HT 171 | ["\\v"] = '\\011', --'\v' vertical tab Ctrl+K VT 172 | ["\\\n"] = '\\010', -- newline 173 | ["\\\\"] = '\\092', -- backslash 174 | ["\\'"] = '\\039', -- apostrophe 175 | ['\\"'] = '\\034', -- quote 176 | } 177 | return str:gsub("(\\.)", ch) 178 | :gsub("\\(%d%d?%d?)", function(n) 179 | return string.char(tonumber(n)) 180 | end) 181 | end 182 | 183 | function Dump(o) 184 | if type(o) == 'table' then 185 | local s = '{ ' 186 | for k, v in pairs(o) do 187 | if type(k) ~= 'number' then k = '"' .. k .. '"' end 188 | s = s .. '[' .. k .. '] = ' .. Dump(v) .. ',' .. "\n" 189 | end 190 | return s .. '} ' 191 | else 192 | return tostring(o) 193 | end 194 | end 195 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/flux.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | -- 5 | -- flux 6 | -- 7 | -- Copyright (c) 2016 rxi 8 | -- 9 | -- This library is free software; you can redistribute it and/or modify it 10 | -- under the terms of the MIT license. See LICENSE for details. 11 | -- 12 | 13 | local flux = { _version = "0.1.5" } 14 | flux.__index = flux 15 | 16 | flux.tweens = {} 17 | flux.easing = { linear = function(p) return p end } 18 | 19 | local easing = { 20 | quad = "p * p", 21 | cubic = "p * p * p", 22 | quart = "p * p * p * p", 23 | quint = "p * p * p * p * p", 24 | expo = "2 ^ (10 * (p - 1))", 25 | sine = "-math.cos(p * (math.pi * .5)) + 1", 26 | circ = "-(math.sqrt(1 - (p * p)) - 1)", 27 | back = "p * p * (2.7 * p - 1.7)", 28 | elastic = "-(2^(10 * (p - 1)) * math.sin((p - 1.075) * (math.pi * 2) / .3))" 29 | } 30 | 31 | local makefunc = function(str, expr) 32 | local load = loadstring or load 33 | return load("return function(p) " .. str:gsub("%$e", expr) .. " end")() 34 | end 35 | 36 | for k, v in pairs(easing) do 37 | flux.easing[k .. "in"] = makefunc("return $e", v) 38 | flux.easing[k .. "out"] = makefunc([[ 39 | p = 1 - p 40 | return 1 - ($e) 41 | ]], v) 42 | flux.easing[k .. "inout"] = makefunc([[ 43 | p = p * 2 44 | if p < 1 then 45 | return .5 * ($e) 46 | else 47 | p = 2 - p 48 | return .5 * (1 - ($e)) + .5 49 | end 50 | ]], v) 51 | end 52 | 53 | local tween = {} 54 | tween.__index = tween 55 | 56 | local function makefsetter(field) 57 | return function(self, x) 58 | local mt = getmetatable(x) 59 | if type(x) ~= "function" and not (mt and mt.__call) then 60 | error("expected function or callable", 2) 61 | end 62 | local old = self[field] 63 | self[field] = old and function() 64 | old() 65 | x() 66 | end or x 67 | return self 68 | end 69 | end 70 | 71 | local function makesetter(field, checkfn, errmsg) 72 | return function(self, x) 73 | if checkfn and not checkfn(x) then 74 | error(errmsg:gsub("%$x", tostring(x)), 2) 75 | end 76 | self[field] = x 77 | return self 78 | end 79 | end 80 | 81 | tween.ease = makesetter("_ease", 82 | function(x) return flux.easing[x] end, 83 | "bad easing type '$x'") 84 | tween.delay = makesetter("_delay", 85 | function(x) return type(x) == "number" end, 86 | "bad delay time; expected number") 87 | tween.onstart = makefsetter("_onstart") 88 | tween.onupdate = makefsetter("_onupdate") 89 | tween.oncomplete = makefsetter("_oncomplete") 90 | 91 | 92 | function tween.new(obj, time, vars) 93 | local self = setmetatable({}, tween) 94 | self.obj = obj 95 | self.rate = time > 0 and 1 / time or 0 96 | self.progress = time > 0 and 0 or 1 97 | self._delay = 0 98 | self._ease = "quadout" 99 | self.vars = {} 100 | for k, v in pairs(vars) do 101 | if type(v) ~= "number" then 102 | error("bad value for key '" .. k .. "'; expected number") 103 | end 104 | self.vars[k] = v 105 | end 106 | return self 107 | end 108 | 109 | function tween:init() 110 | for k, v in pairs(self.vars) do 111 | local x = self.obj[k] 112 | if type(x) ~= "number" then 113 | error("bad value on object key '" .. k .. "'; expected number") 114 | end 115 | self.vars[k] = { start = x, diff = v - x } 116 | end 117 | self.inited = true 118 | end 119 | 120 | function tween:after(...) 121 | local t 122 | if select("#", ...) == 2 then 123 | t = tween.new(self.obj, ...) 124 | else 125 | t = tween.new(...) 126 | end 127 | t.parent = self.parent 128 | self:oncomplete(function() flux.add(self.parent, t) end) 129 | return t 130 | end 131 | 132 | function tween:stop() 133 | flux.remove(self.parent, self) 134 | end 135 | 136 | function flux.group() 137 | return setmetatable({}, flux) 138 | end 139 | 140 | function flux:to(obj, time, vars) 141 | return flux.add(self, tween.new(obj, time, vars)) 142 | end 143 | 144 | function flux:update(deltatime) 145 | for i = #self, 1, -1 do 146 | local t = self[i] 147 | if t._delay > 0 then 148 | t._delay = t._delay - deltatime 149 | else 150 | if not t.inited then 151 | flux.clear(self, t.obj, t.vars) 152 | t:init() 153 | end 154 | if t._onstart then 155 | t._onstart() 156 | t._onstart = nil 157 | end 158 | t.progress = t.progress + t.rate * deltatime 159 | local p = t.progress 160 | local x = p >= 1 and 1 or flux.easing[t._ease](p) 161 | for k, v in pairs(t.vars) do 162 | t.obj[k] = v.start + x * v.diff 163 | end 164 | if t._onupdate then t._onupdate() end 165 | if p >= 1 then 166 | flux.remove(self, i) 167 | if t._oncomplete then t._oncomplete() end 168 | end 169 | end 170 | end 171 | end 172 | 173 | function flux:clear(obj, vars) 174 | for t in pairs(self[obj]) do 175 | if t.inited then 176 | for k in pairs(vars) do t.vars[k] = nil end 177 | end 178 | end 179 | end 180 | 181 | function flux:add(tween) 182 | -- Add to object table, create table if it does not exist 183 | local obj = tween.obj 184 | self[obj] = self[obj] or {} 185 | self[obj][tween] = true 186 | -- Add to array 187 | table.insert(self, tween) 188 | tween.parent = self 189 | return tween 190 | end 191 | 192 | function flux:remove(x) 193 | if type(x) == "number" then 194 | -- Remove from object table, destroy table if it is empty 195 | local obj = self[x].obj 196 | self[obj][self[x]] = nil 197 | if not next(self[obj]) then self[obj] = nil end 198 | -- Remove from array 199 | self[x] = self[#self] 200 | return table.remove(self) 201 | end 202 | for i, v in ipairs(self) do 203 | if v == x then 204 | return flux.remove(self, i) 205 | end 206 | end 207 | end 208 | 209 | local bound = { 210 | to = function(...) return flux.to(flux.tweens, ...) end, 211 | update = function(...) return flux.update(flux.tweens, ...) end, 212 | remove = function(...) return flux.remove(flux.tweens, ...) end, 213 | } 214 | setmetatable(bound, flux) 215 | 216 | return bound 217 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/json.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | --[[ json.lua 5 | 6 | A compact pure-Lua JSON library. 7 | The main functions are: json.stringify, json.parse. 8 | 9 | ## json.stringify: 10 | 11 | This expects the following to be true of any tables being encoded: 12 | * They only have string or number keys. Number keys must be represented as 13 | strings in json; this is part of the json spec. 14 | * They are not recursive. Such a structure cannot be specified in json. 15 | 16 | A Lua table is considered to be an array if and only if its set of keys is a 17 | consecutive sequence of positive integers starting at 1. Arrays are encoded like 18 | so: `[2, 3, false, "hi"]`. Any other type of Lua table is encoded as a json 19 | object, encoded like so: `{"key1": 2, "key2": false}`. 20 | 21 | Because the Lua nil value cannot be a key, and as a table value is considerd 22 | equivalent to a missing key, there is no way to express the json "null" value in 23 | a Lua table. The only way this will output "null" is if your entire input obj is 24 | nil itself. 25 | 26 | An empty Lua table, {}, could be considered either a json object or array - 27 | it's an ambiguous edge case. We choose to treat this as an object as it is the 28 | more general type. 29 | 30 | To be clear, none of the above considerations is a limitation of this code. 31 | Rather, it is what we get when we completely observe the json specification for 32 | as arbitrary a Lua object as json is capable of expressing. 33 | 34 | ## json.parse: 35 | 36 | This function parses json, with the exception that it does not pay attention to 37 | \u-escaped unicode code points in strings. 38 | 39 | It is difficult for Lua to return null as a value. In order to prevent the loss 40 | of keys with a null value in a json string, this function uses the one-off 41 | table value json.null (which is just an empty table) to indicate null values. 42 | This way you can check if a value is null with the conditional 43 | `val == json.null`. 44 | 45 | If you have control over the data and are using Lua, I would recommend just 46 | avoiding null values in your data to begin with. 47 | 48 | --]] 49 | local json = {} 50 | 51 | 52 | -- Internal functions. 53 | 54 | local function kind_of(obj) 55 | if type(obj) ~= 'table' then return type(obj) end 56 | local i = 1 57 | for _ in pairs(obj) do 58 | if obj[i] ~= nil then i = i + 1 else return 'table' end 59 | end 60 | if i == 1 then return 'table' else return 'array' end 61 | end 62 | 63 | local function escape_str(s) 64 | local in_char = { '\\', '"', '/', '\b', '\f', '\n', '\r', '\t' } 65 | local out_char = { '\\', '"', '/', 'b', 'f', 'n', 'r', 't' } 66 | for i, c in ipairs(in_char) do 67 | s = s:gsub(c, '\\' .. out_char[i]) 68 | end 69 | return s 70 | end 71 | 72 | -- Returns pos, did_find; there are two cases: 73 | -- 1. Delimiter found: pos = pos after leading space + delim; did_find = true. 74 | -- 2. Delimiter not found: pos = pos after leading space; did_find = false. 75 | -- This throws an error if err_if_missing is true and the delim is not found. 76 | local function skip_delim(str, pos, delim, err_if_missing) 77 | pos = pos + #str:match('^%s*', pos) 78 | if str:sub(pos, pos) ~= delim then 79 | if err_if_missing then 80 | error('Expected ' .. delim .. ' near position ' .. pos) 81 | end 82 | return pos, false 83 | end 84 | return pos + 1, true 85 | end 86 | 87 | -- Expects the given pos to be the first character after the opening quote. 88 | -- Returns val, pos; the returned pos is after the closing quote character. 89 | local function parse_str_val(str, pos, val) 90 | val = val or '' 91 | local early_end_error = 'End of input found while parsing string.' 92 | if pos > #str then error(early_end_error) end 93 | local c = str:sub(pos, pos) 94 | if c == '"' then return val, pos + 1 end 95 | if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end 96 | -- We must have a \ character. 97 | local esc_map = { b = '\b', f = '\f', n = '\n', r = '\r', t = '\t' } 98 | local nextc = str:sub(pos + 1, pos + 1) 99 | if not nextc then error(early_end_error) end 100 | return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc)) 101 | end 102 | 103 | -- Returns val, pos; the returned pos is after the number's final character. 104 | local function parse_num_val(str, pos) 105 | local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos) 106 | local val = tonumber(num_str) 107 | if not val then error('Error parsing number at position ' .. pos .. '.') end 108 | return val, pos + #num_str 109 | end 110 | 111 | 112 | -- Public values and functions. 113 | 114 | function json.stringify(obj, as_key) 115 | local s = {} -- We'll build the string as an array of strings to be concatenated. 116 | local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise. 117 | if kind == 'array' then 118 | if as_key then error('Can\'t encode array as key.') end 119 | s[#s + 1] = '[' 120 | for i, val in ipairs(obj) do 121 | if i > 1 then s[#s + 1] = ', ' end 122 | s[#s + 1] = json.stringify(val) 123 | end 124 | s[#s + 1] = ']' 125 | elseif kind == 'table' then 126 | if as_key then error('Can\'t encode table as key.') end 127 | s[#s + 1] = '{' 128 | for k, v in pairs(obj) do 129 | if #s > 1 then s[#s + 1] = ', ' end 130 | s[#s + 1] = json.stringify(k, true) 131 | s[#s + 1] = ':' 132 | s[#s + 1] = json.stringify(v) 133 | end 134 | s[#s + 1] = '}' 135 | elseif kind == 'string' then 136 | return '"' .. escape_str(obj) .. '"' 137 | elseif kind == 'number' then 138 | if as_key then return '"' .. tostring(obj) .. '"' end 139 | return tostring(obj) 140 | elseif kind == 'boolean' then 141 | return tostring(obj) 142 | elseif kind == 'nil' then 143 | return 'null' 144 | else 145 | error('Unjsonifiable type: ' .. kind .. '.') 146 | end 147 | return table.concat(s) 148 | end 149 | 150 | json.null = {} -- This is a one-off table to represent the null value. 151 | 152 | function json.parse(str, pos, end_delim) 153 | pos = pos or 1 154 | if pos > #str then error('Reached unexpected end of input.') end 155 | local pos = pos + #str:match('^%s*', pos) -- Skip whitespace. 156 | local first = str:sub(pos, pos) 157 | if first == '{' then -- Parse an object. 158 | local obj, key, delim_found = {}, true, true 159 | pos = pos + 1 160 | while true do 161 | key, pos = json.parse(str, pos, '}') 162 | if key == nil then return obj, pos end 163 | if not delim_found then error('Comma missing between object items.') end 164 | pos = skip_delim(str, pos, ':', true) -- true -> error if missing. 165 | obj[key], pos = json.parse(str, pos) 166 | pos, delim_found = skip_delim(str, pos, ',') 167 | end 168 | elseif first == '[' then -- Parse an array. 169 | local arr, val, delim_found = {}, true, true 170 | pos = pos + 1 171 | while true do 172 | val, pos = json.parse(str, pos, ']') 173 | if val == nil then return arr, pos end 174 | if not delim_found then error('Comma missing between array items.') end 175 | arr[#arr + 1] = val 176 | pos, delim_found = skip_delim(str, pos, ',') 177 | end 178 | elseif first == '"' then -- Parse a string. 179 | return parse_str_val(str, pos + 1) 180 | elseif first == '-' or first:match('%d') then -- Parse a number. 181 | return parse_num_val(str, pos) 182 | elseif first == end_delim then -- End of an object or array. 183 | return nil, pos + 1 184 | else -- Parse true, false, or null. 185 | local literals = { ['true'] = true,['false'] = false,['null'] = json.null } 186 | for lit_str, lit_val in pairs(literals) do 187 | local lit_end = pos + #lit_str - 1 188 | if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end 189 | end 190 | local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10) 191 | error('Invalid json syntax starting at ' .. pos_info_str) 192 | end 193 | end 194 | 195 | return json 196 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/path2d_bezier3.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | --math for 2D cubic bezier curves defined as (x1, y1, x2, y2, x3, y3, x4, y4) 5 | --where (x2, y2) and (x3, y3) are the control points and (x1, y1) and (x4, y4) are the end points. 6 | 7 | local length_function = require('Modules/path2d_bezier_length') 8 | local glue = require('Modules/glue') --autoload 9 | 10 | local min, max, sqrt = math.min, math.max, math.sqrt 11 | 12 | --compute B(t) (see wikipedia). 13 | local function value(t, x1, x2, x3, x4) 14 | return (1 - t) ^ 3 * x1 + 3 * (1 - t) ^ 2 * t * x2 + 3 * (1 - t) * t ^ 2 * x3 + t ^ 3 * x4 15 | end 16 | 17 | --separate coefficients from B(t) for using with *_for() functions. 18 | local function coefficients(x1, x2, x3, x4) 19 | return x4 - x1 + 3 * (x2 - x3), 3 * x1 - 6 * x2 + 3 * x3, 3 * (x2 - x1), x1 --the a, b, c, d cubic coefficients 20 | end 21 | 22 | --compute B(t) for given coefficients. 23 | local function value_for(t, a, b, c, d) 24 | return d + t * (c + t * (b + t * a)) --aka a * t^3 + b * t^2 + c * t + d 25 | end 26 | 27 | --compute the first derivative, aka the curve's tangent vector at t, for given coefficients. 28 | local function derivative1_for(t, a, b, c) 29 | return c + t * (2 * b + 3 * a * t) 30 | end 31 | 32 | --solve B(t)'=0 (use wolframalpha.com). 33 | local function derivative1_roots(x1, x2, x3, x4) 34 | local base = -x1 * x3 + x1 * x4 + x2 ^ 2 - x2 * x3 - x2 * x4 + x3 ^ 2 35 | local denom = -x1 + 3 * x2 - 3 * x3 + x4 36 | if base > 0 and denom ~= 0 then 37 | local sq = sqrt(base) 38 | return 39 | (sq - x1 + 2 * x2 - x3) / denom, 40 | (-sq - x1 + 2 * x2 - x3) / denom 41 | else 42 | local denom = 2 * (x1 - 2 * x2 + x3) 43 | if denom ~= 0 then 44 | return (x1 - x2) / denom 45 | end 46 | end 47 | end 48 | 49 | --compute the minimum and maximum values for B(t). 50 | local function minmax(x1, x2, x3, x4) 51 | --start off with the assumption that the curve doesn't extend past its endpoints. 52 | local minx = min(x1, x4) 53 | local maxx = max(x1, x4) 54 | --if the curve has local minima and/or maxima then adjust the bounding box. 55 | local t1, t2 = derivative1_roots(x1, x2, x3, x4) 56 | if t1 and t1 >= 0 and t1 <= 1 then 57 | local x = value(t1, x1, x2, x3, x4) 58 | minx = min(x, minx) 59 | maxx = max(x, maxx) 60 | end 61 | if t2 and t2 >= 0 and t2 <= 1 then 62 | local x = value(t2, x1, x2, x3, x4) 63 | minx = min(x, minx) 64 | maxx = max(x, maxx) 65 | end 66 | return minx, maxx 67 | end 68 | 69 | --bounding box as (x, y, w, h) 70 | local function bounding_box(x1, y1, x2, y2, x3, y3, x4, y4) 71 | local minx, maxx = minmax(x1, x2, x3, x4) 72 | local miny, maxy = minmax(y1, y2, y3, y4) 73 | return minx, miny, maxx - minx, maxy - miny 74 | end 75 | 76 | --return a quadratic bezier that (wildly) approximates a cubic bezier. 77 | --the equation has two solutions, which are averaged out to form the final control point. 78 | local function to_bezier2(x1, y1, x2, y2, x3, y3, x4, y4) 79 | return 80 | -.25 * x1 + .75 * x2 + .75 * x3 - .25 * x4, 81 | -.25 * y1 + .75 * y2 + .75 * y3 - .25 * y4 82 | end 83 | 84 | --return a catmull-rom segment that approximates a cubic bezier. 85 | --math from http://pomax.github.io/bezierinfo/ 86 | local function to_catmullrom(x1, y1, x2, y2, x3, y3, x4, y4) 87 | return 88 | 1, --default tension 89 | x4 + 6 * (x1 - x2), 90 | y4 + 6 * (y1 - y2), 91 | x1, y1, 92 | x4, y4, 93 | x1 + 6 * (x4 - x3), 94 | y1 + 6 * (y4 - y3) 95 | end 96 | 97 | --evaluate a cubic bezier at time t using linear interpolation. 98 | --for bit more speed, we could save and reuse the polynomial coefficients betwen computations for x and y. 99 | local function point(t, x1, y1, x2, y2, x3, y3, x4, y4) 100 | return 101 | value(t, x1, x2, x3, x4), 102 | value(t, y1, y2, y3, y4) 103 | end 104 | 105 | --approximate length of a cubic bezier using Gauss quadrature. 106 | local length = length_function(coefficients, derivative1_for) 107 | 108 | --split a cubic bezier at time t into two curves using De Casteljau interpolation. 109 | local function split(t, x1, y1, x2, y2, x3, y3, x4, y4) 110 | local mt = 1 - t 111 | local x12 = x1 * mt + x2 * t 112 | local y12 = y1 * mt + y2 * t 113 | local x23 = x2 * mt + x3 * t 114 | local y23 = y2 * mt + y3 * t 115 | local x34 = x3 * mt + x4 * t 116 | local y34 = y3 * mt + y4 * t 117 | local x123 = x12 * mt + x23 * t 118 | local y123 = y12 * mt + y23 * t 119 | local x234 = x23 * mt + x34 * t 120 | local y234 = y23 * mt + y34 * t 121 | local x1234 = x123 * mt + x234 * t 122 | local y1234 = y123 * mt + y234 * t 123 | return 124 | x1, y1, x12, y12, x123, y123, x1234, y1234, --first curve 125 | x1234, y1234, x234, y234, x34, y34, x4, y4 --second curve 126 | end 127 | 128 | if not ... then require 'path2d_bezier3_demo' end 129 | 130 | return glue.autoload({ 131 | bounding_box = bounding_box, 132 | to_bezier2 = to_bezier2, 133 | to_catmullrom = to_catmullrom, 134 | --hit & split API 135 | point = point, 136 | length = length, 137 | split = split, 138 | }, { 139 | hit = 'path2d_bezier3_hit', 140 | interpolate = 'path2d_bezier3_ai', 141 | }) 142 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/path2d_bezier_length.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | --computing the length of any picewise polynomial curve using the Gauss quadrature. 5 | --taken from http://processingjs.nihongoresources.com/bezierinfo/ 6 | 7 | local hypot = require('Modules/path2d_point').hypot 8 | 9 | local abs = math.abs 10 | 11 | --Legendre-Gauss abscissae for 24 steps. 12 | --xi values, defined at i=n as the roots of the nth order Legendre polynomial Pn(x). 13 | local abscissae = { 14 | -0.0640568928626056299791002857091370970011, 15 | 0.0640568928626056299791002857091370970011, 16 | -0.1911188674736163106704367464772076345980, 17 | 0.1911188674736163106704367464772076345980, 18 | -0.3150426796961633968408023065421730279922, 19 | 0.3150426796961633968408023065421730279922, 20 | -0.4337935076260451272567308933503227308393, 21 | 0.4337935076260451272567308933503227308393, 22 | -0.5454214713888395626995020393223967403173, 23 | 0.5454214713888395626995020393223967403173, 24 | -0.6480936519369755455244330732966773211956, 25 | 0.6480936519369755455244330732966773211956, 26 | -0.7401241915785543579175964623573236167431, 27 | 0.7401241915785543579175964623573236167431, 28 | -0.8200019859739029470802051946520805358887, 29 | 0.8200019859739029470802051946520805358887, 30 | -0.8864155270044010714869386902137193828821, 31 | 0.8864155270044010714869386902137193828821, 32 | -0.9382745520027327978951348086411599069834, 33 | 0.9382745520027327978951348086411599069834, 34 | -0.9747285559713094738043537290650419890881, 35 | 0.9747285559713094738043537290650419890881, 36 | -0.9951872199970213106468008845695294439793, 37 | 0.9951872199970213106468008845695294439793 } 38 | 39 | --Legendre-Gauss weights for 24 steps. 40 | --wi values, defined by a function linked to in the Bezier primer article. 41 | local weights = { 42 | 0.1279381953467521593204025975865079089999, 43 | 0.1279381953467521593204025975865079089999, 44 | 0.1258374563468283025002847352880053222179, 45 | 0.1258374563468283025002847352880053222179, 46 | 0.1216704729278033914052770114722079597414, 47 | 0.1216704729278033914052770114722079597414, 48 | 0.1155056680537255991980671865348995197564, 49 | 0.1155056680537255991980671865348995197564, 50 | 0.1074442701159656343712356374453520402312, 51 | 0.1074442701159656343712356374453520402312, 52 | 0.0976186521041138843823858906034729443491, 53 | 0.0976186521041138843823858906034729443491, 54 | 0.0861901615319532743431096832864568568766, 55 | 0.0861901615319532743431096832864568568766, 56 | 0.0733464814110802998392557583429152145982, 57 | 0.0733464814110802998392557583429152145982, 58 | 0.0592985849154367833380163688161701429635, 59 | 0.0592985849154367833380163688161701429635, 60 | 0.0442774388174198077483545432642131345347, 61 | 0.0442774388174198077483545432642131345347, 62 | 0.0285313886289336633705904233693217975087, 63 | 0.0285313886289336633705904233693217975087, 64 | 0.0123412297999872001830201639904771582223, 65 | 0.0123412297999872001830201639904771582223 } 66 | 67 | --return a function that computes the length of a 2nd or 3rd degree picewise polynomial curve at parameter t, 68 | --given the formulas for extracting coefficients and for computing the first derivative based on the coefficients. 69 | local function length_function(coefficients, derivative1_for) 70 | return function(t, x1, y1, x2, y2, x3, y3, x4, y4) 71 | local ax, bx, cx = coefficients(x1, x2, x3, x4) 72 | local ay, by, cy = coefficients(y1, y2, y3, y4) 73 | local z2 = t / 2 74 | local sum = 0 75 | for i = 1, #abscissae do 76 | local corrected_t = z2 * abscissae[i] + z2 77 | local dx = derivative1_for(corrected_t, ax, bx, cx) 78 | local dy = derivative1_for(corrected_t, ay, by, cy) 79 | sum = sum + weights[i] * hypot(dx, dy) 80 | end 81 | return z2 * sum 82 | end 83 | end 84 | 85 | if not ... then require 'path2d_hit_demo' end 86 | 87 | return length_function 88 | -------------------------------------------------------------------------------- /ReaSpaghetti/Modules/path2d_point.lua: -------------------------------------------------------------------------------- 1 | --@noindex 2 | --NoIndex: true 3 | 4 | --basic math for the cartesian plane. 5 | --angles are expressed in degrees, not radians. 6 | 7 | local sqrt, abs, min, max, sin, cos, radians, degrees, atan2 = 8 | math.sqrt, math.abs, math.min, math.max, math.sin, math.cos, math.rad, math.deg, math.atan2 9 | 10 | --hypotenuse function: computes sqrt(a^2 + b^2) without underflow / overflow problems. 11 | local function hypot(a, b) 12 | if a == 0 and b == 0 then return 0 end 13 | a, b = abs(a), abs(b) 14 | a, b = max(a, b), min(a, b) 15 | return a * sqrt(1 + (b / a) ^ 2) 16 | end 17 | 18 | --distance between two points. avoids underflow and overflow. 19 | local function distance(x1, y1, x2, y2) 20 | return hypot(x2 - x1, y2 - y1) 21 | end 22 | 23 | --distance between two points squared. 24 | local function distance2(x1, y1, x2, y2) 25 | return (x2 - x1) ^ 2 + (y2 - y1) ^ 2 26 | end 27 | 28 | --point at a specified angle on a circle. 29 | local function point_around(cx, cy, r, angle) 30 | angle = radians(angle) 31 | return 32 | cx + cos(angle) * r, 33 | cy + sin(angle) * r 34 | end 35 | 36 | --rotate point (x,y) around origin (cx,cy) by angle. 37 | local function rotate_point(x, y, cx, cy, angle) 38 | if angle == 0 then return x, y end 39 | angle = radians(angle) 40 | x, y = x - cx, y - cy 41 | local c, s = cos(angle), sin(angle) 42 | return cx + x * c - y * s, cy + y * c + x * s 43 | end 44 | 45 | --angle between two points in -180..180 degree range. 46 | local function point_angle(x, y, cx, cy) 47 | return degrees(atan2(y - cy, x - cx)) 48 | end 49 | 50 | --reflect point through origin (i.e. rotate point 180deg around another point). 51 | local function reflect_point(x, y, cx, cy) 52 | return 2 * cx - x, 2 * cy - y 53 | end 54 | 55 | --reflect point through origin at a specified distance. 56 | local function reflect_point_distance(x, y, cx, cy, length) 57 | local d = distance(x, y, cx, cy) 58 | if d == 0 then return cx, cy end 59 | local scale = length / d 60 | return 61 | cx + (cx - x) * scale, 62 | cy + (cy - y) * scale 63 | end 64 | 65 | return { 66 | hypot = hypot, 67 | distance = distance, 68 | distance2 = distance2, 69 | point_around = point_around, 70 | rotate_point = rotate_point, 71 | point_angle = point_angle, 72 | reflect_point = reflect_point, 73 | reflect_point_distance = reflect_point_distance, 74 | } 75 | -------------------------------------------------------------------------------- /ReaSpaghetti/Sexan_ReaSpaghetti.lua: -------------------------------------------------------------------------------- 1 | -- @description ReaSpaghetti Visual Scripter 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 0.49.3 5 | -- @changelog 6 | -- Improve data serializer to handle inf,-inf,nan (hopefully) V2 7 | -- @provides 8 | -- api_file.txt 9 | -- Modules/*.lua 10 | -- Examples/*.reanodes 11 | -- Library/*.reanlib 12 | -- ExportedActions/dummy.lua 13 | -- Docs/*.pdf 14 | -- Examples/SCHWA/*.png 15 | -- [main] Sexan_ReaSpaghetti.lua 16 | 17 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]] .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 18 | PATH = debug.getinfo(1).source:match("@?(.*[\\|/])") 19 | NATIVE_SEPARATOR = package.config:sub(1, 1) 20 | 21 | local r = reaper 22 | 23 | local crash = function(e) 24 | r.ShowConsoleMsg(e .. '\n' .. debug.traceback()) 25 | end 26 | dofile(r.GetResourcePath() .. '/Scripts/ReaTeam Extensions/API/imgui.lua')('0.8.7') 27 | 28 | -- IMGUI SETUP 29 | ctx = r.ImGui_CreateContext('My script') 30 | 31 | require("Modules/Defaults") 32 | 33 | FONT = r.ImGui_CreateFont('sans-serif', FONT_SIZE, r.ImGui_FontFlags_Bold()) 34 | FONT_STATIC = r.ImGui_CreateFont('sans-serif', FONT_SIZE_STATIC) 35 | FONT_CODE = r.ImGui_CreateFont('monospace', FONT_SIZE, r.ImGui_FontFlags_Bold()) 36 | 37 | r.ImGui_Attach(ctx, FONT) 38 | r.ImGui_Attach(ctx, FONT_STATIC) 39 | r.ImGui_Attach(ctx, FONT_CODE) 40 | 41 | r.ImGui_SetConfigVar(ctx, r.ImGui_ConfigVar_WindowsMoveFromTitleBarOnly(), 1) 42 | local WND_FLAGS = r.ImGui_WindowFlags_NoScrollbar() 43 | | r.ImGui_WindowFlags_NoScrollWithMouse() 44 | | r.ImGui_WindowFlags_MenuBar() 45 | 46 | FLT_MIN, FLT_MAX = r.ImGui_NumericLimits_Float() 47 | -- IMGUI SETUP 48 | 49 | local profiler2 = require("Modules/profiler") 50 | INSPECT = require("Modules/inspect") 51 | --local profiler = require("Modules/ProFi") 52 | 53 | if r.file_exists(r.GetResourcePath() .. "/UserPlugins/ultraschall_api.lua") then 54 | dofile(r.GetResourcePath() .. "/UserPlugins/ultraschall_api.lua") 55 | ULTRA_API = true 56 | end 57 | 58 | FLUX = require("Modules/flux") 59 | BEZIER = require("Modules/path2d_bezier3") 60 | BEZIER_HIT = require("Modules/path2d_bezier3_hit") 61 | require("Modules/APIParser") 62 | require("Modules/UI") 63 | require("Modules/Utils") 64 | require("Modules/FileManager") 65 | require("Modules/Canvas") 66 | require("Modules/NodeDraw") 67 | require("Modules/Flow") 68 | require("Modules/CustomFunctions") 69 | require("Modules/ExportToAction") 70 | require("Modules/Library") 71 | require("Modules/Undo") 72 | 73 | if STANDALONE_RUN then return end 74 | 75 | local old_time = r.time_precise() 76 | local function UpdateDeltaTime() 77 | local now_time = r.time_precise() 78 | local DT = now_time - old_time 79 | old_time = now_time 80 | FLUX.update(DT) 81 | end 82 | 83 | local function frame() 84 | Top_Menu() 85 | if r.ImGui_BeginChild(ctx, "SideListMain", 240, 0) then 86 | if r.ImGui_BeginChild(ctx, "SideListChild", 0, -25, 1) then 87 | Sidebar() 88 | r.ImGui_EndChild(ctx) 89 | end 90 | r.ImGui_SetNextItemWidth(ctx, 200) 91 | r.ImGui_LabelText(ctx, "##INFO", "Nodes:" .. #GetNodeTBL() .. " Selected:" .. #CntSelNodes()) 92 | r.ImGui_EndChild(ctx) 93 | end 94 | r.ImGui_SameLine(ctx) 95 | r.ImGui_PushStyleVar(ctx, r.ImGui_StyleVar_WindowPadding(), 0, 0) 96 | local visible = r.ImGui_BeginChild(ctx, "Canvas", 0, 0, 1, 97 | r.ImGui_WindowFlags_NoScrollbar() | r.ImGui_WindowFlags_NoScrollWithMouse()) 98 | r.ImGui_PopStyleVar(ctx) 99 | if visible then 100 | --r.ImGui_PushStyleVar(ctx, r.ImGui_StyleVar_FramePadding(), 0, 0) 101 | FunctionTabs() 102 | if r.ImGui_BeginChild(ctx, "Canvas2", 0, 0, 1, r.ImGui_WindowFlags_NoScrollbar() | r.ImGui_WindowFlags_NoScrollWithMouse()) then 103 | -- WE NEED TO CENTER CANVAS IN ITS WINDOW (IN ORDER TO NODE TO BE IN CENTER) 104 | if not CANVAS then 105 | CANVAS = InitCanvas() 106 | end 107 | Popups() 108 | CanvasLoop() 109 | UI_Buttons() 110 | 111 | r.ImGui_EndChild(ctx) -- END CANVAS2 112 | CheckWindowPayload() 113 | end 114 | r.ImGui_EndChild(ctx) -- END CANVAS1 115 | end 116 | end 117 | 118 | DIRTY = nil 119 | local function loop() 120 | if PROFILE_DEBUG then 121 | PROFILE_STARTED = true 122 | profiler2.start() 123 | end 124 | 125 | UpdateDeltaTime() 126 | UpdateZoomFont() 127 | r.ImGui_PushStyleColor(ctx, r.ImGui_Col_WindowBg(), 0x111111FF) 128 | r.ImGui_SetNextWindowSizeConstraints(ctx, 1100, 500, FLT_MAX, FLT_MAX) 129 | r.ImGui_SetNextWindowSize(ctx, 1000, 800, r.ImGui_Cond_FirstUseEver()) 130 | local visible, open = r.ImGui_Begin(ctx, 'ReaSpaghetti - ALPHA - ' .. PROJECT_NAME .. '###ReaSpaghetti', true, 131 | WND_FLAGS) 132 | r.ImGui_PopStyleColor(ctx) 133 | TOOLBAR_DRAG = r.ImGui_IsItemHovered(ctx) 134 | if visible then 135 | frame() 136 | r.ImGui_End(ctx) 137 | end 138 | 139 | if not CLOSE then 140 | r.defer(function() xpcall(loop, crash) end) 141 | end 142 | 143 | if not open then 144 | if AreFunctionsDirty() then 145 | NEW_WARNIGN = true 146 | WANT_CLOSE = true 147 | else 148 | CLOSE = true 149 | end 150 | end 151 | NEXT_FRAME = true 152 | if PROFILE_DEBUG and PROFILE_STARTED then 153 | profiler2.stop() 154 | profiler2.report(PATH .. "profiler.log") 155 | PROFILE_DEBUG, PROFILE_STARTED = false, nil 156 | OpenFile(PATH .. "profiler.log") 157 | end 158 | end 159 | InitApi() 160 | InitLibrary() 161 | InitStartFunction() 162 | r.defer(function() xpcall(loop, crash) end) 163 | -------------------------------------------------------------------------------- /Theme/V6_Button_organizer.lua: -------------------------------------------------------------------------------- 1 | -- @description V6_Button_organizer 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 1.32 5 | -- @changelog 6 | -- + do not allow drag droping between different layouts 7 | 8 | local reaper = reaper 9 | 10 | local rtconfig_content = '' 11 | --local theme = reaper.GetResourcePath() .. "\\ColorThemes\\Default_6.0.ReaperThemeZip" 12 | --local ENTRY_NAME = "Default_6.0_unpacked\\rtconfig.txt" 13 | local theme = reaper.GetLastColorThemeFile() .. "Zip" 14 | local function str_split(s, delimiter) 15 | local result = {}; 16 | for match in (s .. delimiter):gmatch("(.-)" .. delimiter) do table.insert(result, match) end 17 | return result; 18 | end 19 | 20 | function Literalize(str) 21 | return str:gsub( 22 | "[%(%)%.%%%+%-%*%?%[%]%^%$]", 23 | function(c) return "%" .. c end 24 | ) 25 | end 26 | 27 | -- READ RTCONFIG CONTENT 28 | local function Get_RTCONFIG_Content() 29 | local zipHandle, ok = reaper.JS_Zip_Open(theme, 'r', 6) 30 | if not ENTRY_NAME then 31 | local retval, list = reaper.JS_Zip_ListAllEntries(zipHandle) 32 | -- FIND RTCONFIG 33 | for l in list:gmatch("(.-\0)") do 34 | if l:find("rtconfig") then 35 | if not l:lower():find("osx") then 36 | ENTRY_NAME = l 37 | end 38 | end 39 | end 40 | end 41 | if ENTRY_NAME then 42 | local entry_id_r = reaper.JS_Zip_Entry_OpenByName(zipHandle, ENTRY_NAME) 43 | _, rtconfig_content = reaper.JS_Zip_Entry_ExtractToMemory(zipHandle) 44 | reaper.JS_Zip_Entry_Close(zipHandle) 45 | end 46 | reaper.JS_Zip_Close(theme) 47 | end 48 | 49 | local layouts, moded_layouts 50 | local function Get_Layouts() 51 | layouts = { 52 | [1] = { name = "TCP" }, 53 | --[2] = {name = "MCP"}, 54 | [2] = { name = "ENV" }, 55 | [3] = { name = "MASTER" }, 56 | } 57 | -- TCP 58 | local tcp = rtconfig_content:match("TRACK CONTROL PANEL(.*)MASTER TRACK CONTROL PANEL") 59 | for layout in tcp:gmatch('(Layout ".-".-)drawTcp') do -- MATCH EVERYTHING BETWEEN "LAYOUT "X" AND drawTcp 60 | layouts[1][#layouts[1] + 1] = layout 61 | end 62 | 63 | -- MCP 64 | -- local mcp = rtconfig_content:match("THE MIXER(.*)") 65 | -- for layout in mcp:gmatch('(Layout ".-".-)drawMcp') do -- MATCH EVERYTHING BETWEEN "LAYOUT "X" AND drawMcp 66 | -- layouts["MCP"][#layouts["MCP"] + 1] = layout 67 | -- end 68 | 69 | -- MASTER 70 | local master = rtconfig_content:match("MASTER TRACK CONTROL PANEL(.*)ENVELOPE CONTROL PANEL") 71 | for layout in master:gmatch('(Layout ".-".-)drawMasterTcp') do -- MATCH EVERYTHING BETWEEN "LAYOUT "X" AND drawMasterTcp 72 | layouts[3][#layouts[3] + 1] = layout 73 | end 74 | 75 | -- ENV 76 | local env_tcp = rtconfig_content:match("ENVELOPE CONTROL PANEL(.*)THE MIXER") 77 | for layout in env_tcp:gmatch('(Layout ".-".-)drawEnvcp') do -- MATCH EVERYTHING BETWEEN "LAYOUT "X" AND drawEnvcp 78 | layouts[2][#layouts[2] + 1] = layout 79 | end 80 | 81 | moded_layouts = { 82 | [1] = { name = "TCP" }, 83 | --[2] = {name = "MCP"}, 84 | [2] = { name = "ENV" }, 85 | [3] = { name = "MASTER" }, 86 | } 87 | for k in pairs(layouts) do 88 | for l, v in ipairs(layouts[k]) do 89 | moded_layouts[k][l] = str_split(v, '\n') 90 | end 91 | end 92 | end 93 | 94 | -- REFRESH REAPER THEME 95 | local function RefreshTheme() 96 | local thisTheme = reaper.GetLastColorThemeFile() 97 | reaper.OpenColorThemeFile(thisTheme) 98 | end 99 | 100 | -- WRITE TO REATHEMEFILE 101 | local function Write_to_theme_zip() 102 | local zipHandle, ok = reaper.JS_Zip_Open(theme, 'w', 6) 103 | local num_deleted = reaper.JS_Zip_DeleteEntries(zipHandle, ENTRY_NAME .. "\00", #ENTRY_NAME) 104 | local entry_id_w = reaper.JS_Zip_Entry_OpenByName(zipHandle, ENTRY_NAME) 105 | reaper.JS_Zip_Entry_CompressMemory(zipHandle, rtconfig_content, #rtconfig_content) 106 | reaper.JS_Zip_Entry_Close(zipHandle) 107 | reaper.JS_Zip_Close(theme) 108 | RefreshTheme() -- UPDATE REAPER THEME 109 | end 110 | 111 | -- MAKE CHANGES TO RTCONFIG AND REATHEME FILE 112 | local function Store_and_Update_new_button(section, layout_idx) 113 | local current_reordered_layout = table.concat(moded_layouts[section][layout_idx], "\n"):gsub("%%", "%%%%") -- CONCAT NEW MODIFIED LAYOUT TO STRING 114 | local current_original_layout = Literalize(layouts[section][layout_idx]) 115 | rtconfig_content = rtconfig_content:gsub(current_original_layout, current_reordered_layout) -- CHANGE THE ORIGINAL LAYOUT IN RTCONFIG WITH MODIFIED ONE 116 | Write_to_theme_zip() -- WRITE CHANGES TO REATHEME FILE 117 | Init() -- GET RTCONFIG DATA AGAIN 118 | end 119 | 120 | local patterns = { "tcp", "envcp", "master_", "master" } 121 | local function Pattern_remove(str) 122 | str = str:gsub("%.", "") --remove dot 123 | for _, v in ipairs(patterns) do str = str:gsub(v, "") end 124 | return str 125 | end 126 | 127 | local ctx = reaper.ImGui_CreateContext('My script') 128 | local function GUI() 129 | local visible, open = reaper.ImGui_Begin(ctx, 'V6 THEME BUTTON ORGANIZER', true, flags) 130 | if visible then 131 | -- ITERATE THU ALL LAYOUTS 132 | for j = 1, #moded_layouts do 133 | for i = 1, #moded_layouts[j] do 134 | local tbl = moded_layouts[j][i] 135 | -- ITERATE THRU LAYOUT LINES 136 | local layout_name = tbl[1]:match('(Layout ".-")') -- GET ONLY 'Layout "xxx"' 137 | if layouts[j][i]:lower():find('then') then -- IF ORIGINAL LAYOUT STRING HAS 'THEN' (WE ONLY NEED LAYOUTS THAT HAVE REORDERING) 138 | reaper.ImGui_Text(ctx, moded_layouts[j].name .. " - " .. layout_name) -- SET TEXT AS NAME LAYOUT 139 | reaper.ImGui_BeginGroup(ctx) 140 | for k, v in ipairs(tbl) do 141 | -- FIND "THEN" LINES (WHICH ARE USED FOR REORDER) 142 | if string.find(v:lower(), 'then') then 143 | local button_name = v:match("%S+ (%S+)") -- GET WORD AFTER "THEN" 144 | button_name = Pattern_remove(button_name) 145 | reaper.ImGui_Button(ctx, button_name .. "##" .. i .. v) 146 | reaper.ImGui_SameLine(ctx) 147 | -- IF BUTTON IS DRAGGED START DRAG AND DROP 148 | if reaper.ImGui_BeginDragDropSource(ctx) then 149 | reaper.ImGui_SetDragDropPayload(ctx, 'DND_BUTTON', tostring(k .. "," .. i)) 150 | reaper.ImGui_Text(ctx, button_name) 151 | reaper.ImGui_EndDragDropSource(ctx) 152 | end 153 | -- GET DRAG AND DROP TARGET 154 | if reaper.ImGui_BeginDragDropTarget(ctx) then 155 | RV_P, PAYLOAD = reaper.ImGui_AcceptDragDropPayload(ctx, 'DND_BUTTON') 156 | if RV_P then 157 | local p_tbl_key, p_layout = PAYLOAD:match("(%d+),(%d+)") 158 | local payload_n = tonumber(p_tbl_key) 159 | local payload_layout = tonumber(p_layout) 160 | if payload_layout == i then 161 | tbl[k] = tbl[payload_n] 162 | tbl[payload_n] = v 163 | Store_and_Update_new_button(j, i) 164 | end 165 | end 166 | reaper.ImGui_EndDragDropTarget(ctx) 167 | end 168 | end 169 | end 170 | reaper.ImGui_EndGroup(ctx) 171 | end 172 | --RV, contents = reaper.ImGui_InputTextMultiline(ctx, '##source', contents, -1, -1) -- TEXT EDITOR IN SCRIPT 173 | end 174 | end 175 | reaper.ImGui_End(ctx) 176 | end 177 | if open then reaper.defer(GUI) 178 | else reaper.ImGui_DestroyContext(ctx) 179 | end 180 | end 181 | 182 | function Init() 183 | Get_RTCONFIG_Content() 184 | Get_Layouts() 185 | end 186 | 187 | function Exit() end 188 | 189 | Init() 190 | reaper.atexit(Exit) 191 | reaper.defer(GUI) 192 | -------------------------------------------------------------------------------- /Track/Sexan_Create VCA master from selection.lua: -------------------------------------------------------------------------------- 1 | -- @description Create VCA Master from selection 2 | -- @author SeXan 3 | -- @license GPL v3 4 | -- @version 1.713 5 | -- @changelog 6 | -- User setting "reverse" to set groups in non reverse order (1-64) 7 | -- Script default is reverse 8 | 9 | 10 | 11 | -- USER SETTING 12 | --------------- 13 | local reverse = 1 -- (1 groups set from 64-1 , 0 groups set from 1-64) 14 | local group_range = 1 -- (1 creates from 64-1, 32 creates 32-64) 15 | local popup = 0 -- (set to 0 for no popup, set to 1 for popup asking to name the VCA group) 16 | local mute_solo = 1 -- (set to 0 to disable mute and solo flags) 17 | local position = 3 -- (set VCA Master track position 1 - TOP , 0 - Bottom, 3 - Above selected tracks) 18 | local warning = 0 -- (gives user a warning popup to select tracks if no tracks are selected, 0 OFF , 1 ON) 19 | --------------- 20 | -------------------------------------------------------------------------------------- 21 | -- GROUP FLAGS 22 | 23 | local VCA_FLAGS = { 24 | "VOLUME_MASTER", 25 | "VOLUME_SLAVE", 26 | "VOLUME_VCA_MASTER", 27 | "VOLUME_VCA_SLAVE", 28 | "PAN_MASTER", 29 | "PAN_SLAVE", 30 | "WIDTH_MASTER", 31 | "WIDTH_SLAVE", 32 | "MUTE_MASTER", 33 | "MUTE_SLAVE", 34 | "SOLO_MASTER", 35 | "SOLO_SLAVE", 36 | "RECARM_MASTER", 37 | "RECARM_SLAVE", 38 | "POLARITY_MASTER", 39 | "POLARITY_SLAVE", 40 | "AUTOMODE_MASTER", 41 | "AUTOMODE_SLAVE", 42 | "MEDIA_EDIT_LEAD", 43 | "MEDIA_EDIT_FOLLOW", 44 | } 45 | local free_group, master_pos = nil, nil 46 | local tracks, vca_group, cnt = {}, {}, 1 47 | for i = 1, 64 do vca_group[i] = 0 end 48 | 49 | local function scan_groups() 50 | local cnt_tr = reaper.CountTracks(0) 51 | for i = 0, cnt_tr - 1 do 52 | local tr = reaper.GetTrack(0, i) 53 | for k = 1, #vca_group do 54 | if reaper.GetSetTrackGroupMembership(tr, "VOLUME_VCA_MASTER", 0, 0) == 2 ^ (k - 1) or reaper.GetSetTrackGroupMembershipHigh(tr, "VOLUME_VCA_MASTER", 0, 0) == 2 ^ ((k - 32) - 1) then 55 | cnt = 56 | cnt + 1 57 | end 58 | for j = 1, #VCA_FLAGS do 59 | if reaper.GetSetTrackGroupMembership(tr, VCA_FLAGS[j], 0, 0) == 2 ^ (k - 1) or 60 | reaper.GetSetTrackGroupMembershipHigh(tr, VCA_FLAGS[j], 0, 0) == 2 ^ ((k - 32) - 1) then 61 | vca_group[k] = nil 62 | end 63 | end 64 | end 65 | end 66 | end 67 | 68 | function create_VCAs() 69 | local group, high 70 | for i = group_range, #vca_group do 71 | --for k,v in pairs(vca_group) do 72 | if vca_group[i] == 0 then 73 | if i > 32 then 74 | high = true 75 | group = reaper.GetSetTrackGroupMembershipHigh 76 | free_group = 2 ^ ((i - 32) - 1) 77 | else 78 | group = reaper.GetSetTrackGroupMembership 79 | free_group = 2 ^ (i - 1) 80 | end 81 | if group_range == 32 then break end -- ADD BREAK TO ITERIATE FROM 1 to 32, without its 32 to 1 82 | if reverse == 0 then break end 83 | end 84 | end 85 | local group_idx = math.log(free_group, 2) + (high and 32 or 0) + 1 86 | if position == 1 then 87 | master_pos = cnt - 1 88 | elseif position == 0 then 89 | master_pos = reaper.CountTracks(0) 90 | else 91 | master_pos = reaper.CSurf_TrackToID(tracks[1], false) - 1 -- ADD VCA ABOVE SELECTED TRACKS 92 | end 93 | 94 | -- INSERT MASTER VCA TRACK AT TOP OR BOTTTOM 95 | reaper.InsertTrackAtIndex(master_pos, false) 96 | reaper.TrackList_AdjustWindows(false) 97 | local tr = reaper.GetTrack(0, master_pos) 98 | 99 | -- VCA NAMING 100 | if popup == 0 then 101 | local retval, track_name = reaper.GetSetMediaTrackInfo_String(tr, "P_NAME", "VCA: " .. cnt, true) 102 | reaper.GetSetProjectInfo_String( 0, "TRACK_GROUP_NAME:" .. group_idx,"VCA: " .. cnt, true ) 103 | else 104 | local ret, name = reaper.GetUserInputs("ADD VCA NAME ", 1, "VCA NAME :", "") 105 | -- IF OK WAS CLICKED 106 | if ret then 107 | local retval, track_name = reaper.GetSetMediaTrackInfo_String(tr, "P_NAME","VCA: " .. name, true) 108 | reaper.GetSetProjectInfo_String( 0, "TRACK_GROUP_NAME:" .. group_idx,"VCA: " .. name, true ) 109 | -- IF CANCEL OR ESC KEY IS PRESSED DELETE TRACK AND DO NOTHING 110 | else 111 | reaper.DeleteTrack(tr) 112 | return 0 113 | end 114 | end 115 | 116 | -- SET TRACK AS VCA MASTER 117 | local VCA_M = group(tr, "VOLUME_VCA_MASTER", free_group, free_group) 118 | if mute_solo == 1 then 119 | local VCA_M_MUTE = group(tr, "MUTE_MASTER", free_group, free_group) 120 | local VCA_M_SOLO = group(tr, "SOLO_MASTER", free_group, free_group) 121 | end 122 | 123 | -- SET VCA SLAVES 124 | for i = 1, #tracks do 125 | local tr = tracks[i] 126 | local VCA_S = group(tr, "VOLUME_VCA_SLAVE", free_group, free_group) 127 | if mute_solo == 1 then 128 | local VCA_S_MUTE = group(tr, "MUTE_SLAVE", free_group, free_group) 129 | local VCA_S_SOLO = group(tr, "SOLO_SLAVE", free_group, free_group) 130 | end 131 | end 132 | end 133 | 134 | local function main() 135 | local cnt_sel = reaper.CountSelectedTracks(0) 136 | if warning == 1 and cnt_sel == 0 then 137 | reaper.ShowMessageBox("Please select tracks to create VCA", "WARNING", 0) 138 | end 139 | -- IF VCA GROUP TABLE IS EMPTY DO NOT CREATE NEW GROUP 140 | if group_range == 32 and vca_group[64] ~= 0 then return end -- if creating only from 32 to 64 141 | if #vca_group ~= 0 and cnt_sel > 0 then 142 | -- ADD SELECTED TRACKS TO TABLE (FOR MAKING THEM VCA SLAVES) 143 | for i = 0, cnt_sel - 1 do 144 | local tr = reaper.GetSelectedTrack(0, i) 145 | tracks[#tracks + 1] = tr 146 | end 147 | create_VCAs() 148 | end 149 | end 150 | scan_groups() 151 | main() 152 | -------------------------------------------------------------------------------- /Track/Sexan_Folder record monitor arming childs.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Folder record monitor arming childs 3 | * About: Record arming folder arms all child tracks 4 | * Author: SPK77, SeXan 5 | * Licence: GPL v3 6 | * REAPER: 5.0 7 | * Extensions: None 8 | * Version: 1.01 9 | --]] 10 | 11 | --[[ 12 | * Changelog: 13 | * v1.01 (2017-07-13) 14 | + Initial Release 15 | --]] 16 | 17 | 18 | -- USER CONFIG AREA --------------------------------------------------------- 19 | 20 | 21 | local last_proj_change_count = reaper.GetProjectStateChangeCount(0) 22 | local last_proj = string.format("%s",reaper.EnumProjects(-1, "")) 23 | 24 | -- Returns a track's folder depth 25 | function get_track_folder_depth(track_index) 26 | local folder_depth = 0 27 | for i=0, track_index do -- loop from start of tracks to "track_index"... 28 | local track = reaper.GetTrack(0, i) 29 | local folder_depth = folder_depth + reaper.GetMediaTrackInfo_Value(track, "I_FOLDERDEPTH") -- ...to get the actual folder depth 30 | end 31 | return folder_depth 32 | end 33 | 34 | 35 | ----------------------- 36 | -- on_rec_arm_change -- 37 | ----------------------- 38 | t = {} -- table for saving inputs 39 | -- this function is called when rec arm button is pressed on some track 40 | function on_rec_arm_change(track_pointer, track_index) 41 | -- t = {} -- table for saving folders input 42 | -- If this function is called, we know that: 43 | -- last touched track is a folder track (parent) 44 | -- rec-arm button was clicked on that track 45 | 46 | -- call "get_track_folder_depth" to get the actual folder depth 47 | local parent_folder_depth = get_track_folder_depth(track_index) 48 | local total_folder_depth = parent_folder_depth 49 | 50 | local parent_rec_arm = reaper.GetMediaTrackInfo_Value(track_pointer, "I_RECARM") -- get (parent) track's rec arm state 51 | local parent_mon_arm = reaper.GetMediaTrackInfo_Value(track_pointer, "I_RECMON") -- get (parent) track's monitor state 52 | 53 | -- loop from" parent track index" to end of tracks (break when last child is found) 54 | for i = track_index + 1, reaper.CountTracks(0) do 55 | local child_track = reaper.GetTrack(0, i-1) 56 | 57 | if last_a == "toggle track record arming" then 58 | reaper.SetMediaTrackInfo_Value(child_track, "I_RECARM", parent_rec_arm) -- set track armed as folder 59 | local ret, child_state = reaper.GetTrackState(child_track) 60 | local child_input = reaper.GetMediaTrackInfo_Value(child_track,"I_RECINPUT") 61 | 62 | if child_state&1 == 1 then -- if track is a folder 63 | if child_state&64 == 64 then -- if folder is rec-armed 64 | if child_input >= 0 then 65 | t[i]=reaper.GetMediaTrackInfo_Value(child_track,"I_RECINPUT") -- add folder input to table 66 | reaper.SetMediaTrackInfo_Value(child_track, "I_RECINPUT", -1) -- disable folder input (avoid double monitoring issue) 67 | end 68 | else 69 | for k,v in pairs(t) do 70 | local track_from_key = reaper.CSurf_TrackFromID(k, false) -- convert track number to track code 71 | local ret, k_state = reaper.GetTrackState(track_from_key) 72 | if k_state&64 ~= 64 then 73 | reaper.SetMediaTrackInfo_Value(track_from_key, "I_RECINPUT", v) -- restore inputs from table 74 | end 75 | end 76 | t[i] = nil -- empty the table when inputs are restored 77 | end 78 | end 79 | 80 | elseif last_a == "toggle track recording monitor" then 81 | reaper.SetMediaTrackInfo_Value(child_track, "I_RECMON", parent_mon_arm) -- set monitor arm 82 | end 83 | 84 | total_folder_depth = total_folder_depth + reaper.GetMediaTrackInfo_Value(child_track, "I_FOLDERDEPTH") 85 | if total_folder_depth <= parent_folder_depth then 86 | break -- break when last child is found 87 | end 88 | end 89 | 90 | reaper.UpdateArrange() -- update arrange view 91 | reaper.TrackList_AdjustWindows(false) -- update tracklist 92 | end 93 | ----------------------------- 94 | -- on_project_state_change -- 95 | ----------------------------- 96 | -- this function is called when project state changes 97 | 98 | function on_project_state_change(last_action) 99 | last_a = last_action 100 | -- if last action (that changed the project state) was "Toggle Track Record Arming"... 101 | if last_action == "toggle track record arming" or last_action == "toggle track recording monitor" then 102 | local last_touched_track = reaper.GetLastTouchedTrack() -- get last touched track's "track pointer" 103 | local last_touched_track_name, flags = reaper.GetTrackState(last_touched_track) 104 | local last_touched_track_index = reaper.CSurf_TrackToID(last_touched_track, false) - 1 -- get track index from "last touched track" 105 | 106 | -- Check if last_touched_track was a folder track 107 | if flags&1 ~= 1 then -- if last_touched track was not a folder (parent)... 108 | return -- ...return to main function... 109 | end 110 | 111 | on_rec_arm_change(last_touched_track, last_touched_track_index) -- ...(else) call "on_rec_arm_change" 112 | end 113 | end 114 | ---------- 115 | 116 | function main() 117 | local proj_change_count = reaper.GetProjectStateChangeCount(0) 118 | local current_proj = string.format("%s",reaper.EnumProjects(-1, "")) 119 | if proj_change_count ~= last_proj_change_count then 120 | ---check if we are on the same project tab 121 | if current_proj == last_proj then 122 | local last_action = reaper.Undo_CanUndo2(0) -- get last action 123 | if last_action ~= nil then 124 | on_project_state_change(last_action:lower()) -- call "on_project_state_change" to update something if needed 125 | end 126 | else 127 | last_proj = current_proj 128 | end 129 | last_proj_change_count = proj_change_count -- store "Project State Change Count" for the next pass 130 | end 131 | reaper.defer(main) 132 | end 133 | 134 | main() 135 | -------------------------------------------------------------------------------- /Track/Sexan_Remove selected VCA master and its slaves with all flags.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * ReaScript Name: Remove selected VCA master and its slaves with all flags.lua 3 | * About: Script removes selected VCA master its slaves and all flags associated 4 | * Author: SeXan 5 | * Licence: GPL v3 6 | * REAPER: 5.0 7 | * Extensions: None 8 | * Version: 1.03 9 | --]] 10 | 11 | --[[ 12 | * Changelog: 13 | * v1.03 (2018-02-27) 14 | + Fixed for 64 group remove 15 | --]] 16 | 17 | -------------------------------------------------------------------------------------- 18 | local tr_group = reaper.GetSetTrackGroupMembership 19 | 20 | local function remove_slave_flags(VCA_GROUP) 21 | local cnt_tr = reaper.CountTracks(0) 22 | 23 | for i = 0 , cnt_tr-1 do 24 | local tr = reaper.GetTrack(0,i) 25 | -- REMOVE ALL SLAVES FROM GROUP 26 | local VCA_S =tr_group(tr,"VOLUME_VCA_SLAVE", VCA_GROUP,0) 27 | local VCA_S_MUTE =tr_group(tr,"MUTE_SLAVE", VCA_GROUP,0) 28 | local VCA_S_SOLO = tr_group(tr,"SOLO_SLAVE", VCA_GROUP,0) 29 | end 30 | 31 | end 32 | 33 | local function remove_master_flags() 34 | local sel_tr = reaper.GetSelectedTrack(0,0) 35 | -- Find ACTIVE GROUP 36 | if tr_group(sel_tr,"VOLUME_VCA_MASTER", 0, 0) == 0 then tr_group = reaper.GetSetTrackGroupMembershipHigh end 37 | local VCA_GROUP = tr_group(sel_tr,"VOLUME_VCA_MASTER", 0, 0) 38 | -- REMOVE VCA MASTER AND GROUP 39 | local VCA_M = tr_group(sel_tr,"VOLUME_VCA_MASTER", VCA_GROUP, 0) 40 | local VCA_M_MUTE = tr_group(sel_tr,"MUTE_MASTER", VCA_GROUP,0) 41 | local VCA_M_SOLO = tr_group(sel_tr,"SOLO_MASTER", VCA_GROUP,0) 42 | remove_slave_flags(VCA_GROUP) 43 | end 44 | remove_master_flags() -------------------------------------------------------------------------------- /Utils/Key_Intercept.lua: -------------------------------------------------------------------------------- 1 | local reaper = reaper 2 | 3 | local start_time = reaper.time_precise() 4 | local key_state, KEY = reaper.JS_VKeys_GetState(start_time - 2), nil 5 | for i = 1, 255 do 6 | if key_state:byte(i) ~= 0 then KEY = i; reaper.JS_VKeys_Intercept(KEY, 1) end 7 | end 8 | if not KEY then return end 9 | local cur_pref = reaper.SNM_GetIntConfigVar("alwaysallowkb", 1) 10 | reaper.SNM_SetIntConfigVar("alwaysallowkb", 1) 11 | 12 | function Key_held() 13 | key_state = reaper.JS_VKeys_GetState(start_time - 2) 14 | return key_state:byte(KEY) == 1 15 | end 16 | 17 | function Release() reaper.JS_VKeys_Intercept(KEY, -1) reaper.SNM_SetIntConfigVar("alwaysallowkb", cur_pref) end 18 | 19 | function Handle_errors(err) 20 | reaper.ShowConsoleMsg(err .. '\n' .. debug.traceback()) 21 | Release() 22 | end 23 | 24 | function Main() 25 | if not Key_held() then return end 26 | reaper.ShowConsoleMsg('Hello!' .. '\n') 27 | reaper.defer(function() xpcall(Main, Handle_errors) end) 28 | end 29 | 30 | reaper.atexit(Release) 31 | xpcall(Main, Handle_errors) 32 | -------------------------------------------------------------------------------- /Utils/PipeWireConfig.lua: -------------------------------------------------------------------------------- 1 | -- @description PipeWire configurator (Linux) 2 | -- @author SeXan 3 | -- @license GPL v3 4 | -- @version 1.02 5 | -- @changelog 6 | -- Hardcode buffers and sample rates 7 | 8 | local r = reaper 9 | 10 | if not r.ImGui_GetBuiltinPath then 11 | r.ShowMessageBox("ReaImGui is needed.\nPlease Install it in next window", "MISSING DEPENDENCIES", 0) 12 | r.ReaPack_BrowsePackages('"Dear Imgui"') 13 | return 14 | end 15 | 16 | package.path = r.ImGui_GetBuiltinPath() .. '/?.lua' 17 | local im = require 'imgui' '0.9.1' 18 | 19 | local RATES, BUFFERS 20 | local function GetUpdate() 21 | RATES, BUFFERS = {}, {} 22 | local settings = r.ExecProcess(('/usr/bin/pw-metadata -n settings'), 1000) 23 | for line in settings:gmatch("[^\r\n]+") do 24 | if line:match("clock%.allowed%-rates") then 25 | local rates = line:match("clock%.allowed%-rates' value:'%[ (.*) %]") 26 | for rate in rates:gmatch("[^,]+") do RATES[#RATES + 1] = tonumber(rate) end 27 | elseif line:match("clock%.%rate") then 28 | DEF_RATE = tonumber(line:match("clock%.%rate' value:'(%d+)")) 29 | elseif line:match("clock%.%quantum") then 30 | DEF_BUF = tonumber(line:match("clock%.%quantum' value:'(%d+)")) 31 | elseif line:match("clock%.min%-quantum") then 32 | MIN_BUF = tonumber(line:match("clock%.min%-quantum' value:'(%d+)")) 33 | elseif line:match("clock%.max%-quantum") then 34 | MAX_BUF = tonumber(line:match("clock%.max%-quantum' value:'(%d+)")) 35 | elseif line:match("clock%.force%-quantum") then 36 | FORCE_BUF = tonumber(line:match("clock%.force%-quantum' value:'(%d+)")) 37 | elseif line:match("clock%.force%-rate") then 38 | FORCE_RATE = tonumber(line:match("clock%.force%-rate' value:'(%d+)")) 39 | end 40 | end 41 | 42 | local TMP_BUF = MIN_BUF 43 | while TMP_BUF <= MAX_BUF do 44 | BUFFERS[#BUFFERS + 1] = TMP_BUF 45 | TMP_BUF = TMP_BUF * 2 46 | end 47 | end 48 | GetUpdate() 49 | 50 | local ctx = im.CreateContext('PW BUFFER') 51 | local HC_BUFS = { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 } 52 | local HC_RATES = { 44100, 48000, 96000, 192000, 384000 } 53 | 54 | local function loop() 55 | im.SetNextWindowSizeConstraints(ctx, 150, 320, 150, 320) 56 | local visible, open = im.Begin(ctx, 'PipeWire', true) 57 | local cur_rate = FORCE_RATE ~= 0 and FORCE_RATE or DEF_RATE 58 | local cur_buffer = FORCE_BUF ~= 0 and FORCE_BUF or DEF_BUF 59 | if visible then 60 | im.BeginGroup(ctx) 61 | im.Text(ctx, "BUFFER") 62 | for i = 1, #HC_BUFS do 63 | if im.RadioButton(ctx, HC_BUFS[i], cur_buffer == HC_BUFS[i]) then 64 | local cmd = ("pw-metadata -n settings 0 clock.force-quantum %s"):format(HC_BUFS[i]) 65 | r.ExecProcess(('/usr/bin/%s'):format(cmd), 1000) 66 | GetUpdate() 67 | end 68 | end 69 | im.EndGroup(ctx) 70 | im.SameLine(ctx) 71 | im.BeginGroup(ctx) 72 | im.Text(ctx, "SAMPLE RATE") 73 | for i = 1, #HC_RATES do 74 | if im.RadioButton(ctx, HC_RATES[i], cur_rate == HC_RATES[i]) then 75 | local cmd = ("pw-metadata -n settings 0 clock.force-rate %s"):format(HC_RATES[i]) 76 | r.ExecProcess(('/usr/bin/%s'):format(cmd), 1000) 77 | GetUpdate() 78 | end 79 | end 80 | im.EndGroup(ctx) 81 | if im.Button(ctx, "RESET TO DEFAULTS") then 82 | local cmd = 83 | "pw-metadata -n settings 0 clock.force-rate 0; pw-metadata -n settings 0 clock.force-quantum 0" 84 | r.ExecProcess(('/bin/bash -c "%s"'):format(cmd), 1000) 85 | GetUpdate() 86 | end 87 | 88 | im.End(ctx) 89 | end 90 | 91 | if open then 92 | r.defer(loop) 93 | end 94 | end 95 | r.defer(loop) 96 | -------------------------------------------------------------------------------- /VirtualTrack/Images/VT_icon_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/VirtualTrack/Images/VT_icon_empty.png -------------------------------------------------------------------------------- /VirtualTrack/Images/comp_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoranKovac/ReaScripts/34b61acd4172abf9e1304d9fd5b9aef5a197d020/VirtualTrack/Images/comp_test.png -------------------------------------------------------------------------------- /VirtualTrack/Modules/Utils.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.03 5 | * NoIndex: true 6 | --]] 7 | 8 | local reaper = reaper 9 | function Break( msg ) 10 | local line = "Breakpoint at line " .. debug.getinfo(2).currentline 11 | local ln = "\n" .. string.rep("=", #line) .. "\n" 12 | local trace = debug.traceback(ln .. line) 13 | trace = trace:gsub("(stack traceback:\n).*\n", "%1") 14 | reaper.ShowConsoleMsg(trace .. ln .. "\n" ) 15 | reaper.MB(tostring(msg) .. "\n\nContinue?", line, 0 ) 16 | end 17 | 18 | function Open_url(url) 19 | local OS = reaper.GetOS() 20 | if (OS == "OSX32" or OS == "OSX64") or OS == 'macOS-arm64' then 21 | os.execute('open "' .. url .. '"') 22 | elseif OS == "Win64" or OS == "Win32" then 23 | os.execute('start "" "' .. url .. '"') 24 | else 25 | os.execute('xdg-open "' .. url .. '"') -- LINUX 26 | end 27 | end 28 | 29 | function Check_Requirements() 30 | local reaper_version = reaper.GetAppVersion() 31 | local big, small = reaper_version:match("(6).(%d%d)") 32 | -- TEMPORARY NEEDS DEV RELEASE UNTIL FIXED LANES ARA IN STABLE 33 | if not reaper_version:match("+dev") then 34 | reaper.MB( "Reaper DEV Prerelease version v6.50+dev is required for this script. Please download latest DEV prerelease from www.landoleet.org", "SCRIPT REQUIREMENTS", 0 ) 35 | Open_url("www.landoleet.org") 36 | return reaper.defer(function() end) 37 | else 38 | if tonumber(small) < 53 then 39 | reaper.MB( "Reaper DEV Prerelease version v6.50+dev is required for this script. Please download latest DEV prerelease from www.landoleet.org", "SCRIPT REQUIREMENTS", 0 ) 40 | Open_url("https://www.landoleet.org") 41 | return reaper.defer(function() end) 42 | end 43 | end 44 | if not reaper.APIExists("JS_ReaScriptAPI_Version") then 45 | reaper.MB( "JS_ReaScriptAPI is required for this script. Please download it from ReaPack", "SCRIPT REQUIREMENTS", 0 ) 46 | reaper.ReaPack_BrowsePackages('JS_ReaScriptAPI:') 47 | return reaper.defer(function() end) 48 | else 49 | local version = reaper.JS_ReaScriptAPI_Version() 50 | if version < 1.301 then 51 | reaper.MB( "Your JS_ReaScriptAPI version is " .. version .. "\nPlease update to latest version.", "Older version is installed", 0 ) 52 | reaper.ReaPack_BrowsePackages('JS_ReaScriptAPI:') 53 | return reaper.defer(function() end) 54 | end 55 | end 56 | if not reaper.ImGui_GetVersion then 57 | reaper.MB( "ReaImGui is required for this script. Please download it from ReaPack", "SCRIPT REQUIREMENTS", 0 ) 58 | reaper.ReaPack_BrowsePackages( 'ReaImGui:') 59 | return reaper.defer(function() end) 60 | end 61 | end 62 | 63 | local crash = function(errObject) 64 | reaper.JS_VKeys_Intercept(-1, -1) 65 | local byLine = "([^\r\n]*)\r?\n?" 66 | local trimPath = "[\\/]([^\\/]-:%d+:.+)$" 67 | local err = errObject and string.match(errObject, trimPath) or "Couldn't get error message." 68 | local trace = debug.traceback() 69 | local stack = {} 70 | for line in string.gmatch(trace, byLine) do 71 | local str = string.match(line, trimPath) or line 72 | stack[#stack + 1] = str 73 | end 74 | local name = ({reaper.get_action_context()})[2]:match("([^/\\_]+)$") 75 | local ret = 76 | reaper.ShowMessageBox( 77 | name .. " has crashed!\n\n" .. "Would you like to have a crash report printed " .. "to the Reaper console?", 78 | "Oops", 79 | 4 80 | ) 81 | if ret == 6 then 82 | reaper.ShowConsoleMsg( 83 | "Error: " .. err .. "\n\n" .. 84 | "Stack traceback:\n\t" .. table.concat(stack, "\n\t", 2) .. "\n\n" .. 85 | "Reaper: \t" .. reaper.GetAppVersion() .. "\n" .. 86 | "Platform: \t" .. reaper.GetOS() 87 | ) 88 | end 89 | end 90 | 91 | function GetCrash() return crash end 92 | 93 | function MSG(m) reaper.ShowConsoleMsg(tostring(m) .. "\n") end 94 | 95 | function string.starts(String,Start) return string.sub(String,1,string.len(Start))==Start end 96 | 97 | function trim(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end 98 | 99 | function round(num) return math.floor(num + 0.5) end 100 | 101 | function tableToString(table) 102 | return serializeTable(table) 103 | end 104 | 105 | function stringToTable(str) 106 | local f, err = load("return "..str) 107 | return f ~= nil and f() or nil 108 | end 109 | 110 | function serializeTable(val, name, skipnewlines, depth) 111 | skipnewlines = skipnewlines or false 112 | depth = depth or 0 113 | local tmp = string.rep(" ", depth) 114 | if name then 115 | if type(name) == "number" and math.floor(name) == name then 116 | name = "[" .. name .. "]" 117 | elseif not string.match(name, '^[a-zA-z_][a-zA-Z0-9_]*$') then 118 | name = string.gsub(name, "'", "\\'") 119 | name = "['".. name .. "']" 120 | end 121 | tmp = tmp .. name .. " = " 122 | end 123 | if type(val) == "table" then 124 | tmp = tmp .. "{" .. (not skipnewlines and "\n" or "") 125 | for k, v in pairs(val) do 126 | tmp = tmp .. serializeTable(v, k, skipnewlines, depth + 1) .. "," .. (not skipnewlines and "\n" or "") 127 | end 128 | tmp = tmp .. string.rep(" ", depth) .. "}" 129 | elseif type(val) == "number" then 130 | tmp = tmp .. tostring(val) 131 | elseif type(val) == "string" then 132 | tmp = tmp .. string.format("%q", val) 133 | elseif type(val) == "boolean" then 134 | tmp = tmp .. (val and "true" or "false") 135 | else 136 | tmp = tmp .. "\"[inserializeable datatype:" .. type(val) .. "]\"" 137 | end 138 | return tmp 139 | end 140 | 141 | function Literalize(str) 142 | return str:gsub( 143 | "[%(%)%.%%%+%-%*%?%[%]%^%$]", 144 | function(c) 145 | return "%" .. c 146 | end 147 | ) 148 | end 149 | 150 | function Split_by_line(str) 151 | local t = {} 152 | for line in string.gmatch(str, "[^\r\n]+") do 153 | t[#t + 1] = line 154 | end 155 | return t 156 | end 157 | 158 | function ChunkTableGetSection(chunk, key) -- ADDOPTED FROM BirdBird and daniellumertz! 🦜 159 | local chunk_lines = Split_by_line(chunk) 160 | local section_chunks = {} 161 | local last_section_chunk = -1 162 | local current_scope = 0 163 | local i = 1 164 | while i <= #chunk_lines do 165 | local line = chunk_lines[i] 166 | 167 | local scope_end = false 168 | if line == '<'..key then 169 | last_section_chunk = i 170 | current_scope = current_scope + 1 171 | elseif string.starts(line, '<') then 172 | current_scope = current_scope + 1 173 | elseif string.starts(line, '>') then 174 | current_scope = current_scope - 1 175 | scope_end = true 176 | end 177 | 178 | if current_scope == 1 and last_section_chunk ~= -1 and scope_end then 179 | local s = '' 180 | for j = last_section_chunk, i do 181 | s = s .. chunk_lines[j] .. '\n' 182 | end 183 | last_section_chunk = -1 184 | table.insert(section_chunks, s) 185 | end 186 | i = i + 1 187 | end 188 | 189 | return next(section_chunks) and table.concat(section_chunks, "\n") 190 | end 191 | 192 | function GetChunkSection(chunk, key) -- ADDOPTED FROM LBX 193 | local chs, che 194 | chs, _ = string.find(chunk,'<' .. key) 195 | local level = 0 196 | local cpos = chs 197 | repeat 198 | local s, e = string.find(chunk,'[%<%>]', cpos) 199 | if s then 200 | local char = string.sub(chunk,s - 1, s) 201 | if char == '\n<' then level = level + 1 202 | elseif char == '\n>' then level = level - 1 203 | end 204 | end 205 | cpos = s + 1 206 | if level == 0 then che = s break end 207 | until level == 0 208 | 209 | if chs == nil or che == nil then return end 210 | local fchunk = string.sub(chunk,chs,che) 211 | return fchunk 212 | end 213 | 214 | function DBG_TBL(A) 215 | for index, value in pairs(A) do 216 | reaper.ShowConsoleMsg("K: "..tostring(index).." - V: "..tostring(type(value) == "table" and #value or value).."\n") 217 | end 218 | end 219 | 220 | function GenPalette(val) 221 | local a = {r = 0.5, g = 0.5, b = 0.5} 222 | local b = {r = 0.5, g = 0.5, b = 0.5} 223 | local c = {r = 1, g = 1, b = 1} 224 | local d = {r = 0, g = 0.33, b = 0.67} 225 | 226 | local brightness = 0.0 227 | 228 | local col = {} 229 | col.r = math.floor(math.min(a.r + brightness + math.cos((c.r * val + d.r) * 6.28318) * b.r, 1) * 255 + 0.5) 230 | col.g = math.floor(math.min(a.g + brightness + math.cos((c.g * val + d.g) * 6.28318) * b.g, 1) * 255 + 0.5) 231 | col.b = math.floor(math.min(a.b + brightness + math.cos((c.b * val + d.b) * 6.28318) * b.b, 1) * 255 + 0.5) 232 | return col.r, col.g, col.b 233 | end 234 | 235 | function Deepcopy(orig) 236 | local orig_type = type(orig) 237 | local copy 238 | if orig_type == 'table' then 239 | copy = {} 240 | for orig_key, orig_value in next, orig, nil do 241 | copy[Deepcopy(orig_key)] = Deepcopy(orig_value) 242 | end 243 | setmetatable(copy, Deepcopy(getmetatable(orig))) 244 | else -- number, string, boolean, etc 245 | copy = orig 246 | end 247 | return copy 248 | end 249 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Activate_lane_under_mouse.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.02 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 17 | if track_tbl.lane_mode == 0 then return end -- IF NOT IN LANE MODE IGNORE 18 | local func = "ActivateLaneUndeMouse" 19 | Show_menu(track_tbl, func) 20 | end 21 | 22 | xpcall(Main, GetCrash()) 23 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Copy_to_Comp.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.02 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 17 | if track_tbl.lane_mode == 0 then return end -- IF NOT IN LANE MODE IGNORE 18 | local func = "CopyToCOMP" 19 | Show_menu(track_tbl, func) 20 | end 21 | 22 | xpcall(Main, GetCrash()) 23 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_CreateNew.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "CreateNew" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Delete.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "Delete" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Duplicate.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "Duplicate" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_New_COMP.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 17 | local func = "NewComp" 18 | Show_menu(track_tbl, func) 19 | end 20 | 21 | xpcall(Main, GetCrash()) 22 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Rename.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "ReaperRename" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_SWIPE_to_Comp_HOLD.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.02 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | -- adopted from BirdBird 14 | local terminateScript = false 15 | local VKLow, VKHi = 8, 0xFE 16 | local VKState0 = string.rep("\0", VKHi - VKLow + 1) 17 | local startTime = 0 18 | 19 | -- adopted from BirdBird 20 | function awake() 21 | keyState = reaper.JS_VKeys_GetState(startTime - 0.5):sub(VKLow, VKHi) 22 | startTime = reaper.time_precise() 23 | thisCycleTime = startTime 24 | 25 | reaper.atexit(atExit) 26 | reaper.JS_VKeys_Intercept(-1, 1) 27 | 28 | keyState = reaper.JS_VKeys_GetState(-2):sub(VKLow, VKHi) 29 | 30 | local terminate = false 31 | if terminate == true then 32 | return true 33 | else 34 | return false 35 | end 36 | end 37 | -- adopted from BirdBird 38 | function scriptShouldStop() 39 | local prevCycleTime = thisCycleTime or startTime 40 | thisCycleTime = reaper.time_precise() 41 | local prevKeyState = keyState 42 | keyState = reaper.JS_VKeys_GetState(startTime - 0.5):sub(VKLow, VKHi) 43 | -- All keys are released. 44 | if keyState ~= prevKeyState and keyState == VKState0 then return true end 45 | -- Any keys were pressed. 46 | local keyDown = reaper.JS_VKeys_GetDown(prevCycleTime):sub(VKLow, VKHi) 47 | if keyDown ~= prevKeyState and keyDown ~= VKState0 then 48 | local p = 0 49 | ::checkNextKeyDown:: do 50 | p = keyDown:find("\1", p + 1) 51 | if p then 52 | if prevKeyState:byte(p) == 0 then 53 | return true 54 | else 55 | goto checkNextKeyDown 56 | end 57 | end 58 | end 59 | end 60 | 61 | return false 62 | end 63 | 64 | PREV_RAZOR_DATA = nil 65 | local func = "CopyToCOMP" 66 | function SWIPE() 67 | local track_tbl = OnDemand() 68 | if not track_tbl then return end 69 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 70 | if track_tbl.lane_mode == 0 then return end -- IF NOT IN LANE MODE IGNORE 71 | local CURRENT_RAZOR_DATA = Get_Razor_Data(track_tbl.rprobj) 72 | if not CURRENT_RAZOR_DATA then return end 73 | CURRENT_RAZOR_DATA = table.concat(CURRENT_RAZOR_DATA) 74 | if CURRENT_RAZOR_DATA ~= PREV_RAZOR_DATA then 75 | Show_menu(track_tbl, func) 76 | PREV_RAZOR_DATA = CURRENT_RAZOR_DATA 77 | end 78 | end 79 | 80 | function Main() 81 | if scriptShouldStop() or terminateScript then 82 | atExit() 83 | return 0 84 | end 85 | SWIPE() 86 | reaper.defer(Main) 87 | end 88 | 89 | function atExit() 90 | reaper.JS_VKeys_Intercept(-1, -1) 91 | end 92 | -------------------------------------- 93 | local terminate = awake() 94 | if terminate == false then 95 | xpcall(Main, GetCrash()) 96 | end -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_SWIPE_to_Comp_TOGGLE.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.02 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local _, _, sectionID, cmdID, _, _, _ = reaper.get_action_context() 14 | reaper.SetToggleCommandState(sectionID, cmdID, 1) 15 | reaper.RefreshToolbar2(sectionID, cmdID) 16 | 17 | PREV_RAZOR_DATA = nil 18 | local func = "CopyToCOMP" 19 | function SWIPE() 20 | local track_tbl = OnDemand() 21 | if not track_tbl then return end 22 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 23 | if track_tbl.lane_mode == 0 then return end -- IF NOT IN LANE MODE IGNORE 24 | local CURRENT_RAZOR_DATA = Get_Razor_Data(track_tbl.rprobj) 25 | if not CURRENT_RAZOR_DATA then return end 26 | CURRENT_RAZOR_DATA = table.concat(CURRENT_RAZOR_DATA) 27 | if CURRENT_RAZOR_DATA ~= PREV_RAZOR_DATA then 28 | Show_menu(track_tbl, func) 29 | PREV_RAZOR_DATA = CURRENT_RAZOR_DATA 30 | end 31 | end 32 | 33 | function Main() 34 | SWIPE() 35 | reaper.defer(Main) 36 | end 37 | 38 | function DoAtExit() 39 | -- set toggle state to off 40 | reaper.SetToggleCommandState(sectionID, cmdID, 0); 41 | reaper.RefreshToolbar2(sectionID, cmdID); 42 | end 43 | 44 | reaper.atexit(DoAtExit) 45 | xpcall(Main, GetCrash()) 46 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_ShowAll.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | if reaper.ValidatePtr(track_tbl.rprobj, "TrackEnvelope*") then return end -- DO NOT ALLOW ON EVELOPES 17 | local func = "ShowAll" 18 | Show_menu(track_tbl, func) 19 | end 20 | 21 | xpcall(Main, GetCrash()) 22 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Switch_DOWN.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "CycleVersionsDOWN" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Shortcuts/VT_Switch_UP.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.01 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]]:gsub("[\\|/]Shortcuts", "") .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | local function Main() 14 | local track_tbl = OnDemand() 15 | if not track_tbl then return end 16 | local func = "CycleVersionsUP" 17 | Show_menu(track_tbl, func) 18 | end 19 | 20 | xpcall(Main, GetCrash()) 21 | -------------------------------------------------------------------------------- /VirtualTrack/Virtual_track_Mouse.lua: -------------------------------------------------------------------------------- 1 | -- @description Virtual Tracks 2 | -- @author Sexan 3 | -- @license GPL v3 4 | -- @version 1.45 5 | -- @changelog 6 | -- + Properly calculate fade-in/fade-out for new item 7 | -- @provides 8 | -- {Images,Modules}/* 9 | -- [main] Shortcuts/*.lua 10 | -- [main] Virtual_track_SelTrack.lua 11 | 12 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]] .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 13 | 14 | require("Modules/VTCommon") 15 | require("Modules/Utils") 16 | 17 | Check_Requirements() 18 | reaper.SetProjExtState(0, "VirtualTrack", "ONDEMAND_MODE", "mouse") 19 | local function Main() 20 | local track_tbl = OnDemand() 21 | if not track_tbl then return end 22 | Show_menu(track_tbl) 23 | end 24 | 25 | xpcall(Main, GetCrash()) 26 | -------------------------------------------------------------------------------- /VirtualTrack/Virtual_track_SelTrack.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Author: SeXan 3 | * Licence: GPL v3 4 | * Version: 0.02 5 | * NoIndex: true 6 | --]] 7 | 8 | package.path = debug.getinfo(1, "S").source:match [[^@?(.*[\/])[^\/]-$]] .. "?.lua;" -- GET DIRECTORY FOR REQUIRE 9 | 10 | require("Modules/VTCommon") 11 | require("Modules/Utils") 12 | 13 | Check_Requirements() 14 | reaper.SetProjExtState(0, "VirtualTrack", "ONDEMAND_MODE", "track") 15 | local function Main() 16 | local track_tbl = OnDemand() 17 | if not track_tbl then return end 18 | Show_menu(track_tbl) 19 | end 20 | 21 | xpcall(Main, GetCrash()) 22 | --------------------------------------------------------------------------------