My Manifold engine and script implements a multieffects type of system. I’ve had plans on implementing the ability to route the effects into each other in different ways but I haven’t gotten around to it. You might consider checking it out to see if it’s worth modifying. As of right now all the effects run in parallel.

1 Like

Thanks, this was super helpful! I was initially scared off by R’s complexity, but after playing around with SC for a while and becoming more comfortable with the syntax and patterns, it was a little more approachable. As you said, it’s doing way more than I think I need in my case, but there were definitely some helpful patterns in there.

I’ve put up what I’ve got so far here: https://github.com/21echoes/norns-pedalboard. There aren’t actually many effects yet (a test one that just lets you control volume, and a super basic reverb (JPVerb) that you can’t even change its parameters yet other than wet/dry and volume), but it’s now at a point where most all of the extensible structure is there, and from here on out I can just focus on adding new effects.

If you don’t mind, that would be nice to see! I feel alright about where I ended up, but as this is my first time writing SC I’m sure I did some stupid stuff :woman_shrugging: You could also just take a peek at the Engine and a sample effect and let me know what you think if you’d like.

1 Like

Awesome, I’ll take a look! I may end up lifting some of the effects themselves, if you don’t mind :smile:

1 Like

The GitHub code looks great! I love the approach you are taking! I’ll learn a lot from this.

1 Like

it looks very good!

one thing i noticed:

  • when fx are created, i only see them added to the head of the context.xg group. you probably want to manage order of execution more explicitly, which is a very idiomatic SC thing. there is a really good order of execution overview in the help that explains better than i can.
  • in that vein, you could do processing in-place on a single bus using ReplaceOut, instead of maintaining separate busses, if you want. (it would be a little more efficient but not a big deal, and maybe it’s helpful to be able to tap any point in the chain as you can now.)
1 Like

Thanks!

The part of code that does this is much messier than I was hoping for, so I think you may have just missed it, but here’s where I believe I’m adding synths to places other than context.xg \addToHead: https://github.com/21echoes/norns-pedalboard/blob/master/lib/Engine_Pedalboard.sc#L94-L106 unless I’m misunderstanding something.

I’ll read up more on ReplaceOut – that messy function I linked right above is something I’m not particularly happy with, and it’s mainly messy because of the bus management, so finding a way around doing all that so manually would be nice.

yep, totally missed it, sorry

i’m getting the “error: SUPERCOLLIDER FAIL” message and no audio on bootup, and i was wondering if someone could help me interpret this output from sclang.

here's what sclang spit out
*** Welcome to SuperCollider 3.10.0. *** For help type ctrl-c ctrl-h (Emacs) or :SChelp (vim) or ctrl-U (sced/gedit).

Booting server 'localhost' on address 127.0.0.1:57110.

sc3> Found 0 LADSPA plugins

Cannot connect to server socket err = No such file or directory

Cannot connect to server request channel

jack server is not running or cannot be started

JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock

JackShmReadWritePtr::~JackShmReadWritePtr - Init not done for -1, skipping unlock

terminate called without an active exception

could not initialize audio.

if you need more info about how i ended up here in the first place, i outlined it in this post. i found out about the sclang command after doing some searching around on here, but have no idea how to interpret it in order to troubleshoot lol. as always, if this is the wrong place for this post, feel free to point me in the right direction or just move my post :slight_smile:

This bit is saying Jack has crashed (or otherwise is not working properly with sc in norns). I usually do a reboot at this stage with norns and clears up

Not really sure I understand how you’re ended up there. Something may be out of whack from your restart during install and starting over from disk image might be easier in the long run.

1 Like

thanks steven! fortunately it seems to have sorted itself out!

Sorry if I missed this elsewhere in the thread but: how do I best investigate how hard my SuperCollider code is pushing norns’s CPU? Some of the synthdefs I’ve made are getting more and more complicated, and I don’t know how much CPU headroom I have (especially when running 4 or more long-lived synths at once)

1 Like

I think if you get to the settings page in the main menu (where “sleep” is) and press K2 you can toggle the system stats.

1 Like

just a note on that: the display in the norns menu is an average over all 4 cores.(*) on norns we presently use the scsynth backend for supercollider, which is single-threaded and so will never account for more than 25%. (same goes for each of softcut, mixer+fx, and lua interprter / event system.)

for engine development, i’d recommend just using these functions from within supercollider:

Crone.server.peakCPU;
Crone.server.avgCPU;

which can be posted periodically to the REPL. if your engine has very dynamic usage (e.g. a modular environment like R) you may want to create a peak CPU poll or something.

i’m not 100% sure but i’d guess these functions work by actually measuring the time spent by scsynth in each audio callback, and comparing that to (blocksize / samplerate).

(*) on norns, we are just periodically parsing contents of /proc/stat, so it’s a very high-level view of the system.

3 Likes

Awesome, this worked perfectly. For posterity, I dropped this line in my CroneEngine subclass’s alloc method:
fork { loop { [context.server.peakCPU, context.server.avgCPU].postln; 3.wait; } };
and was happy to see I never cleared 50% peak CPU (JPVerb eats up around 30% CPU, the rest of my synths without it were much closer to 5-10% CPU each. I don’t currently allow more than 4 at once, and you can’t use the same synth twice, so no chance of having 4 JPVerbs :smile:)

(For some reason I kinda get but kinda don’t, the simpler [context.server.peakCPU, context.server.avgCPU].poll(3) did not work. Perhaps .poll only makes sense in a UGen/Synthdef context?)

2 Likes

yes that’s right 20ch

1 Like

I’m developing a synth engine, and while I noticed that if I disconnect my midi keyboard while holding down notes they get stuck and I have to reboot norns to stop them. Changing engine or reloading it does not work. How can I guarantee that all synths are cleared at load / init?

your polyphonic engine needs to manage this. for each synth that is created, you must have a way of freeing it. in fact you must free all resources you created (including synths) from your engine’s cleanup method. cleanup will be called on your engine whenever a different engine is loaded.

a typical technique is to matintain a dedicated Group that is the parent of all the synths you create. then you can easily free everything in that group.

for example, in Molly the Polly, the killAllNotes method looks like this:

where voiceGroup is a Group (server-side construct) to which all the per-voice synths belong (so messages to voiceGroup will be passed to its children.)

and voiceList is a collection of client-side handles for manipulating the synths directly.

4 Likes

did you end up doing this filter bank thing? i wanted to try doing something with that on norns but have not touched SuperCollider yet.