(norns/circle/01) drone in three worlds

a gathering— a group study where participants each create a script according to a prompt. scripts are submitted by an established deadline. discussion and help will be provided to facilitate completion of scripts.

this series will focus on softcut. for an introduction, see softcut studies. for general norns scripting, see norns studies.

upon completion we will release the pack of scripts as a collection along a bandcamp compilation of captures from each script.

we’ll be here throughout the process to assist everyone in getting scripts working. please ask questions— this is an ideal time to learn.

future prompts will have different parameters. don’t go overboard building out your script with extra functionality— try to stay close to the prompt.

norns/circle/01 drone in three worlds

create an interactive drone machine with three different sound worlds

  • three samples are provided
  • no USB controllers, no audio input, no engines
  • map
    • E1 volume
    • E2 brightness
    • E3 density
    • K2 evolve
    • K3 change worlds
  • visual: a different representation for each world

build a drone by locating and layering loops from the provided samples. tune playback rates and filters to discover new territory.

parameters are subject to interpretation. “brightness” could mean filter cutoff, but perhaps something else. “density” could mean the balance of volumes of voices, but perhaps something else. “evolve” could mean a subtle change, but perhaps something else.


deadline: march 1

  • submit your script by submitting a PR to github: https://github.com/monome-community/nc01-drone (we will help with instructions when the time comes, or feel free to submit early)
  • record 2-6 minutes of the output of your script using TAPE. feel free to use the built-in reverb. upload to google drive, dropbox, etc. post link on thread.

to get started, go to maiden’s project manager, refresh the collection, and install nc01-drone. note, this will take some time to download as it includes some audio files.

if you need a hint getting started, check out seeker.lua

-- seeker (nc01-drone)
-- @tehn
--
-- E1 volume
-- E2 brightness
-- E3 density
-- K2 evolve
-- K3 change worlds

function init()
  file = _path.code .. "nc01-drone/lib/dd.wav"
  softcut.buffer_read_mono(file,0,0,-1,1,1)
  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.rate(1,1.0)
  softcut.play(1,1)

  print("approaching...")
end

function enc(n,d)
    
end

function key(n,z)

end

function redraw()
  screen.clear()
  screen.move(64,50)
  screen.aa(1)
  screen.font_face(4)
  screen.font_size(50)
  screen.text_center("3")
  screen.update()
end

does that not look easy? i’ll slowly build on this script weekly, if you’d like to follow along.

63 Likes

phenomenal idea

i will to make my first scene based on this

3 Likes

love this idea! this feels like a perfect opportunity to get started with scripting for norns.

4 Likes

Excited for this, thanks for setting this all up!

1 Like

this sounds like a lot of fun! :partying_face: :partying_face: :partying_face:

2 Likes

I can’t get the script to respond right now. It generates a drone and the screen shows the number 3, but even with no device plugged in it does not change volume, brightness, density, evolve, change worlds etc.

I want to evolve and change worlds, that sounds delightful!

Edit: Oops! I get it now. This is such a great idea!

2 Likes

Excited to participate in this. I’ve spent too little time with softcut.

1 Like

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.

2 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.

7 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