^^ crow: druid scripts

This is fantastic, @crim! I recently came over to Euro from livecoding (TidalCycles / Hydra / Orca) and had high hopes that Crow would bridge that gap.

I’m new to Lua but already getting some ideas from your script.

  • a second, related melody on outs 3&4
  • shift position, ie 1 becomes 2, 2 becomes 3, last becomes first - perhaps on subsequences
  • yank - inverse of copy, shortens the sequence by removing notes

Also, please think of a fun name to call this wonderful little sequencer

2 Likes

Thanks! I’m glad you like it. Yes I got lazy with the name :slight_smile: … I’ll try to think of something.

Yes I thought about this. I wasn’t sure if it should be an independent sequence, or somehow linked to the 1st sequence. If it’s linked, it could for example be a clock divided version of the 1st sequence with configurable rate, and maybe with options to change the playback direction (reverse, random, etc), or shift the steps by musical intervals.

Alternatively it could be a second independent sequence. This could be tedious if you had to indicate which sequence you wanted to edit for every command, but maybe it could also work by setting the “edit mode” dynamically, so if edit mode is 1, every command changes sequence 1, and if 2, commands change sequence 2. This is potentially the more powerful option, but there are pros/cons to both.

Your other suggestions should be easy to add. Maybe I’ll add a few more features and submit to bowery. It might need it’s own repo with documentation if it gets too complex though :slight_smile:

2 Likes

Despite the fact that I have plenty of LFOs, I chose a quad LFO as my Getting to Know Crow and Lua project. :man_shrugging: It’s a dual-clock quad LFO. I still have some more stuff I’d like to add to it, but since it’s at a useful state and seems to be more-or-less working as-is I thought I’d go ahead and post it now (since who knows when I’ll have time to add more stuff…).

Summary

  • Create 4 LFOs based on:
    • 2 clocks
      –OR–
    • 1 clock plus cv input for depth
  • timing for each clock can be based on a clock (trigger) input or cv input
  • each lfo has independent settings for:
    • clock source
    • waveform
    • skew (currently only sets duty cycle for square wave)
    • unipolar or bipolar output
    • time ratio to it’s clock
    • depth ratio to it’s clock
  • are constructed (not built-in) LFOs so they are able to change rate dynamically

Details on user settings hidden below (the script was getting kind of big and inline comments were causing problems…).

User Settings Guide

The following settings can be changed in the lua file or sent in realtime via druid (except for lfoInputs[n].type, which has to be set at run time).

Clock 1

lfoInputs[1].type – ‘clock’ or ‘cv’ (cannot be changed after run)
lfoInputs[1].depth – pole-to-pole depth (irrelevant if clock 2 set to depth)

Clock 2

lfoInputs[2].type – ‘clock’, ‘cv’, or ‘depth’ (cannot be changed after run)
lfoInputs[2].depth – pole-to-pole depth (irrelevant if type set to depth)

LFO Outputs 1-4

lfoOutputs[n].clockSource – 1 or 2 - selects which clock it follows
lfoOutputs[n].wave – ‘saw’, ‘sawdown’, ‘tri’, or ‘square’
lfoOutputs[n].skew – 0.0-1.0 - only sets duty cycle for square (for now…)
lfoOutputs[n].mode – ‘unipolar’ or ‘bipolar’
lfoOutputs[n].rateDivisor – sets ratio to the speed of it’s clock
lfoOutputs[n].depthDivisor – set the ratio to the depth of it’s clock

Sundry Setup

cvInputRange – applies to both cv clock and depth

(the following speeds are in cycle time, not Hertz, and apply only to cv clocks)
cvRateFastest – maximum speed of LFO
cvRateSlowest – minimum speed of LFO

cvRateCurve – applies a curve to cv input for clock mode clocks (2 seems pretty good, but try other values and see what feels best to you)
cvDepthMin – minimum mulitplier for depth type input (do not use negative values)
cvDepthMax – maximum depth multiplier depth type input

dual_clock_quad_lfo.lua (4.6 KB)

14 Likes

Made a bunch of updates to the sequencer thing I posted upthread, including a second random melody on outputs 3/4, as well as new functions mv (move sequence step to new position, effectively shifting the sequence to the right or left), mod (transpose part or all of the sequence by a scale degree), and ptrn (a sort of meta-sequencing function). Full docs are available in the readme on github if anyone is interested.

I had more ideas for it but it’s already pretty big and uploading to crow seems to be getting more unstable the bigger the file gets… I figure maybe it should be a norns script if I want it to get any more complex.

scrolls.lua (6.8 KB)

I also finally checked out the M4L devices today, and had a lot of fun using a random midi arpeggiator with the “macros” device to send this script different bits of lua. Here’s a generative little ditty featuring dualing DPO sine waves and a bit of reverse delay from Mimeophon.

13 Likes

Here is a “leaky histogram quantizer”, a script for generating random voltages that are sorta-kinda-maybe like recent input. It keeps a histogram of quantized voltages it has seen recently on CV input 1, then when it receives a trigger on input 2 it randomly samples 4 times from the distribution this histogram approximates, and sets each CV output to one of these samples. The histogram is “leaky” - histogram bins that aren’t being hit will gradually decay back to “empty”, making voltages that haven’t been seen recently less likely.

Some knobs:

  • set_scale(tbl_of_voltages) – change which voltages are legal for the quantizer, i.e. the bin values. You can use arbitrary voltages, the quantizer will choose whichever bin is closest to the input voltage. Currently I am mainly using it with scales specified in voltages, e.g. major = { 0 / 12, 2 / 12, 4 / 12, ... so it repeats the provided table 5 times, each an octave up. (default: major scale)
  • set_halflife(t) – set how long it will take a given bin to decay to half its value, assuming no further inputs land in that bin in that time. t is supposed to be in seconds (default: 30 seconds) but I might not have the calculation right.
  • monitor = true – when set, crow sends a visualization of the histogram content to druid once a second.
20 Likes

Sorry if this is stupid but will you be adding this to the Bowery collection?

Thanks!

Sure, I could do that, but I think I’d still like to refine it some and add some other parameters. For instance it would be nice to select (maybe per-output) whether the samples should be the same as bin values (more useful for pitch CV) or should be sampled randomly from the range of values that fall in that bin. Of course, it’s easy to update a script on Bowery, but I feel like I’m still experimenting with the idea a bit. If you want to try out this version you can click the “Raw” button on the GitHub page to get a version you can copy-paste, or equivalently right-click this link and select some option like “download link” in most web browsers.

1 Like

this seems super interesting. hope to get the chance to give it a try…thinking about feeding the input a sequence from Bloom, then slowly mutating the input sequence over time…:metal:

1 Like

Getting a [string "eval"]:1: <eof> expected near 'end' User script evaluation failed. error with the following simple code. is there something i’m missing here?

--- simple tuner/buff mult app. put a voltage into input 1, stream the value to druid and send voltage to all outputs
-- in1: tuning voltage
-- out1-4: duplicates of in1 voltage

function init()
	input[1].mode('stream', 0.01)
end

input[1].stream = function(volts)
	output[1].volts = input[1].volts
	output[2].volts = input[1].volts
	output[3].volts = input[1].volts
	output[4].volts = input[1].volts
end

I have the following set in sublime for tab size. Does crow expect a certain tab size?

// The number of spaces a tab is considered equal to
    "tab_size": 4,

Make sure you have a newline after the last line. It seems that it sometimes has a problem loading scripts if not. Also, I think it’s still better to set your editor’s newline setting for the file to be carriage-return/line-feed (if you’re on a Mac or Linux it will default to just line-feed, I believe PC already should be set to cr-lf). There was some talk of this being addressed in a Druid update, but I’m not sure this has happened or if it’s completely addressed the issue.

Also, sometimes a reset of Crow (^^r) before uploading the script can help.

Assuming your "translate_tabs_to_spaces" setting is false, it doesn’t matter. That just sets how tabs are displayed in Sublime. If it’s set to true it also doesn’t matter as far as Crow is concerned, but once you start writing longer scripts you may find all those extra spaces are pushing your script over the 8kb limit for script upload.

1 Like

Ah ok thanks for info!

I no longer believe line endings make a difference and tabs shouldn’t matter, but missing a line ending at the end of the file might. Personally I am most suspicious of the very long comment in the first line of the script causing some kind of problem, I will experiment with this script some and see what I can find. Certainly none of the above should be a problem but it may require some changes to druid.

I just copy+pasted your posted script into a text file & had no problem uploading it to my crow.

What version of crow firmware are you on? You can check by typing ^^v in druid. Also, what version of druid are you on? You can check by typing druid --version in Terminal.

I believe we fixed all the issues regarding long lines & carriage-return/newlines in the latest crow&druid. Tabs vs spaces doesn’t matter, and whether there’s a newline at the end of the script doesn’t matter.

@Oootini
This is beside the error message you’re seeing, but i don’t think the script will work due to using the argument name volts to the input[1].stream function. This argument will mask the existing behaviour of the input & output tables when using the key ‘volts’, instead trying to index into those tables using the actual voltage on the input jack. Something like this should do it:

input[1].stream = function(v)
  for n=1,4 do
    output[n].volts = v -- because v == input[1].volts
  end
end

OK thanks all for detailed and thoughtful info as always. It seems I was on an older dev version of druid, I’ve updated to druid, version 0.2.1. crow is ^^version(‘v1.0.1’).

With this config, If I upload the script without the final carriage return, I get:

[string "eval"]:13: 'end' expected (to close 'function' at line 11) near <eof>

If i add the final carriage return, the script loads successfully, but only after I run ^^c.

on another note - in the below updated script, only input[2] streams to druid, how can i make input[1] stream to druid and the outputs?

--- simple buff mult. put a voltage into input 1, stream the value to druid and send voltage to all outputs
-- in1: tuning voltage
-- out1-4: duplicates of in1 voltage

input[1].stream = function(v)
	for n=1,4 do
    output[n].volts = v -- because v == input[1].volts
  end
end

function init()
	input[1].mode('stream', 0.01)
	input[2].mode('stream', 0.01)
end

anyway. this works pretty well for what I wanted to do - compare v/oct tuning between various oscillators.

Thanks for the details! I’ll try and reproduce again. Which OS are you running? To clarify, when you say “add the final carriage return” does that mean you’ve added a blank line at the end of your text file?

re: streaming to druid
This works by using the default event for input[n].stream. When you redefine input[1].stream that stops sending the value to druid, instead using the value in your script. You can work around this by adding the default action from the input library to your event:

input[1].stream = function(v)
  crow.tell('stream',1,v) -- sends the voltage to druid
  for n=1,4 do
    output[n].volts = v -- because v == input[1].volts
  end
end

Or you could use a metro instead and leave the input event untouched:

function set_outs()
  for n=1,4 do
    output[n].volts = input[1].volts -- need to query the input lib again
  end
end

function init()
  input[1].mode('stream', 0.01)
  input[2].mode('stream', 0.01)
  m = metro.init(set_outs, 0.01)
  m:start()
end
2 Likes

:slight_smile: I’m on window 10. Yes - I’ve added the final blank line.

image

Thanks for stream details.

1 Like

this is a very simple chord voicing script for crow. trying to understand lua and what is possible. also my math might be off :confused:

chord.lua
--- generate a chord from a single input 
-- in1: gate in
-- in2: chord root quantized to v/oct 
-- out1: chord root
-- out2-4: chord degrees from root
--3 note chords also have an octave below root on out4.

maj = {1,4,7,-12}
min = {1,3,7,-12} 
dim = {1,3,6,-12}
maj7 = {1,4,7,11}
min7 = {1,3,7,10}
dom7 = {1,4,7,10}
sus2 = {1,2,7,-12}
sus4 = {1,5,7,-12}
aug = {1,4,8,-12}

--set the chord to play. also change this from druid.
chord = min7

--clock in
function init()
	input[1]{mode = 'change', direction = 'rising'}
end

--build the chord
input[1].change = function()
	--get the voltage from input 2
	v = input[2].volts
	
	--get the chord degrees, /12 to get semitones in v/oct
	ii = chord[2]/12
	iii = chord[3]/12
	iv = chord[4]/12
	
	--output the chord
	output[1].volts = v
	output[2].volts = (v + ii)
	output[3].volts = (v + iii)
	output[4].volts = (v + iv)
end

chord.lua (942 Bytes)

10 Likes

I’ve not tried it yet but I’m reading through the Boids script and it’s blowing my mind. This module is so exciting.

I was messing around making a Krell patch (I’ll share that later…) where I wanted some more control over the weight of the randomness than a simple exponential curve. I figured other people might find the curve function useful so I put together a simple example script. In addition to the min/max value settings, the method has three parameters that control how the randomness is weighted, each an integer value 1 -6:

  • curveLevel - higher values make a steeper curve favoring one end
  • bellFactor - higher values focus the curve more sharply in the middle
  • direction - which end the curve favors - up or down

Here’s a chart that will hopefully help make sense out of how the curveLevel and bellFactor interact.

Click to see chart


Here’s the example script. It doesn’t do anything interesting, it just has a metro sending random voltage out of output 1 based on the settings. Connect output 1 to an oscillators pitch and you can hear how the curve sounds as you adjust the values (curveLevel, bellFactor, and curveDirection) via druid.

curvedrandom.lua (1.1 KB)

5 Likes