Norns: softcut studies

it is reciprocal of Q-factor. therefore RQ = bandwidth / cutoff. (bandwidth defined at -3db.)

the topology and response are similar to this SVF described by andy simper / cytomic:

some transfer functions are plotted on p.13

1 Like

cool, thanks. I’ll keep reading up on state variable filters.

Is there some sample rate or bit rate reduction going on with softcut? I’m just starting my journey and on the fourth study, I’m listening to the input signal and then the “echo” and the recorded signal sounds markedly different (even at a playback rate of 1).

Hmmmmm ….


what i’m seeing in study 4 is that the gain staging is not ideal for all setups.

here, it is summing both ADC channels at unity gain to softcut voice 1 input:

so there will be clipping if you are taking a dual-mono source with less than 6db headroom. i would change the scaling to 1/2 or make it an option (for mono/stereo input, i think otis does this for example.)

there are two other things affecting the input signal path that you may be noticing:

    1. at each voice’s input, there is a multimode filter that by default is in lowpass mode and modulated by the rate (it is at 12khz when rate=1 and is reduced proportionately as abs(rate) goes towards zero.) this can be disabled by adding the following lines:
  softcut.pre_filter_dry(1, 1)
  softcut.pre_filter_lp(1, 0)
    1. at the input, after the filter, there is a soft clipper that kicks in around -3.34dBu. presently there’s no option to disable this. (sorry, maybe in next version.) so you want to leave that much headroom if you don’t want harmonic distortion artifacts.


It was the pre filter that did the trick. I was listening back to a snare sample that was losing top end and it was driving me nuts.

1 Like

thanks ezra for spotting this! cc @dan_derks (to discuss… we should be more explicit about input gain/mixing…)


Is it possible to change engines while softcut keeps running?

Use case:
I’m currently learning SC with the goal to build my own synthesizer engines to run on norns.
I understand I can only run one engine at a time on norns,
I would like to play it in realtime via connected MIDI keyboard,
record its output in softcut (using it as a looper),
change to a different engine and repeat.

While I am changing the engine, is it possible for softcut to continue playback of my looped recording without audbile glitches?

What would I have to watch out for when writing according scripts for norns in order to allow glitchless softcut loop playback while switching scripts?

Thanks much in advance!

  • when changing scripts, softcut state and parameters are reset to a default configuration. this behavior is defined at the system level and could only be changed there. so without introducing a mod it’s not possible to continue a softcut “session” across script launches.

  • it is possible to change engines within a script, but it is a little fiddly. here’s a very old example that AFAIK should still work:
    norns engine switching test · GitHub
    i seem to recall some script using the method in a more serious way, but have forgotten which one it was.

  • however, the most idiomatic solution if you are making your own engine class would be to just make your various voice types or synth architectures controllable from a single engine class. mx.synths is an example where multiple synth types are “isomorphic” w/r/t parameters and voice handling, so they are implemented as interchangeable synthdefs. it would also be possible to make a more heterogenous collection and/or use a deeper class structure.


Thank you, I will have a close look at both the engine switching test and the mx.synths. I am glad to hear that engine switching within a script is possible, I always thought it would make something terrible happen like crash or glitches. But I am really a noob, so this is just my naive interpretation. Guess I’m guilty of taking the second step (learn about engine switching) before getting the first one done (learn how to make my own SynthDef run on norns).

@wolfgangschaltung Orca allows for the changing of engines. My implementation is rooted in @zebra gist above, but a bit more convoluted.

  1. User selects engine in PARAMS menu

  2. This triggers the change of hidden engine_name_index param

  3. load_engine_ method is called and loads engine (if installed)

Maybe that’s helpful.

1 Like

Thank you, I will try to understand it!

1 Like

Sorry, noob here, but i’m having an issue running softcut study #6 on my norns. i’m able to load it up, but when i try to run my audio thru it nothing happens, I have both the feed and preserve encoders turned all the way up. can anyone tell me what I am doing wrong? thank you in advance

there’s a good chance the input level isn’t getting explicitly set in the script. check your param menu for input to softcut level.

it’d be good for the script to do a sane default

Hello there, I recently got a norns and I’m trying to create a softcut-powered effect. My idea is to record a one-shot sample and loop it very quickly to produce a pseudo-autotune effect (e.g. you send a note-on message and the incoming audio loops at 440Hz).

I’m guiding myself using the studies and the softcut API and had stubbed this small proof of concept:

But the resulting code doesn’t seem to work. Using larger loop times (0.5s) seems to make it kinda work (first press of the key does nothing but subsequent ones do) but not for smaller, audible-level times. I’m assuming this is a limitation of the runtime/softcut lua bridge or may I be missing something? Any help would be appreciated.

Also I’m doubting how could it mute the incoming audio once the sample is recorded (the idea is to only hear the loop once its recorded and nothing else). Is there a specific way to do this? The documented functions seem to only affect the incoming audio at softcut level and not whatever is monitoring the source input.

link isn’t working for me. so i’m guessing.

my guess is you are running into the fact that crossfade time basically acts as a lower bound for loop time. make fade time shorter than half the desired period.

anyways, looping at a a desired fundamental frequency isn’t going to yield the effect you describe. it will make a naive/glitchy kind of wavetable synth. if that’s what you want i’d consider implementing it in supercollider. (at minimum i think you will want ability to specify envelope shapes tjat are not soctcut’s crossfade shape.)

if instead what you want is a granular autotune using softcut, make the loop times longer than the threshold of pitch (50ms or so.)

for your second question, see docs for audio API module. you probably want funtion

link works now. again i don’t think this will do what you want. but you can run softcut loops at audio rates and use them as resonators if you want. here some specific things:

  • yeah, you want to set fade time to zero or so.
  • use rec_level instead of rec toggling to avoid one kind of click
  • be aware that loop times are quantized to nearest sample. this is design decision, it trades subsample loop time accuracy for perfect preservation of onset transient at loop start.

Thanks for the insights @zebra!

make fade time shorter than half the desired period

Setting the loop time helped getting sound, indeed. I didn’t think on the crossfade getting into the (short) loop.

isn’t going to yield the effect you describe. it will make a naive/glitchy kind of wavetable synth

This was more like what I wanted to achieve, something of an ‘on-the-fly-wavetable synth’. Claiming it would auto-tune sounded more pretentious now that I think of it :sweat_smile: .

consider implementing it in supercollider

Given the specs softcut was describing to have, it seemed like nice giant shoulders to stand on. I wanted to have a minimum proof this would work beyond what I was thinking. Building it in SuperCollider should be the next step :slight_smile:

I updated my gist including your feedback and got it to somewhat work. There’s some problem with the poll function, it doesn’t seem to get called back. As far as I could get was to set the audio-rate loop and enable recording on K2 press. It would just stay on.

By the latest caveats you described it would be more valuable just to move along to SC so I could get sample-accurate looping and precise envelope control :thinking:

Wasnt clear to me what you were trying to do with he phase poll, if anything. So now I gather you are trying to use it to stop recording when a single period is captured

Without auditing I can say that this won’t really work, the polling mechanism is not designed to work with this time granularity, it is an OSC message that is sent only on audio block boundaries, and only if the “logical phase” has changed modulo the specified quantum. (By logical phase I mean the actual phase of whichever r/w head is active / not presently fading out.) Think about what it means that you have not set the quantum to be strictly less than the loop period.

I would just modulate rec_level manually or with some small delay in Lua. A “record once” function has been implemented but not yet in main branch. I don’t think it will matter much for your application (I’ve been happy with manual control in such applications in the past.) Digging into this further in a different environment would let you do other stuff to make the wavetable.sound “good”, like shift/stretch the cycle capture window to match zero crossings / cross correlation, bandlikit the captured cycle, etc.

I see. I was hoping polls would be in a lower level. I also get the poll wouldn’t execute anyway since it was set to trigger at the exact same time the loop is fading (even if the fade time is 0).

What do you mean by manually modulating rec_level? Lua seems to have a coroutine construct, or maybe you’re referring to something like metro/clock? I’ll give it another couple of hours just for the sake of completing a working stub before switching to SuperCollider. The features you mentioned actually makes sense for a project like this if I don’t want it to almost always make it sound awful.

I’m not sure when this started happening, but: I’m seeing that disabling then re-enabling a voice (softcut.enable(1, 0) then softcut.enable(1, 1)) causes the voice to never re-enable.

I can provide a more minimal repro case if needed, but I’m noticing it as part of Samsara here: samsara/samsara.lua at 8a0d38b5f7d0cb508f89f48673703ba517f3c529 · 21echoes/samsara · GitHub. Commenting out that line makes play/pause (almost) work as expected (it acts more like a “mute”/“unmute” with the line commented out, but at least it’s usable)

Did anything change with softcut.enable with the newest norns image? Is there some other gotcha I’m missing?


finally taking a minute to sit down with the norns.

@21echoes i’m not seeing any issues with enable. in particular i am able to pause and resume voices (with clicks, as expected) by toggling enable from the REPL. not tried with samsara, only my own stuff.

there have been some changes in past few months (in 2021 actually iirc) to the behavior of voices while disabled; i think they will now continue to respond to position changes by queing them or something like that.