Norns 2.0: softcut

here’s an alternative take/syntax:

function init()
  params:add{id="rate12", name="rate12", type="control", 
    controlspec=controlspec.new(0.5,4.0,'lin',0,1,""),
    action=function(x)
      softcut.rate(1,x)
      softcut.rate(2,x)
    end}
end

rates = {0.5,1,2,4}

function rateN()
  params:set("rate12", rates[math.random(1,4))
end
2 Likes

Thanks! I think this is doing the trick.

Hello,

I’m trying to get my head around the wonderful norns.

Coming to it from a background of using Supercollider, primarily for the processing of live audio, I’m looking right now at whether I can actually simply use softcut and lua.

I have a few - hopefully simple - questions.

Am I right in thinking that 1.0 as a softcut.position / softcut.loop_start is actually 0.0 seconds in terms of the soundfile ? In your annotation soft cut.loop_start(1,1) is noted as start @ 1.0s, similarly for position. But when I use these values my file plays from the top, not one second in.

How does one get information on the soundfile ? I’ve tried using audio.file_info but get blank values, e.g. duration: nan sec

Is fade the equivalent of attack and release times on an envelope ?

I’ve tried experiments to determine the answer to these questions but am still not quite sure !

Thanks,

Jem

2 Likes

Hello,

A question about modulating level:

I’m trying to modulate a voice’s level from 0 to 1.0 over a period of time. I assumed that softcut.level_slew_time would do this in the same way that softcut.rate_slew_time modulates between two rates (as in softcut studies 2-multi.lua).

Is this correct ? I can’t get it to work.

Thanks,

Jem

I thought this as well. I had to dig into the code (see: SoftCutVoice.cpp) before I realized that the level slew time applies to a voice’s record and feedback levels, rather than its output level.

Coincidentally, it dawned on me yesterday that this does provide an effective level control, but you have to use an additional head to accomplish this. I haven’t tested it yet, though.

OK, thanks. That’s one mystery solved.

So . . . is there a simple ramp one can use to modulate or does one have to make one with metro and / or controlspecs ?

Not that I’m aware of. The API, while pretty comprehensive, seems to encourage routing over modulation.

Actually, this doesn’t make sense. 2-multi.lua (in softcut-studies) is an example that seems to be written to demonstrate slewing rate and level. But the levels don’t slew. Is this a bug ?

oh yikes, there is a very strong chance I got this wrong in study 2, let me fix the mess

1 Like

right, levelSlew applies to pre and rec levels only. i agree this is misleading, sorry.

per-voice output and pan levels do have slew but there is presently no parameter to set the slew time for either. that’s in some sense an oversight, in another sense it’s just a feature that no-one has asked for before. such params can be easily added. same for general mixer levels.

created issue here, suggestions/PRs welcome

can you share your code? i’m confused about the use of “soundfile” here. loop start/end and positition are set in seconds, zero is top of buffer, i’ve never seen a problem with this.

i guess so; it is the length of an equal-power (raised-cosine) crossfade applied at loop points and when setting position explicitly. playback begins precisely at the loop start position or requested cut position, but it takes [fade] seconds to reach full volume. likewise, fadeout starts precisely at the loop end point. so effectively, there is post-roll but no pre-roll.

Thanks @zebra.

Regarding start points I have realised where my confusion lay - looking at 1-basics.lua the sound file is being loaded into the buffer starting at 1 second:

-- buffer_read_mono (file, start_src, start_dst, dur, ch_src, ch_dst)
  softcut.buffer_read_mono(file,0,1,-1,1,1)

So if I then tried to play back from position 0 second I heard a second of silence.

And thanks for the clarification over fade and the levels parameters. I’ve commented on the issue you created.

I think the confusion is with start_src and start_dst. Try

sofcut.buff_read_mono(file, 0, 0, -1, 1, 1)

start_src is where your source material starts in your audiofile.
start_dst is where it will start in your softcut buffer.

Thank you, exactly. Obvious really !

Would you happen to know how to get the duration of a file you load into a buffer ? I am having no luck with

function print_info(file)
  if util.file_exists(_path.dust..file) == true then
    local ch, samples, samplerate = audio.file_info(file) -- FIXME: audio.file_info uses audio path???
    local duration = samples/samplerate
    print("loading file: "..file)
    print("  channels:\t"..ch)
    print("  samples:\t"..samples)
    print("  sample rate:\t"..samplerate.."hz")
    print("  duration:\t"..duration.." sec")
  else print "read_wav(): file not found" end
end

Maybe the FIXME has yet to be fixed. I am just getting blank values, e.g. duration: nan sec.

where is your file located? it’s probably a path problem.

i’ll submit a fix for audio.file_info() as the current behavior is somewhat inflexible

The path is

file = "/home/we/dust/code/softcut-studies/lib/whirl1.aif"

post window says

read_wav(): file not found
  • if I change the file path to
file = "/code/softcut-studies/lib/whirl1.aif"

then post window says

loading file: /code/softcut-studies/lib/whirl1.aif
  channels:	2
  samples:	215941
  sample rate:	44100hz
  duration:	4.8966213151927 sec

but file doesn’t play !

  • If I change
if util.file_exists(_path.dust..file) == true then

to

if util.file_exists(file) == true then

and use the original full path above then the post window says

loading file: /home/we/dust/code/softcut-studies/lib/whirl1.aif
  channels:	0
  samples:	0
  sample rate:	0hz
  duration:	nan sec

and the sound file plays.

I hope that helps !

1 Like

thanks for the details. i’ll need to fix audio.file_info() right away.

It looks like audio.file_info() prepends /home/we/dust/ to whatever path you pass it. This makes it hard to get info about files loaded with add_file type params.

So, with…

local function load_sample(file)
  softcut.buffer_clear()
  softcut.buffer_read_mono(file, 0, 1, -1, 1, 1)
  print(audio.file_info(file))
end

params:add_file("sample", "SAMPLE")
params:set_action("sample", function(file) load_sample(file) end)

audio.file_info(file) will fail because file contains the full path already.

file_info: /home/we/dust//home/we/dust/audio/tape/0003.wav
0	0	0

there is a PR open to have audio.file_info use absolute path instead. will merge and release update within a few days, and also address fixes in mlr etc

2 Likes

Is there an annotated version of the github soft cut syntax somewhere? I’m trying to diagnose some distortion and sizzle, and I’m having a hard time understanding the gain staging in the signal path, which parameters to adjust, and by how much.

Thanks!

annotated? not really

i’m going to do a deep test/fix session on the gain staging and meters. probably tonight…

oh, one thing to note is that inputs to each softcut voice are softclipped before writing to the buffer. so the input gain matrix for each voice is probably the first thing to check.

1 Like