Clone function?

I would like to use the clone () function to clone a user envelope and then be able to restore to original via macro button, after making edits . I tried following the example of cloning a program shown at the developer site, however there is no mention of how to restore a cloned object.

If anyone has some code that can clone and restore an envelope could you please post it?

Thank you :slight_smile:

You cannot clone just the user envelope - you would need to clone the whole zone. But it should be possible by creating a couple of variables and store the relevant envelope parameters. I guess you would need the EnvelopePoints, SustainIndex and probably Mode. You can use getParameter to store those values into variables. Then to restore those value simply use setParameter.

1 Like

I just need to be able to restore the env points table. I suppose I could try various deep copy/clone table functions out there on the net. You wouldā€™nt happen to know of one that would work well, do you?

Iā€™ve created a script and macro that Iā€™m using to manipulate the points table in whole or even just sections of the table and it would be nice to be able to restore the original without having to always fummble with the preset menu.

In my other post about the script reset buttonā€¦, that is
related to this same script project. Any time I want to reset the env points table or load a different one I have to also click the script reset button so that my function can gather the table data.
I was hoping to be able to assign it to a macro button so I could control it via midi, this way I wouldnā€™t have to reach for the mouse as much. :slight_smile:

You can try something like this to copy and restore an envelope.

defineParameter("CopyEnv", nil, false, function() copyEnvelope("Amp Env") end)
defineParameter("RestoreEnv", nil, false, function() restoreEnvelope("Amp Env") end)
defineParameter{name = "DataCopied", default = false, persistent = false, automatable = false, readOnly = true}

zone = this.parent:getLayer():getZone()

function copyEnvelope(envType)
	if CopyEnv then
		envelopePoints = zone:getParameter(envType..".EnvelopePoints")
		sustainIndex = zone:getParameter(envType..".SustainIndex")
		mode = zone:getParameter(envType..".Mode")

		DataCopied = true
		
		wait(50)
		CopyEnv = false
	end
end

function restoreEnvelope(envType)
	if RestoreEnv and DataCopied then
		zone:setParameter(envType..".EnvelopePoints", envelopePoints)
		zone:setParameter(envType..".SustainIndex", sustainIndex)
		zone:setParameter(envType..".Mode", mode)
		
		wait(50)
		RestoreEnv = false
	end
end

Restore Envelope.vstpreset (12.8 KB)

1 Like

ooh cool! Iā€™ll try it out and let you know how it goes.
Thank You :smiley:

Tried it out and it works greatā€¦, thank you so much.

There is one other thing I was wondering if you might have a solution to? So, say Iā€™m iterating over the level values of an envelope, using just the standard for loop, there is the step parameter which allows for things like every nā€™th, but what Iā€™m looking to do is to manipulate groups of points. So things like
xxoxxo or xxooxxoo, ā€˜xā€™ being the points I want to control. I donā€™t know if it would require a nested for loop or some sort of custom function? Any ideas?

Not sure I understand correctly.

If it is a repeating pattern you could try modulus operatorā€¦

-- xx0
for i = 1, 12 do
	if i % 3 == 1 or i % 3 == 2 then
		print(i)
	end
end

for i = 1, 12 do
	if i % 3 ~= 0 then
		print(i)
	end
end

--xx00
for i = 1, 12 do
	if i % 4 == 1 or i % 4 == 2 then
		print(i)
	end
end

Yes, repeated patterns, I believe you understood correctly and just glancing at the code it looks like that will be a good solution. Unfortunately itā€™s bedtime so Iā€™ll have a go at it in the morning and let you know how it went. Appreciate all your help! :smiley:

Well it works, however Iā€™m not sure if modulus is the way to go, certain ratios donā€™t work out quite right.

So basically what Iā€™m looking to do is control a group of points which will be a repeated pattern but the ratio of points being controlled vs stationary points could be anythingā€¦, 1/3, 3/1, 2/2, 5/2ā€¦, whatever. Also the function should take into account that there could be a ā€œstart and end offsetā€ or rather a range.

Here is a pic of the what I originally came up with, on the right you can see part of the macro I created.

What Iā€™m thinking now, which would be even more versatile is two sliders, each of which would control itā€™s own group of points and then maybe just a couple of knobs to set the ratio.

I guess you need to sort out the range first before checking against the pattern. How do you set the ratio? Do you have parameters for it?

Here is what I tried for my loop which works except when startL = 2, 5, 8ā€¦ etc. Also I was messing around with the modulus and couldā€™nt figure out how I could produce a pattern such as xxxooo.

function myLevel()
   for i = startL, endL do
	   if i % 3 == 2 or i % 3 == 1 then
	      uE[i].level = myLevel
              zone:setParameter("User Env.EnvelopePoints", uE)  	
   end
      end
end

The more I think about, Iā€™d like to go with a 2 slider approach, so as to be able to control both point groups,
xā€™s and oā€™s, but I donā€™t know how to go about doing it that way.

You need to sort out the range so that whatever point you start with is considered point 1 of the pattern. I would use setParameter at the very end after you finish the loop.

startL = 15
endL = 30

function myLevel()
	for i = startL, endL do		
		if (i - startL + 1) % 6 > 0 and (i - startL + 1) % 6 < 4 then
			print(i, "X")
		else
			print(i, "O")
		end		
	end
end

myLevel()

Hopefully that should give you the xxxooo pattern starting from startL.

*** Another idea for checking the patterns:

patterns = {
	{[0] = true, true, false, false},
	{[0] = true, false, false, false},
	{[0] = true, true, true, false, false, false},
}

startL = 15
endL = 30
selectedPattern = 3

function myLevel()
	for i = startL, endL do
		local point = i - startL
		local mod = #patterns[selectedPattern] + 1
		if patterns[selectedPattern][point % mod] then
			print(i, "X")
		else
			print(i, "O")
		end		
	end
end

myLevel()

Awesome!

Both solutions work really well.
I think I may go with the table of patterns one because it seems to be the most flexable, plus super quick to add other patterns. So much exciting territory to transverse, I canā€™t thank you enough!

Good to hear it works. Maybe we could do a slight variation of the table version and get rid of the [0] index:

patterns = {
	{true, true, false, false},
	{true, false, false, false},
	{true, true, true, false, false, false},
}

startL = 15
endL = 30
selectedPattern = 3

function myLevel()
	for i = startL, endL do
		local point = i - startL
		local mod = #patterns[selectedPattern]
		if patterns[selectedPattern][point % mod + 1] then
			print(i, "X", point % mod + 1)
		else
			print(i, "O", point % mod + 1)
		end		
	end
end

myLevel()

I was going to ask you about that, what was the purpose of that? I was defining a parameter to select which pattern to use and thought I might have a problem with those indexes, but surprisingly it worked fine.

So here is a crazy idea I just had. Given the clone script discussed earlier I wonder if you created a clone of the envelope then you could make a point selection using HALionā€™s selection tool, (even non-contiguous by holding shift key), then move the points just enough to make it different from the clone, you could then run a comparison function that would return the edited points, then those could be saved into a pattern table.
How cool would that be? ā€¦, anyway just an idea.

Oh, by the way how hard would it be to mod that ā€œclone/resetā€ script into a sort of ā€˜a/bā€™ toggle?

Try if this worksā€¦

defineParameter("AB", nil, 1, {"A", "B"}, function() abChanged("Amp Env") end)

envelope = {{}, {}}

zone = this.parent:getLayer():getZone()

function copyEnvelope(envType, index)	
	envelope[index].envelopePoints = zone:getParameter(envType..".EnvelopePoints")
	envelope[index].sustainIndex = zone:getParameter(envType..".SustainIndex")
	envelope[index].mode = zone:getParameter(envType..".Mode")	
end

function restoreEnvelope(envType, index)	
	zone:setParameter(envType..".EnvelopePoints", envelope[index].envelopePoints)
	zone:setParameter(envType..".SustainIndex", envelope[index].sustainIndex)
	zone:setParameter(envType..".Mode", envelope[index].mode)		
end

function abChanged(envType)
	local newIndex = AB
	local oldIndex = math.abs(AB - 2) + 1
	copyEnvelope(envType, oldIndex)
	if envelope[newIndex].envelopePoints then
		restoreEnvelope(envType, newIndex)
	end
end

Envelope AB.vstpreset (12.8 KB)

1 Like

Wow, that was quick, and yes it sure does work. :grin:
Thanks.

@misohoza,

One more thing which Iā€™d like to add to the ā€œpatternsā€ code which Iā€™m struggling to figure out isā€¦, Iā€™d like to be able to have a 3rd defined parameter that can move both groups together while keeping their relative difference intact, is this possible?

I would probably create an on/off parameter that would link the two sliders. When the link is turned on you need to check the values of both sliders and assign the difference to a variable.

The callbacks for the sliders need to be adjusted to take into account the link parameter. If the link is on you should also change the other slider and apply the difference to it.

Cool, thanks for the info. I like the idea of the link switch. I wonder if there are any 3-way switches in the macro templates? I could maybe set it up to where I only need one slider. Position 1 & 2 would allow control of point groups 1 & 2 independently, and sw pos.3 would allow control of both groups together.