tidalcycles / Tidal

Pattern language
http://tidalcycles.org/
GNU General Public License v3.0
2.26k stars 256 forks source link

Binary distribution - next step? #867

Open yaxu opened 2 years ago

yaxu commented 2 years ago

Thanks to @polymorphicengine we have a tidal-listener building into a relocatable binary, great ! We should make use of this for the next tidal release.

We could distribute a ghci drop-in replacement. @jwaldmann already made this: https://github.com/jwaldmann/safe-tidal-cli . It looks good and is safe for exposing to untrusted users (e.g via flok), although doesn't support definitions with let.

Or we could skip that and prioritise editor support for the OSC API.

I quite like the idea of turning tidal-listener into a multi-function tidal engine, that can act like a ghci session, act as an OSC API over UDP, or run a web server serving up a codemirror based interface, depending on what parameters are given..

polymorphicengine commented 2 years ago

turning tidal-listener into a multi-function tidal engine

sounds like a good idea!

ndr-brt commented 2 years ago

We could distribute a ghci drop-in replacement. @jwaldmann already made this: https://github.com/jwaldmann/safe-tidal-cli . It looks good and is safe for exposing to untrusted users (e.g via flok), although doesn't support definitions with let.

On feedforward I implemented a way to interpret haskell code thorough hint, and it supports let for sure, not sure about the other constructs. This functions gets tidal code and evaluate it, I use(d) it to load shortcuts into the interpreter, don't know if it can be usable in the tidal-listener context https://github.com/yaxu/feedforward/blob/master/src/TidalHint.hs#L68

yaxu commented 2 years ago

A note on this - currently tidal-listener restarts the interpreter when an exception is raised. I'm not sure when this happens, it shouldn't on a type error as the typeChecksWithDetails call should detect that before the code is interpreted. If/when it does happen though, any definitions would be lost.

yaxu commented 2 years ago

Well I guess if it type checks, there shouldn't be a problem with interpreting the code.

polymorphicengine commented 2 years ago

Well I guess if it type checks, there shouldn't be a problem with interpreting the code.

As far as I know it does a lazy type-check. So in an expression like s "bd sn*" it would type check it to ControlPattern, even though the parser will fail to parse the expression and raise an exception.

yaxu commented 2 years ago

Ah yes I see. If I do this:

import Sound.OSC.FD as O
udp <- udpServer "127.0.0.1" 6012
r <- openUDP  "127.0.0.1" 6011
sendMessage r $ Message "/code" [string "hello", string "sound \"bd sn*\""]

The interpreter thread doesn't crash, but the whole of tidal-listener does! So the exception isn't raised in the interpreter (good) but later, when the parsec parser is invoked on the mininotation. So we want some exception handling elsewhere, probably similar to how Sound.Tidal.Stream works, where it catches an exception it returns to the previous pattern.

We should also try to make things as strict as possible so we can catch these errors before updating the pattern state. Just forcing the first cycle to be calculated would be fine.

Or we could probably do something fancy with template haskell, so that the parsec parsing is done during typechecking.

yaxu commented 2 years ago

Ah yes I see. If I do this:

import Sound.OSC.FD as O
udp <- udpServer "127.0.0.1" 6012
r <- openUDP  "127.0.0.1" 6011
sendMessage r $ Message "/code" [string "hello", string "sound \"bd sn*\""]

The interpreter thread doesn't crash, but the whole of tidal-listener does! So the exception isn't raised in the interpreter (which is what we want) but later, when the parsec parser is invoked on the mininotation. So we want some exception handling elsewhere, probably similar to how Sound.Tidal.Stream works, where it catches an exception it returns to the previous pattern.

We should also try to make things as strict as possible so we can catch these errors before updating the pattern state. Just forcing the first cycle to be calculated would be fine.

Or we could do probably something fancy with template haskell, so that the parsec parsing is done during typechecking.