softcut is a multi-voice sample playback and recording system built into the norns environment. It features level-smoothing, interpolated overdubbing, and matrix mixing. It was written by
For an introduction to norns scripting, see the norns studies
First, some nomenclature:
- a play/record head
- each playhead is mono
- each has its own parameters (ie rate, level, etc)
- there are 6 voices
- digital tape
- there are 2 buffers
- each buffer is one channel / mono
- each buffer is 5 minutes 49.52 seconds in length
softcut parameters are reset when a script is loaded. To get a looping sound, we need to set up the following, at a minimum. The arguments are
softcut.enable(1,1) softcut.buffer(1,1) softcut.level(1,1.0) softcut.loop(1,1) softcut.loop_start(1,1) softcut.loop_end(1,2) softcut.position(1,1) softcut.play(1,1)
note: if we wanted to play and record one-off instead of looping we would still have to set the
loop_end to tell softcut which section of the buffer to use.
The buffers are blank (they are erased with each script load). To 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
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
-1for entire file)
ch_src– which channel in file to read
ch_dst– which buffer to write
Enable more voices, then set their parameters using the first argument in the various param functions. Here are a few more playback parameters:
softcut.pan(voice,position) softcut.level_slew_time(voice,time) softcut.rate_slew_time(voice,time)
softcut cross-fades nicely when cutting to a new position and looping. To specify the fade time:
We can read the playback position of a voice by setting up a poll.
function update_positions(voice,position) print(voice,position) end
And then inside
softcut.phase_quant(voice,time) softcut.event_phase(update_positions) softcut.poll_start_phase()
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.
First, activate record mode for voice 1:
We can 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:
audio.level_adc_cut(1) softcut.level_input_cut(1,1,0.5) softcut.level_input_cut(2,1,0.5)
Finally, set the
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
1.0. An echo effect can be easily created by setting middle ranges to each.
softcut can apply filtering pre-record and post-playback.
softcut.pre_filter_dry(voice,value) softcut.pre_filter_lp(voice,value) softcut.pre_filter_hp(voice,value) softcut.pre_filter_bp(voice,value) softcut.pre_filter_br(voice,value)
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. The taps of each filter share a filter cutoff value.
To set the filter cutoff and q values:
pre filters are the same – just replace
pre in the commands above.
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.
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.
Sections of a softcut buffer can be copied and pasted, for creative collage or straightforward duplication.
softcut.buffer_copy_mono(src_ch, dst_ch, start_src, start_dst, dur, fade_time, reverse) softcut.buffer_copy_stereo(start_src, start_dst, dur, fade_time, reverse)
Buffer content can also be rendered as a series of floats, -1 to +1, for waveform visualization.
To request a numerical snapshot of a section:
softcut.render_buffer(ch, start, dur, samples)
To perform a task after the snapshot, use the
8-copy.lua script for an example of how to turn the -1 to +1 floats to a waveform.
In cut and poll, we used a poll to continuously report the position of a voice’s playhead. softcut can also query any voice’s playhead position on-demand using:
This command will send the
voice identifier (
6) and its current playhead position through to a callback function:
9-query.lua, we use K3 to query the playhead’s position at the moment of press, which sends the data through the
event_position callback. The callback then sets the loop points to create a user-adjustable micro-loop.
If you simply wish to sync the playhead of one voice to another’s position, use:
softcut.voice_sync(dst, src, offset)
This command will set the playhead of a specified voice (
dst) to the position of another’s (
src), with an option for timed
offset (in seconds) between the two.
contributions welcome: github/monome/softcut-studies