the ‘bad code smell’ here is breaking into the “private” data structure underlying a parameter that has already been :added to the default paramset, making it part of the persistent storage for the script, target of midi-learn, etc.

well, that is fine, but there is no concept of parameter dependencies in a paramset, so there is no particular guarantee that e.g. B will be loaded before A. (in fact, in the example it will be the other way around, so surprising things could happen.)

guess i’m just saying that i would be careful about making the UI component configurations part of the same data store as their targets, at present. this doesn’t mean you can’t leverage control and/or controlspec outside of paramset.

maybe the easiest solution is to just formally guarantee the present behavior: the order in which parameters are :added to a paramset, is the order in which they will update when the paramset is banged. it’s the most basic kind of dependency management but maybe it’s enough.

in any case i’d be more comfortable recommending this if we added ParamSet:set_range(index) to the API in addition to get_range. then we would at least have a shot at managing the edge cases.

if there is desire for something like Flux pattern:
store -> events/queries -> views -> actions -> dispatcher -> callbacks -> store…

then i agree that it seems like asking for more layers on top of paramset and parameter actions.

The great benefit of a flux type approach is the data reactivity. So if you update the data model, from wherever, the UI renders the required updates without imperative programming. That solves these kinds of edge cases because as long as values are initialised with reasonable defaults, then after loading or user input, updates are handled appropriately.
To be clear I’m not espousing a full-blown approach like that in this context because of the overhead. Just as importantly I think it should be easy from a community perspective for people to get into writing scripts. I’m sure you have thought long and hard about these various options and getting the right compromise.

Using event listeners might be a simple way of accessing some benefits of the reactive approach. (Listening to model changes, not to specific user inputs).

But I’m just thinking out loud here, I will stop commenting on this until I know the system a bit better.

having trouble with incrementing param values

I have the following - but… my param menu item increments 50 ms for each turn of the encoder.

  local delay_time_spec = controlspec.new(0.1, 5000, "lin", 1, 300, "ms") 
  delay_time_spec.default = 1000
  params:add {
    type="control",id="delay_time_spec",name="DelayTime",controlspec=delay_time_spec, formatter=Formatters.round(1),
    action=function(value) engine.set("Delay.DelayTime", value) end
  }

The step for the controlspec seems to be ignored?

I tried also adding a formatter - but I’m not really certain how that should be used.

What I am doing wrong?

step is the output quantum

i gather that at some point you are calling something like

params:delta("DelayTime", 1)

the delta method i hard-coded to incremement in steps of 1/100 of the range (maxval - minval), times the increment.

but the increment passed to delta doesn’t have to be an integer, so you can work around this in scripts by scaling the input to delta; unfortunately that’s of no use in the params menu.

i mentioned this a bit here, it would be nice to have an input quantum:

opend GH issue.

2 Likes

Aha! Thanks for the detailed response!

This is also crow related (although I guess a similar situation can occur when using a MIDI to CV adapter as well), but I think this is the best topic for this question.

I was wondering for those who have written something that outputs pitch/voltages for modular/eurorack how you handle the different types of CV inputs on modules?

I’m mainly wondering about the difference between modules that only take a positive voltage as pitch input vs modules that support both positive and negative voltage.

I was thinking of putting together a super basic norns + lua tutorial yesterday, which led me to another, probably more interesting and useful idea…a game of exquisite corpse in the scripting realm :slight_smile:

The basic idea is that I (or someone) would create a basic tutorial to get started (could be video or written), and then someone picks up where I left off and keeps building the script, turning their work into a second tutorial, and so on and so forth. Whatever I explore and develop in my initial tutorial is by no means set in stone; future participants have the freedom to take the script in a completely different direction.

What I find potentially interesting about the idea is that anyone can participate, and each successive pass doesn’t necessarily have to push the script into further complexity (although it could do that, too). So long as each one sheds light on something new, that’s cool.

Does that sound fun to anyone else? What would we end up with?!

9 Likes

that sounds very fun to me

could be a live streaming thing

2 Likes

Totally! Live streaming scares the shit out of me, personally, but that shouldn’t stop anyone from going that route to share their work/tutorial :slight_smile:

EDIT — I’ll try to record a first installment today or tomorrow, and then I’ll create a (wiki?) thread with a sign-up sheet.

4 Likes

What’s your git workflow?

I’ve been connected to smb, then clone my repo in /dust/code/mything. This seems to be the best way? Though I don’t really like having my git stuff in there that I wouldn’t have bundled with the actual release. So maybe I should have this be /dust/code/mythingdev and then once mything is in released and in maiden don’t touch that at all?

soooo

lets say i’m weirdly curious about how to visualize the two orbiting “tape” leds from the ob-4 for an interface

how might i script something that simple in lua?

2 Likes

Is that possible with trigonometry? For the x,y values of the individual points: x = rsin(alpha), y = rcos(alpha). Where r is the radius and alpha is an angle between 0 and 360

I know this is not a script yet, but a geometric approach.

3 Likes

https://github.com/bgc/bgc_dust/blob/master/lib/ui_utils.lua <- this could be a starting point for that.
my shield is still not working, if it was i would code those, seems fairly simple.

from my code you just take out the arc in draw knob and put to squares, 180 degrees apart (or PI radians)

1 Like

in lua that should look something like:

loop_time = 3 --(seconds)
radius = 10
framerate = 1/30 -- (30 frames per second == 1/30th second per frame)

metro.init(function(tick_count)
  elapsed_time = tick_count / framerate
  theta = elapsed_time  / loop_time * 2 * math.pi
  pixel_x = math.cos(theta) * radius
  pixel_y = math.sin(theta) * radius

  --- draw the pixel
end, framerate)

(probably : ) )

3 Likes

I don’t have a norns to try it (arrives next week, I am sketching this in p5.js), but maybe also the higher level graphics functions such as screen:arc() would simplify things by letting the computer do the math :slight_smile: I am imagining something like

loop_time = 3
framerate = 1/30
pixel_size = 1
speed = 360/loop_time * frame_rate

metro.init(function(tick_count)
    screen:arc(10, 10, radius, tick_count * speed % 360, tick_count % 360 + pixel_size)

end, framerate)
2 Likes

thanks yall

when i have time to test i’ll report back but this will definitely help guide my attempts

Barycenter is based off this motion / idea + a couple nested layers of the same. Cosine & Sine will get you one side, the inverse (1 - Cosine, or 1 - sine) will get you the opposite point.

o[1].x = viewport.width/2 + (math.cos(delta) * radius)
o[1].y = viewport.height/2 + (math.sin(delta) * radius)
o[2].x = viewport.width/2 + (1 - math.cos(delta) * radius)
o[2].y = viewport.height/2 + (1 - math.sin(delta) * radius)

2 Likes

@eigen ran into an issue with a script where an animation was not wired up quite correctly, causing flickering when the norns global menu was open. @tyleretters came up with the fix, which was to call the global (userspace) redraw() function, rather than a function in a custom module, on the animation clock. I was not aware before that it had to be set up this way. Is this already documented anywhere, and if not, where would be the appropriate place to add the docs? I apologize if this is the wrong thread for the question.

1 Like

it is not documented, but is on the todo list.

generally, never touch the screen outside of redraw()

there are some backend changes that could be added to protect against this, i will make an issue

2 Likes

Thank you! If I can help with docs or Lua (I’m a little shy on the C/C++ side of things), I’m happy to.