Yeah, I thought so too at first, but that was just incrementing my value by 4 instead of adding an offset :thinking: (x - min) % (max-min) + min seems to be doing the trick, though!

1 Like

I tried to search for this, but I couldn’t find anything: is there a way to use supercollider’s pattern language (from sclang) in norns. E.g., make a script that plays a pbind when a button is pressed…

Edit: maybe it’s as easy as adding a this.addCommand in the engine that calls a pbind

2 Likes

I’ve been thinking about that too. That should work, but it seems like if you want to do anything more than play/stop you’ll get a crazy web of polls and this.addCommands pretty fast.

For instance, I was experimenting with polling control rate ugens in SuperCollider to use elsewhere in my script as LFOs and modulators, and it was cool but it was beginning to feel like twice the work once I wrote a bunch of Lua code to wrap it up and add params.

Another day, another lua question.

I’m wondering if folks have tips for modifying the range of a for loop dynamically, or if such a thing is even possible. :thinking:

For context, I originally had a function - newPattern() - that created a new 16-step note pattern in my recent script, Patchwork. It’s called from init, but it can also be called via a special command at any point by the user. Works great as is:

function newPattern()
   for i=1,16 do
    table.insert(pattern[1], i, math.random(8))
   end
end

I’ve since been experimenting with new variables that let you change the start and end points of the sequence with the encoders (which also works great)…

local seqStart = 1
local seqEnd = 16

…which naturally led me to updating my newPattern() function accordingly:

function newPattern()
   for i=seqStart,seqEnd do
    table.insert(pattern[1], i, math.random(8))
   end
end

The weird thing - and this may very well be due to my limited knowledge of for loops - is that this modified function works great, but when I change the seqStart and seqEnd values and then call newPattern() again, the loop iterates from seqStart (cool) to 16 when I’d expect it to stop at whatever seqEnd is set as. Basically, I just want new values inserted within the new range set by seqStart and seqEnd.

Does this make any sense? It’s been driving me a little nuts because half of it works as expected. I suspect there’s some fundamental thing I’m missing…

numbers in lua are always passed by value, not by reference (i.e. it’s passing 16 to ā€˜for’, not your variable)

i think the best way to do this would be giving a function to ā€˜for’ that returns your variable

(untested)

1 Like

this sounds like a scope issue (short of seeing the whole script, if you want to post more)

i’d suggest:

function newpattern(start, end)
for i=start,end do
    table.insert(pattern[1], i, math.random(8))
   end
end

and then use it newpattern(seqStart, seqEnd) or similar.

you could parameterize the pattern number as well. basically using less global vars might make things cleaner

3 Likes

the first statement is true, but also kinda red herring here. the "numeric for" is a subset of "generic for" - under the hood it generates a factory function with an invariant state (the endpoints a and b), a control variable (i), and a closure (i = i + 1; return i < b). so:

i’m not sure i understand the original problem without more context. but let’s say in general you want to mutate the constraints of the loop from within the loop (my gut reaction is that this is not a good pattern, but OK.)

two ways i think think of

  1. ā€œgeneric for,ā€ that is, an explicit iterator function that mutates
  2. while loop
3 Likes

Love it - thank you all for the super helpful explanations. A good incentive to dust off my pdf of Programming in Lua and sharpen my skills.


EDIT: The solution was simple, in the end. Instead of using table.insert, I modified my function and now all is working great. The answer was in my own script the whole time :man_facepalming:

function newPattern_A(a,b)
  for i = a,b do
    pattern[1][i] = math.random(scaleLength)
  end
end

Hi,

Does anyone know if there is a way to save a pattern_time as a textfile with tab.save? I’ve recorded some button presses on my grid to a pattern_time and I want to save it and call it up with tab.load, sort of as a saved pattern/preset pattern.
When I use tab.save it makes a nice textfile but of course with a lot of ā€œextraā€. And when I load it in again, it is of course just some text, and no longer the function that I can send start() to for example.
Is there a way to store a pattern recorded with pattern_time, and recall it again later?
Does this make sense?
Thanks
Anders

There are a few properties of a pattern that you would want to save, event, time, count & time_factor. If you copy these properties into a new table and save that table you won’t get the extra stuff and functions.

So assuming myPattern is your pattern_time:

saveablePattern ={
event=myPattern.event,
time=myPattern.time,
count=myPattern.count
}

The save saveablePattern using table save.

On load:
loadedPattern = table.load(…)
myPattern = pattern.new()
myPattern.event = loadedPattern.event
myPattern.time = loadedPattern.time
myPattern.count = loadedPattern.count

This example is untested, it doesn’t include time factor and there’s always a chance I missed something, but hopefully it helps?

2 Likes

This is very helpful. It makes sense, and I think I can get it to work now.
Thanks!

Finally having fun getting into nornsing. Today’s progress: didn’t write any of the sound stuff yet, but started on the UI for some wind chimes, and ended up finally wrapping my head around Vectors, and have got a passable Vector2 implementation inside this script, for dynamically handling all image placement, rotatoin, etc:

For now, the striker position is just random within the circle, but the next step is making it follow the wind. And then I plug in the sound.

15 Likes

Good. Lord.

This has literally been on my mind for months now, and I’ve been waiting for it to gel properly so I could start working on it.

Google utterly failed to return anything useful to me re: wind chime simulation (at any level of complexity)

Kudos!

1 Like

well, at the moment, my striker is largely random, and the wind direction and intensity don’t do much. Daniel Shiffman’s The Nature of Code is helping a lot, both with understanding of vectors, and thinking about applying forces to things.

1 Like

Trying to get my head around lua by making a simple norns sequencer thingy. I’m trying to be cheekily lazy and avoid using a table to store midi note_on values to note_off them later.

Here’s my lazy idea: my notes are being generated in a metro callback handler every x seconds. Immediately after sending a note_on I’d like to start a one time metro to send a matching note_off after a set time. I’ll still need to figure out how to pass params to the note_off metro callback handler, but that is for later, for now even the first step throws me a curveball.

function init()
  re = metro.init()
  re.time = 1.0 / 15
  re.event = function()
    engine.hz((440 / 32) * (2 ^ ((notes[noteIndex] - 9) / 12)))
    if params:get("send_midi") 
    then 
      --m.note_on
      noteoff_delayed = metro.init()
      noteoff_delayed.time = 1
      noteoff_delayed.count = 1
      noteoff_delayed.callback = function() 
        --would like to note off here
        --print("hello from the future") 
        end
      noteoff_delayed:start()
    end
  end
end

seems to start off fine but gives me following error after some time

metro.init: nothing available

lua: /home/we/dust/code/arpcore/arpcore.lua:46: attempt to index a nil value (global ā€˜noteoff_delayed’)

I don’t get why I only get the error after some time.
Is my cheeky hack even possible? Any pointers appreciated.

1 Like

I believe there is a limit to the number of metros you can initialize, so your error is happening here because you have run out.

If you call metro.free(noteoff_delayed.id) at the end of your noteoff_delayed callback, it should free up the metro so you don’t run out. I’m doing basically the same thing in Animator, and I’ve seen this pattern used elsewhere, so it should work fine.

2 Likes

How does one update the value of a param option from the param action?

I have something like

 things =  {"foo", "bar", "baz"}
 params:add{type = "option", id = "myid", name = "Stuff", options = things , default = 1,
    action = function(value) -- change things here
end}

Thanks for that, I tried it and gave me more time but I’m still running out of metros after a while. I’ve looked at the source code of Animator and indeed I saw you are doing more or less the same thing. Then I noticed I used callback instead of event, changed it to event and now it’s fine.

1 Like

doesn’t seem like softcut.buffer_clear_region_channel is working for me at the moment ?

in a script softcut.buffer_clear_region(0,5) clears my buffer 1 region but softcut.buffer_clear_region_channel(1,0,5) does not

I’m not certain that I understand…
Do you want to mutate things inside of action = function(value)?
If yes, what happens when you do?