[WIP] FaustGen - a UGen for interpreting Faust code

I added support for flexible numbers of inputs/outputs today…

1 Like

Sorry for resurrecting the topic. Is there any update about the project? I can’t stop thinking about all the good things that could result from a nice embedded FaustGen object.

1 Like

Hi Bubo ! I haven’t had time to work on this in a while. Hope to get more time in the fall. The project is not too far from finished with it’s first version in my opinion. BUt among other things there are some realtime optimizations that need to be done to make the allocation safe. If you feel adventurous (and are prepared to see it change alot) you can download and compile it from source and try it out and feel free to add feedback on it for things we can add to the todo-list :slight_smile:

There are instructions for building here:

1 Like

OK Thanks! I’ll start experimenting with it :slight_smile: . I don’t really mind if there are updates breaking my code.The Faust code will still be functional!

I wanted to take some time during the holidays to try out FaustGen, but I get an error in the very end of building it (I replaced my user name with Xs):

In file included from /home/[XXX]/Downloads/git/faustgen/faust/compiler/generator/llvm/llvm_dsp_aux.cpp:44:
/home/[XXX]/Downloads/git/faustgen/faust/compiler/generator/llvm/llvm_dsp_aux.cpp: In member function ‘virtual bool llvm_dsp_factory_aux::writeDSPFactoryToMachineFile(const string&, const string&)’:
/home/[XXX]/Downloads/git/faustgen/faust/compiler/generator/llvm/llvm_dsp_aux.hh:55:36: error: ‘F_None’ is not a member of ‘llvm::sys::fs’; did you mean ‘OF_None’?
   55 | #define sysfs_binary_flag sys::fs::F_None
      |                                    ^~~~~~
/home/[XXX]/Downloads/git/faustgen/faust/compiler/generator/llvm/llvm_dsp_aux.cpp:480:56: note: in expansion of macro ‘sysfs_binary_flag’
  480 |   raw_fd_ostream out(machine_code_path.c_str(), err, sysfs_binary_flag);
      |                                                      ^~~~~~~~~~~~~~~~~

make[2]: *** [faust/build/CMakeFiles/staticlib.dir/build.make:1658: faust/build/CMakeFiles/staticlib.dir/__/compiler/generator/llvm/llvm_dsp_aux.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:269: faust/build/CMakeFiles/staticlib.dir/all] Error 2
make: *** [Makefile:156: all] Error 2

Any idea why this could be the case? Maybe something to do with the (latest) version of LLVM I have installed? (I know it caused problems with running FaustLive at some point.) Or something else?

I’m on Arch and have both the Faust and SuperCollider repositories cloned to their relevant places relative to the FaustGen repository.

EDIT: In case it’s relevant, I have LLVM version 13.0.0-6 on my system.

oh wow. That’s weird. I haven’t had time to finish faustgen yet but hope fully soon. And I also haven’t tested it since I upgraded but testing it now I get the same error as you when compiling. Oh crap. It looks like it might be an incompatibility issue between faust and llvm - will open an issue with faust.

1 Like

It seems that LLVM 13 caused some problems with Faust that have been (at least partly?) fixed in the bleeding edge version of Faust. Updating to LLVM 13 broke FaustLive for me when using the regular Faust Arch package but worked again once I switched to the git version. This was the Github issue I made back then:

Just in case this helps locating the problem.

2 Likes

I just tried installing bleeding edge faust from the github repo and compiling with that did not do the trick either.

Yes, same here, I also tried compiling FaustGen with the bleeding edge version of Faust.

ah I see you need to use the master-dev branch. I did not try that yet.

Recompiling with the master-dev branch worked! But now SuperCollider throws me this error after I recompiled the class library (again, user name Xed out):

*** ERROR: dlopen '/home/[XXX]/.local/share/SuperCollider/Extensions/FaustGen/FaustGen/FaustGen_supernova.so' err '/home/[XXX]/.local/share/SuperCollider/Extensions/FaustGen/FaustGen/FaustGen_supernova.so: undefined symbol: _ZN16llvm_dsp_factory9getTargetB5cxx11Ev'
Server 'localhost' exited with exit code 0.

I tried to delete FaustGen_supernova.so (since I’m not using Supernova anyway), but now I get the same for scsynth:

*** ERROR: dlopen '/home/[XXX]/.local/share/SuperCollider/Extensions/FaustGen/FaustGen/FaustGen_scsynth.so' err '/home/[XXX]/.local/share/SuperCollider/Extensions/FaustGen/FaustGen/FaustGen_scsynth.so: undefined symbol: _ZN16llvm_dsp_factory9getTargetB5cxx11Ev'
Server 'localhost' exited with exit code 0.

So there’s still some kind of LLVM problem. (I haven’t replaced the Faust libraries on my system with the master-dev ones though, just used the branch for compilation.)

The master-dev branch should fix the problem, but you’ll have to replace the compiled libraries.

2 Likes

Thanks! I kind of guessed so. I’ll wait with the FaustGen testrun then until the fix arrives in the master branch, don’t want to mess too much with my libraries…

The build works again now. (with faust built from master branch) If you’ve already cloned the repo and tried before it’s important to run

git submodule update --remote

Inside of the repo to update the faust submodule to include the latest changes.

1 Like

Soundfile primitive support added on this fork: Commits · sletz/faustgen-supercollider · GitHub, working on macOS for now.

Hi all - this effort came up in this thread:

just wanted to throw this in here in case anyone wants to jump in and join @Stephane_Letz finishing this!

also please see: Faust.quark - Create SuperCollider packages with automatically compiled Faust plugins

1 Like

I might be able to do this. However, not for another month or so.

Sam

As there seems a big demand for this we could maybe also add some new language primitives if this makes working with Faust easier? Haven’t looked into all the details properly yet though.

@Spacechild1 @Sam_Pluta There is an old TODO here faustgen-supercollider/todo.md at main · sletz/faustgen-supercollider · GitHub, that can be a starting place, but which should probably be completed.

I think I know how to fix the RT question for Faust DSP instance management (having to use RTAlloc/RTFree at the approximate locations). But my knowledge in SC is too basic for now to do much more at this stage.

I had a quick look at the code. FaustGen uses plugin commands (/cmd) to implement async commands for things like dynamic Faust code compilation. As such, the plugin must keep a dictionary of all Faust UGens on the Server.

One problem I see is that every FaustGen instance uses a unique ID and those IDs must be managed by the user. IMO this is not a nice API.

A better solution would be to make the ID per SynthDef and pair it together with the node ID. This way the ID could default to 0 in the common case where there is only a single FaustGen in the SynthDef. As such, the ID argument should probably be moved to the right and made optional.

Old:

FaustGen {
    *ar { |numChansOut=2 ... audioInputs|
        // ...
    }
}

New:

FaustGen {
    *ar { |numChansOut=2, audioInputs, id=0|
        // ...
    }
}

Also note that the audio inputs are now an Array. One the one hand this interferes with multichannel expansion, but on the other hand this is what many existing multi-channel UGens do (Out, BufWr, etc.) More importantly, it allows to add more arguments in the future!


Personally, I would rather use unit commands instead of plugin commands because, well, their purpose is to send commands to particular units. This is what I have been doing in Pure Data libraries / vstplugin · GitLab and aoo / aoo · GitLab.

However, unit commands come with their own set of issues:

  1. getting the Synth index of a particular UGen is currently a bit involved. This can be easily solved in the future with a SynthDef post-build hook.
  2. Unit commands must make sure that the unit is still alive when exchanging data in stage 3 (RT) of the async command. At the moment, this can be done by using a reference counted “stub” object, but I have concrete plans to improve the plugin API in this regard. (One idea I had is adding a dedicated DoUnitCmd API function for perfoming an async command on a particular unit. Graphs would be refcounted so that the underlying memory is only freed when there are no pending unit commands for that graph. They would also get a new mAlive member that can be checked in stage 3 to make sure that the graph/unit is still accessible.)

If we want to stick with plugin commands (/cmd), that’s fine, but we should address my concerns above. If we want to switch to unit commands (/u_cmd), I am happy to assist.

2 Likes