Home | ER-101 | ER-102 | ER-301 | Wiki | Contact

Middle Layer SDK (aka patching with Lua)

Oh cool, if it’s available in the future that’d be amazing. You could make complex modules much more efficient.

I guess you can use a limiter to do similar things by layering bandpass filters. Though that would require a lot of processing power for something that can be done by one function if it were available.

Can’t wait for what the future brings! Wish you had an easier time blowing through tasks. There must be so much.

hey,

I’m still a bit confused about how much learning lua would help – and it’s relevant cos I do think that – with the right documentation – I can learn how to use it.

Could one program in lua to e.g. generate n random values between 0 and 1 of increasing size, as I was attempting here… on the one hand, I should be able to do that without lua, but, on the other, it’s great to learn new tricks if you can

In lua you can definitely generate a fixed number of constant voltages, in my experience it comes up so often I wrote a special function for it mConst :slight_smile:

As for your problem of trying to pick a new sample every time, you might consider this idea: S&H the last output value and use it to offset the next randomly chosen value in such a way that they can’t be the same. Idk the exact algo, but conceptually I think that would get you there.

2 Likes

What I wanted to hear… I’m going to get the lua book.

Sample and hold, hmmm…

For learning lua I went through the first couple of chapters on Programming in Lua online. Particularly focusing on understand tables, classes, and inheritance since it’s different from the other langauges I’m familiar with. You can even try stuff out in the online repl to get it under your fingers.

1 Like

@odevices I had an idea for a middle layer feature that could be cool: allow units to create internal managed chains that the user can hook into to customize specific parts of the unit.

For example, I could make a tape delay unit that has a sub chain on it called feedback, the user could add a filter to that chain and the unit would send the feedback signal through the chain before directing it back into itself to record.

I spent a little time trying to hack this together by abusing the builtin lua classes but I think it would take too long to really get it stable. It seems like all the pieces are there though, what do you think?

Have you checked out the various container units and how they are made?

Yea, the difference here would be that the unit itself would provide the input to the chain. So the input would be fixed, unlike the containers that allow you to set an input yourself.

Edit: I guess in the case of a feedback like I mentioned it’s not truly necessary since you can just pass the output back in through a chain anyways.

Edit2: It’s kind of like passing a function to a function instead of a value. In the unit I’m building there’s some careful control of the feedback level that wouldn’t be easy to replicate outside of the unit. But it could be nice to be able to hook in a chain on the feedback path before the level is adjusted afterwards.

Also, doing feedback in the middle layer (and above) means you will have at least 1 frame of delay.

Speaking of delay, how much delay is introduced actually going to the output and back into an input? For instance with a delay effect going out to a low pass filter and back in for feedback.

I haven’t measured it in awhile but I think it is:

Normal latency firmware

  • 4-5ms for 96kHz
  • 8-9ms for 48kHz

Low latency firmware

  • 2ms for 48kHz
1 Like

Hi all! I’m trying to get into Middle Layer patching, and I thought starting with the simplest possible unit, a pass-through, would be easy. Also, since it came up in some other recent thread. I have something working, but it’s not as minimal as I would have hoped: I can’t seem to patch self In1 to self Out1. This piece of code works fine:

local app = app
local Class = require "Base.Class"
local Unit = require "Unit"
local Encoder = require "Encoder"
local ply = app.SECTION_PLY

local Thru = Class{}
Thru:include(Unit)

function Thru:init(args)
  args.title = "Pass Through"
  args.mnemonic = "Thru"
  Unit.init(self,args)
end

function Thru:onLoadGraph(channelCount)
  if channelCount==2 then
    self:loadStereoGraph()
  else
    self:loadMonoGraph()
  end
end

function Thru:loadMonoGraph()
  local vca = self:createObject("ConstantGain","a")
  a:hardSet("Gain", 1.0)

  connect(self,"In1",a,"In")
  connect(a,"Out",self,"Out1")
end

function Thru:loadStereoGraph()
  local a = self:createObject("ConstantGain","a")
  local b = self:createObject("ConstantGain","b")

  a:hardSet("Gain", 1.0)
  b:hardSet("Gain", 1.0)

  connect(self,"In1",a,"In")
  connect(self,"In2",b,"In")

  connect(a,"Out",self,"Out1")
  connect(b,"Out",self,"Out2")
end

function Thru:onLoadViews(objects,branches)
  local views = {
    expanded = {},
    collapsed = {},
  }

  local controls = {}

  return controls, views
end

return Thru

If I do this instead:

function Thru:loadMonoGraph()
  connect(self,"In1",self,"Out1")
end

Then I get

er301::Unit::addInput (arg 3), expected 'er301::Object *' got 'table'

Any suggestion what I’m doing wrong? Also, is there another way to get this pass-through object even more minimal? I know I could use an empty custom effect, but where’s the fun in that, right? :slight_smile:

Sorry if my noob-question has been answered here before, but I couldn’t find a reference to the error I’m getting.

1 Like

This looks pretty minimal to me, can you post the full stack trace? This error means you’re calling a function incorrectly but I can’t tell which without the full error

x:/startup/on-load-app-module.lua:100: Error in er301::Unit::addInput (arg 3), expected 'er301::Object *' got 'table'
stack traceback:
[C]: in method 'addInput'
x:/startup/on-load-app-module.lua:100: in upvalue 'connectUnitInput'
x:/startup/on-load-app-module.lua:136: in function 'connect'
1:/ER-301/libs/YRN1/Thru.lua:29: in function 'YRN1.Thru.loadStereoGraph'
1:/ER-301/libs/YRN1/Thru.lua:18: in function 'YRN1.Thru.onLoadGraph'
X:/Unit/init.lua:54: in function 'Unit.init'
1:/ER-301/libs/YRN1/Thru.lua:13: in function 'YRN1.Thru.init'
X:/Base/Class.lua:78: in function <X:/Base/Class.lua:76>
[C]: in function 'xpcall'
X:/Unit/Factory/init.lua:100: in function <X:/Unit/Factory/init.lua:92>
(...tail calls...)
...
X:/Base/Widget.lua:178: in function 'SlicingView.ShiftWidget.sendUpHelper'
X:/Base/Widget.lua:168: in function 'SlicingView.ShiftWidget.sendUp'
X:/Base/Context.lua:231: in function 'Base.Context.notify'
X:/Application.lua:120: in upvalue 'notify'
X:/Application.lua:267: in upvalue 'dispatch'
X:/Application.lua:417: in function 'Application.loop'
x:/startup/start.lua:56: in function <x:/startup/start.lua:49>
[C]: in function 'xpcall'
x:/startup/start.lua:59: in main chunk
[C]: in function 'dofile'
[string "dofile('x:/startup/start.lua')"]:1: in main chunk

Issue is in the connect call on line 29 in the loadStereoGraph function

Yes, I figured that. It simply says

connect(self,"In1",self,"Out1")
connect(self,"In2",self,"Out2")

on those lines. It’s like ‘self’ is not an object, but a table, right?

Hard to tell without the rest of the code, if you share it on GitHub could probably see what’s wrong. Seems like a method call is missing a ‘:’

Sorry, I don’t have the code on github. This is the full code:

local app = app
local Class = require "Base.Class"
local Unit = require "Unit"
local Encoder = require "Encoder"
local ply = app.SECTION_PLY

local Thru = Class{}
Thru:include(Unit)

function Thru:init(args)
  args.title = "Pass Through"
  args.mnemonic = "Thru"
  Unit.init(self,args)
end

function Thru:onLoadGraph(channelCount)
  if channelCount==2 then
    self:loadStereoGraph()
  else
    self:loadMonoGraph()
  end
end

function Thru:loadMonoGraph()
  connect(self,"In1",self,"Out1")
end

function Thru:loadStereoGraph()
  connect(self,"In1",self,"Out1")
  connect(self,"In2",self,"Out2")
end

function Thru:onLoadViews(objects,branches)
  local views = {
    expanded = {},
    collapsed = {},
  }

  local controls = {}

  return controls, views
end

return Thru

Everything looks right to me hm, maybe it’s an issue with connecting self to self

That’s what I figure too. If I put anything in between (Multiply, ConstantGain…) it works fine.