Low Level Norns

Note: I do not have a norns (yet). Apologies if that has been discussed somewhere else.

Since the Norns seems to be running on Linux, I would be interested in what it would take to get low-level access peripherals (on board encoders, display, audio I/O, etc) from C instead of default norns software stack (lua, SC, etc). I have my own homegrown ecosystem for sound design and composition that I would love to try and get running on the norns hardware.

Has anyone tried this?

4 Likes

As you mentioned norns is running Linux, so pretty much anything is possible :slight_smile:
Since norns is using JACK as the audio backend it’s pretty easy to add additional audio applications as long as they can be run as a JACK client.

Tying these additional applications into the UI and controlling them using the buttons and encoders will be a bit more difficult. You’ll either need to figure out a way to integrate it with the norns components (which effectively means talk OSC) or you’ll need to shutdown the norns components and just run your own.

FYI there is an idea to support different “engines”, currently the only supported one is SuperCollider but that would allow you to run any kind of application (like Pure Data, but also LV2 plugins or standalone applications).
If you have any input on what exactly you’d like to run (sounds like a standalone application, compiled from C?) and what controls and feedback it would expose that might be helpful as input.

Note that all of this is currently just in the idea phase, I’m not promising this will happen :wink:

3 Likes

Thank you for the reply!

Yup, it’s essentially a command line program that uses JACK. It also integrates with libmonome directly (no OSC) to utilize the Grid and the Arc. It is written in C, but is configured using higher level languages (a homegrown forth-like language and a hacked up version of s9 scheme).

I would probably opt to shut down the default norns components, though I would still want the it to be able to boot up to a Linux environment that I can ssh into. Being able to auto-login and boot up custom software at startup would be a plus too.

If I had a magic wand, I would zap into existence a core C library called libnorns similar in style to libmonome, that provide a lightweight API for doing this sort of stuff. Short of that, it would be good enough for me to manually poll events from each of the peripherals and parse serial data, and also to be able to read/write to the raw framebuffer like you would /dev/fb.

2 Likes

In the default norns software stack, all the stuff you mention (audio, GPIO, screen, etc.) is controlled from C. The Lua layer talks to the hardware through the C half of matron (the Lua/UI process) and it and Supercollider talk to the crone audio process via JACK and OSC. Here’s the code if you want to see what you’d need to do to talk to the hardware from your own process:
https://github.com/monome/norns/tree/master/matron/src/hardware
https://github.com/monome/norns/tree/master/crone

But as Simon says above, you could leave the crone and matron processes running and have your code talk to it (and JACK) in place of Supercollider. Enabling this kind of engine replacement is where the system is headed but it isn’t officially supported yet.

(Edited to better describe the distinction between crone and matron.)

8 Likes

Ah good! This is what I needed to find. I’ll take a loot at things, and see how much trouble I am in for.

My engine is currently controlled scheme REPL, which I have been launching inside of emacs. Replacing the default emacs scheme interpreter is mostly a matter of supplying a command that works with standard input/output, which to me is pretty neat! I haven’t tried it yet, but I want to see if I can use a scheme interpreter over SSH. That way, I can still use the emacs environment that I am comfortable in.

1 Like

I’d definitely suggest to take a look at the code in the norns repo. The links posted by @Dewb should cover most of what you mentioned.

Apart from that, in case you wanted to get started with what you already have immediately and look at the hardware/norns integration later there’s nothing stopping anyone from disabling the norns services that are running on the device. They are just normal systemd units, so a (temporate) systemctl stop <unitname> is enough to stop them.

This of course does assume you know how these normal Linux things work (I’m assuming you do). For anyone reading this who doesn’t: Don’t try this at home :wink:

So you’d want to run emacs locally (on your desktop/laptop) and do the coding there?

2 Likes

Yeah. I’d ideally want to set up a live coding rig to incrementally develop ideas. Emacs would run locally, I would send blocks of scheme code to be evaluated on a process running on the Norns. If I wanted a program to run headless, I guess I’d scp/rsync the whole file to the Norns and edit the start up script to run that file? Haven’t fully thought that one out yet.

2 Likes

As luck would have it I’ve already spent some time building a libmatron proof of concept with all the lower level physical device logic (along with midi/osc) separated out from the lua interpreter and related code.

Unfortunately it was done prior to the norns 2.0 push and I haven’t had a chance to go back and update it yet. That said it should still work for your purpose. If you are curious the work is on the libmatron branch in my norns fork:

The experiment which sent me down this road was wanting to build an alternate standalone environment along side the traditional norns environment which allowed me to develop in common lisp and explore an alternate synthesis engine. The alternate synthesis engine I was eyeing at the time was sporth (which I’m assuming you are very familiar with!)

The super incomplete code (nothing beyond FFI tests for libmatron) is over here:

PS: @PaulBatchelor - if you need any help let me know.

9 Likes

Hey this is a neat idea! I’ll have to take a closer look at this. It is certainly a good effort to decouple the core C api from the rest of the ecosystem. Thanks for the share!

When/if I get a norns, my goal will be to create a set of small self-contained C programs that show how to control various norns components. One program would show what is needed to read and poll from a knob. One program would show how to draw a pixel on a screen. etc, etc.

Small, simple programs are fun to read, and fun to hack on! I get tremendous satisfaction working at this layer.

I also like being able to choose my software stack. You certainly don’t need fancy-dancy communication protocols OSC/UDP/MIDI to poll an encoder. And you certainly don’t need cairo if you want to draw a few pixels on a 128x64 monochrome display.

I really do love the norns ecosystem though! It enables a lot of creative people to do great things. Bonzai Trees vs. Rain Forests. Different kinds of appreciations.

Oh yes, that old thing :wink: Happy to help where I can. I should mention that Sporth by itself doesn’t have any realtime audio support out-of-the-box (I do this to try and keep things more portable). You may want to have a look at an old project of mine called Spigot: https://github.com/paulbatchelor/spigot

Not only is Spigot configured to do realtime JACK audio (via RtAudio), but it also has some rudimentary live coding abilities (it has a UDP listener for evaluating and hotswapping Sporth code).

Most of the sporth code related to hotswapping can be found in main.cpp:

3 Likes

we don’t poll encoders using any of those things, just normal GPIO file handles.

[ https://github.com/monome/norns/blob/master/matron/src/hardware/gpio.c ]

lua interpreter lives in the same process as MIDI / HID / GPIO / TTY commuication, so these things are low overhead. incoming events are pushed to a queue and handled by the lua main thread and that’s that.

communication with supercollider uses OSC b/c that is the way of supercollider.

communication with crone also uses OSC, b/c it was migrated from supercollider. but replacing this with more appropriate local IPC is a high priority.

that is how norns lua layer works. we wrap stdio in websockets and that is how it is plumbed to the web UI. this would be pretty easy to modify if you want different plumbing, or maybe use the same plumbing with different interpreter process.

anyways yeah it sounds like we should definitely break out hardware i/o to a library. buuut… (@PaulBatchelor @ngwese) i’m not super clear on the “right” way to structure that interface. specifically:

  • should the lib maintain an event thread and queue, as is done now, and the lib user implements a single-threaded handler function?
  • or, something else, like user lib handling each event as its generated (from different threads)?

(i’ve looked a bit at the libmatron branch but do not yet grok the strategy.)

(ed: oh - i see that there is a new callback passed to event_data_new for freeing the data… is that “just” for tidiness?)

re: cairo. we also need to break this out to a dedicated thread / event loop. i’m now thinking it should maybe be a separate process altogether.

but this

read/write to the raw framebuffer like you would /dev/fb.

should be trivial right now. the framebuffer is right there at /dev/fb0 and it’s all yours if you don’t laumch the matron process.

4 Likes

@zebra Thank you for providing more insights into how the system works, and on some of the design decisions. The backend looks quite clean and readable. I look forward to diving in more.

Just to clarify, does this mean that the lib abstracts away the thread handling from the user? I personally would want an API that gives me the option to implement my own thread if I wanted to, like how liblo does it with their high level and low level APIs. This is what I do with libmonome right now, and having that kind of control has been super helpful for me.

that’s kinda what i’m asking. lib doesnt exist so let’s decide. sounds like you would want a callback whenever an event is posted, regardless of what thread it originates from. so the onus of implementing thread-safe handlers, or a queue or whatever, is on the library user.

Would it be possible to design things in such a way to that you could have both, or is it an either/or sort of thing? Could there be a way for the thread-safe interfaces to be built on top of the callback driven interface? I don’t have much experience building things with thread-safe considerations, so I’d be interested to know what kind of considerations go into that.

yes, definitely possible. gotta think about the details though. (and hopefully get input from other people - realistically, i can’t see myself working on this particular refactor anytime very soon.)

here’s another wacky idea: flip it around; instead of libnorns being embedded in some program, matron could have a plugin interface for different interpreter VMs? (???)

2 Likes