also intruiged! the sounds are very rich - whole sound worlds indeed.

in like flynn in twenty characters

Oh yes, very nice. waiting for two rpis to arrive, and I will join via my DIY norns shield.

Oh I scrolled down and noticed the empty key and enc functions now! :blush:

1 Like

I hope I can make this my first Norns scripting experience. I am so keen to learn, time permitting. This device and community are gifts that keep giving. I hope to give back sometime

2 posts were merged into an existing topic: Norns: scripting

Started looking at this last night. Really impressed with softcut. Such an amazing and expressive tool. Planning a norns/circle/01 code haiku now. Also imagining scripts as whole instructions for songs in and of themselves.

1 Like

I’ve gotten the first bit of functionality down, minus an issue with levels, which you can reproduce with the code below:

-- K3 invert level

level = 1.0

function key(n,z)
  if z == 1 then
    if n == 3 then
      level = 1.0 - level
      softcut.level(1, level)
    end
  end
end

function init()
  file = _path.code .. "nc01-drone/lib/eb.wav"
  softcut.buffer_read_mono(file, 0, 0, -1, 1, 1)
  softcut.enable(1, 1)
  softcut.buffer(1, 1)
  softcut.loop(1, 1)
  softcut.loop_start(1, 0)
  softcut.loop_end(1, 3)
  softcut.position(1,1)
  softcut.rate(1, 1.0)

  softcut.level_slew_time(1, 10.0)
  softcut.level(1, 0.0)
  softcut.play(1, 1)
  softcut.level(1, level)
end

When the above script starts, it starts playing at full blast - I was expecting it to ramp up.
I then press K3, and get the 10-second slope until sound goes out, as I expected. Pressing K3 again, however, takes it straight back to 1.0, no slewing.

Is this the expected behaviour, or am I overlooking something obvious?

unfortunately we can’t presently guarantee that the slew and level commands are processed in the order they were issued, without a workaround like adding a short delay on the lua side.

here’s an example with short delay

-- K3 invert level

level = 1.0

function key(n,z)
  if z == 1 then
    if n == 3 then
      level = 1.0 - level
      softcut.level(1, level)
    end
  end
end

-- helper
function delay(func, time)
    if time == nil then time = 0.005 end
    local m = metro.init(func)
    m:start(time, 1)
end

function init()
  file = _path.code .. "nc01-drone/lib/eb.wav"
  softcut.buffer_read_mono(file, 0, 0, -1, 1, 1)
  softcut.enable(1, 1)
  softcut.buffer(1, 1)
  softcut.loop(1, 1)
  softcut.loop_start(1, 0)
  softcut.loop_end(1, 3)
  softcut.position(1,1)
  softcut.rate(1, 1.0)
  softcut.level(1, 0.0)
  softcut.play(1, 1)
  softcut.level_slew_time(1, 10.0)
    delay(function() 
    softcut.level(1, level)
  end)
end

i forgot that i promised @dan_derks i’d add a combined command for envelopes to make this use case easier, since he ran into the same thing in cheatcodes.

now that it’s on my mind i’ll look right now. there might be a simpler backend change i could make that would (at least) guarantee slew commands are always executed before level commands if they arrive in the same control period.

(and actually now that i’m debugging at this i’m not exactly sure why the slew isn’t taking effect first, since the commands are arriving in the correct order. so i’ll continue to look at it. would be nice if it’s simply a case of re-ordering some statements in the audio thread.)

long-term, i do have a design that will replace OSC for this transport layer and make everything more efficient and predictable. it’s on the list.

3 Likes

there’s another quirk to note about the level fades: they are simple 1-pole smoothers in the linear amplitude domain. as a consequence, fade-ins sound much, much faster than fade-outs.

actually, looking closely at this it’s worse than i realized.

the up/down ramps in the linear domain look like this:


but the real problem is that in the perceptual loudness domain (exponential), the exponential decay curve becomes linear, but the exponential attack curve is doubly exponential:


opened GH issue.

9 Likes

Wow, a picture is indeed worth a thousand words. Excellent stuff, thank you for taking the time to explain this.

Alright, so I have my first draft finished, and I’m pretty excited. But I have a question:
The way I’m changing filter frequency is pretty brute-force. Is there a way to slew it so the changes in frequency are smoother? maybe controlspec? I know it will do exp freq mapping, which will help a bit, but I am just wondering if there’s an additional way.

function enc(n,d)
    if  n == 2 then
          filter_freq = util.clamp(filter_freq + d*50, 500, 12000)
          softcut.post_filter_fc(i,filter_freq)
    end
end

EDIT: Question 2: I’m attempting to cycle through changing worlds with modulo. But my math is definitely wrong.

function key(n,z)
    if n == 3 then
    -- new world (mode_number from 1..3)
        if z == 1 then
            mode_number = ((mode_number + 1) %3) + 1
            print(mode_number)
        end
    end
end

makes the number decrement by 1 each time. If I do %6 or some number larger than 3, I see that the number is incrementing by 2 each time.
Am I wrong in thinking that the modulo should be applied first, and then scaled up by 1? ex. (x+1)%3 = 0…2 +1 = 1…3

no sorry, no smoothing on filters now, too expensive, may update, search around for details

qeuestion 2:

3 Likes

Thanks for going to the trouble of digging up your replies. I’ll try searching more first before I ask another question! Also, amazing work with softcut. It’s a real joy to work with.

yr most welcome.

also, i think you just want mode_number = (mode_number %3) + 1 - you were incrementing twice.

break down

x        -- in range [1, 3]
+ 1      -- maps to range [2, 4]
- 1      -- you need this to get back in range [1, 3] before taking modulo!
% 3      -- maps [1, 3] -> [0, 2]
+ 1      -- now back to  [1, 3]
2 Likes

just under a month to go!

curious to hear how people are doing— have the softcut studies been clear?

any questions we can answer? anyone need suggestions?

1 Like

I haven’t even started yet :grimacing: but I plan on getting things going tonight!

1 Like

me: if I have 4-5 hours to spend on Norns scripting I’ve got a ton of things to do to Kria and at least two other scripts that need to be finished and published

also me:

(the three worlds sounds a bit similar in that video but they aren’t - and they all bear quite long term listening - I’ve found myself just leaving it on)

I’m way too lazy to have gone through and curated loops etc - all three worlds are aleatoric systems that evolve over time - all seem kind of slow to respond to the controls in that video since they are designed to be slow moving but they have a strong influence over time!

It’s been a fantastic way of learning softcut!

Need to fix a stupid bug in the world switching and make the visualisations now

8 Likes

Was enjoying working on it until i stupidly broke my norns and had to ship it off for repair - i’m an idiot.

I referred a lot to the softcut studies and to scripts like MLR and Cranes/Cheat codes - i’d say these were more useful resources than the API documentation as i work better with seeing real use-cases. Will be super curious to dig into the repo when everyone pushes up their scripts!

1 Like

I think in general the API docs can be kind of mysterious until you’ve seen an example. I still ended up digging around in other peoples source code (but FULL marks to maiden for making that trivial - it’s a lovely environment to mess about in for the Lua side).

Essentially the studies are a good introduction but as soon as you want to go a bit deeper the docs are a little brief. On the other hand it’s so easy to look at source and examples it’s not too bad

(I probably should add that compared to an awful lot of things I’ve worked on over the years it is absolute luxury in terms of documentation. :slight_smile: )

1 Like