^^ crow 2.0+ help: general (connectivity, device q’s, ecosystem)

the easiest thing to do is just call the time() function which returns the number of milliseconds since booting up.

1 Like

Help! I just started with Crow two days ago, and it was working fine, but after trying to “get” the value of the jf time knob (which worked for a few loops), I am now no longer able to get/set ANY data from JF! It always returns “nil”.
I already:

  • uploaded First instead of my script
  • switched out i2c wires in my case, as well as chose different connectors in the case
  • updated JF to the last version
  • powered my case up several times
  • dis- and reconnected Crow several times
  • connected the i2c of JF to the i2c of the W next to it, instead of in the case
  • connected the W next to it through the i2c connectors of Just Friends, W still works/JF still does not…

JF is fine and functional without i2c, it just does not respond to ANY commands from Druid anymore. I hope someone can help me. Of my two w’s I AM able to get/set parameters.
I bought my JF at SchneidersLaden just two months ago or so.

EDIT: OK, after doing a factory reset (this page at the bottom: JF: Latest Version – WHIMSICAL RAPS)- AND rebooting, it seems to be BACK! :slight_smile:

1 Like

Back with some additional questions; this time about metros! I put together a small system this weekend and started writing a new control scheme using a pair of crows with a couple of TXi’s and a couple Switchblades. It’s an experiment to see if I can distill the ideas in my system down to a tight set of controls for two voices and drums. I had some questions about how I am approaching things, so I wanted to sanity check some stuff.

Firstly: A metro with count = 1 seems to remain is_running = true after completing its run? Is this intended behavior? I would assume it would be false. (The docs don’t mention this attribute. It seems like it could be useful for people to know? I assumed it would exist, and found it in the lua source.) Also is_running is nil unless you call start or stop at some point, even though my impression was that metros were pre-allocated? I’m manually stopping then re-starting the timer and using is_running to detect (code below).

Another general crow coding question: For more complex behavior, is a robust function closure better/worse/the same as having it call a function in the script? (Which I guess is to say, I don’t know lua’s guts, so I’m not sure about best practices related to performance on something that’s called with high frequency like a fast metro.) Similarly, I have read that local variables tend to be preferable. Is it worth scoping the contents of a metro to local?

I implemented some stuff with “tapping”, a tap tempo master clock with a press and hold for a duration to stop and reset the clock. I also have a tapped in clock divider (kind of like Tempi). To do the long press, I decided to use metros, as that seems to be the way crows prefer to do something later. Mostly asking for a code review to see if this is a fine way to do this kind of behavior for crow.

the clock divider code

This bit is in my init:

metro[2].event = function(e)
      setClockDivider(1)
    end
    metro[2].time = 0.4
    metro[2].count = 0
    metro[2]:stop()

	metro[3].event = function(e)
      setClockDivider(2)
    end
    metro[3].time = 0.4
    metro[3].count = 0
    metro[3]:stop()

The inputs are detecting rising change, which then calls this:

function countCounterTap(index)
    	-- print(index)
    	if (metro[index+1].is_running) then
    		metro[index+1]:stop() -- reset averaging timer
        end  

	counters[index] = counters[index] + 1
	if (metro[index+1].is_running == false) then
		metro[index+1]:start()
    end
end

function setClockDivider(index)
	if (metro[index+1].is_running == true) then
      metro[index+1]:stop()
    end
    if (counters[index] < 2) then
    	dividers[index] = counters[index]
    else
    	dividers[index] = 2 ^ (counters[index] - 1)
    end
    
    counters[index] = 0
    -- print(dividers[index])
end

Another question: I’ve been keeping pretty robust comments, but I noticed comments contribute to maximum script length. Is there a nice way around this? I started removing comments to make room for functional code which isn’t ideal.

1 Like

The behaviour you’re seeing is ‘expected’, though I agree it’s not ‘desired’. The is_running is only accurate for ‘endless’ metros (ie count = 0). The Metro lib is one of the only things pulled in directly from the norns project - I just checked that codebase and it appears the behaviour is identical on norns too.

We could add it, but it would require another callback from C into Lua. The norns-style clock library is coming to crow in a new update, which I imagine might be a better fit here in future anyway.

From a memory perspective it is substantially more intensive to create a closure (which essentially creates a new function & an attached table every time it’s called). Conversely though, using closures is sometimes unavoidable, and other times makes the code far more readable. eg. ASL is a big stack of nested closures and it runs just fine.

I always favour readability, especially in a top-level script. I’d only think about optimization if you’re seeing performance issues, out-of-memory errors, or you want your code to be included as part of a library.

Optimization ideas

If you are seeing issues, the first thing (as always), is to profile the system. Try and understand what the bottleneck is, and focus on that.

Crow is far more sensitive to memory issues, than CPU (it runs at 216MHz (fast!) but only has ~155kB of userspace RAM available (very little)). You can check how much RAM is in use by Lua with print( collectgarbage 'count' ) which returns current memory use in kB. A fresh crow environment uses 100kB for the standard libs, but as long as you’re under 150, everything should be fine.

Lua is garbage collected, and on crow we have it set to be very aggressive. The only way to exhaust the memory is to try and allocate something that is bigger than can fit in RAM, or (for eg) building a table as a merge of 2 other tables (the total of all 3 must fit in RAM). In any other case, if there’s not enough memory, Lua will run the garbage collection until there is, or until there’s nothing to collect and throw an error.

On crow we never really call to Lua faster than 1500Hz (=667uS) which is actually not that fast in the context of the rest of the system (eg DSP processing), so don’t be afraid to push it!

While there is probably a performance difference, it’s likely negligible when compared to the choice of named function & table vs closure. The big reason local is preferable is you can use any name you want, meaning you don’t have to worry about trampling some global you don’t know about / forgot.

This is correct for now. The clock library will likely be preferable in more complex cases like this.

I read through the code you posted but I don’t really get it. Typically a clock divider just uses the count argument from the metro callback with a if (count % n) == 0 then <clock divided event> end. I’m sure there’s a reason you’re doing something more complex, but it’s not clear to me from the code you posted. Perhaps you could explain why the current metro system isn’t able to express your desired behaviour?

This is true, and it’s because we wanted to provide the ^^print command to query the current script. In that context it seemed ideal to return the script as it was entered, not stripped of comments and whitespace etc.

That said, I’ve started to see more people like yourself pushing the 8k character limit. We could add support to strip comments on upload, but this would require a separate implementation on each host platform (druid, norns, max).

I’m going to experiment with increasing the maximum script size. I’ll aim for 16k but I think even 10k could give a substantial buffer. It seems that 8k is almost enough for these big scripts. I’m always happy to code review if you’re looking for ways to refactor existing scripts.

3 Likes

i’m not a teletype user, so never really looked into txi and txo. are they basically open i2c modules that can be configured to be used with other (than teletype) i2c compatible modules? how do you use the txi’s and crows together? looks like a really neat system!

Thanks, as always, for your thorough response. I’m sorry my example wasn’t a bit more transparent:

The divider in question is receiving it’s clock tic (1-16) from the “leader” crow, which is actually managing the clock. The first crow is running the “Grids” like drum script I posted elsewhere with the addition of a tap clock to make it self-driving. The tap clock code is similar but longer, so I took the simpler code from from the “follower” crow – which is doing more complex stuff: recording a pattern of voltages and triggers and then mixing that trigger pattern against a ^2 clock divider (the tapping code posted above) with a TXi knob (emulating behavior similar to Noise Engineering’s Confundo Funkitus). I’m doing that twice, for two voices, letting me increase or decrease the complexity of the recorded pattern.

I’m happy to share the full code later, but mostly I was just trying to get a sense of whether using metros to detect short and long presses as a “timeout” for a behavior - knowing a series of taps has completed or knowing a long press has occurred is a good “crow” way to do things: like calling stop and start again using is_running as means of reset and managing my timings. I haven’t seen much discussion on such usages, so I wanted to check and hoped it might be informative to others.

Right now, the issue is that I have a ton of i2c traffic, but I also need to update the crows to use the newer faster i2c rate to see how that effects things. It’s hard to troubleshoot, but I effectively need the crows to poll the TXi’s as fast as possible without causing the bus to overload (I’m effectively just adjusting the metros in ~0.01 second amounts to try and find the limits as I add features), which is tough because there are 4 devices that all need to share, though most of the traffic is between each crow and its respective TXi partner - the clock tick you suggested previously is the only inter-crow communique.

I desperately wish there was a way to be able to just treat the TXi inputs like the crow inputs (“TXi, tell the crow the input went high!”), but in lieu of totally rewriting the TXi firmware as part of this experiment, I’ll have to settle for very fast polling times for now (trigger detection). It’d also be nice if one didn’t need to request each input on the TXi rather than just being like, “TXi, give me your 8 values!” and then processing those. As requesting each param and in is obviously more onerous on the network traffic.

But the ecosystem is what it is.

Something that might be helpful is to detect comments and count both lengths, if that’s not a herculean lift. That way the comments can remain for ^^print, but then we’re coding against a real “script length” rather than a simple character limit - this was actually my assumption. :sweat_smile:

I think without additional devices, you need to think really outside the box (or like, hard coding huge sequences) with the two inputs to push 8k. I haven’t gotten into envelope land yet myself though, but ASL seems concise. I have 3 crows (one in a separate case), and I find working with them to be wonderful. It’s hard for me to express how much I love crow, and really I want a super crow - a raven - that has more i/o.

extended thoughts on crow

I’ve seen some comments occasionally where people seem to see it as an expensive and glorified utility module, and there is some truth to that, but it’s hard to appreciate that it can do anything in a very easy to understand way - if you have even moderate lua or ECMA-like programming experience. I find teletype inorganic to how I think, but crow is perfect (I still like teletype, but I fight against how it works).

In a world like modular, two inputs is tricky: a clock or trigger, and something, two cv signals, a couple of triggers. There is a lot you can do there, but I find I run out i/o every quickly even with this setup of two crows and two TXi’s. The way crow works is rad as hell, I just want more to work with. To me, crow feels like the start of the music cyberdeck I want.

The down side is they are quite expensive because they need to be able to do so much, but at the same time, when you have a second one acting as a glorified i/o expander, it’s easy to imagine building quite an expensive little rig! That said, if you can modularize the way you think about what the crows are doing, you can distribute the actual work they’re doing in the system. That said, in my case, I’m really considering the system I’ve been refining, and considering how I might implement that myself in a more focused and compact way. That’s really the experiment here.

Maybe a norns could get involved, maybe I’ll need more crows. This is really the first step in that experiment, as it’s what I’ve got to work with. And it’s a good proof of concept anyway! I’m not sure how many people have been using modular to build a specific system rather than an “experiment box”, but crow has a ton to offer folks who want an easy way to try radically specific ideas without buying a mess of modules just to try out an idea.

They are not configured, they are followers on the i2c network. So the notion is you “call” to them and they report back a value. The limit is your imagination. Essentially you get additional input and outputs for i2c devices - with TXi and TXo respectively (I have an unfinished TXo, but haven’t needed it yet). They’re not identical to an onboard i/o, but they expand your options if you enjoy designing music systems. The downside is that DIY and used are your only options for them, as no one is regularly producing them as bpcmusic’s life seems to have busied them away.

2 Likes

(also @Galapagoose )
on norns, the metro.is_running field is dead code. i’ll remove it for now, and maybe fix+doc in future. (metro needs a little TLC in any case.) the

(under the hood, there is no mechanism for the C layer to update the lua layer when a finite-length metro sequence completes. dunno how you want to handle it on crow.)

A quick question: can I sync Ableton (leader) to my euro main clock (Pam’s) with the Crow? I assume it’s possible. Do I need to use Max for Live to do this? And would this take 1 or 2 of the outputs of Crow? Pam’s is kind of tricky to sync because in some setups it needs a clock in and run in signals.

Just wondering if I can use Crow for this or if I should buy a dedicated midi-to-cv device for clock syncing purposes.

start by checking if your audio interface has dc coupled outputs. if so, you can use ableton’s cv tools to send out run and clock signals directly to pam without the need for any module. more fun to keep your crow free for other things!

if not, the easiest way is to use crow-m4l to sync ableton with pam via crow. i think you have to set it up to send a clock on one output via the ^^outs device, and a manual midi note run signal out on another output via the ^^trigs device.

Unfortunately my Kmix doesn’t have dc coupled outputs :frowning: That would’ve been a really handy solution!

Thanks for the info about the Crow m4l integration. Cool to know it should be possible. But you’re right, it would be more fun to use Crow for other purposes! :smiley: I’ll have to see if I can find some other handy way to make the sync work. Right now I’m using a Keystep to translate midi clock to cv but there is an issue with Pam’s starting at slightly different times every time I start Ableton clock. I’ll need to do more research on midi-to-cv syncing.

1 Like

Another way to sync with Ableton is over Link. The new Missing Link from Circuit Happy puts Link in your rig in only 2hp:

This also lets you sync with other Link-enabled devices, such as iOS or Android…

I’m getting one soon :sunglasses:

2 Likes

I put my crows on the most recent update, and I feel like I am seeing errors from network flooding more often than on whichever version I was using before? I somewhat expected the faster bus speed to improve capacity for high speed poling, but I also may not understand what increasing ii transmission speed actually does. Should the increased transmission speed allow for better traffic handling?

Could you be more specific about what kind of errors you’re seeing? And could you try and quantify how much more often?

I’m sure you’ve mentioned before, but can you remind me which devices you are querying? If you had a minimal reproduction script, that would be fantastic so I can do regression testing.

1 Like

It’s the system pictured above: The bus is two crows and two TXi’s. (Mostly being fed 5v+ tap inputs or v/o.) I find when I start polling too fast, I get ii: lines are low errors streaming on repeat. It seems to happen after playing with the scripts for a while (cannot really guess at the moment on how long), it’s too new to know for sure. I’ll try to note it as I continue to develop these. I believe I was getting this behavior before if I set either crow’s polling speed to be too fast.

Crow 1 and 2 are currently polling their respective TXi’s at 0.1 seconds:

metro[1].event = function(c) 
    for i=1,4 do ii.txi[1].get('param', i) end
end
metro[1].time = 0.1
metro[1]:start()

and

metro[1].event = function(c)
    -- for i=1,4 do  ii.txi[2].get('in', i) end
	ii.txi[2].get('in', 1)
	ii.txi[2].get('in', 2)
	ii.txi[2].get('in', 3)
	for i=1,4 do ii.txi[2].get('param', i) end
end

metro[1].time = 0.1
metro[1]:start()

Right now I’m really just polling things as I use them building these scripts, but I imagine I’ll want to poll the entire TXi state of at least one of the units. There’s also a regular call from crow 1 to crow 2 that’s a clock pulse kind of deal.

metro[2].event = clock_tic
    metro[2].time = 0.125
    metro[2]:start()

function clock_tic(c)
    ii.crow.call1(clock)
    (... do other stuff locally...)

I don’t have a minimal script(s) at the moment, but I can try to work on one. I ultimately want to poll the TXi’s as fast as I can, as I am using the inputs for additional trigger/gate detection. I can message you the full scripts if you want to see them.

One consequence of the increased ii rate is that a bus that is close to unstable may be more likely to fail. The rates at which you’re querying the TXi’s is certainly far slower than the bus should be able to handle.

Makes me think you might want to invest in a powered ii busboard of some kind.

Hmmm. Interesting. I’ve run scripts with much much faster times when it was 1:1 with no problems, so I assumed the instability was the additional crosstalk. I have a Teletype with a backpack in a different system. Can I just… plug power into the backpack without mounting it to a Teletype to test this? Seems like that should work…

How come with the cable connected, druid doesn’t connect after crow is powered on? I have disconnect and reconnect the cable while powered to get Crow to connect. Also, Crow doesn’t start the internal script if it powers up with the cable on. Is there a way to change this? I’d prefer to leave the cable connected 100% of the time.

I tried to search in a couple of threads but didn’t turn up anything.

Sounds like you may need to force the bootloader. I’ve done this a few times when the Crow locks up, especially after running a script that pushes close to the kB limit.

Hi,

No Crow mostly works fine. I mean if I power up my rack with the USB cable connected, crow doesn’t come up in its user script and won’t connect to druid. If I unplug the USB cable, the user script will start running, and upon reconnecting the cable, I can connect to druid. Sorry I should have specified USB cable in my previous post. I’d prefer to leave Crow connected to USB 100% of the time.

This is the first time i’ve heard of this happening. To be clear, this is not the correct operation (it shouldn’t matter whether crow is attached via USB). Can you tell us more about your setup so we can try and reproduce the behaviour?

What OS? What computer? Are you using any adaptors / dongles / hubs to connect? Is there anything connected to the I2C port on crow? Can you try clearing the script (with ^^c) and see if that allows druid to connect on boot? Are you running any virtual machines on your computer? Which terminal / shell program are you using? What version of crow firmware are you using (check with ^^v)? Is it a brand new crow?