Norns: development

Thank you for the in-depth reply, super helpful!

Yes exactly. I just implemented the formula used in taper.lua (hadn’t noticed that before) and it looks good, certainly close enough for visuals I’d say. So that’s a quick win :smile:

Yeah I think just getting something representative is the way to go. If we had visuals for a LP/HP & BP/NP in 2 & 4 pole variations, resonant/non-resonant then that’d be plenty for now. The difference between implementations I’m guessing won’t look that different on a tiny screen. Still a little beyond my understanding right now but I’ll tidy up the rest of what I have and keep thinking on it!


thanks! you were right, once telling csound to use jack it worked as expected.

i had a long 6 hour flight from santa cruz back home to boston, so i was even able to begin work on passing the csound output back into an SC engine. for someone who hasnt done much development this is starting to feel within reach :slight_smile:


SC’s curvature formula is most accessible in the implementation to the SimpleNumber:lincurve / SimpleNumber:curvelin. It basically amounts to:

		a = outMax - outMin / (1.0 - grow);
		b = outMin + a;
		scaled = (this - inMin) / (inMax - inMin);

		^b - (a * pow(grow, scaled));

If in and out ranges are 0…1, it’s more like:

		grow = exp(curve);
		a = 1.0 / (1.0 - grow);
		b = a;
		scaled = this;

		^b - (a * pow(grow, scaled));
1 Like

Aha good spot! Will try this out

Also a note on filters - the wslib quark has filter coeffs for all of the common EQ-style filters in SuperCollider, plus code to plot them (if you need a reference). If you install via Quarks.install("wslib") and then recompile and search for the coeffs method, you’ll see them (plus magResponse where the actual calculation is happening). It’s probably faster with FFT, but given that the norns screen is low res and doesn’t need to show a lot of bands, you might be able to brute-force it per band ala magResponse.

1 Like

@tehn , re last study : “in Lua variables do not need declaring” …

I think that probably should be clarified a bit.

today, I had a r nasty bug, as i was using colours, and had the variables r,g,b…
where i found, after loading my script, i couldn’t load any others.
I then saw that script.clear() was throw errors about ‘g’ being numeric, and suddenly twigged g was a global variable. (not sure single character globals are a good idea!?)

so now, id always say declare them as local, so you can keep the namespace ‘clean’


i have to agree, 1) g is not a good global variable name, 2) its terrifying that the first thing we’re teaching people is to use global variables by default, and 3) the combination is catastrophic.

@TheTechnobear one thing is that we would like to just use a different global environment for sandboxing scripts, avoiding this issue. see here [ ] - i’ve added “help wanted.”

its not difficult to call user scripts with sandboxed environment. the issue i don’t know how to solve (easily) is making that same environment accessible in the REPL. (maybe evaluating each REPL chunk with explicit envrionment argument. blech)

  1. yes we need sandboxing
  2. making everything a local variable means you can’t access them via the REPL

for the sake of teaching the system in the form of the studies, i chose to put off discussing local

but if someone has a concise, meaningful way to frame the problem to be included early in the studies i’m all for it.


I know scope is a tough concept for a beginner, but this is one of those times when I’d strongly encourage even an absolute beginner to bear down and learn the lesson. It’s very important.


yeah, I think if sandboxing is not there yet - scope is important, otherwise a beginner is going to find scripts working one minute, and not the next - due to the order they load them. (even more problematic, if at the time they are running headless)

btw: I fully respect, its really difficult writing short ‘studies’ they don’t open a can of worms. perhaps given the basics, and a link for further study?

is there any concept of cleanup on script? (deinit())
when I was allocating a metro, I found it disturbing when I couldn’t see other scripts deallocating… perhaps im old school, but even if there are ‘auto’ cleanup methods, I still like to clean up manually.
(im assuming script.clear() deallocates all metros except screensaver etc)

also is there a way for a script to return to the menu?
only way I found was to fake a button 1 event.

ok, here’s some specific feedback.

in lua, variables don’t need to be declared. we just made two variables.

reword or remove. if the reader doesn’t know about declaration / definition / initialization, it’s unhelpful to invoke those concepts; if they do, it’s inaccurate. say: “we just made two variables” or “we just declared and initialized two global variables.”

i agree, there needs to be an immediate introduction to scope. it doesn’t have to be extremely detailed. how about something like this:


if we are going to have single-letter global variables, they should be very prominently documented.

i agree, sandboxing needs to happen. that’s why i made specific suggestions on the GH issue. as far as i can tell, these suggestions work. but i need a little help moving the feature forward. the next step is to actually try integrating a sandboxing function into the script launcher (i didn’t write the script launcher.) the next next step would be using the same sandbox for REPL evaluation. (i did write the REPL glue so i’ll try that when i can)

finally: i really really appreciate that writing intro tutorials is very difficult. its a task i don’t envy.


yes, if a script defines a (global) function called cleanup() then it will be called the next time a script is loaded.

yes, metros are cleaned up automatically but no harm in doing it yourself i suppose.

i don’t know if this is a good idea, but we could make the menu module “includable” by adding return menu to the end.

1 Like

one wrinkle here is that declaration order matters for locals (e.g., they need to have been declared before use). in general, just adding local will probably break your script. (i speak from intimate experience.)


thanks @zebra, this is a nice concise intro. i’ll get that fix in also.

just to be more clear with that last paragraph, perhaps it’s relevant to just list all of the globals that you shouldn’t overwrite or stuff will break. we tried to introduce as few globals as possible in the menu/overhead/etc but there are only a handful. generally you won’t break a script by using globals in another script. it’s just easy to get confused while developing. as a safeguard people need to know that their scripts need to work on a clean startup… ie, if things are acting really weird, reboot to a clean state (with sandboxing this would be unneeded).

also, as is it’s important to acknowledge things are pretty great! even without sandboxing the behaviors are pretty predictable.


i don’t think using globals is a big problem necessarily - even if it’s not sandboxed the chances are you’ll just overwrite it with something else when switching to new scripts. overwriting globals that are used for grid etc is a bigger problem. perhaps those could be given more distinct names? (as a side effect it might make it more readable too: grid:refresh instead of g:refresh). alternatively, perhaps they could start with an underscore?

I thought this was a convention intended to imply “private” or “protected” in languages that can’t support such features. Sort of a “don’t touch” signal. Users are expected to use the grid global, right?

typically, yeah. i don’t know if it has the connotation of “don’t touch” - to me it’s usually just an indicator it’s part of internal class wiring, not its external interface. in any case i think norns is a different enough environment that we could have our own conventions (but i don’t know much about lua or supercollider, so it’s entirely possible they have their own that wouldn’t work well with this scheme).

the idea is to be able to visually distinguish globals at a glance. another option could be to capitalize them - Grid or G


in scripts and lua libs, i suggest always declaring methods using the dot syntax, for instance function Grid.refresh(self) ... end instead of function Grid:refresh() ... end.

“instance methods” can still be called using the colon syntax then of course.

this gives the benefit of self always being explicitly defined as an argument for new methods. if this looks good, we can also add this suggestion to the lua coding guidelines.


i agree, and almost included that list in my reply. but i didn’t, mostly because this really should be generated from ldoc.

these globals are all declared in startup.lua (i hope!) and are mostly includes of commonly needed modules:
[ ]

except - oh dear - there are more. a lot more. they are in script.lua and all over the place. i’m taking this to github.

so, i’m probably a broken record at this point, but i don’t think any of these really need to be global, and some of them really aren’t going to be used much at all (wifi).

but g is really the odd one out. is it really, really necessary for it to be global and a single letter? could be a field in the grid module, requiring the single line local g = grid.g? (or better, something descriptive like local g = grid.default_device.)

as it is, kind of assumes that the absolute most important first thing that every script will do is get a handle to the default grid device. (like s in supercollider for the default server.) if that’s the assumption than why not have e for engine, s for screen, at the very least… since almost every script will use those.

sure, convention for globals isn’t a bad idea. lua already has some internal conventions and predefined globals. all-caps plus preceding underscore represents some important ones: _G for the global environment, _VERSION, &c.

a soft convention we’ve used so far is initial capital in Modulename. (but usually assigned to a lowercase modulename when included.)

oh that’s interesting, i don’t think i ever even assumed that declaration order would not matter. is this a javascript thing? (you don’t have to hoist anymore?)

ok, last thought re: scope and then i’ll stop banging on about this

could be worth linking to lua style guide

and maybe the scope tutorial.


i’ve just submitted a PR for arc support, for now i went with _arc = require 'arc' and then using arc as the global variable.

on a semi related note, might be good to wrap all grid/arc functions in something else that would check if the device is connected, this way we don’t have to write if g then ...