The command is described and a link to the source code on github is given in this documentation page for the First script.

1 Like

It’s also documented in the list of command (which maybe should be on it’s own page linked from the crow startpage? It’s not very discoverable where it is now)

1 Like

If you were going to live code a square wave lfo, how would you do it? I’ve got it working with metro with pulse, but is there any way to do it with ASL? Or even just a simple For loop? I feel dumb at the moment.

A for loop won’t do it because you need something to manage the passing of time. The two options are a metro (or delay), or an ASL.

Since 1.0.3 you can simply use the lfo function like:

-- assign an LFO to out1 with duration of 0.1s, 5V scaling & square shape
output[1].action = lfo( 0.1, 5, 'now' ) -- assign it
output[1]() -- start the LFO

-- or execute it immediately
output[1]( lfo( 0.1, 5, 'now' )

Or in pre 1.0.3 ASL:

output[1].action =
  loop{ to(5     , 0)
      , to('here', 0.05)
      , to(-5    , 0)
      , to('here', 0.05)
      }
2 Likes

My first actually useful script: a 4-way modulation source with inputs for rate and shape. Outputs are sine LFO, shaped LFO, stepped random, and slewed random. And open to feedback in general. First time with Lua as well.

I’m having a bit of an issue with some runtime errors due to how I’m handling deriving LFO rate from clock. It works despite those errors, but definitely interested in how I can better handle this part.

Summary
-- Input 1: Rate for both LFOs (Clock)
-- Input 2: Shape for LFO 2 (0-5V)
-- Out 1: Sine LFO (Bipolar)
-- Out 2: Shaped LFO (Bipolar)
-- Out 3: Random at clock rate (Unipolar/Bipolar)
-- Out 4: Slewed, distinct random at clock rate (Unipolar/Bipolar)

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

-- [[	USER DEFINABLE    ]]--
out1Lev = 5			-- Out 1 Level (5 or 10)
out2Lev = 5			-- Out 2 Level (5 or 10)
out2Mult =	1		-- Mult Out 2 by N. Resets on Clock
out4Slew = 0.1 		-- Out 4 Slew
out3Pol = 5 		-- 0 for Unipolar 10v, 5 for Bipolar 5v
out4Pol = 0 		-- 0 for Unipolar 10v, 5 for Bipolar 5v

-- [[	SHAPES    ]]--
-- < 1V - Sine
-- 1-2V - Lin
-- 2-3V - Log
-- 3-4V - Exp
-- > 4V - Rebound

input[2].stream = function(v)
	if v < 1 then
		dynShape = 'sine'
	end
	if v  > 1 and v < 2 then
		dynShape = 'lin'
	end
	if v > 2 and v < 3 then
		dynShape = 'log'
	end
	if v > 3 and v < 4 then
		dynShape = 'exp'
	end
	if v > 4 then
		dynShape = 'rebound'
	end
end

-- [[	INPUT 1 CLOCK    ]]--
input[1].change = function(s)
	--Output 1 and 2
		--Calculate delta between peak to trough
		--How to deal with initial nil values?
	
	if s == true then
		t1 = time()
	elseif s == false then
		t2 = time()
		rateMs = t2 - t1   
		--print(rateMs)
		rateSec = rateMs/1000
	end
	output[1](lfo(rateSec, out1Lev, 'sine'))
	output[2](lfo((rateSec * out2Mult), out2Lev, dynShape))

-- [[	RANDOM OUTS    ]]--
	rand1 = math.random() * 10.0 - out3Pol
    output[3].volts = rand1
	rand2 = math.random() * 10.0 - out4Pol
	output[4].slew = out4Slew
    output[4].volts = rand2
end
7 Likes

Some fun with math. Inputs 1 and 2 are CV signals. Outputs 1-4 are the result of some math function on this inputs. Easily expandable with new functions (very open to ideas of fun stuff to add). Also, if anyone has any ideas how I could define functions in real time, hit me (i.e., while the script is running, redefine output[4] as max() instead of div().

Summary
--Input 1 - CV 1
--Input 2 - CV 2
--Output 1-4 - Defined math functions

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

--Clamps outputs to +peak/-5
peak = 5
function clamp(n)
	return math.max(math.min(n, peak), -5)
end

--MATH FUNCTIONS
	function sum()
		return clamp(a+b)
	end

	function dif()
		return clamp(a-b)
	end

	function mult()
		return clamp(a*b)
	end

	function div()
		return clamp(a/b)
	end

	function min()
		return clamp((math.min(a,b)))
	end

	function max()
		return clamp((math.min(a,b)))
	end

input[1].stream = function(v)
	input[2].stream = function(v)
		a = input[1].volts
		b = input[2].volts
		
		output[1].volts = sum()
		output[2].volts = dif()
		output[3].volts = mult()
		output[4].volts = min()
	end
end
3 Likes

I’m preparing for a livestream this week and just had a major ‘A HA!’ moment with this script. I’m still really confused in lua, but this script was so easy to turn into a clock divided quad LFO. Just wanted to say thanks for this great utility script.

1 Like

Would it be easy to add the new asl sine wave lfo function to this script?

function lfo( time, level, shape )
time,level,shape = time  or 1
                 , level or 5
                 , shape or 'sine'

local function half(t) return asl.runtime( function(a) return clamp(a/2) end, t ) end

return loop{ to(        level , half(time), shape )
           , to( negate(level), half(time), shape )
           }

end

I’m basically looking for an easy way to set up 4 clock divided sine wave lfos. I’m still very new to messing with code but it seems possible?

Not sure which script you’re referring to? The ‘new’ lfo is the old one, it just accepts an optional third parameter for ‘shape’. If the script you refer to uses lfo() anywhere it should automatically use ‘sine’ by default.

If you just want 4 lfos with matched frequencies, you could try something like:

function init()
  for n=1,4 do
    output[n]( lfo( 1.0 / n ) ) -- results in 1s, 500ms, 333ms, 250ms
  end
end

function reset() -- to synchronize lfos
  for n=1,4 do
    output[n]()
  end
end
6 Likes

Thanks! I was trying to reply to @voidstar about his modes.lua script and adding sine wave lfo’s to that as an option. Still trying to wrap my head around things but it’s all starting to make a kind of sense :face_with_monocle:

Fantastic in its simplicity!

I’m wondering if there is a way to get an output to hold or hang at its current voltage when input 2 sees a high gate. In the S&H bowery scripts, they’re calling a math random function rather sampling an input at the time of being triggered.

To freeze an output you have to unset any active ASL. The easiest way to do that is:

output[n].volts = output[n].volts -- set destination to current voltage

This works because output[n].volts returns the current voltage at the output jack (not the destination).

2 Likes

is it possible to have 2 different id’s for 2 x Just Friends so they can be used seperately within the same script.

1 Like

Has anyone already worked on a quantizer script for just intonation? Just started messing around with different tunings and crow seems to be capable of doing this. :pray:

1 Like

Hi everyone,
I’ve been exploring crow by writing my first script, a stand alone clock with inputs to control tempo and swing with cv. I thought using a metro[] would be the best approach, but after failing to figure our how to dynamically change metro[].time I am not so sure. I have all the code to take volt from an input and convert it to time, and when I print that to druid it all works. I just can’t seem to figure how to make metro[] take the new value.

I found the following note within metro.lua:

– NB: metro time isn’t applied until the next wakeup.
– this is true even if you are setting time from the metro event;
– metro has already gone to sleep when lua main thread gets
– if you need a fully dynamic metro, re-schedule on the wakeup

If I still wanted to use metro[], what would be the way to do it? Or should just attempt to write this some other way (asl I suppose)? Thanks in advance for any pointer anyone may have.

you can’t currently change metro.time without triggering the metro again (which means it just runs very very fast)

If you build and install the latest firmware from git it works just fine (@Galapagoose fixed it around the time of his live stream demonstrating the technique I guess) - otherwise you’ll just have to wait for the new update

It’s pretty easy to build though - you just need to the arm dev compiler from arm.org

1 Like

There’s no need to build it yourself if you just want to run from a branch or current master, the firmware gets automatically built for every commit.
To get there click the checkmark next to the commit, click details and top-ish right is an Artifacts dropdown that contains the bin.

Note that running unreleased versions comes with obvious warnings, it’s not a release so no guarantees, although no one obviously intends to break anything :wink:

3 Likes

nice! didn’t spot that. ( I have all the tool chain installed anyway so just did what was obvious to my mind :slight_smile: )

Is there a date planned for the next official release? I guess I should jump on the latest dev build. The quantize feature looks pretty fun.

We should do a 1.1 release soon. Some of the features are still experimental, and I always want to finish ‘one more thing’, but the current master branch is a big step up from the last release.
Happy to continue this discussion on the Crow github issue tracker.

6 Likes