PSYCLE's home     
     since may 2000
  news / home  files songs boards links all registered members about psycledelics Statistics    
» Welcome to -psycledelics-. If this is your 1st visit please read the FAQ - Frequently Asked Questions You must register before you can post here: Please click above on Registration to register yourself. You do not need to register if you only want to read Threads.
Login with Username & Password:

Remember me on this PC.
-psycledelics- » Discussions » TECH BOARD » LuaScript questions
« Previous Thread Next Thread » Show a Printable Version  Send this to a Friend  Add to Favorites
Thread closed
Author
Post [  1  2    »  ]
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
  LuaScript questions        Go on top to this Page

Hello out there.

Lua is a great option to create custom plugins based on existing ones. I started creating a Lua plugin for Mid/Side processing using several native plugins (CLICK HERE TO SEE A PREVIEW SCREENSHOT)...

... but my mind went blank manipulating channel buffers. I can eq the original input signal fine but now I need to modify internally.

I want to add left channel to right channel to output a mono signal, and then to subtract this mono signal to the left channel and to the right channel to get a side signal. Could you explain me how can I do this?

Thjs is an example function in Lua I've written:

quote:

local function Stereo2Mid(inputChannel0,inputChannel1)
midLeft = ((inputChannel0 + inputChannel1) / 2)
midRight = midLeft
return (MidLeft,MidRight)
end


... but this function leads to this error ''machine.lua:119: attempt to perform arithmetic on a userdata value''.

Thanks in advance.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

08.12.2014, 13:33 Profile of Angelus Add Angelus to your Buddy-List
[JAZ]
Psycle Developer



Date Registered:
11.2001
Location:
Balaguer (Spain)
Posts: 1365


[JAZ] ist offline
         Go on top to this Page

I don't have right now an in-depth knowledge of this new host.

What Stefan focused is on adding operations that could be applied to buffers, which is what you get. Basically, operating value by value in lua was quite slow.

I can only suggest to read the .pdf manual (luascriptingmanual.pdf, it's included in the docs folder).

I think the relevant chapter is 3.1, in pages 6, 7 and 8


__________________
<[JAZ]> Pa pi pa pa pa pi pa.... ;·D

08.12.2014, 21:34 Profile of [JAZ] Add [JAZ] to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

Hi Angelus,

nice that you are using lua.

>> (inputChannel0 + inputChannel1) / 2
ok, I think that is a bug and should normally work.
In general you should prefer the array object methods
to the operators(* + - /), because there is no return value
optimization and temporary arrays will be created for
evaluating the term.

Here are three versions that should work. The first is mostly
like yours, in the second example, the midLeft/midRight
arrays are just created once and not at every work call.
The last assumes that the inputChannel and your output buffer
are the same.


Code 1:

local array = require("psycle.array")

local function Stereo2Mid(inputChannel0,inputChannel1)
local size = inputChannel0:size()
-- create two new arrays
local midLeft = array.new(size)
local midRight = array.new(size)
-- mix left channel
midLeft:add(inputChannel0)
midLeft:add(inputChannel1)
midLeft:mul(0.5)
-- copy to right *1
-- Note : you can avoid this copy here if you
-- replace (*2) with self:channel(1):copy(left)
midRight:copy(midLeft)
return midLeft, midRight
end

function machine:work(num)
local left, right = Stereo2Mid(self:channel(0),self:channel(1))
self:channel(0):copy(left)
self:channel(1):copy(right) -- *2
end

Code 2:

local array = require("psycle.array")

local midLeft = array.new(256)
local midRight = array.new(256)

local function Stereo2Mid(inputChannel0,inputChannel1, out1, out2)
local size = inputChannel0:size()
-- resize out to in size
out1:resize(size)
out2:resize(size)
-- mix left channel
out1:copy(inputChannel0)
out1:add(inputChannel1)
out1:mul(0.5)
-- note this is maybe not needed if you
-- change (*2) to self:channel(1):copy(midLeft)
out2:copy(out1)
end

function machine:work(num)
Stereo2Mid(self:channel(0),self:channel(1), midLeft, midRight)
-- copies midLeft, midRight to the machine buffer
self:channel(0):copy(midLeft)
self:channel(1):copy(midRight) --*2
end


Code 3

function Stereo2Mid(inputChannel0,inputChannel1)
inputChannel0:add(inputChannel1):mul(0.5)
inputChannel0:copy(inputChannel1)
end

function machine:work(num)
self:channel(0):add(self:channel(1):mul(0.5)
self:channel(1):copy(midRight) --*2
end


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

08.12.2014, 22:01 Profile of luadev Add luadev to your Buddy-List Email to luadev
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

Sorry, Code 3 must be:

function Stereo2Mid(inputChannel0,inputChannel1)
inputChannel0:add(inputChannel1):mul(0.5)
inputChannel1:copy(inputChannel0)
end

function machine:work(num)
Stereo2Mid(self:channel(0), self:channel(1))
end


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

08.12.2014, 22:15 Profile of luadev Add luadev to your Buddy-List Email to luadev
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

Thanks for the replies, guys!

I've already read the manual but I wasn't able to perform what I need (maybe the problem is on my side)

luadev: Thanks for the in-depth tips. I'll test them when I'll get some free time available and will inform here.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

08.12.2014, 22:51 Profile of Angelus Add Angelus to your Buddy-List
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

Hello.

luadev: I've tried the three suggestions you shared but unfortunately without success.

Then I tried to know if there's any problem with local setbuffer on loaded Psycle machines. To that effect, I tested it on the example plugin 'plugloaddemo'. I've changed the setbuffer parameters as follows:

code:
function machine:work(num)
reverb:setbuffer({self:channel(0),self:channel(0)});
-- or even 'reverb:setbuffer({self:channel(1),self:channel(1)});'
reverb:work(num)
end


It should be sent the input buffer for left channel to both left & right channels of reverb effect (shouldn't it?)...
...but it sounds as it were set ({self:channel(0),self:channel(1)}) (send channel0 to plugin left channel, and channel1 to right channel) in both configurations.

Another issue I've found is related to the method numchannels. The sentence ''local aMSeqNumChan = numchannels()'' reports me the error message ''machine.lua:203: attempt to call global 'numchannels' (a nil value)'', within init and work methods.

PS: The lua feature rocks! Instead of tracking... I (am trying to) code.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

12.12.2014, 19:14 Profile of Angelus Add Angelus to your Buddy-List
[JAZ]
Psycle Developer



Date Registered:
11.2001
Location:
Balaguer (Spain)
Posts: 1365


[JAZ] ist offline
         Go on top to this Page

I should warn that there might be some vsts that will not work with lua.

There are two ways that plugins offer to receive and return the audio. One is process and the other processReplace. The former existed since VST 1 and was deprecated in 2.3, and used accumulation over the variable. The latter uses an input output schema.

Due to the way it is implemented in Psycle, when doing process, the buffer is constantly changing (swapping input and output), so it cannot be given to lua.


Said that, it probably it not the problem you talk about.


__________________
<[JAZ]> Pa pi pa pa pa pi pa.... ;·D

12.12.2014, 20:12 Profile of [JAZ] Add [JAZ] to your Buddy-List
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

[JAZ]: I've used the example demo lua plugin to illustrate what I've observed. It happens too with my script using dw-eq.dll.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

12.12.2014, 22:14 Profile of Angelus Add Angelus to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

<< reverb:setbuffer({self:channel(0),self:channel(0)});

This means the reverb processes and modifies self:channel(0).

self:channel(1) is unmodified (reverb doesn't know this buffer) buf of course channel(1) has yet the sound data from the input machine and will route it without modification to the right output wire.

<< aMSeqNumChan = numchannels()

you need to call it with self:numchannels(), self is the instance of your machine. (In c++ you would call it this pointer)




__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

12.12.2014, 22:20 Profile of luadev Add luadev to your Buddy-List Email to luadev
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

Oh! I've forgotten that channel(1) was already there (noooooob!).

I've kept calm and I've read again your suggestions so I've been able to create the mid signal (phew!)... and the side signal!

code:
Thanks:mul(1000);

I've tried using: ''localSide0:sub(localMid0)'' (there's a misprint in the Manual subs(num) > sub(num) ) but Psycle reports me an error on lua script. Does this method works as add() does?

Next question: How do I call back the output signal from a local psycle plugin to go on doing more local functions?

PS: Thanks in advanceª


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

13.12.2014, 18:34 Profile of Angelus Add Angelus to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

Nice that your mid signal is now working

<< ''localSide0:sub(localMid0)''

Unfortunatley, i forgot to implement sub. (I will add it to the next release.)
Please use instead for now : localSide0:add(-1*localMid0)

Second question:
You get the output of an inner plugin (like reverb in plugindemo),
if you to do two steps:
reverb:setbuffer({buf1, buf2}) -- give reverb an input buffer
reverb:work(buf1:size()) -- let reverb process the data

the output is buf1 and buf2, because
work writes the result over buf1, and buf2.
You can now continue modifying these buffers.
e.g : buf1:mul(0.5) -- reduce volume of result


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

13.12.2014, 19:08 Profile of luadev Add luadev to your Buddy-List Email to luadev
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page


luadev: It works! Thanks for your help. I hope to release my script soon.

I have in mind other plugins... time will tell.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

13.12.2014, 19:56 Profile of Angelus Add Angelus to your Buddy-List
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

Ok... so here they are my plugins: [CLICK HERE TO DOWNLOAD THE DEMOS]

I've coded 2 plugins: aMS and aMSeq. The first one is a simple Mid/Side encoder, and the second one is a specialized plugin to perform Eq separately on both mid & side components.

There's a psy song inside to test both plugins. Read the Properties on the psy song, and the plugin help.

Suggestions, comments, IMPROVEMENTS and critics are really welcome.

Thanks in advance...

... more to come.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

14.12.2014, 13:25 Profile of Angelus Add Angelus to your Buddy-List
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page


Is Lua script plugin preset saving not implemented yet? If yes Bank manager doesn't show it. Anyway I can't find its user preset manually.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

14.12.2014, 16:40 Profile of Angelus Add Angelus to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

Congratulations for your first plugins!

<< Is Lua script plugin preset saving not implemented yet?
It's implemented. If you open View->Bank Manager, you can write a preset name and press save. If you select it again and press use, you can load your preset.

<< If yes Bank manager doesn't show it.
try to save a preset for luaris or a native plugin, to see if that works.

<< Anyway I can't find its user preset manually.
You could check first the user preset directory in the Configuration settings and check, if you have write access from your os for that directory. (My test with your plugin works. It creates a file aMS.prs in the Preset Directory)


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

14.12.2014, 21:04 Profile of luadev Add luadev to your Buddy-List Email to luadev
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

Now I'm having problems with pattern tweaking. I can program tweaks without problems for the local Psycle native plugins in the script, but I've got errors when I tweak internal functions: They work fine if the script GUI is not shown, but Psycle shows an error that leads to a machine mute if the GUI is shown. I tried to add listeners but I'm still having problems.

I.e. I have this parameter that I want to tweak:

code:
aMSParams.MidOutput = param:newknob(''Mid Output'','''',0,1,1,1)
function aMSParams.MidOutput:display() return paramOffOn[self:val()+1] end



I have this function inside work() that carries the effect out:
code:
if aMSParams.MidOutput:val() == 0 then
aMSParams.SideOutput:setval(1);
midCh0:fillzero();
midCh1:fillzero();
end
if aMSParams.SideOutput:val() == 0 then
aMSParams.MidOutput:setval(1);
sideCh0:fillzero();
sideCh1:fillzero();
end


If the GUI is not open the action is performed correctly on tweak. But with the GUI open I've got an error window like this:

code:
---------------------------
Error
---------------------------
Machine: aMS
DLL: D:\PLUGINS\LuaScripts\Psycle 1.12.00\aMS.lua
An exception occured in module: (unknown module), function: class psycle::host::LuaProxy :: class std::basic_string<char,struct
std::char_traits<char>,class std::allocator<char> > __thiscall psycle::host::LuaProxy::get_parameter_display(int), file:
.\src\psycle\host\LuaHost.cpp:670
exception type: class std::runtime_error
function parameter:display must return a string
The machine has been set to bypassed/muted to prevent it from making the host crash.
You should save your work to a new file, and restart the host.
---------------------------
Ok
---------------------------



__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

20.12.2014, 16:04 Profile of Angelus Add Angelus to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

Lua scripts parameters are internally normalized to the range of 0..1 That means, inside the patternview you tweak with 0..FFFF. FFFF means param:val() gets one. Your table local paramOffOn = {"Off", "On"} accepts as index one and two. Inside the display method you use paramOffOn[self:val()+1]. If you tweak with e.g. 7FFF, your display method gets as param value 0.5.
This means you call paramOffOn[1.5]. The paramOnOff table doesn't round and thus doesn't find the index for your On or Off String.
Solution:
Add a listener and to all your other methods with an on/off switch
:
aMSParams.MidOutput = param:newknob("Mid Output","",0,1,1,1):addlistener(self)

Now add this method to your machine, which will reacts on tweaks:

code:

function machine:ontweaked(param)
if param:id() == "MidOutput" or
param:id() == "SideOutput" or
param:id() == "MidNegative" or
param:id() == "SideNegative" then
param:setval(math.floor(param:val() + 0.5))
end
end



or if you want, that a twk cmd should work inside the range of 0 and 1 and not to 0..FFFF add instead:

code:

function machine:ontweaked(param)
if (param:id() == "MidOutput" or
param:id() == "SideOutput" or
param:id() == "MidNegative" or
param:id() == "SideNegative") and
(param:val() > 0) then
param:setval(1)
end
end





Maybe we change in the next release, that the twk cmd rounds repective to the step value.


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

20.12.2014, 23:01 Profile of luadev Add luadev to your Buddy-List Email to luadev
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page

luadev: As always... thank you so much for your tips. They worked as they should.

I hadn't seen the point of the range of values (0..1 in contrast to 0000...FFFF). That's why my listener didn't work.

Time for a new release...


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

21.12.2014, 10:48 Profile of Angelus Add Angelus to your Buddy-List
Angelus
Psycler



Date Registered:
09.2002
Location:
Santiago> Galicia> Spain> Europe> Earth
Posts: 415


Angelus ist offline
         Go on top to this Page


I'm delving more and more into lua coding. But I'm not a Jedi yet . Now I want to perform the following operation into work():

output0 = input0:add(output0prev);

...where:
- output0, input0 and output0prev are arrays;
- output0prev is an array of the previous output buffer (after some calculations);
- the arrays were defined into init() to avoid deleting the output array each time in work().

The problem now is that output0prev array size doesn't match with current output0 one, so the operation can't be carried out (sometimes is 128, sometimes is 256).

Any suggestions?

One last question: What's more efficient in Lua: to create the array into init() and then resize it into work() or to create the array directly into work() each time with array.new()?

Thanks in advance.


__________________

(???)Oo. X( :( :| :) :)) :D .cC(Psycle!)

28.12.2014, 15:41 Profile of Angelus Add Angelus to your Buddy-List
luadev
Psycler



Date Registered:
12.2014
Location:
Germany
Posts: 11


luadev ist offline
         Go on top to this Page

<< (sometimes is 128, sometimes is 256

You need to distinguish between three cases,

1. currnum == numprev
work as usual
2. currnum < numprev
work as usual, but create outputprev new
newoutputprev = oldoutputprev [curnumm .. numprev]
3. currnum > numprev
split work in parts

Cause you need to split your work, I've created in the following example a partwork method. Do your buffer process there as though it were your normal work method

Inside the regular machine work method call it with:

self:prevwork(num, self.input0, self.output0, self.output0prev)

Here's the example code with same remarks:

code:

function machine:init()
self.input0 = array.new(256)
self.output0 = array.new(256)
self.output0prev = array.new(256)
end


function machine:partwork(num, input, output, outputprev)
-- do your buffer process here as though it were your normal work method
-- test unit : convergent series with value 5
output:copy(input)
output:add(outputprev)
output:mul(0.5)
outputprev:copy(output)
end

function machine:carry(num, input, output, outputprev)
-- work num samples and create carry
-- [{start, end}] creates a new sub array with a copy from start to end
local carry = outputprev[{num, outputprev:size()}]
outputprev:resize(num)
self:partwork(num, input, output, outputprev)
outputprev:resize(carry:size())
outputprev:copy(carry)
end

function machine:split(num, input, output, outputprev)
-- avoid modifying the input array
local tmp = array.new(num)
tmp:copy(input)
input = tmp
-- split work
local pos = 0
while (num > outputprev:size()) do
local prevnum = outputprev:size()
-- [{start, end}] creates a new sub array with a copy from start to end
local inputpost = input[{prevnum, num}]
local outputprevold = outputprev[{0, prevnum}]
input:resize(prevnum)
local out = array.new(prevnum)
self:partwork(prevnum, input, out, outputprev)
-- copy part work to output
output:copy(pos, out) -- pos: target start index of copy
pos = pos + prevnum
input = inputpost
-- concatenates output0prevold..output0prev
local outputprevnew = outputprevold..outputprev
-- copy back to outputprev
outputprev:resize(outputprevnew:size())
outputprev:copy(outputprevnew)
num = num - prevnum
end
if (num < outputprev:size()) then
local out = array.new(num)
self:carry(num, input, out, outputprev)
-- copy rest of part work to output
output:copy(pos, out)
end
end

function machine:prevwork(num, input, output, outputprev)
-- check size
local prevnum = outputprev:size()
if num == prevnum then
-- it's equal, just work all
self:partwork(num, input, output, outputprev)
elseif num < prevnum then
-- num is less, work num samples and create carry array for next
-- work turn
self:carry(num, input, output, outputprev)
elseif num > prevnum then
-- num is greater, split work in parts
self:split(num, input, output, outputprev)
end
end

function machine:work(num)
-- test unit
self.output0:resize(num)
self.input0:resize(num)
self.input0:fill(5) -- or copy self:channel(0)
-- start your work
self:prevwork(num, self.input0, self.output0, self.output0prev)
-- this works, too, if you want that input writes over the output buffer:
-- self:channel(0): input
-- self:prevwork(num, self:channel(0), self:channel(0), self.output0prev)
-- self:channel(0): gets as result the output
-- or if you use another out buffer copy out to the machine buffer
-- self:channel(0):copy(self.output0)
-- output terminal for debugging
-- psycle.output(self.output0:tostring())
end




Question2:

Yes, in general it's faster, because mostly you get 256 num samples from psycle and if the array length hasn't changed, resize will just do nothing. To avoid global variables, you could create your arrays as object variables inside the init method ( function machine:init() self.output0 = array.new(256) end. Inside your machine methods you acces output0 with self.output0. function machine:work(num) self:output0:resize(num) end


__________________
42 PRINT"42":REM A FOR ALL Q 43 GOTO 42:REM FIND Q FOR A

29.12.2014, 06:50 Profile of luadev Add luadev to your Buddy-List Email to luadev
[  1  2    »  ]   « Previous Thread Next Thread »
Thread closed
Jump to:

© 2002-2007 psycledelics | Powered by Woltlab Burning Board v1 Beta4.5e ©2001 Woltlab GbR|Setup & mod for psycledelics by: SAS