I’ve always admired how SuperCollider had a bunch of examples in their docs, which are also available in a window right inside the editor. Looks like LDocs (the lua doc-writing tool that norns uses) has that ability based on this (also a plug for the lua functional lib). We could embed the code examples straight in the API page.

4 Likes

@nattog probably the easiest is to use maiden (accessible at http://norns.local when norns/your coding computer are on the same wifi), cmd+s/cmd+p to save and send your script to norns.

a more “power-user” workflow would be to use smb and then open dust/code of that norns network drive in your editor of choice. run maiden-repl in a terminal to send the script to norns. vs code is nice because both the terminal and code editor could be in the same window.

you could do it with ssh but that seems a little more primitive to me

One thing I’ve done that works for me is I copied most of norns to my local harddrive. I then setup my IDE to SSH into norns and automatically upload code whenever it’s modified.

The main reason I do this is all of the code is indexed locally so I can more easily do a “global search” if I’m trying to look something up. I also like having it locally so I can still work on things when away from the norns and then test it later.

3 Likes

Thanks - i might try out the power user way! This would work for making edits to say existing parts of the the core lib?

1 Like

do you mind doing a brief write-up of how you’ve done this? i’ve done rsync-based approaches like this before, but typically in a corp environment where the tools team could do most of the heavy lifting for me there :sweat_smile:

1 Like

so as I am porting m18s from crow to norns, these are the things that I have had to do this with:

  • how do I advance the sequencer clock (your post covered it)
  • what are the sound engines I could potentially use for generating notes (searched “list of engines” on lines, got pointed to https://monome.org/docs/norns/app/#synths-and-audio-processing by a post of yours)
  • how do I properly set note lengths (couldn’t find a place where that was solved, so I used the clock api docs, combined with a guess that subsequent parameters to clock.run woudl get passed and params to the function it calls)
  • how do I see a list of monospace fonts (this one, the docs are only a subset of the first few fonts…I had to search font in monome/norns github and then look for commits to find where @zebra added a bunch of fonts to look at the source…foudn out this was a thing by searching “norns fonts” on lines)
  • how do I pan some notes hard left, some hard right…found that the rings engine included some panning, but it’s not pan-per-note. I started looking into the “Pan2” supercollider docs and got overwhelmed on that one, so moved on for the time being
  • what’s best practice for calling redraw (polling on a metro/calling imperatively inside of another function) (I couldn’t quickly find an answer to this one…my guess is the metro, but I’m going with the latter for now just coz it was easier to set up).

I’m finding it pretty difficult to guess what questions someone who has less familiarity with coding (in general) would ask, because they might not know what they want yet.

2 Likes

well, I’m using webstorm to do all of the hard work for me, so I’m not sure how useful my instructions would be for people using something else. I haven’t really used rsync much.

I basically just copied the stuff I wanted locally using scp, and then webstorm has a “deployment” feature where you can configure norns as a remote host, connect to it over SFTP, and map your local path to a “deployment path” on the device.

I only have webstorm because my job pays for it, but I imagine other IDEs have similar features… I’m sure you could do all this with rsync and some good bash-fu though

1 Like

oh yes and this is why i love it! basically i always have two ssh sessions open to norns. all the tools i need are old, established, just work

5 Likes

Could definitely see that. If you have l33t vim skills it most definitely is less primitive than the way I use the code editor hah

I dont think we need to try to answer that question. Rather, documenting for yourself-from-2-days-ago is perhaps far more useful. Not to mention we’re typically best at explaining things to folks with one step less knowledge. It’s turtles all the way down :turtle::turtle::turtle:

Maybe we need a thread of ‘a-ha moments while scripting for norns’? Specifically open to all skill levels.

8 Likes

I’ll happily volunteer to pair program, help with architecture, design patterns, etc.

2 Likes

@jlmitch5 @crim FYI I’ve been looking at a more “power user” way of editing scripts using a remote editing setup.


It’s currently mainly focused on working on scripts but the same idea could also be applied to core libs of course.

I figured most the people interested in this would be on GitHub and chime in there but maybe we should create a topic for this as well? I’d like to get some feedback on what does and doesn’t work to determine what should be improved.

2 Likes

My object-oriented grid lib initially kicked off about ten years ago (Java, over OSC, for the original binary grid) and I now have the Lua port working; I’m hard at work on demos and docs right now. GitHub repo. with various READMEs is here - would be interesting to compare/contrast with yours.

3 Likes

Everything is on GitHub, so I have a repo. of the code on the Mac, for general Lua development and unit testing, and a repo. on the norns. I’ll edit via maiden for actual for on-the-box testing, then when I want to sync I mount the norns via SMB for the git client. (I suppose command-line Git would work fine directly on the norns as well, but I’ve never tried it.)

EDIT: Just tried it now. Command-line Git on norns is fine, with norns-generated SSH key on GitHub, and with ssh-agent running to avoid excessive password typeage.

I just had a quick peek but they look pretty darn different ?

mine has a lot more to do with laying out interaction patterns, display-wise it doesn’t do much of anything fancy

I’m not sure what you mean by interaction patterns - could you explain?

I’ve basically implemented a scene graph for grids/arcs: you create a stack of layers each of which contains LED patterns of varying brightness and opacity, and they’re rendered onto a device. You then shift them around, alter visibility etc. to animate an interface. There’s also some smart-ish press management machinery which ensures that any object receiving a button press will get the release at the same local coordinates, no matter how things shift around in the meantime.

I have a few self-made table functions that might be useful to other people. append, take, drop, and rotate. Did a quick rewrite so that they could fit in tabutil.

function tab.append(t1, t2)
  local new_t = {}
  local i = 1
  for j = 1,  tab.count(t1) do
    new_t[i] = t1[j]
    i = i + 1
  end
  for j = 1, tab.count(t2) do
    new_t[i] = t2[j]
    i = i + 1
  end
  return new_t
end

function tab.take(t, n)
  local new_t = {}
  local len = tab.count(t)
  if n > len then n = len end
  for i=1, n do
    new_t[i] = t[i]
  end
  return new_t
end

function tab.drop(t, n)
  local new_t = {}
  local len = tab.count(t)
  if n > len then return new_t end
  for i=1, len do
    new_t[i] = t[i+n]
  end
  return new_t
end

function tab.rotate(t, n)
  local len = tab.count(t)
  local mod = n % len
  local imod = len - mod
  if mod == 0 then return t end
  local t1 = tab.drop(t, imod)
  local t2 = tab.take(t, imod)
  return tab.append(t1, t2)
end
3 Likes

it is worthwhile to become familiar with lua’s standard table library, in particular unpack and move.

most of the functions in table operate in place. {table.unpack(t)} is a quick-and-dirty method to clone a (flat) table if you want to return a copy.

here’s how i might implement those operations using the standard library.

t_print = function(t) for i,v in ipairs(t) do print(i, v) end print('') end 

t = {'foo', 'bar', 'baz', 'zip', 'zap', 'rap' }

z = {'one','two','three'}

-- return first `n` entries
function t_take(t, n)
    return table.pack(table.unpack(t, 1, n))
end

t_print(t_take(t, 3))

  --- return the last 'n' entries
function t_drop(t, n)
    return table.pack(table.unpack(t, #t - n + 1, #t))
end

t_print(t_drop(t, 3))

-- add contents of `t2` to end of `t1`
function t_append(t1, t2)
    local t_new = {table.unpack(t1)}
    return table.move(t2, 1, #t2, #t1+1, t_new)
  end

t_print(t_append(t, z))

-- remove the first `n` elements of `t` and add them to the end
  function t_rotate(t, n)
    local t_new = {table.unpack(t)}
    for i=1,n do
        table.insert(t_new, table.remove(t_new, 1))
    end
    return t_new
  end   

t_print( t_rotate(t, 2) )

in general, using the table library is more efficient than doing the same things in lua code. (the lib is implemented in c and avoids extra allocations, rehashings &c)

5 Likes

Thanks for the tip. I think t_rotate could be kept as appending drop and take, because it handles negative n without extra cases.

-- this
function tab.rotate(t,n)
  local len = tab.count(t)
  local mod = len - (n % len)
  return tab.append(tab.drop(t, mod), tab.take(t, mod))
end

-- vs something like this
function tab.rotate2(t, n)
  local t_new = {table.unpack(t) }
  if n > 0 then
    for i=1,n do
      table.insert(t_new, 1, table.remove(t_new, #t_new))
    end
  else
    for i=1,n do
      table.insert(t_new, #t_new, table.remove(t_new, 1))
    end
  end
  return t_new
end

I can see myself using tab.rotate and tab.append often. Wondering what peoples thoughts are on manipulating the table in place, versus returning a new table.

xs = {1,2,3}
ys = {4,5,6}

xs = tab.append(xs, ys)

vs

tab.append(xs, ys)
1 Like

a Set type would be really handy for many applications too.

1 Like