Middle Layer Adventure - Revolver

Thanks for doing this @Joe! I’ll be following this thread with great interest.

1 Like

Excellent, thanks for doing this publicly @Joe. Great learning resource.

1 Like

Thanks for doing this @Joe. I like the way you are showing your thinking as you approach the middle layer for the first time, rather than just documenting a completed project retrospectively.

1 Like

I sort of have to do it this way. I don’t know what I’m doing enough to complete it without some (probably a lot of) coaching from the one guy on the planet who does. I have a fair amount of other development experience, so I know enough to be able to start hacking at this and will try to move it forward on my own. But I wouldn’t assume my approach at any given point is correct, the best way, or even functional.

Hopefully we’ll all learn a lot. I’m just volunteering to be the public guinea pig. :slight_smile:

8 Likes

You’re the Major Tom of the middle layer! :sparkles:

2 Likes
1 Like

Ha! I hope I don’t meet the same fate as Major Tom. :slight_smile:

3 Likes

I’m sure you won’t, was mainly thinking of

”I’m stepping through the door
And I’m floating in the most peculiar way
And the stars look very different today”

:slight_smile:

(Sorry for the ot, was just inspired by Joe’s daring!)

2 Likes

I am cross-quoting from the other thread here. Been looking at this a bit and I see how you are using this, for example, in the NativeSpeedPlayerUnit and PlayerUnit code. Their LUA files are extremely short and very similar (the difference of args.enableVariableSpeed and the unit names).

So I assume if I did this in my code, I would inherit all of the header menu items, as well as the view controls? Ultimately I think this will contain 4 sample players so I don’t really want 4x duplicates of all of them exposed. If I explicitly include the methods for onLoadViews and onLoadMenus will that overload what it is inherited from the BasePlayer so that I can be specific about what I want?

1 Like

Thinking that calling on the builtins is not going to be the way to go here. A little experimentation proved unsuccessful. However, I did manage to add the sample selection to the header dialogue, and am able to select a sample from the card and get back to the unit view without crashing. This by copiously stealing some code from the Sample Scanner unit and making slight modifications. For now I have just commented out the lines where it actually does anything with the sample, like assign it. The unit still does nothing. :slight_smile:

Detach does not cause a crash. Have not tested slice or edit.

As of this post, commit f942f39.

1 Like

After examining BasePlayer.lua for a while, I decided it was quite complicated and that I would take a short instant gratification detour and see if I could make this unit make some sound. So there is a new branch in the repo called “makesound”. I simply added sine oscillator (code copied from the FMOperator example) with a V/Oct and f0 control (The V/Oct control is the original added above in the master branch).

Questions:

I really tried not to add the f0 control, but rather just do without it and hard code the base frequency f0 of sinosc to a “C” note:

sinosc:hardSet(“Fundamental”,32.7)

This didn’t work. There was no output until I added the GainBias control and connected the it up to the sine oscillators fundamental:

local f0 = self:createObject(“GainBias”,“f0”)
connect(f0,“Out”,sinosc,“Fundamental”)

Why, I wonder… :slight_smile:

Also, nearly every createObject I have added to the project has necessitated that I add a “require” library up at the top, if it wasn’t already there. The SineOscillator did not. Where does it live?

Edit: Regarding eliminating the f0 control also tried this, which causes a system crash.

sinosc:getOption(“Fundamental”):set(32.7)

And then this was just a total SWAG. Also caused a system crash.

sinosc:setFundamental(32.7)

Oops. I totally forgot to say anything about the difference between ports (Inlets and Outlets) and Parameters and Options. Ports come in two flavors, Inlets and Outlets. Signal travels from an Outlet port to any number of Inlet ports at the system sampling rate (48kHz or 96kHz). Parameters are values that can be assigned (tied) to other Parameters or controlled by UI controls. Parameters are updated at the system frame rate (375Hz or 750Hz). Options are like Parameters except they take their values from a given list of valid discrete values (like yes/no or left/both/right).

sinosc:hardSet(“Fundamental”,32.7)  -- won't work

So in your case you were trying to set the value of an Inlet (SineOscillator’s Fundamental inlet) as if it was a Parameter. There are a number of ways to go about doing this. The simplest is to use a Constant object like this:

local freq = self:createObject("Constant","freq")
freq:hardSet("Value",32.7)
connect(freq,"Out",sinosc,"Fundamental")

The Constant object will output the value of the Value parameter at audio rate which is what the SineOscillator’s Fundamental inlet needs.

Parameters can be hardSet or softSet. The former sets the value immediately, while the latter will linearly tween towards the target value over time.

(P.S. Documentation is forthcoming but I’m in the middle of some manufacturing tasks at the moment. :bowing_man: )

3 Likes

I am catching errors in the initial execution of the unit modules (when your unit class is defined) but it looks like I have neglected to catch errors during the instantation (when onLoadGraph and so on are called). Was never necessary until now :wink: I’ll fix that.

2 Likes

Does softSet accept a second optional param for the tween time? Or is it fixed? I see it used in some of the delay units, and it looks like it is used a if a preset was made prior to v0.3.04 when the feedback was made modulatable it converts it to the new schema. Not really sure why it was needed there - I guess to cause an abrupt jump from zero when it’s loaded?

Also, where does app.log write to? A file on the card, or somewhere on the display?

I have encountered the error.log in the libs\appfolder too. So I guess the goal would be for all debugging information relevant to the app (should we call these middle layer patches apps? :slight_smile:) would end up in this file (and also not force a reboot)?

The crash.log seems to append to itself, and assume error.log will too. Is it safe to delete these files and they will just get recreated?

Yay! This works great and the f0 control was successfully removed in commit 67ce03d of branch makesound.

1 Like

No. It’s a fixed length tween at the moment. It’s just there to prevent unseemly noises. You wouldn’t use it to do to automation or modulation. Also, it is not necessary in the onLoadGraph function because the unit hasn’t been inserted into the DSP scheduler yet. You would typically only use it to a make change to a parameter while the unit is running and generating signal.

app.log(…) writes to the UART which I monitor in real-time via one of these.

You are of course free to do file I/O on your own using the builtin Lua io library.

1 Like

Yes, it is safe to delete either of these files.

  • ER-301/crash.log: Trace and error message dumped here when there is a system-wide crash.
  • ER-301/libs/your-library/error.log: Trace and error message dumped here when there is an error instantiating a unit in this library.
1 Like

Now that I have another folder in ER-301/libs, and another init.lua inside that folder, I no longer see the FMOperator or Countdown units from ER-301/libs/testlib. I only see my “Revolver” unit when I go to insert a unit. Can there only be a single init.lua in the directory structure?

Just tried it and works for me…

0037

I:\ER-301\LIBS
├─testlib
│      Countdown.lua
│      FMOperator.lua
│      init.lua
│      error.log
│
└─ER301-Revolver
        init.lua
        LICENSE
        README.md
        revolver.lua

Are you using the most recent version of testlib?

I thought so because it contains the countdown unit, but let me confirm.

Slightly tangential, but when I set up the github repo it prompted me for a license type. I picked GPL. I’m essentially just copying and pasting your code here. Is there a better choice? (None is an option). I’m not super familiar with these choices since much of the code I write is either not shared in a public repo, or becomes the property of my employer.

Working now. Must have downloaded to my computer for reference but neglected to actually copy it to the card. I did promise some of my questions would be stupid ones. :blush: