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 :- )
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!
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.
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.
Although I have no crow to test with, you can improve your
zl queue approach by using something like this:
----------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.
sprintf is quite programmer-y and oldschool. Maybe something like
combine would be better, especially if you put the. message formatting after the
dang, this is gold, thank you so much rod!!!
^^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.
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!
PS: Also, would these formatting differences be the same in Druid? Or is the change Max specific?
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”.
output.volts = 3
tell_crow “output.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
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:
In geode, (range switch set to shape range), the function is:
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
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!
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).
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
- connect patcher to crow
- enable pullups, if needed
- enable geode
- [bang] the  number object
- set channel , division , repeats  (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 , repeats  (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)
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!
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 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
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.
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.
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.