Norns: softcut studies

softcut studies

softcut is a multi-voice sample playback and recording system build into the norns environment. it features level-smoothing, interpolated overdubbing, and matrix mixing. it was written by @zebra.

for an introduction to scripting see the norns studies and tutorial.

1. basic playback

  • see/run softcut-studies/1-basic (source)

first, some nomenclature:

  • voice — a play/record head. mono. each has its own parameters (ie rate, level, etc). there are 6 voices.
  • buffer — digital tape, there are 2 buffers. mono. just about 5 minutes each.

softcut parameters are reset when a script is loaded. to get a looping sound we need at a minimum the following, where the arguments are (voice, value):


the buffers are blank. load a file (wav/aif/etc):

softcut.buffer_read_mono(file, start_src, start_dst, dur, ch_src, ch_dst)
  • file — the filename, full path required ie "/home/we/dust/audio/spells.wav"
  • start_src — start of file to read (seconds)
  • start_dst — start of buffer to write into (seconds)
  • dur — how much to read/write (seconds, use -1 for entire file)
  • ch_src — which channel in file to read
  • ch_dst — which buffer to write

2. multivoice and more parameters

  • see/run softcut-studies/2-multi (source)

enable more voices, then set their parameters using the first argument in the various param functions. here are a few more playback parameters:


3. cut and poll

  • see/run softcut-studies/3-cut (source)

softcut cross-fades nicely when cutting to a new position and looping. specify the fade time:


we can read the playback position of a voice by setting up a poll.

function update_positions(voice,position)

and then inside init():


phase_quant specifies the time quantum of reporting. for example, if voice 1 is set to 0.5, softcut will call the update_positions function when the playback crosses a multiple of 0.5.

4. record and overdub

  • see/run softcut-studies/4-recdub (source)

first activate record mode for voice 1:


then set up the input source. first we route audio input to softcut, and then set unity levels for each input channel on voice 1:


finally, set the rec and pre levels.

  • rec: how much of the input gets recorded to the buffer
  • pre: how much of the pre-existing material stays in the buffer

so, full overdub would have both levels set to 1.0. just playback would have rec set at 0.0and pre at 1.0. an echo effect can be easily created by setting middle ranges to each.

5. filters

  • see/run softcut-studies/5-filters (source)

softcut can apply filtering pre-record and post-playback.


both are state variable filters with all taps available, so you can freely mix the outputs of dry, low pass, high pass, band pass, and band reject.

to set the filter cutoff and q values:


post filters are the same. just replace pre with post in the command set.

6. routing

  • see/run softcut-studies/6-routing (source)

the audio routing within softcut is highly configurable.

first we can specify a mix of softcut’s input source:

audio.level_adc_cut( level )
audio.level_eng_cut( level )
audio.level_tape_cut( level )

then assign input levels per voice:

softcut.level_input_cut( ch, voice, level )

we can also cross-patch the output of voices to the input of other voices:

softcut.level_cut_cut( src, dst, value )

each voice can have a separate level for final output:

softcut.level( voice, value )

the example script uses two voices. the first just plays a loop. the second jumps positions, overdub-recording into the same loop using the first playhead as the input for recording. it’s a sort of feedback buffer process that radically restructures sound.

7. files

  • see/run softcut-studies/7-files (source)

softcut reads files to buffers and writes buffers to files, in mono and stereo.

softcut.buffer_read_mono (file, start_src, start_dst, dur, ch_src, ch_dst)
softcut.buffer_read_stereo (file, start_src, start_dst, dur)
softcut.buffer_write_mono (file, start, dur, ch)
softcut.buffer_write_stereo (file, start, dur)

the example script reads a “backing track” clip when K1 is long-pressed. this sets a loop length, and the playback volume can be changed with E1. a second clip is recorded from the audio input, with configurable rec/pre levels with E2/E3 respectively. the recorded clip can be saved at any time with K3, to dust/audio/ with a ss7- prefix along with a random number. this functions as a live “clip grabber” with overdub options.


contributions welcome: github/monome/softcut-studies


Perfect. Thank you so much for this,
I will dive into softcut!


added #2 and #3.

these little sample scripts sound nice— #3 is sortof a mlr-ish auto-cutter. use them as a basis to make little things:

  • change the soundfile
  • change rates, panning, etc

I get how to play a sample and jump across various position, what I am most interested in, now that I am properly teased, is:

  • How to change the pitch of the sample.
  • How to use the filters, especially mod.
  • Start a new recording of what comes through audio L/R.
  • How to replay that sample.

Where I want to go

What is a good way to make let say a sampler that can hold more than one sample at a time, a large number of samples, think Ableton Drum Rack. Let say I have a bank of 64 samples. Right now the buffer seems to always overwrite the previous sample.

change pitch with rate

the buffer is super super long, so use cut positions as storage points for clips. think about it like tape or RAM

recording is up next!


Oh that is clever!! Okay yes I think I know just how to make myself the perfect sampler.


in upcoming version (current master branch), there are now two controllable filter stages: one before the write head, one after the playback head.

both have identical topologies: 2nd-order state variable. each filtering stage puts out an arbitrary blend of lowpass, highpass, bandpass, band-reject and dry signal.

the “mod” parameter is a little weird and deserves a special explanation. it applies only to the pre-filter. the preFcMod parameter (normally in [0, 1]) allows the cutoff frequency to be affected by the rate parameter. this “modulation” can only decrease the filter FC, not increase it.


fcModValue = min(fcBase, fcBase * abs(rate))
fcValue = (fcModValue * fcModAmount) + (fcBase * (1 - fcModAmount))

there is a specific reason to have this: if you set the rate below 1.0 when writing to the buffer, you are effectively decreasing the sample rate of the material in the buffer.

at the extreme, when (say) sweeping the rate from positive to negative, rate ~=0 means effectively
sr ~=0, and any values written there will cause a nasty click when played back at higher speeds.

so, if you set up the pre-filter as follows:

  • dry mix = 0
  • lowpass mode = 1
  • all other modes = 0
  • base frequency at, say, 12k or 16k or something (well below nyquist, to accommodate shallow rolloff of 2nd-order SVF)
  • rq = 1
  • fcMod = 1

then the pre-filter acts as a fairly effective antialiasing device when changing the rate.

this isn’t “needed” in the post-filter.

also i should note that there’s no smoothing of filter parameters at the moment. this could be added… problem is the coefficient update method is rather heavy. so will take some work, like (a) profiling individual ops in coeff update on ARM (tan function) and making approximations / refactors as appropriate, and/or (b) downsampling the filter parameter signals (except when modulated, so… kinda tricky)… or maybe weirder things like smoothing the coefficients directly after calculation… i intend to try some of this stuff on the postfilter (no mod) and profile.


with this new version, does halfsecond.lua need an update from filter_dry to pre_filter_dry or post_filter_dry (along with other filter_ variables?)

Yes indeed. But I suppose we could add aliases in lua

[update] added

#4 record and overdub added.


During my vacation I can’t escape the voice in the back of my head, telling me it’s excited to get home to the Norns.

#5 filters, added. anyone making scripts?


Are the post filters currently available, or do I need to git pull in home/we/norns?

1 Like

oh, good point. you’ll need to:

cd /home/we/norns
git pull

then reboot

we should have a formal update out very soon

1 Like

I want to script an asyncronous 4 track looper in the vein of mlr. What is the max loop length if I want 4 loops? 2,5ish minutes?

anyone making scripts?

My 128 samples script is almost done, a should have the library up on here in a few more days. :fist:


I have a couple count to 5 inspired things, and something else that hasn’t quite taken shape yet. Softcut seems so endlessly scriptable. :smiling_face_with_three_hearts:

edit: also adding filters to otis and bounds will be great!


I interpreted this to mean the loop length, which would also be cool


Am I wrong to think of (slowly) working on a softcut based script that emulates a tape delay ala RE-201? Or is this a bit too basic for softcut? Been thinking of some ideas for scripts to build (while attempting to learn Lua).

1 Like

no, seems reasonable.

softcut isn’t a tape emulator exactly. but you could program some warbles on the lua side, use the filters, get somewhere in the territory rather easily.

1 Like