^^ crow strategies: Just Friends

Is there a sound demo of Just Friends used in 6 voices polyphonic mode somewhere please ? (re-reading, I understand this is a work in progress, maybe in a near future :- )

1 Like

@dan_derks & @germinal wow. I never even thought of something like this.

Dan, thanks for taking the time in (all) of the crow threads to give great specific information in regards to initial and future integration with crow & other devices. Excited to place my order soon for it & a just friends!

1 Like

The new crow videos shows all the voices being used, the first one is sequenced by Awake on Norns and near the end with the arpeggios played by the standalone script.

1 Like

I know I posted this once before but couldn’t find it, sorry for spamming, but this is all Just Friends controlled via Teletype, sequenced by Kria.

2 Likes

Thanks @Jonny and @kbit ! :wink:

Although I have no crow to test with, you can improve your zl queue approach by using something like this:

Max Patcher

----------begin_max5_patcher----------
2023.3oc2Z87bqhiD9ryeETbc83RBPBXp4xt6g2o8zbXpsRMkKrQ1QumLhED
uj7lZ9ee0O.r.C1XhsyTSNPHcift+zW2sjR+GOsvcC+MRoqyO67ryhE+wSKV
nEoDrn9uW3dH4ssrjR8i4lQdku4qtKMpDj2DZw4EzLQizrpC7JAiHzCATKMO
Qr8EZ190EjsBymL.tBrzAFDp9kum5pm7pyue7EQyZdOvZgzT8WTZE+TfqRze
9zSpKKmnGbfTVlrmbhKTKuboifuzYaA+0g8mF6vHR7dNw3Ltts18ntpef1gg
WvU8N0U8miqN1jkyFogSJV8C1p+WEohb6czXe80vqdJE5Z+pIE0dWs6svcGk
Q9NonjxyrdCKbSxysDuvZHJL4qb8KJZYqHZlQDrUTA46zlwCZklTHcPgz6pJ
ztu6a3.2iuFdJoHqhpeSFgxYmZSROOjkH4U4IaMCVMc0n9HjEh0bCn9WAg.0
uPwVnlbddOiu8ajTaiykmSxnY4EjRRlHQzy1cSI6RpXh063YhR5OzVfl4Mf9
c0V3fJU9f17+mEzDVqCruflxyTFQmYBk3lO2yNPjlwircF8SjkjOvfkT.IrL
hxRoSVUtIoPMQsgQrBUjraNm0UU63XjchZ04zrrdnnfmOtxB59WNyX2vkJOb
t2sVS45pLi10RNgXcYx26h1hDFqNXs6q+sjL5gDAQPMSAdfVkjrDoi9RoLSE
i0weMZ99.ZRkb7sjWoohWzeHaxf7wo4MjH21Y4TpLmnnqLQx9xtRJEua.cKQ
UapigWKHGxYRun6Czo1ic.qcZsNx6kdaK+vARaYmgylKSl670c1OxfUmFKaF
LVmw1ORcMRGf5Ar3xikRqeZMjaiXcJ75DE2A+9C5tnXcxGOc5aunY6u9OJ+k
w44NhWJ3U6ewQWLyoJSPYNRJm3c6gvnYjsboR6zFWMB46qSOGfBWAAQvnf35
e7jY4.lD49y.vhAOJDqpjTCTRtRofWPbjYebnYxAI8UmlHmQwN+OJ1A7WECB
gXLv7CLRgcHS0uYfcQQOJrKkvRduEgb17tztOTd2XY93fUg.LL.0vxjqoJd1
brH7iBm1xyjqFSnYXueXCmot6aDRtiUd48DgZAd2bZlmd009xHz9XGDDOeRV
viB7n6bRZvIG4CJAKZlSImmQJjo5RxjpUzN48Do7WoRDvYup75XPYvrgx.cI
.nrFfG.B7vMXIVsKFMXhmS4gHuaIX1YaN8JG5rwgMd4P6.zS1lyljr8tKs1t
yEpZ56IWq..A8BaxqIQISfr8VflLHEF7f.oevbr2F30hSSCiLaqIPtImf949
Q3KiQdifQv+VQjpAIr2Jb+EW7AHR3nGEHwMY6GGmfmkHMQ7wOTkNpapcSH37
fmvGD7XV8.DLS3QSitDDUmwdPHJX1gY3GUX1+vANSzQc9iWDb.lfHenL9xGD
50.NHov3UnYhNA3GVRHlylOPV5IwfpqlYNAO77y5DfdPnhZoONdmi3bCJe4Y
BdBCWEAjEvZJwCB+PwUAOpR7+hLsyp6ejELBIKu6AP9MQV9pcwLa7A9vJuSO
zcqHWAAZGimHlDKpAk7i0KmFF2vhT02Cm+hftkfj9qc2JfiZ28ZyJZ7O69G.
ibZIcB1a1L04O2OZVJ4MqCp+lfVFHX9m2lIsBBFMU.YriOxaL.45vgiGRuZC
jib5rZGQoeX.pjWUrsgRTu9SIouiOkRJEzr1+mEOezKb557a4Ly+nlmc.qBj
ZWoNrHcTjBllzT4UauvSLigs2P34sWvRqKvdSqGno4bYt0ZP1CEpV.h5vwh.
XbHnICpzoggwin6dg.QSDAv2PDnwKiiFX2OvvKoScfO8WxaMndpp6DtI2x9m
.tgiZbRL.g8ZXGQnN.POc2KDXh..7r..b..3tXtvoFpKWi+ksWjrjNFd2M5f
fIlOc.53mQ9zfoFUbo7+fkVLi6n8hlJo3zIhOM6cR7gKZtimzgWjZ5FCvmuO
.9n9.793C3qg2b8ISNyhG.lSu.ij047QQMGrQDTsaC+QzcuV7P3MZ4SOnzSg
SsFv.qJ5SwdmZ5eb3eIr23IWiEcCR+WKroMrbU8ZS5ZSeEsNQHJnapDlc1X2
WYWU+urmw2jvp6tk1tiZf1i4oiFWcq6o8ttatxzIe8Q05946zUrXiQiAjlmY
vNFbpeG+I7cfm7cLtWulwS8I50Dd8Z.uSa9twa7t9Mcmdl1z.R8fzi8sVUJk
+q5tGa8+gjUYloZ5wst.wl86nLVKuylizbRG0rx197yli5EG.U+Os.q7g9gd
X8cxaPH6XVyXfsAhnfX0Y.IuC6EFfz2E44i70j8dCy632RUhP+E.wQf.yclp
F1ELbSx1W2sbgVs7UdAOmWz11fq7iae9JAeeQRJs9PD.c3wKq4QERs866K2C
R.k1LFadW6jw2JYT4D3uolcO2DQ+JhctzP59f1h4DA+WrJRSimNrsjrcq7Cz
YhVtqSbPnBxwsydwJQv6fAVveM6psvi1ERx+Bh0zi6jE9ueO45MPfWLJPyeC
C888zfYjGDB8u8F3WJHjYXgZzyW8i5N4NswJy7Vab+WBiwe87VmcW79rtOdQ
w.PTaF5Ar9HODTCpgQvHyJIQRDGcScfpCaHEegyRuZvUQEA5oeTrGDosTnc5
qahAVXR2nrvym1+5rskOcZteb.F6GWyhCCM7YIdGOe9rod5HcR9S+4S+ey5P
NyC
-----------end_max5_patcher-----------

In your version you are staggering everything received by 10ms, which also means that any message sent can be up to 10ms late (if you just missed the metro bang). Also having a constantly running metro 10 in your patch can maybe jam up the scheduler, particularly if you have lots of other metros at play.

The patch above will send any message received, instantly. IF it receives a message within 10ms of the last message, it will then add it to zl queue and send it after 10ms. This gives you instant response time and note staggering when you’re dealing with polyphony.

Also sprintf is quite programmer-y and oldschool. Maybe something like combine would be better, especially if you put the. message formatting after the zl queue.

8 Likes

dang, this is gold, thank you so much rod!!!

implemented into ^^jf_synth and the help patcher!

agreed, but am having a hard time wrapping my head around it. will explore. heck, folks are gettin’ crows today, maybe someone else will <33333

I started whipping something up, but didn’t know how critical the %.2f thing was in terms of what crow is expecting. If it matters matters you can just use round 0.01 before the combine object to get the same results. The , is weirder/harder, in which case sprintf may be a good way to go.

Hello All,
I got my Crow plugged in tonight and connected to a JF via ii. Exciting!

I’m trying to wrap my head around how I can script the various Just Type modes to JF using Crow instead of Teletype (which I don’t have). I assume everything that can be done via Teletype can be done via Crow… Is that correct?

In comparing the messages sent to Crow from the Max and from the Just Type documentation there appears to be a formatting difference that I’m trying to understand.

For instance, in the Just Type documentation what’s written as:
“JF.NOTE pitch velocity” becomes:
“ii.jf.play_note(NOTE, VELOCITY.)” in Max.
So it looks like we need to prepend our messages with “ii.jf.play”?

I’m specifically interested in playing around with the Geode mode, so would the formatting be: ii.jf.play_note(NOTE, VELOCITY, DIVISION, REPEATS.)"?

Are these difference documented anywhere?

Thanks so much!
B

PS: Also, would these formatting differences be the same in Druid? Or is the change Max specific?

1 Like

In Max, you use the exact same command as you would in druid - the only difference is you wrap it in quotes to make sure they are a single symbol, and prepend that symbol with “tell_crow”.

In druid:
output[1].volts = 3

In max:
tell_crow “output[1].volts = 3”

The quotes are crucial here because they make it so that the Lua code is treated a single chunk.

Typically, the I use the sprintf object with the symout argument to format my Lua chunks and turn them into a single symbol, followed by a prepend object to tack on the tell_crow.

Mobile right now but can post a max code snippet as a demo tomorrow! The help file should have a lot of this already though. The max for live devices would also be good references.

In synthesis, (range switch set to sound range), the function is:
ii.jf.play_note(pitch,vel)

In geode, (range switch set to shape range), the function is:
ii.jf.play_note(repeats,division)

geode does not make sound, just cv slopes.

The two functions are equivalent to teletype with the small exception of scaling for pitch and velocity in synthesis - remember on teletype you need to use a lookup to set the velocity (N 3 instead of 3 or V 5 instead of 5), whereas on crow I believe you just pass midi note and voltage level though you should confirm that for yourself since I’m not at my case!

7 Likes

This is sooo helpful. Thank you!!
And thanks for the clarification on the Geode mode. I realize that I was a bit confused on that.

EDIT: One of the things that’s still confusing me is the added “play” formatting in Max that doesn’t appear in the Just Type documentation. “JF.NOTE pitch velocity” becomes “ii.jf.play_note(pitch,vel)”.

It would be fine to follow that but it gets confusing for some of the other commands, like “JF.TICK”. What should this become in Max? I’ve tried “ii.jf.tick(BPM)”, “ii.jf.play_tick(BPM)”, “ii.jf.tick_BPM” and “ii.jf.tick BPM”. None of them seem to work as expected (though as I’m new to this mode it is possible I’m mistaken on that).

Thanks again!
Ben

added the sprintf bits to the scripting part of the FAQ!

example code snippet
<pre><code>
----------begin_max5_patcher----------
2443.3oc4as0iiaaE94Y9UHHf7lWCdQjTL.8grca2VzcSCxNEKBRVLP1l1Qy
HKYnKykFj7au7hjrrsrtXyYV214AOTzjhmqemCOj92t9J2YIOIxbc9Vme14p
q9squ5JcWpNtp74qbWG7z7nfL8vbmmrdsHN2ch46xEOkq6W7Tv5MQBmjkNKS
RWGjmKV3rVjkErRTM3vE5glL6t2.YUcFWrNLNRjqe8vsclTjW0Knr2MA4y+0
v3U2lJlmaHZLFNkQl3fA7ofINPFV8ODXJv4KpI86Wes5iICj61ifq4tbQTzs
ySSdz4WbkD1lh7eF9koOjDkm47mb7lxP+haabIoUtD0JWB6fKQzoRlD4SzLo
OV+DRwjkSx7dxedivLCW2Sh+Ol1UwoGQQhsjhzyWwTTfhC8XmkVbYThbcaiX
gt0TPZvZQtH8VQbvrHQSpyX+p5gNbVC0EqoYGtl0H5O6Q2MwwcVP7J6pCM1s
N+820hfgaGkHjosSg.scJ47zhwhGkj1ArgxKrENXL3I3N3.ei9w3o4MFk0jS
0o6HL5lTwFQ7BmZrmV3Z5H3ZX+bsgeg.7.Xaaxp4NybV1B6QbsoCHDqUpHd+
nmUJTIRhBI3jX0h0yDosvT3gfAcdLbo9rjge4gbNhZMaSZXb9RmrmUz81Pme
S31XmeyTzxVich.cF6bYRbdV3+VS+PIqU187jnjTCOAlxo.luGFhYHhGehrG
eDyi.39.LGAILUWPB0mtsaoTqgbpcOH0ZGKUcZZ86RCChb6WWvMFeX5X8szi
yMJLd+D0zKlp+c0LYIEoyqdUkfDNaWsEhr7v3f7vj3FiQkohCrdPqCWrIQp6
xp3AiOiI6JB.T+zVlHcgPK3AsZ+LTZUEgtWhkXFyYsPCQnv1YL0bH7rVXkcc
uqL0Bb3tZz1WGMwbT0NlZvMMVvd.Svc+iGPeLjFXHjF3njFYKwLox9zFjF9r
IsJhgvaRZpmZwsNXylGDoYkueMUIgVuyfg4OQ+XXr4QM7iap3gvpwqQ8bCRk
XN4R.mhTCjzSTOWyTSjlrwEgkVsR4gbIyxeNZenjsnYEKBS9TdPdQ1seTDWX
.1jxgkAEQ46J6lsZYXTTMh6U0eiLDPIXVId7jxt2AcFw8fPeEDrFglpaofpI
MLIKmCrZRdRfb.RMTOMnstkOBSvpVf8lFZ6ZAfbyJnf48LsjcA2AuWJKiWYB
DiXfpfJRimzjMIoUVAxoxqGeQdxpzfEgpLtqP+LpXi31DmW9sZwtVlTJSWKE
ngUyoooZsx3CEyC5RADLet7EuiPEWEoCqCnoaUF8qYbscliGiHyTXhVLg84l
VDHft2jDQh06udLeJkomgO.56aZIWZDZ24Na0tQlAdPlIhLm3wXlog3lWEgV
OulgZkde+SYFwNeJHNy4Sh0gyRhj4KTMzLI8MWoi1k.QR9PKGfTFxXk3C.Pu
coOUNK54caXrxgTTa4nxTfZDIUldHcVE6yf86LTanbD+gAZitqGgesefOCP7
8MsNf.22ifVYdPU+wLsLuoKWGhOFjm2kCQyjBk.wM.Dze0xfJndXET7YRP2j
JsEMytK5p15ZrVU6wPMyZrEm+g9VGgqHyqS2evjFezg+dW11xVjc7CuqPFzc
Y37FgcgGCP3GKlEdua+twcPnek7awLpGyv9JMjdZd6JMFSTLo6K6B0q8y27W
GgSqe213DfTto0iTBFZ1AGDAQcEfCp2AnNxhdmeZC6pLM5I.mGEBAlzL3Hpm
V5S3PIBamF7PJVpd0TGyix4ks.7C8uaXM+2ddQZxJQ7MZKuuzbSkpTW2yYWx
U53YR1mPMA8UA.zrG+Bv.ePoh7+FYpEL8dwKSlZ6YWMrv16aW8cwKBhDNeLI
Nou7kL0LotVIv5RjfObE1FOEziwZWuUswpUzB5BRENe3fM7twZ7JqHTasNd1
zCbR6oX8wblI2MLWtwnxVLBtSE66EwhGBNm3esquNqvksrmO33XySFTXeQZY
5PG15jfRrIhQos5aKxykKPGVrMXInQk3WKM.ksfaqsfcHq2UWSyKHh58Agw+
w.oJUVUUg5Ork8IsrGCk9QiJD.rz2Z6GuHzD5hhn9GYQgKpNVjgYasG0zUtZ
mFz6QA6ZOBYuqhMkWePrXb9gswGsIqnGLXaR1xMpmF9z77znyf5sJAoNmsNA
OrnA0qJzy2mrPjcZo7bJQKOM4jUY3QAg.dgMr99FGya6DSanHGFz7Efz9gv4
48Kq9pqO+gTQlH+hKaiOMOYiX3oar83H3X0e8WSrWUg7MAyFNqLPTu1rb5EE
wpLkb2Ny5MA5V1X2QiT9JlIzMIqT65vZoy1gR4nkZzxrz+ZcOmX3qn38yAOH
TWju+v5R3wmUHXJwRL2hfz6eSb3peM+M5MtOpCcXfmTTaNLbBpb25DooDnD4
8PHg1qlfWMT.q9XIpOfBe8qwBkqruJqa85KX8RUZy5KDl9vIdRYsn9GXUG20
jwCBYZoCsVNA00Ar65fMPiz8qvo5VX471cNP3WjhgcQTZ8S7LeG7ztnps9cZ
shHE.Ju8113UgFyNlHG0paVjPl8g4FI71jjFmD47HQP5PK3OnWavsdfGzvdE
mcXT3+G.dd2lv36GUrUpBZyuFi.WddG8DVc.yZriu0Z8z+zNQT3Csx2dVqlK
eayV8mE0.nzi4eLYmOsvYVLbZ5ULAjKJj46MUW3ypae3W6z9iTIE2+lAa08n
NWTRMZWkJrqp7A3dkWVNNG6yJaw7s592MWs92FUHdCbrmvLjUdGD1xg7l7kM
IvzjGiGME1qj2hT3e94fwSf.DmXtyGLFFiLWNJDTBxYeB78oBwIPgZoWcImf
5eLC1m39QwhQSZrZvOXc9D.DlfdAbP9IQTTxicShGdY5Hb.vuq.z9Hh4NFw7
g9ZDc4bH066w9L.5+FY.cIveubuWi2DotZBjs+fbZF2yJD3lhzMcWpsCf18.
HtoNE.JWaCi7ITj+.u0vr5akmm9ZtnwMTdlVUvmJlKBen6S+oMah5T51Rbfl
am2NDmI4.kYwfKAG0iRwk+Psfrx6hpzZki6LR7qiUTlHdQ1kF5bdvl9PLZre
0ODjm37AUlRtVa8yxEKKhhxGW4rOwpCA8IDno.hTLCatqyTowK0tBUCS8BwS
VLGTjbSYl6PGt1HCi3XtuUkGhrKqqc+ipcb77vII0O5xiUCm2Ell+ryeYUu2
LRfR6py2GWpTkHOk0EePAEFXUTaeCtPNGP8Kgp8JO6SJ.fgm7Mnz7KPSedIJ
4Q1lR8j9G660+90+GzFfLZ.
-----------end_max5_patcher-----------
</code></pre>

also testing this now and getting unexpected results. will keep you updated as I learn more

Okay thanks Dan!
Glad I’m not just being dense.

closing the loop!

for the Max folks, here’s a Geode patch that demonstrates the functionality: geode_ex.maxpat (30.8 KB)

how to navigate the patch:

  • throw JF into transient and shape
  • connect patcher to crow
  • enable pullups, if needed
  • enable geode
  • [bang] the [49] number object
  • set channel [1], division [4], repeats [3] (wait till it all dies down before moving on)
  • [bang] that section and you should see 4 pulses from channel 1 (repeats assigns how many pulses after initial pulse)
  • under that: division [3], repeats [2] (wait till it all dies down before moving on)
  • [bang] that section and you should see 3 pulses from channel 6 (repeats assigns how many pulses after initial pulse)
5 Likes

Thanks again for your help Dan!

In the Max Geode patch is there a reason why we need to divide the repeats and division by 1638?

Yeah! It has to do with synthesis mode and Teletype though…

Are you familiar with Teletype?

Yeah i’m familiar with TT but i never tried Geode on it. Guess I’m wondering how it applies to Crow here as I couldn’t find anything related in the docs

The fundamental reason is the underlying I2C code which runs Just Type was written long before the crow idea had begun germinating. It was originally written only with Teletype in mind; Teletype does not have floating point numbers in its scripting language, just integers.

I wrote the description below on a crowded rush hour train, please excuse any typos or not rigorously formatting code snippets!

Teletype explanation

In synthesis mode, you would do the following to play a note:

JF.NOTE pitch vel

How should Pitch and Velocity (ie peak-to-peak voltage) be scaled? What velocity input should correspond to a 5V peak-to-peak waveform? What about 2.5vpp? What about 2.342vpp? The natural choices would be “use the number exactly as is" - but since Teletype is limited to integers, you could only set a 1 or 2 or 3 or 4 or 5vpp waveform but not 2.342vpp or 2.5vpp.

Since Teletype can’t handle floating points, our options would be very limited.

Solution: choose a larger number to represent 10vpp loudness, for instance 1000. Then, typing in 1000 for velocity would result in 10vpp, 900 would be 9vpp, 250 would be 2.50vpp and so on… but we still could not get 2.342vpp. How can we maximize our available precision?

Solution: Make an extremely large number equal to 10vpp. Let’s call this our “super precise large number scaling system.” Now, every voltage like 2.342vpp corresponds to some integer. For instance, to figure out what 1vpp is, just take our super large number and divide it by 10. That’s annoying to do every time though, so… hello Teletype V operator

V 1 conveniently converts the number 1 into the correct number in our “super precise large integer scaling system” for 1vpp. VV 132 creates the correct number for 1.32vpp.

The velocity argument of JF.NOTE expects to be given an integer from our special scale, but instead of doing so directly, we do it by picking an easier voltage number and converting it with the V operator.

Similarly, the pitch input expects numbers to be specified in the super precise scaling system and then interprets them as volt-per-octave voltages. So suppose I want a 1-octave increase above the default of C3 - I would do V 1. What if I want 7 semitones? Then I can use the N operator to accurately convert 5 into first the correct volt per octave voltage, then into the correct “super large integer scaling system” number.

At the same time, I also have the ability to pick some very precise microtonal pitches beyond just semitones though if I set the argument directly instead of using a “lookup table” to (the N or V operators) first.

So why does this matter?

The same I2C command JF.NOTE on teletype is used to control geode mode.
In geode on teletype, you do not need to use the lookup tables; since the arguments only make sense as whole numbers and there is no need for floating points, you set the number of repeats and divisions directly.

So JF.NOTE 1 1 means either make one envelope using the first click division length in geode, or it means play an incredibly quiet (silent really) note that is essentially no different than C3, the default 0 note in synthesis mode.

Alternatively, JF.NOTE V 1 V 1 means play thousands of repeats of an extremely long envelope in geode V 1 is really just a super large integer, or it means play a note one octave above C3 at 1vpp in synthesis mode.

Crucially, the same command is used to talk to both modes; the range switch on JF is what determines the difference in meaning, not the sending device.

Fast forward to crow, which can handle floating point numbers after all. The play_note functions was written with the pitch priority in mind however JF is still expecting to receive an integer in our “super large integer scaling system” which it will then internally convert to the right pitch.

So on crow, play_note expects a floating point v/oct voltage; it then converts this to our “super large integer scale” and sends it to jf.

This poses an issue when we try to use geode - if you type in “1” to play_note, it converts that into a super large integer before sending it to JF.

As such, when we actually want to send a 1 to JF, eg in geode mode, we can’t give play_note a 1 as an argument - we need to give it a much smaller decimal number which will then be immediately made bigger again by play_note, landing on the integer 1.

9 Likes