Old 03-14-2019, 03:36 PM   #1
Reno.thestraws
Human being with feelings
 
Reno.thestraws's Avatar
 
Join Date: Nov 2009
Location: Belgium
Posts: 10,474
Default Copy/ paste FX parameter

Hi Everyone

Is there a way to copy all settings from a TRack FX to the same FX on another track (without copy/pastin the plug-in or ctrl drag)

I think it could be doable with

Code:
EEL: bool TrackFX_GetFXName(MediaTrack track, int fx, #buf)

Lua: boolean retval, string buf = reaper.TrackFX_GetFXName(MediaTrack track, integer fx, string buf)
Code:
EEL: int TrackFX_GetNumParams(MediaTrack track, int fx)

Lua: integer reaper.TrackFX_GetNumParams(MediaTrack track, integer fx)
Code:
EEL: double TrackFX_GetParam(MediaTrack track, int fx, int param, &minval, &maxval)

Lua: number retval, number minval, number maxval = reaper.TrackFX_GetParam(MediaTrack track, integer fx, integer param)
Code:
EEL: bool TrackFX_SetParam(MediaTrack track, int fx, int param, val)

Lua: boolean reaper.TrackFX_SetParam(MediaTrack track, integer fx, integer param, number val)
but my coding ability is way too low to achieve something

Someone could help me?

Thanks in advance
__________________
http://www.residenceemilia.com
Reno.thestraws is offline   Reply With Quote
Old 03-14-2019, 03:59 PM   #2
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by Reno.thestraws View Post

Is there a way to copy all settings from a TRack FX to the same FX on another track (without copy/pastin the plug-in or ctrl drag)
Maybe have a look at these scripts, on reapack ..
Copy Focused FX data
Paste Focused FX data
Edgemeal is offline   Reply With Quote
Old 03-14-2019, 09:16 PM   #3
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Quote:
Originally Posted by Edgemeal View Post
Maybe have a look at these scripts, on reapack ..
Copy Focused FX data
Paste Focused FX data
Deprecated and removed though.
mpl is offline   Reply With Quote
Old 03-14-2019, 11:39 PM   #4
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by mpl View Post
Deprecated and removed though.
Why, was it the Chunking?
Edgemeal is offline   Reply With Quote
Old 03-15-2019, 12:05 AM   #5
mpl
Human being with feelings
 
mpl's Avatar
 
Join Date: Oct 2013
Location: Moscow, Russia
Posts: 3,960
Default

Mostly yes. Also bad designed (at code level). I'll probably return to work on it, if people will be really interested.

Last edited by mpl; 03-15-2019 at 12:28 AM.
mpl is offline   Reply With Quote
Old 03-15-2019, 11:59 AM   #6
Reno.thestraws
Human being with feelings
 
Reno.thestraws's Avatar
 
Join Date: Nov 2009
Location: Belgium
Posts: 10,474
Default

PT refugees will
__________________
http://www.residenceemilia.com
Reno.thestraws is offline   Reply With Quote
Old 05-05-2019, 05:36 AM   #7
strangy
Human being with feelings
 
Join Date: Apr 2019
Posts: 29
Default

Quote:
Originally Posted by mpl View Post
Mostly yes. Also bad designed (at code level). I'll probably return to work on it, if people will be really interested.
Very interesed
strangy is offline   Reply With Quote
Old 05-03-2020, 02:05 PM   #8
Berg
Human being with feelings
 
Join Date: Jul 2014
Location: Rennes, FR
Posts: 195
Default

Would be very helpful !
Berg is offline   Reply With Quote
Old 08-29-2020, 02:07 PM   #9
Thunderfinger
Human being with feelings
 
Join Date: Jun 2020
Posts: 48
Default

I would definitely use this every day if it copied all of the FX parameters, not just the focused one like the old version.
Thunderfinger is offline   Reply With Quote
Old 08-30-2020, 07:27 AM   #10
Meo-Ada Mespotine
Human being with feelings
 
Meo-Ada Mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig
Posts: 6,621
Default

So if I get it right, it shall replace the parameters of an existing fx, not pasting a new version.

So if two tracks have ReaEQ, shall it replace the ReaEQ-settings of track 2 with the settings of ReaEQ of track 1, or shall it insert a second ReaEQ into track 2?
__________________
Use you/she/her.Ultraschall-Api Lua Api4Reaper - Donate, if you wish

On vacation for the time being...
Meo-Ada Mespotine is offline   Reply With Quote
Old 11-16-2020, 06:05 AM   #11
Fox the Reaper
Human being with feelings
 
Join Date: May 2018
Posts: 9
Default Same thing

Hey,

would love to have this. I'm working on a bigger Projekt. So I have on EQ for Notches for every actor. If the actor is at the same location, I want to copy and paste all the notches I did before, again to the same EQ I use for Notches.

A workflow that makes this possible:

Copy all Parameters from ReaEQ at one point. Go to the place where you want it like that. Select the Region/Area you want the same parameters. Go into Latch Mode. Paste the Settings to the same eq again. And write it to the selected area. Go to read mode again.

Something like that would be nice.
Fox the Reaper is offline   Reply With Quote
Old 01-04-2021, 08:30 AM   #12
Thunderfinger
Human being with feelings
 
Join Date: Jun 2020
Posts: 48
Default Possible using FX presets?

Hello,

I started to work on this with my very limited programming skills, but I am currently stuck. My idea is to save a preset that is always named "temp" for the copy, and to set the "temp" preset for the paste.

I have the paste script figured out:

Code:
retval, tracknumber, fxnumber = reaper.GetLastTouchedFX()
trackid = reaper.GetTrack(0, (tracknumber - 1))
reaper.TrackFX_SetPreset(trackid, fxnumber, "temp")
However, for the copy, I cannot figure out how to save an FX preset in a reascript. Does anyone know if it is possible?
Thunderfinger is offline   Reply With Quote
Old 01-04-2021, 11:37 AM   #13
Thunderfinger
Human being with feelings
 
Join Date: Jun 2020
Posts: 48
Default

To follow up on my previous message, I found a script from eugen2777 to save an FX preset:

https://forum.cockos.com/showthread.php?t=178127

The script works to save a plugin preset, but it increments the FX preset index in the preset name. What I would need for it to work in a copy/paste workflow would be to write the preset name without the index. That way, the paste script can use the same preset name. I'll try to modify eugen2777's script to make it work.

Last edited by Thunderfinger; 01-04-2021 at 11:38 AM. Reason: Clarification
Thunderfinger is offline   Reply With Quote
Old 04-26-2023, 11:05 PM   #14
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

I miss those scripts. Is there another method for easily copying and pasting all parameters of a specific track FX from one area to another without affecting other envelopes, like FX, volume, and pan? Eugens Save Preset for the last touched FX works well, but it creates new presets every time. After a while of saving FX data, the preset menu gets quickly cluttered!

Last edited by hans; 04-27-2023 at 01:28 AM.
hans is offline   Reply With Quote
Old 04-29-2023, 03:01 AM   #15
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
I miss those scripts. Is there another method for easily copying and pasting all parameters of a specific track FX from one area to another without affecting other envelopes, like FX, volume, and pan? Eugens Save Preset for the last touched FX works well, but it creates new presets every time. After a while of saving FX data, the preset menu gets quickly cluttered!
I came up with this:

This script copies VST or CLAP data to clipboard for (last) focused FX (it's probably possible to do with chunks for any type):
Code:
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
reaper.PreventUIRefresh(1)
_, fx_type = reaper.TrackFX_GetNamedConfigParm( track, fxnumber, 'fx_type' )
if fx_type:find('VST') then
  _, buf = reaper.TrackFX_GetNamedConfigParm( track, fxnumber, 'vst_chunk_program' )
elseif fx_type:find('CLAP') then
  _, buf = reaper.TrackFX_GetNamedConfigParm( track, fxnumber, 'clap_chunk' )
end
reaper.CF_SetClipboard( buf )
reaper.PreventUIRefresh(-1)
This script pastes VST or CLAP data from clipboard for (last) focused FX:
Code:
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
reaper.PreventUIRefresh(1)
reaper.Undo_BeginBlock2(0)
_, fx_type = reaper.TrackFX_GetNamedConfigParm( track, fxnumber, 'fx_type' )
if fx_type:find('VST') then
  _, buf = reaper.TrackFX_SetNamedConfigParm( track, fxnumber, 'vst_chunk_program', reaper.CF_GetClipboard() )
elseif fx_type:find('CLAP') then
  _, buf = reaper.TrackFX_SetNamedConfigParm( track, fxnumber, 'clap_chunk', reaper.CF_GetClipboard() )
end
reaper.Undo_EndBlock2(0, 'Paste FX preset from clipboard', 2)
reaper.PreventUIRefresh(-1)
vitalker is online now   Reply With Quote
Old 04-29-2023, 07:22 AM   #16
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
I miss those scripts. Is there another method for easily copying and pasting all parameters of a specific track FX from one area to another without affecting other envelopes, like FX, volume, and pan? Eugens Save Preset for the last touched FX works well, but it creates new presets every time. After a while of saving FX data, the preset menu gets quickly cluttered!
Okay, I've spent quite a lot of time and it finally worked. Even after deleting preset there was still a variable inside presets file (yes, it's one for all custom presets), which shows presets number. And if not change it, you'll got empty presets, which can't be deleted. So I've decreased that variable by one after deleting.

As Edgemeal stated using this script for non-last created preset may lead to unexpected results. I recommend to use it ONLY for last created preset. If you need the script for deleting last created preset, then use version from this post:
https://forum.cockos.com/showpost.ph...6&postcount=20

The script deletes active preset for (last) focused FX. It isn't refreshing, so you'll see change only after, for example, closing and opening FX window again.
Code:
reaper.PreventUIRefresh(1)
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
presetfile = reaper.TrackFX_GetUserPresetFilename( track, fxnumber )
_, presetname = reaper.TrackFX_GetPreset( track, fxnumber )

find_preset = 'Name='..presetname

local file = io.open(presetfile, "r")
contents = file:read("*all")
file:close()

contents = string.gsub(contents, "\n%[[%d%a]+]\nData=[%d%u]+\nLen=%d+\n" .. find_preset .. "\n", "")
presets_number = string.match(contents, "NbPresets=%d+")
presets_number = string.gsub(presets_number, "NbPresets=", "")
presets_number = tonumber(presets_number) - 1
contents = string.gsub(contents, "NbPresets=%d+", "NbPresets="..tostring(presets_number))

file = io.open(presetfile, "w")
file:write(contents)
file:close()
reaper.PreventUIRefresh(-1)
I also changed a bit Eugen's code, so it follows the right order as when you save preset manually. Another change is (last) focused FX, not last touched:

Code:
--[[
   * 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.03
  ]]

--------------------------------------------------------------------------------
-- 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:write("\nLen=".. Len//2 .."\nName=".. Preset_Name .."\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 Get_LastTouch_FX()
  --local retval, tracknum, fxnum = reaper.GetLastTouchedFX()           -- fxnum  
  local retval, tracknum, _, fxnum = reaper.GetFocusedFX2()
  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                                  -- New Preset_Name
  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

Last edited by vitalker; 05-03-2023 at 06:25 AM.
vitalker is online now   Reply With Quote
Old 05-02-2023, 04:16 AM   #17
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Vitalker... Thank you very much for the scripts! And the gen-modded version you made suits my needs way better too. Nice one!

Just one thing regarding the paste script. If I paste the Fx data to the same plugin on a different track, and there are no created envelopes for it from before, it won't paste the data until i have manually created them. Don't mind this if it's not a quick fix for you mate.

Last edited by hans; 05-02-2023 at 04:26 AM.
hans is offline   Reply With Quote
Old 05-02-2023, 04:29 AM   #18
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Vitalker... Thank you very much for the scripts! And the gen-modded version you made suits my needs way better too. Nice one!

Just one thing regarding the paste script. If I paste the Fx data to the same plugin on a different track, and there are no created envelopes for it from before, it won't paste the data until i have manually created them. Don't mind this if it's not a quick fix for you mate.
Ah, looks like API doesn't allow for envelopes. I'll see whether it won't be difficult to make.

Last edited by vitalker; 05-02-2023 at 04:39 AM.
vitalker is online now   Reply With Quote
Old 05-02-2023, 04:57 AM   #19
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Thanks. If not, I think I can get around using the presets saving workflow. I don't want to ask for too much, but "load last created preset in last focused FX" would solve quite much..
hans is offline   Reply With Quote
Old 05-02-2023, 06:50 AM   #20
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Thanks. If not, I think I can get around using the presets saving workflow. I don't want to ask for too much, but "load last created preset in last focused FX" would solve quite much..
This should do. And it will work for any preset regardless the way it was created.
Code:
reaper.PreventUIRefresh(1)
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
presetfile = reaper.TrackFX_GetUserPresetFilename( track, fxnumber )

local file = io.open(presetfile, "r")
contents = file:read("*all")
presets_number = string.match(contents, "NbPresets=%d+")
presets_number = string.gsub(presets_number, "NbPresets=", "")
presets_number = tonumber(presets_number) - 1
file:close()

reaper.TrackFX_SetPresetByIndex( track, fxnumber, presets_number )
reaper.PreventUIRefresh(-1)
You'd probably just want to have two operations in one script. This one will set last created preset regardless the way it was created and then delete it:

Code:
reaper.PreventUIRefresh(1)
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
presetfile = reaper.TrackFX_GetUserPresetFilename( track, fxnumber )

local file = io.open(presetfile, "r")
contents = file:read("*all")
presets_number = string.match(contents, "NbPresets=%d+")
presets_number = string.gsub(presets_number, "NbPresets=", "")
presets_number = tonumber(presets_number) - 1
file:close()

reaper.TrackFX_SetPresetByIndex( track, fxnumber, presets_number )
_, presetname = reaper.TrackFX_GetPreset( track, fxnumber )
find_preset = 'Name='..presetname

contents = string.gsub(contents, "\n%[[%d%a]+]\nData=[%d%u]+\nLen=%d+\n" .. find_preset .. "\n", "")
presets_number = string.match(contents, "NbPresets=%d+")
presets_number = string.gsub(presets_number, "NbPresets=", "")
presets_number = tonumber(presets_number) - 1
contents = string.gsub(contents, "NbPresets=%d+", "NbPresets="..tostring(presets_number))

file = io.open(presetfile, "w")
file:write(contents)
file:close()
reaper.PreventUIRefresh(-1)

Last edited by vitalker; 05-02-2023 at 07:00 AM.
vitalker is online now   Reply With Quote
Old 05-02-2023, 06:55 AM   #21
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Works great. Thanks man. Sent a little donation. Hope it covers some of the efforts.
hans is offline   Reply With Quote
Old 05-02-2023, 06:59 AM   #22
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Works great. Thanks man. Sent a little donation. Hope it covers some of the efforts.
Thanks! Already made a version for two operations.
Updated my previous comment.
vitalker is online now   Reply With Quote
Old 05-02-2023, 07:06 AM   #23
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Amazing. Thanks!
hans is offline   Reply With Quote
Old 05-02-2023, 07:41 AM   #24
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Done some testing here. "load last preset in last focused FX" will load the preset name in the preset list, but the parameters are not being updated. I need to open the fx preset list and select something else and then click the new preset to get the automation loaded.

Is there a fix there?
hans is offline   Reply With Quote
Old 05-02-2023, 07:49 AM   #25
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Done some testing here. "load last preset in last focused FX" will load the preset name in the preset list, but the parameters are not being updated. I need to open the fx preset list and select something else and then click the new preset to get the automation loaded.

Is there a fix there?
Hm, works for me. I got it just immediately.
Which script are you using? Both for setting last created preset and for setting + deleting works correctly. Second script deletes the preset, but parameters remain from it.

vitalker is online now   Reply With Quote
Old 05-02-2023, 08:24 AM   #26
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Done some testing here. "load last preset in last focused FX" will load the preset name in the preset list, but the parameters are not being updated. I need to open the fx preset list and select something else and then click the new preset to get the automation loaded.

Is there a fix there?
What about last scripts with automation?
vitalker is online now   Reply With Quote
Old 05-03-2023, 12:35 AM   #27
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Sorry for the delay here.

Ahh.. It works. It's just that I always need to run the load action twice to load the preset.
I'm always using Latch Preview..

In the following gif. These are the steps:

1. Saving a new preset with your modded version of Eugens script.
2. Move edit cursor to another place in the project where I want to load the preset..
3. I have to run your action "load last created preset in last focused FX.lua" twice to load it. As you might can see.

So I just have to run it twice. That means I can't use the combined Load and delete of preset since I have to actually run the load preset action two times before it gets loaded.


So you've done everything Right.








Last edited by hans; 05-03-2023 at 12:41 AM.
hans is offline   Reply With Quote
Old 05-03-2023, 01:17 AM   #28
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Sorry for the delay here.

Ahh.. It works. It's just that I always need to run the load action twice to load the preset.
I'm always using Latch Preview..

In the following gif. These are the steps:

1. Saving a new preset with your modded version of Eugens script.
2. Move edit cursor to another place in the project where I want to load the preset..
3. I have to run your action "load last created preset in last focused FX.lua" twice to load it. As you might can see.

So I just have to run it twice. That means I can't use the combined Load and delete of preset since I have to actually run the load preset action two times before it gets loaded.


So you've done everything Right.
Got it. Did you try last scripts with copying automation? They probably won't have this issue.
vitalker is online now   Reply With Quote
Old 05-03-2023, 02:19 AM   #29
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

I don't know if those scripts are something for me, since I'll be copy and pasting different EQ settings around between tracks and fx, and I want to preserve all previous written envelope data for that FX.

The replace script isn't working for me. I have triple checked that I have pasted the codes correctly.

It will delete the target FX.
hans is offline   Reply With Quote
Old 05-03-2023, 02:22 AM   #30
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
I don't know if those scripts are something for me, since I'll be copy and pasting different EQ settings around between tracks and fx, and I want to preserve all previous written envelope data for that FX.

The replace script isn't working for me. I have triple checked that I have pasted the codes correctly.

It will delete the target FX.
You asked me for it. Maybe you meant something else.

Sorry, it was working for me yesterday. Now it also doesn't work. I'll need to check.

Quote:
Originally Posted by hans View Post
Just one thing regarding the paste script. If I paste the Fx data to the same plugin on a different track, and there are no created envelopes for it from before, it won't paste the data until i have manually created them. Don't mind this if it's not a quick fix for you mate.

Last edited by vitalker; 05-03-2023 at 02:28 AM.
vitalker is online now   Reply With Quote
Old 05-03-2023, 02:50 AM   #31
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Sorry if I haven't been clear enough. You have created the scripts I've asked for, and I will use them all. Very useful. Except the following: "replace last focused FX with automation" which i suspect will remove ALL automation on the target track, not what I'm looking for.. I only want to paste FX data to a certain selections, sometimes between tracks, preserving data outside written area.


Like another guy in this thread wanted to quickly copy and paste EQ settings, like fox the reaper. But I want to make sure it also activates all envelopes necessary when pasting them to the same FX on a different track, if they don't exist.


Quote:
So I have on EQ for Notches for every actor. If the actor is at the same location, I want to copy and paste all the notches I did before, again to the same EQ I use for Notches.

Last edited by hans; 05-03-2023 at 02:56 AM.
hans is offline   Reply With Quote
Old 05-03-2023, 03:08 AM   #32
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Sorry if I haven't been clear enough. You have created the scripts I've asked for, and I will use them all. Very useful. Except the following: "replace last focused FX with automation" which i suspect will remove ALL automation on the target track, not what I'm looking for.. I only want to paste FX data to a certain selections, sometimes between tracks, preserving data outside written area.
No, the last scripts are using FX chain menu for copying FX with automation and then pasting it. There is some timing issue, which prevents paste it and I am investigating what can be done to make it work.
vitalker is online now   Reply With Quote
Old 05-03-2023, 05:56 AM   #33
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Okay, I was able to make it work with chunks. Just replace contents of the ones, which didn't work.

For copying (last) focused FX including automation to clipboard.
Code:
--returns success, fxchunk, start loc, end loc
local function GetFXChunkFromTrackChunk(trchunk, fxn)
  local s,e, fnd = 0,0,nil
  local fxchunk
  for i = 1,fxn do
    s, e = string.find(trchunk,'(BYPASS.-WAK %d %d)',s)
    if s and e then
      fxchunk = string.sub(trchunk,s,e)
      if i == fxn then fnd = true break end
      s=e+1
    else
      fxchunk = nil
      fndn = nil
      break
    end
  end
  return fnd, fxchunk, s, e  
end

retval, trnum, _, fxnum = reaper.GetFocusedFX2() if not retval then return end
if trnum ~= 0 then tr_from = reaper.GetTrack( 0, trnum-1 )
else tr_from = reaper.GetMasterTrack(0)
end

ret, chunk_from = reaper.GetTrackStateChunk(tr_from, '', false)
_, fx_chunk, _, _ = GetFXChunkFromTrackChunk(chunk_from, fxnum+1)
reaper.CF_SetClipboard(fx_chunk)
For replacing (last) focused FX from clipboard.
Code:
function Chunk_GetFXChainSection(chunk)
  -- If FXChain - return section, If none - return char after MAIN SEND \n
  local s1 = string.find(chunk, '<FXCHAIN.-\n')
  if s1 then
    local s = s1
    local indent, op, cl = 1
    while indent > 0 do
      op = string.find(chunk, '\n<', s+1, true)
      cl = string.find(chunk, '\n>\n', s+1, true) + 1
      if op == nil and cl == nil then break end
      if op then
        op = op + 1
        if op <= cl then
          indent = indent + 1
          s = op
        else
          indent = indent - 1
          s = cl
        end
      else
        indent = indent - 1
        s = cl        
      end
    end
    local retch = string.sub(chunk,s1,cl)
    return retch, s1, cl
  else
    local s1, e1 = string.find(chunk, 'MAINSEND.-\n')
    return nil, s1, e1
  end
end

--returns new track chunk, new fxguid, old fxguid
function Chunk_InsertFXChunkAtEndOfFXChain(trn, trchunk, insfxchunk, keepid)
  local guids = {}
  local ofxid, nfxid, rchunk, rchunk2 = nil, nil, nil, nil
  if keepid == nil then --prepare insert chunk
    if insfxchunk then
      insfxchunk = string.gsub(insfxchunk,
                              'FXID ({%x%x%x%x%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%-%x%x%x%x%x%x%x%x%x%x%x%x})',
                              function(d) if guids[d] == nil then guids[d]=reaper.genGuid('') end return 'FXID '..guids[d] end)
    end
    for i, v in pairs(guids) do --should be just one
      ofxid = i
      nfxid = v 
    end
  end
  local insfxchunk2 = string.gsub(insfxchunk,'<PROGRAMENV.->\n','')--condition insfxchunk, PROGRAMENV
  local chunk, chs, che = Chunk_GetFXChainSection(trchunk)
  if chunk then --insert before final character
    rchunk = string.sub(trchunk,0,che-1) .. insfxchunk .. string.sub(trchunk,che-1)
    if insfxchunk2 ~= insfxchunk then
      rchunk2 = string.sub(trchunk,0,che-1) .. insfxchunk2 .. string.sub(trchunk,che-1)      
    end
  else
    if trn == -1 then --master track
      local ms, me = string.find(trchunk,'.+>')
      if me then --insert at very end
        rchunk = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,me)  
        if insfxchunk2 ~= insfxchunk then
          rchunk2 = string.sub(trchunk,0,me-1).. '<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,me)
        end
      end
    else
      --normal track -- insert after MAINSEND
      rchunk = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk ..'\n>\n'..string.sub(trchunk,che+1)
      if insfxchunk2 ~= insfxchunk then
        rchunk2 = string.sub(trchunk,0,che)..'<FXCHAIN\nSHOW 0\nLASTSEL 0\nDOCKED 0\n'.. insfxchunk2 ..'\n>\n'..string.sub(trchunk,che+1)
      end
    end    
  end
  return rchunk, nfxid, ofxid, rchunk2
end

function SetTrackChunk(track, track_chunk)
  if not (track and track_chunk) then return end
  return reaper.SetTrackStateChunk(track, track_chunk, false)
end

retval, trnum, _, fxnum = reaper.GetFocusedFX2() if not retval then return end
if trnum ~= 0 then track = reaper.GetTrack( 0, trnum-1 )
else track = reaper.GetMasterTrack(0)
end
fx_data_from = reaper.CF_GetClipboard()

reaper.PreventUIRefresh(1)
reaper.Undo_BeginBlock2(0)
ret, chunk_to = reaper.GetTrackStateChunk(track, '', false)
insert = Chunk_InsertFXChunkAtEndOfFXChain(trnum, chunk_to, fx_data_from)
SetTrackChunk(track, insert)
reaper.TrackFX_Delete(track, fxnum)
fx_n = reaper.TrackFX_GetCount(track)
reaper.TrackFX_CopyToTrack(track, fx_n-1, track, fxnum, true)
reaper.Undo_EndBlock2(0, 'Replace (last) focused FX', 2+64)
reaper.PreventUIRefresh(-1)

Last edited by vitalker; 05-03-2023 at 06:12 AM.
vitalker is online now   Reply With Quote
Old 05-03-2023, 06:16 AM   #34
Edgemeal
Human being with feelings
 
Edgemeal's Avatar
 
Join Date: Apr 2016
Location: ASU`ogacihC
Posts: 3,913
Default

Quote:
Originally Posted by vitalker View Post
The script deletes active preset for (last) focused FX. It isn't refreshing, so you'll see change only after, for example, closing and opening FX window again.
Code:
reaper.PreventUIRefresh(1)
_, tracknumber, _, fxnumber = reaper.GetFocusedFX2()
if tracknumber ~= 0 then track = reaper.GetTrack( 0, tracknumber-1 )
else track = reaper.GetMasterTrack(0)
end
presetfile = reaper.TrackFX_GetUserPresetFilename( track, fxnumber )
_, presetname = reaper.TrackFX_GetPreset( track, fxnumber )

find_preset = 'Name='..presetname

local file = io.open(presetfile, "r")
contents = file:read("*all")
file:close()

contents = string.gsub(contents, "\n%[[%d%a]+]\nData=[%d%u]+\nLen=%d+\n" .. find_preset .. "\n", "")
presets_number = string.match(contents, "NbPresets=%d+")
presets_number = string.gsub(presets_number, "NbPresets=", "")
presets_number = tonumber(presets_number) - 1
contents = string.gsub(contents, "NbPresets=%d+", "NbPresets="..tostring(presets_number))

file = io.open(presetfile, "w")
file:write(contents)
file:close()
reaper.PreventUIRefresh(-1)
I'd be very careful using that code as is, if you remove a preset you'll likely need to rename/renumber all the [Preset#] sections after it.

Example I select Ed's Bass_0001, run the script, refresh the plugin, and now 0020 is no longer listed at the bottom and there is an empty slot where 0001 was.
Edgemeal is offline   Reply With Quote
Old 05-03-2023, 06:19 AM   #35
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by Edgemeal View Post
I'd be very careful using that code as is, if you remove a preset you'll likely need to rename/renumber all the [Preset#] sections after it.

Example I select Ed's Bass_0001, run the script, refresh the plugin, and now 0020 is no longer listed at the bottom and there is an empty slot where 0001 was.
Looks like you are right. Then it's better to use the next version, where the last created preset is set and deleted. The only use case was here for last preset, so I don't recommend using it for anything else. Added a comment there.
vitalker is online now   Reply With Quote
Old 07-07-2023, 12:52 AM   #36
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

I've noticed that the action "save preset for the last touched FX" isn't working on some plugins. It will save a new .rpl if i go manually up in the + menu and click save from there.
For example, I could run this action after touching ReaEQ before, but not working anymore.

Here is the code I'm trying to run:

Code:
--[[
   * 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.03
  ]]

--------------------------------------------------------------------------------
-- 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:write("\nLen=".. Len//2 .."\nName=".. Preset_Name .."\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 Get_LastTouch_FX()
  --local retval, tracknum, fxnum = reaper.GetLastTouchedFX()           -- fxnum  
  local retval, tracknum, _, fxnum = reaper.GetFocusedFX2()
  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                                  -- New Preset_Name
  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
hans is offline   Reply With Quote
Old 07-07-2023, 01:00 AM   #37
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
I've noticed that the action "save preset for the last touched FX" isn't working on some plugins. It will save a new .rpl if i go manually up in the + menu and click save from there.
For example, I could run this action after touching ReaEQ before, but not working anymore.

Here is the code I'm trying to run:
Are you using my modified version? It works for (last) focused FX instead of last touched one. The code is here:

https://forum.cockos.com/showpost.ph...8&postcount=16
vitalker is online now   Reply With Quote
Old 07-11-2023, 10:53 PM   #38
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

Yes, Using your one. Also tried with Eugens original. It won't save preset on multiple plugins I have, but some. I think something has gone corrupt.
hans is offline   Reply With Quote
Old 07-11-2023, 11:08 PM   #39
vitalker
Human being with feelings
 
vitalker's Avatar
 
Join Date: Dec 2012
Posts: 13,333
Default

Quote:
Originally Posted by hans View Post
Yes, Using your one. Also tried with Eugens original. It won't save preset on multiple plugins I have, but some. I think something has gone corrupt.
To check whether anything is corrupted, I'd need to take a look at those preset files. Also I could try to check it for myself, but I need to know which plugins to test it with.
vitalker is online now   Reply With Quote
Old 07-12-2023, 01:39 AM   #40
hans
Human being with feelings
 
Join Date: Aug 2020
Posts: 276
Default

I just tried all Cockos plugins. It won't work on any of these. Your load and delete last touched works great. Saving is currently not working on barely anything atm.
hans is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 04:40 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.