Created
November 9, 2020 16:18
-
-
Save X-Raym/448e8afea7d91bce96b520ca12ddc698 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
* ReaScript Name: Save_FX_Preset | |
* Lua script for Cockos REAPER | |
* Author: EUGEN27771 | |
* Author URI: http://forum.cockos.com/member.php?u=50462 | |
* Licence: GPL v3 | |
* Version: 1.04 | |
* Mod by X-Raym | |
]] | |
-------------------------------------------------------------------------------- | |
-- Base64_to_Hex(modded from lua.org functions) ------------------------------- | |
-------------------------------------------------------------------------------- | |
-- decryption table -- | |
local base64bytes = {['A']=0, ['B']=1, ['C']=2, ['D']=3, ['E']=4, ['F']=5, ['G']=6, ['H']=7, ['I']=8, ['J']=9, ['K']=10,['L']=11,['M']=12, | |
['N']=13,['O']=14,['P']=15,['Q']=16,['R']=17,['S']=18,['T']=19,['U']=20,['V']=21,['W']=22,['X']=23,['Y']=24,['Z']=25, | |
['a']=26,['b']=27,['c']=28,['d']=29,['e']=30,['f']=31,['g']=32,['h']=33,['i']=34,['j']=35,['k']=36,['l']=37,['m']=38, | |
['n']=39,['o']=40,['p']=41,['q']=42,['r']=43,['s']=44,['t']=45,['u']=46,['v']=47,['w']=48,['x']=49,['y']=50,['z']=51, | |
['0']=52,['1']=53,['2']=54,['3']=55,['4']=56,['5']=57,['6']=58,['7']=59,['8']=60,['9']=61,['+']=62,['/']=63,['=']=nil} | |
-------------------------------------------- | |
-- Decode Base64 to HEX -------------------- | |
-------------------------------------------- | |
function B64_to_HEX(data) | |
local chars = {} | |
local result = {} | |
local hex | |
for dpos=0, #data-1, 4 do | |
-- Get chars ------------------- | |
for char=1,4 do chars[char] = base64bytes[(string.sub(data,(dpos+char), (dpos+char)) or "=")] end -- Get chars | |
-- To hex ---------------------- | |
if chars[3] and chars[4] then | |
hex = string.format('%02X%02X%02X', -- if 1,2,3,4 chars | |
(chars[1]<<2) + ((chars[2]&0x30)>>4), -- 1 | |
((chars[2]&0xf)<<4) + (chars[3]>>2), -- 2 | |
((chars[3]&0x3)<<6) + chars[4] ) -- 3 | |
elseif chars[3] then | |
hex = string.format('%02X%02X', -- if 1,2,3 chars | |
(chars[1]<<2) + ((chars[2]&0x30)>>4), -- 1 | |
((chars[2]&0xf)<<4) + (chars[3]>>2), -- 2 | |
((chars[3]&0x3)<<6) ) | |
else | |
hex = string.format('%02X', -- if 1,2 chars | |
(chars[1]<<2) + ((chars[2]&0x30)>>4) ) -- 1 | |
end | |
--------------------------------- | |
table.insert(result,hex) | |
end | |
return table.concat(result) | |
end | |
---------------------------------------- | |
-- String_to_HEX ---------------------- | |
---------------------------------------- | |
function String_to_HEX(Preset_Name) | |
local VAL = {Preset_Name:byte(1,-1)} -- to bytes, values | |
local Pfmt = string.rep("%02X", #VAL) | |
return string.format(Pfmt, table.unpack(VAL)) | |
end | |
-------------------------------------------------------------------------------- | |
-- FX_Chunk_to_HEX ------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
-- Variant 1 --------------------------- | |
function FX_Chunk_to_HEX(FX_Type, FX_Chunk, Preset_Name) | |
local Preset_Chunk = FX_Chunk:match("\n.*\n") -- extract preset(simple var) | |
--------------------------------------- | |
-- For JS ----------------------------- | |
--------------------------------------- | |
if FX_Type=="JS" then | |
Preset_Chunk = Preset_Chunk:gsub("\n", "") -- del "\n" | |
--reaper.ShowConsoleMsg(Preset_Chunk..'\n') | |
return String_to_HEX(Preset_Chunk..Preset_Name) | |
end | |
--------------------------------------- | |
-- For VST ---------------------------- | |
--------------------------------------- | |
local Hex_TB = {} | |
local init = 1 | |
--------------------- | |
for i=1, math.huge do | |
line = Preset_Chunk:match("\n.-\n", init) -- extract line from preset(simple var) | |
if not line then | |
--reaper.ShowConsoleMsg(Hex_TB[i-1].."\n") | |
Hex_TB[i-1] = "00"..String_to_HEX(Preset_Name).."0010000000" -- Preset_Name to Hex(replace name from chunk) | |
--reaper.ShowConsoleMsg(Hex_TB[i-1].."\n") | |
break | |
end | |
--------------- | |
init = init + #line - 1 -- for next line | |
line = line:gsub("\n","") -- del "\n" | |
--reaper.ShowConsoleMsg(line.."\n") | |
Hex_TB[i] = B64_to_HEX(line) | |
end | |
--------------------- | |
return table.concat(Hex_TB) | |
end | |
-- Variant 2(without Name to Hex, simple var) ------ | |
--[[ | |
function FX_Chunk_to_HEX(FX_Type, FX_Chunk, Preset_Name) | |
local Preset_Chunk = FX_Chunk:match("\n.*\n") -- extract preset(simple var) | |
---------------------------------------- | |
Preset_Chunk = Preset_Chunk:gsub("\n","") -- del "\n" | |
if FX_Type=="JS" then return String_to_HEX(Preset_Chunk..Preset_Name) | |
else return B64_to_HEX(Preset_Chunk) | |
end | |
end | |
--]] | |
-------------------------------------------------------------------------------- | |
-- Get_CtrlSum ----------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
function Get_CtrlSum(HEX) | |
local Sum = 0 | |
for i=1, #HEX, 2 do Sum = Sum + tonumber( HEX:sub(i,i+1), 16) end | |
return string.sub( string.format("%X", Sum), -2, -1 ) | |
end | |
-------------------------------------------------------------------------------- | |
-- Write preset to PresetFile -------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
function Write_to_File(PresetFile, Preset_HEX, Preset_Name) | |
local file, Presets_ini, Nprsts | |
---------------------------------------------------------- | |
-- Rewrite header(or create) ----------------------------- | |
---------------------------------------------------------- | |
local ret_r, ret_w | |
if reaper.file_exists(PresetFile) then | |
-- BR function works faster than lua r,w -- | |
ret_r, Nprsts = reaper.BR_Win32_GetPrivateProfileString("General", "NbPresets", "", PresetFile) | |
Nprsts = math.tointeger(Nprsts) | |
------------------ | |
ret_w = reaper.BR_Win32_WritePrivateProfileString("General", "NbPresets", math.tointeger(Nprsts+1), PresetFile) | |
else Nprsts = 0 | |
Presets_ini = "[General]\nNbPresets="..Nprsts+1 | |
file = io.open(PresetFile, "w") | |
file:write(Presets_ini) | |
file:close() | |
end | |
---------------------------------------------------------- | |
-- Write preset data to file ----------------------------- | |
---------------------------------------------------------- | |
file = io.open(PresetFile, "r+") | |
file:seek("end") -- to end of file | |
------------------ | |
file:write("\n[Preset"..Nprsts.."]") -- preset number(0-based) | |
-------------------------------------- | |
-------------------------------------- | |
local Len = #Preset_HEX -- Data Lenght | |
local s = 1 | |
local Ndata = 0 | |
for i=1, math.ceil(Len/32768) do | |
if i==1 then Ndata = "\nData=" else Ndata = "\nData_".. i-1 .."=" end | |
local Data = Preset_HEX:sub(s, s+32767) | |
local Sum = Get_CtrlSum(Data) | |
file:write(Ndata, Data, Sum) | |
s = s+32768 | |
end | |
-------------------------------------- | |
--- Preset_Name, Data Lenght --------- | |
-------------------------------------- | |
file:write("\nName=".. Preset_Name .."\nLen=".. Len//2 .."\n") | |
------------------- | |
file:close() | |
end | |
-------------------------------------------------------------------------------- | |
-- Get FX_Chunk and PresetFile ------------------------------------------------ | |
-------------------------------------------------------------------------------- | |
function Get_FX_Data(track, fxnum) | |
local fx_cnt = reaper.TrackFX_GetCount(track) | |
if fx_cnt==0 or fxnum>fx_cnt-1 then return end -- if fxnum not valid | |
local ret, Track_Chunk = reaper.GetTrackStateChunk(track,"",false) | |
--reaper.ShowConsoleMsg(Track_Chunk) | |
------------------------------------ | |
-- Find FX_Chunk(use fxnum) -------- | |
------------------------------------ | |
local s, e = Track_Chunk:find("<FXCHAIN") -- find FXCHAIN section | |
-- find VST(or JS) chunk | |
for i=1, fxnum+1 do | |
s, e = Track_Chunk:find("<%u+%s.->", e) | |
end | |
---------------------------------- | |
-- FX_Type ----------------------- | |
local FX_Type = string.match(Track_Chunk:sub(s+1,s+3), "%u+") -- FX Type | |
if not(FX_Type=="VST" or FX_Type=="JS") then return end -- Only VST and JS supported | |
---------------------------------- | |
-- extract FX_Chunk -------------- | |
local FX_Chunk = Track_Chunk:match("%b<>", s) -- FX_Chunk(simple var) | |
---------------------------------- | |
--reaper.ShowConsoleMsg("\n\n"..fxnum.."\n"..FX_Chunk.."\n") | |
------------------------------------ | |
-- Get UserPresetFile -------------- | |
------------------------------------ | |
local PresetFile = reaper.TrackFX_GetUserPresetFilename(track, fxnum, "") | |
------------------------------------ | |
return FX_Type, FX_Chunk, PresetFile | |
end | |
-------------------------------------------------------------------------------- | |
-- Main function -------------------------------------------------------------- | |
-------------------------------------------------------------------------------- | |
function Save_VST_Preset(track, fxnum, Preset_Name) | |
if not (track and fxnum and Preset_Name) then return end -- Need track, fxnum, Preset_Name | |
local FX_Type, FX_Chunk, PresetFile = Get_FX_Data(track, fxnum) | |
--reaper.ShowConsoleMsg(FX_Chunk..'\n') | |
----------- | |
if FX_Chunk and PresetFile then | |
local start_time = reaper.time_precise() | |
local Preset_HEX = FX_Chunk_to_HEX(FX_Type, FX_Chunk, Preset_Name) | |
--reaper.ShowConsoleMsg("Processing time = ".. reaper.time_precise()-start_time ..'\n') -- time test | |
local start_time = reaper.time_precise() | |
Write_to_File(PresetFile, Preset_HEX, Preset_Name) | |
--reaper.ShowConsoleMsg("Write time = ".. reaper.time_precise()-start_time ..'\n') -- time test | |
reaper.TrackFX_SetPreset(track, fxnum, Preset_Name) -- For "update", but this is optional | |
end | |
end | |
---------------------------------------------------------------------------------------------------- | |
-- GetLastTouchedFX ------------------------------------------------------------------------------- | |
---------------------------------------------------------------------------------------------------- | |
function GetPresetName(track, vsti_id) | |
local retval, presetname = reaper.TrackFX_GetPreset(track, vsti_id, "") | |
return presetname | |
end | |
function Get_LastTouch_FX() | |
local retval, tracknum, fxnum = reaper.GetLastTouchedFX() -- fxnum | |
if not retval then return end | |
local track = reaper.GetTrack(0, tracknum-1) -- track(trackID) | |
local Pidx, Npt = reaper.TrackFX_GetPresetIndex(track, fxnum) | |
local Preset_Name = "New "..Npt+1 | |
local Preset_Name_2 = GetPresetName(track, fxnum ) | |
if Preset_Name_2 and Preset_Name_2 ~= '' then Preset_Name = Preset_Name_2 end | |
return track, fxnum, Preset_Name | |
end | |
---------------------------------------------------------------------------------------------------- | |
-- Start ------------------------------------------------------------------------------------------ | |
---------------------------------------------------------------------------------------------------- | |
local track, fxnum, Preset_Name = Get_LastTouch_FX() -- any function can be used | |
Save_VST_Preset(track, fxnum, Preset_Name) -- RUN | |
x, y = reaper.GetMousePosition() | |
reaper.TrackCtl_SetToolTip( "Saved", x, y, false ) | |
function HideTooltip() | |
reaper.TrackCtl_SetToolTip( "", x, y, true ) | |
end | |
---------------------------------------------------- | |
-- EDIT THE WAITING TIME IN SECONDS BETWEEN RUNNING ACTIONS HERE | |
wait_time_in_seconds = 2 | |
-- waiting code taken from schwa, thanks | |
-- http://forum.cockos.com/showthread.php?t=168270 | |
lasttime=os.time() | |
loopcount=0 | |
function runloop() | |
local newtime=os.time() | |
if (loopcount < 1) then | |
if newtime-lasttime >= wait_time_in_seconds then | |
lasttime=newtime | |
-- do whatever you want to do every x seconds | |
-- reaper.ShowConsoleMsg("waited ".. wait_time_in_seconds .. " seconds") | |
loopcount = loopcount+1 | |
end | |
else | |
---------------------------------------------------- | |
-- PUT ACTION(S) YOU WANT TO RUN AFTER WAITING HERE | |
HideTooltip() | |
---------------------------------------------------- | |
-- reaper.ShowConsoleMsg("stop !") | |
loopcount = loopcount+1 | |
end | |
if | |
(loopcount < 2) then reaper.defer(runloop) | |
end | |
end | |
reaper.defer(runloop) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://forum.cockos.com/showthread.php?t=178127#7