Hello, all! I've been experimentally building a Tidal editor (drawing inspiration from @polymorphic.engine's GSoC work) and thinking through how tidal (particularly the internal Stream.hs
logic) could better integrate with external tools.
Here's a sketch of some things I'm interested in. I'd be willing to work on the development, but wanted to see which ideas other folks like or have critiques of first. Since some of these involve breaking changes, it would be good to coordinate a nice release, etc. Particularly interested in @ndr_brt's thoughts in terms of the Atom plugin, and @yaxu's thoughts how this could be informed by his remake experiments. But, I'd also love to hear any other thoughts, comments, requests, wild dreams that anyone else has!
A more specific type for pattern (etc) ids
Right now, patterns can be named by any Show
able ID, which is very useful for numbering patterns, but gets weird for other things—for example, the ID of the pattern p "bev" $ s "cp"
is not "bev"
, but rather "\"bev\""
.
I've already implemented this, but then got distracted trying to figure out git rebase. Sorry about that. One cool result is that it would enable things like this:
-- Silence d1, d2 & d3
p [1..3] $ silence
Mutable targets
Most fields of the Stream
object are already MVar
s, so should be easy to change the sCxs
field to be an MVar
without disrupting too much. This way, one target can come from BootTidal.hs
, another can be added by an editor, others can be added/reconfigured during live performance, etc.
I think the tidiest interface would be something like this, resembling how patterns work:
startStream :: Config -> IO Stream
-- Add target to context list, open UDP port, etc
streamAddTarget :: Stream -> String id -> Target -> IO ()
-- Remove from context list and close UDP port, etc
streamRemoveTarget :: Stream -> String id -> IO ()
I think startTidal
stay the same for backwards compatibility, but this would be a breaking change for anyone who's used startStream
directly.
Mechanism for "subscribing" to stream changes
Speaking of MVar
s, one limitation is that there's not a good way to wait for an MVar
to change if, for example, you want the editor to display changes to /ctrl
values.
Ideally, State
fields can be written to and read from, like now, but also would allow some sort of subscription where the first read gets the current value, and then all subsequent reads block a thread until the value changes. I think the closest thing is the "skip channel" described in the concurrent Haskell paper, but would love to hear if others know of existing mechanisms for achieving this.