Embedding Tidal cycles in sclang

With the new ongoing FFI, I just had this thought and I have no idea how practical it is because I don’t know much about tidal cycles or Haskel… but, would it be possible to create a c API for tidal cycles so you can pass strings to it?

This would mean we could do something like…

~t = TidalCycles(callback: { |...args|
   ...
});

~t.update(\1, "... cycles code ...");

This assumes you can rewrite tidal cycles to perform a arbitrary call back rather than send osc messges, by that would be okay.

I know basically very little about tidal cycles and even less about Haskel, if anyone has any expertise with this I appreciate any insight, or if anyone knows of anyone else who might be able to answer these questions please pass this along!

More generally, the FFI allows us to embedded any language / program that has a c API inside of supercollider. If we have better dsl language support, we could pitch supercollider as a sort of framework/interchange that bridges between all the different music languages/programs out there.

3 Likes

GHC FFI User Guide
Safe vs Unsafe FFI in Concurrent Haskell (YouTube)

Example with traditional FFI export:

Another way is to use C++ directly as quasi-quotation—you import libraries and write C++ code in Haskell.
Maybe you can write a library that embeds SuperCollider’s C++ primitives using inline-C, which looks cleaner:

EDIT: @jordan, if you want any, feel free to talk to me. I wrote some FFI toy projects. Since it is not audio-related, like some of the ones I did, I think there will be NO challenging tasks, but the details are essential on the Haskell side, which doesn’t deal directly with memory management (normally, so you sometimes feel like you are using another language). And there are different tools to do that, and sometimes the names do not help much, like “safe” or “capi unsafe”, hot the types on the Haskell side need to match (there are special types for that), and also there is a more modern features which is just inline c and c++ code and libraries in your haskell program.

I could tell you more, but I don’t know what exactly you want to do right now

Thanks for this @smoge!

To be honest, I know ZERO Haskel and am really struggling here. I can’t even get tidal to build for some reason!

In my mind, this should be easy, as there are two functions to export to sc:

  1. Initialisation
  2. Accepting a string as code.

This would be the first step, then tidal could be made to call a c function ptr, which would inturn call back into sc triggering a callback. The function ptr and callback object would be passed at in step 1 from sc.

I’ve done all the SC side stuff to make this work, I just cannot wrap my head around Haskel!

I was wondering if you might fancy collaborating on this? To be honest though, I’m not sure how much I could help as you could just do the whole thing in Haskel, which I’d be no help with!

1 Like

Just a note: the GHC guide is really good. You can find most things there. For example, some parts offer very good information:

On the other hand, a foreign call to a function that is guaranteed to take a short time, and does not call back into Haskell can be marked unsafe. This works both for the single-threaded and the multi-threaded runtime. When considering what “a short time” is, a foreign function that does comparable work to what Haskell code does between each heap allocation (not very much), is a good candidate.

Also

A safe call … guarantees to leave the Haskell system in a state that allows callbacks from the external code. In contrast, an unsafe call, while carrying less overhead, must not trigger a callback into the Haskell system. If it does, the system behaviour is undefined. … Note that a callback into the Haskell system implies that a garbage collection might be triggered after an external entity was called, but before this call returns.

This project with Pipewire is also very informative, and very good code to get to know the inline-c method:

Yes, I think it can be a great proof-of-concept. I can help, unless someone else more experienced in Haskell is available to collaborate.

There’s also the Zwirn effort of porting to sclang. Such ports are now known as uzulangs.

1 Like

DM me, let’s see what’s going on. If you are building with stack (a deterministic dependency tool that uses “resolvers”), maybe you have some configuration issue with GHC, cabal, or stack? First let’s build the stuff hehe

I just noticed something, too. To make this project (very cool), I’ll need to build your SC branch as well. Is it working already?

Yea the FFI has work for a few days. I think it is settled and stable now, been adding tests today.

(I think stack should probably do all this by itself. I don’t know how you tried the first time. stack usually is all you need.
Maybe you installed just some components?

What resolver is declared in the stack.yaml file?
check here: https://www.stackage.org/

In the terminal, ghcup tui (cli super simple tool) and check what is installed in your machine!

{For this problem, let’s continue in chat (which can become a group), anyone with the same question can join )