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.

extremely dumb question:

i have a table of numbers. i want to divide it evenly (as possible) into n subtables where each subtable is 1/nth the size of the big table:

big_table={3,29,55,13,38,25}
divider = 2

[missing brain here]

lil_table_1={3,29,55}
lil_table_2={13,38,25}

and then, if i were to change it to divider = 3 , return 3 tables of two values instead.

i can definitely figure this out, but knowing how easy it must be to do––and also how long i’ve been staring at maiden––it’s totally plausible that someone here might be able to answer me before i work it out.

i know it probably involves table.unpack(big_table,something,something) and maybe also the % operator. just cant find the logic in my brain.

Maybe not particularly Lua specific as i cant remember table funcs off the top of my head, but I would just do this in a for loop. I reckon creating nested table within a liltables var for each time the index wraps around the divisor (modulo) could achieve this

1 Like

totally different from the rabbit hole i was going down and this feels like it’s going to work. modulo remains one of the most difficult things for my hobbiest brain to remember how to use.

thank you!!!

1 Like

yea a four loop & modulo of ‘i’ will get you there quick, i won’t give away the fun parts ; )

miiiight need math.floor too as i believe lua modulo yields floats

1 Like

another angle is that this is analogous to the idea of “euclidean rhythm,” assuming you want clumps to be “as evenly-sized as possible” when the clump size doesn’t evenly divide the table size. (if you’d prefer a number of same-sized clumps, plus a remainder, then it is more straightforward in concept [if not implementation.])

for euclidean distribution, i like the “bucket” algo demonstrated in norns/lua/lib/er.lua.


-- clump table `x` into `n` parts, with remainder
function clump_remain(x, n)
  local len = #x
  local w = math.floor(len/n)
  local remain = len - (w * n)
  local y = {}
  local src_idx = 1
  
  for i=1,n do
    local z={}
    for j=1,w do
      table.insert(z, x[src_idx])
      src_idx = src_idx + 1
    end
    table.insert(y, z)
  end
  if remain > 0 then
    local z = {}
    for i=1,remain do
      table.insert(z, x[src_idx])
      src_idx = src_idx + 1
    end
    table.insert(y, z)
  end
  return y
end

-- clump table `x` into `n` parts, with euclidean distribution
function clump_er(x, n)
  local len = #x
  local y = {}
  local z = {}
  local b = 0
  for i,v in ipairs(x) do
    table.insert(z, v)
    b = b + n
    if b > len then
      table.insert(y, z)
      z = {}
      b = b - len
    end
  end
  if #z > 0 then table.insert(y, z) end
  return y
end

function print_clumps(y) 
  for _,v in pairs(y) do
    print("{")
    for _,w in pairs(v) do
      print("  " .. w)
    end
    print("}")
  end
end

given x = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} and n=4,

y = clump_remain(x, n) yields {{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10, 11}}

and y = clump_er(x, n) yields {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11}},|

[update: cleaned up and fixed clump_remain function.]

PS: i believe i’ve mentioned this previously in this very thread, but: i’d avoid the use of the modulo operator in general unless you are specifically looking for a % b == a - math.floor(a/b)*b. (that is the literal underlying implementation of lua’s %. i see people trying to use it to “optimize” loop bookkeeping, where it usually will have the opposite effect.)

3 Likes

i pressed heart in lieu of thanks before but as i’m bumping this thread again anyway, this was super helpful, thank you for writing this up and pointing it out. (it’s in use on a microtonal thing i will share when i get a chance to work out the kinks!)


ok, my new issue is with polysub on the supercollider end.

  1. engine.start takes a hz value to launch a note.
  2. the notes travel through a low pass filter which takes values from 0 to 32.
  3. this works as expected on lower frequencies, but on notes around 750hz and above, the filter clamps all the way down rather than staying at the top (letting 0 hz through instead of 20k and below hz).

easier to reproduce than explain. in the below script, if you sweep the cutoff with enc 3 while pressing buttons on the norns you’ll hear it.

-- polysub test 
-- enc 3 adjusts filter cutoff 
-- key 2 works with cutoff in the expected way 
-- key 3 breaks when filter cutoff approaches 32 
-- key 1 breaks master cutoff into something like 3 parts

polysub = include 'we/lib/polysub'
engine.name = 'PolySub'

function init()
  polysub:params()
end

function key(n,z)
  --expected: 
  if n==2 then 
    if z==1 then engine.start(1,740) else engine.stop(1) end
  --error:
  elseif n==3 then 
    if z==1 then engine.start(2,750) else engine.stop(2) end 
  --more obvious error: 
  else
    if z==1 then engine.start(3, 3220) else engine.stop(3) end
  end
end

function enc(n,d)
  if n==3 then
    params:set('cut', params:get('cut')+(d/10))
    print(params:get('cut'))
  end
end

i can’t quite make sense of the supercollider code but i assume this has something to do with aliasing.

is this a bug that can be fixed, or am i simply using the wrong engine for the job if the job involves calling a bunch of high frequencies?

(also sorry if this should be somewhere else, i see polysub might technically be a ‘legacy’ engine? but it sounds so good)

in polysub, the filter cutoff frequency is not specified in Hz, but as a ratio of the main oscillator frequency.

the final cutoff is clamped to nyquist. this clamping had a typo in earlier versions but has been fixed for about 9 months:

i’m not noticing any particular issues related to the filter sweep here in this script/

what i can hear is:

  • some steppiness from the E3 delta function
  • some aliasing appearing as low frequencies. (the VarSaw component of the wave shape function is not bandlimited.)
1 Like

thanks for checking. i was hearing the 9 month old typo…

definitely triple checked i was up to date before writing out a demo script, but i was not up to date. my bad!

Does Norns have a ‘unique ID’ concept similar to the Crow unique_id()? I’m curious on adapting the First script to Norns as a learning exercise. Ill probably use some kind of current time stamp if this isn’t available (or maybe some kind of ‘create your own seed’ feature)