Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pd multichannel #1034

Merged
merged 9 commits into from
Jul 11, 2024
Merged

Conversation

Spacechild1
Copy link

Add multichannel support to generated Pd external.

To maintain backwards compatibility with older Pd versions, we try to find the signal_setmultiout API function at runtime with dlsym() resp. GetProcAddress(), falling back to single channel mode if not available.

@Spacechild1 Spacechild1 marked this pull request as draft July 11, 2024 20:19
@sletz
Copy link
Member

sletz commented Jul 11, 2024

Thanks a lot but faust2pd is another tool, see https://github.com/grame-cncm/faust/blob/master-dev/tools/faust2pd/README. faust2pd is related to the Albert Pure language.

faust2puredata is the tool that has to be updated, like adding a new-mc like it was done for faust2max6 here

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 11, 2024

Thanks a lot but faust2pd is another tool

I see! I just updated the examples Makefiles because I saw they used their own copies of puredata.cpp instead of the one in architecture. I can remove that commit, no problem.

Apart from that, I only really changed architecture/puredata.cpp (= the actual Pd external)

faust2puredata is the tool that has to be updated,

If I'm not mistaken, this uses faust2pd to create the UI:

if [ $(which faust2pd) ]; then
faust2pd -s $F2PDPOLY $f.xml

Note that you can use the external without the UI. But if we want a working UI for multi-channel mode, we would need to update the faust2pd program - which, unfortunately, is written in Pure...

@sletz
Copy link
Member

sletz commented Jul 11, 2024

I suggest we only update the faust2puradata (without UI) for now. And hope @agraef can help update the faust2pd in a second step.

@Spacechild1
Copy link
Author

I suggest we only update the faust2puradata

AFAICT there is nothing to update. With the changes in puredata.cpp, the external should be multichannel capable. Please let other people test and report back! (I did not test at all.)

And hope @agraef can help update the faust2pd in a second step.

Sounds good :)

@sletz
Copy link
Member

sletz commented Jul 11, 2024

OK, but my point is: do we want/need a specific -mc option to activate multichannel support , and have the default mode just keep the old behaviour ?

@Spacechild1
Copy link
Author

I've added a -m flag to enable multichannel support, as is common with Pd externals. By default, the external still uses single-channel mode.

@sletz
Copy link
Member

sletz commented Jul 11, 2024

I've added a -m flag to enable multichannel support, as is common with Pd externals. By default, the external still uses single-channel mode.

Where that ?

to remain backwards compatible with older Pd versions,
we check the presence of signal_setmultiout at runtime
and fall back to single-channel mode if not present.
no need for copy construction.
I *think* this is done to force all static initialization.
On modern systems where Pd is typically running, it is extremly hard to actually run out of memory.
Pd itself doesn't really check for out-of-memory errors and most externals don't either.
Finally, the existing checks aren't done consistently, so let's just get rid of them.
instead reference the one in architecture/
@Spacechild1
Copy link
Author

Spacechild1 commented Jul 11, 2024

Where that ?

As a creation argument flag:
b7ecd21#diff-d31e5a8ad77759877417938d130196e0d530692b01274984a99549ac1d5417c2R657-R669

That's how you typically do it in Pd if you want your object to support both modes.

[foo~ bar] -> single-channel
[foo~ -m bar] -> multi-channel

@sletz sletz marked this pull request as ready for review July 11, 2024 23:06
@sletz sletz merged commit f8f1616 into grame-cncm:pd-multichannel Jul 11, 2024
@Spacechild1
Copy link
Author

Spacechild1 commented Jul 11, 2024

Did you actually test this before merging? As I said, I didn't test at all!

@Spacechild1
Copy link
Author

Ah, nevermind, I now realized you only merged into pd-multichannel :)

@sletz
Copy link
Member

sletz commented Jul 11, 2024

Can you @alainbonardi and @paulgoutmann test the pd-multichannel branch ?

@sletz
Copy link
Member

sletz commented Jul 11, 2024

Yes, it does compile here like:

faust2puredata organ.dsp
organ.cpp:1141:10: warning: building without multi-channel support; requires Pd 0.54 or later [-W#pragma-messages]
# pragma message("building without multi-channel support; requires Pd 0.54 or later")
         ^
1 warning generated.
organ.cpp:1141:10: warning: building without multi-channel support; requires Pd 0.54 or later [-W#pragma-messages]
# pragma message("building without multi-channel support; requires Pd 0.54 or later")
         ^
1 warning generated.
organ~.pd_darwin: replacing existing signature
./organ~.pd_darwin;

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 11, 2024

Cool! Now you should also build with a more recent Pd header :)

@Spacechild1
Copy link
Author

BTW, the faust2puredata build script seems to be macOS and Linux only... Did nobody try to build this on Windows in the past?

@sletz
Copy link
Member

sletz commented Jul 11, 2024

Nothing I'm aware of.

@Spacechild1
Copy link
Author

Maybe I can find some time to update the Makefile. Or even better: integrate https://github.com/pure-data/pd-lib-builder

@alainbonardi
Copy link

Thank you very much Christof and Stéphane for this contribution. I just tested with an ambisonic decoder at order 1 for 4 loudspeakers (I included below the zipped dsp code). It works well. Normally this [decoder1~] has 3 signal inputs (the three ambisonic harmonics) and 4 signal outputs. When we write it as [decoder1~ -m] in the patch, we get one multichannel input and one multichannel output.
Just a weird thing about the placement of inputs and outputs: as you can see on the joined screenshot of the patch, on the inlet side the multichannel inlet is on the right and the control parameters enter on the left, whereas on the outlet side, the multichannel outlet is on the left.

Capture d’écran 2024-07-12 à 17 23 00 [decoder1.dsp.zip](https://github.com/user-attachments/files/16196001/decoder1.dsp.zip)

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 12, 2024

@alainbonardi Thanks for testing! Did you also try [decoder1~] (without -m) to check that the single-channel mode still works?

Just a weird thing about the placement of inputs and outputs: as you can see on the joined screenshot of the patch, on the inlet side the multichannel inlet is on the right and the control parameters enter on the left, whereas on the outlet side, the multichannel outlet is on the left.

The original author decided to use the leftmost inlet for messages only, which is indeed very unidiomatic. Unfortunately, there's nothing I can do without breaking backwards compatibility...

Even more confusing: the leftmost inlet is actually a signal inlet, so you won't even get an error if you accidentally make a connection. At least this is something that can be fixed.

@sletz I don't know about Faust's stance on backwards compatibility, but the next time there's a release with breaking changes, we can take the chance and fix this.

Another question: is there ever a situation where a Faust Ugen could have no inputs and no outputs?

@sletz
Copy link
Member

sletz commented Jul 12, 2024

The original author decided to use the leftmost inlet for messages only, which is indeed very unidiomatic. Unfortunately, there's nothing I can do without breaking backwards compatibility...

@agraef any comment here ?

Even more confusing: the leftmost inlet is actually a signal inlet, so you won't even get an error if you accidentally make a connection. At least this is something that can be fixed.

Could we add an new option in faust2puredata script itself to have the proper behaviour ? In regular mode and -m mode ?

Another question: is there ever a situation where a Faust Ugen could have no inputs and no outputs?

A Faust DSP code always has at least one audio output, see:

image

@agraef
Copy link
Collaborator

agraef commented Jul 17, 2024

The original author decided to use the leftmost inlet for messages only, which is indeed very unidiomatic.

It's been a long while since I wrote that architecture... :) Yeah, it has a pair of control inlet and outlet on the left, and the remaining iolets are for audio. I've used the same design in pd-faust and pd-faustgen2 as well. Agreed, this isn't very idiomatic, and is also at odds with Stephane's Max faustgen~ external.

But I prefered it because it makes the layout more symmetric, so that you can simply wire through the audio cables if you have a bunch of dsps with the same number of audio channels in a chain. IMHO, it looks tidier in a patch that way, and it also seems more logical to do it that way if you're always going to have a single control iolet and a variable number of audio iolets on all the objects.

Of course, we can argue about this until the cows come home. In principle, I'm not against changing puredata.cpp to the more idiomatic layout, as long as I don't have to do it myself. :)

Concerning faust2pd, I'm afraid that this has been falling victim to bitrot as I never got around updating the Pure interpreter to a modern LLVM version. You can still get Pure up and running on modern Intel-based systems, but it's a major hassle since it requires LLVM 3.5 (the last version with the old JIT).

However, if you need GUI generation then you can use pd-faustgen2. This is my fork of Pierre Guillot's pd-faustgen which has improved MIDI and polyphony support and the GUI generation stuff built into it. It also replaces my own pd-faust which was written in Pure as well, and thus is no longer palatable. :)

The downside is that pd-faustgen2 doesn't have multi-channel support yet. @Spacechild1 Maybe you could port over the multi-channel support from puredata.cpp? I'll gladly accept any pull request. :) Otherwise I'll have to port it myself, and I'm always busy with too many other projects. pd-faustgen2 is also still relatively new, so at this point we might still change the iolet layout to something more idiomatic if this is what everybody wants, without major repercussions concerning backward compatibility.

@Spacechild1
Copy link
Author

@agraef Thanks for chiming in!

But I prefered it because it makes the layout more symmetric

That's what I figured as well after I realized that the message outlet also comes first. It's still not very idiomatic, but now I understand where you are coming from.

so that you can simply wire through the audio cables if you have a bunch of dsps with the same number of audio channels in a chain.

Note that you can do the same with the new (idiomatic) layout, as the signal inlets and outlets line up.

Maybe you could port over the multi-channel support from puredata.cpp? I'll gladly accept any pull request. :)

I'll put it on my list, but I'm always very busy as well...

pd-faustgen2 is also still relatively new, so at this point we might still change the iolet layout to something more idiomatic if this is what everybody wants, without major repercussions concerning backward compatibility.

That would be cool!


@agraef IIUC, pd-faustgen2 is a generic Faust Pd external that compiles Faust DSP code on the fly? faust2puredata statically compiles a single Faust script, i.e. it treats Pd as a compilation target. These are really two different projects, each with their own merits.

Concerning faust2pd, I'm afraid that this has been falling victim to bitrot as I never got around updating the Pure interpreter to a modern LLVM version. You can still get Pure up and running on modern Intel-based systems, but it's a major hassle since it requires LLVM 3.5 (the last version with the old JIT).

So faust2pd probably won't see any updates for the foreseeable future... I think the way forward is to rewrite faust2pd in a common scripting language, e.g. Python. @sletz In theory I can do that, but it's not something I prefer to do in my free time :)

@sletz
Copy link
Member

sletz commented Jul 17, 2024

I guess we need first to evaluate the need of rewriting faust2pd, how is it still used ? @agraef what do you think ?

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 17, 2024

That's what I've been thinking as well: do people actually (still) use faust2pd to generate a UI for the generated Pd external? If not, there is no need to update it in the first place.

(BTW, one thing that is missing from faust2puredata is a help patch for the generated external.)

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 17, 2024

Personally, I don't think that faust2puredata needs to generate an UI. People have wildly different UI preferences, so it might be better to just leave it to the users. IMO an accompanying help patch that documents the inputs and outputs and all messages would be more important.

@agraef
Copy link
Collaborator

agraef commented Jul 17, 2024

I've had a few emails over the years indicating that some people were actually using faust2pd. But I doubt that it has been used very much recently because of the Pure dependency.

The GUI layout algorithm in pd-faustgen2 should still be fairly similar to what faust2pd does, so it should be possible to rewrite the Pure script to something more portable in C++, employing faust2puredata to build the external. I agree, though, that it would be much easier to write the glue code in some modern scripting language instead. Porting the layout code shouldn't be too difficult either, IIRC it's just a recursive function carrying around some accumulating parameters. Any language with decent FPL support including lexical closures should do.

pd-faustgen2 is a generic Faust Pd external that compiles Faust DSP code on the fly?

That's true, but usually JIT compilation is very fast, and it's convenient because everything is built into the loader, and you don't even need to have the full Faust toolchain installed if you're just using Faust inside Pd. That doesn't make the need for something like faust2pd go away, but at least there's an alternative.

Oh well, I'll see what I can do about the faust2pd port once I've finished the other stuff that's on my TODO list right now. Maybe some time next year. I've already ported a good deal of my Pd-related Pure scripts to Lua, maybe this one will be next.

@agraef
Copy link
Collaborator

agraef commented Jul 17, 2024

Personally, I don't think that faust2puredata needs to generate an UI. People have wildly different UI preferences, so it might be better to just leave it to the users.

Well, if you have the generated GUI then you can just edit it to get what you want. And most of the time it will be all you need. And don't even get me started about all the necessary plumbing between GUI and external, this stuff is really tedious and error-prone if you have more than a handful of control parameters.

@Spacechild1
Copy link
Author

Spacechild1 commented Jul 17, 2024

Well, if you have the generated GUI then you can just edit it to get what you want.

Fair point. I'm totally not against offering a generated UI, I just don't find it too important. I mean, most Pd externals come without ready-made UIs. Often you just need to set a handful of parameters, which can be easily done with a few sliders or number boxes. But for that you'd need a help patch :)

@alainbonardi
Copy link

From my teaching experience (every year 40 to 50 music students working on PureData, Faust, Max, etc.) a generated GUI is very important when learning graphical languages for instance Pd. It helps a lot students to build patches connecting what they consider more as plugins than as objects, abstractions or canvas. Typically students using Pd on Windows cannot compile Faust code to make objects. Therefore they use Albert's pd-faustgen2 to implement the Faust processes with an extra subpatcher automatically generated to display the controls.

Therefore I am very much in favour to have an automatically generated GUI directly from faust2puredata

@Spacechild1
Copy link
Author

It helps a lot students to build patches connecting what they consider more as plugins than as objects, abstractions or canvas.

Fair enough. I'm not a teacher, so I tend to forget about the educational aspects.

Typically students using Pd on Windows cannot compile Faust code to make objects.

That's a problem. FWIW I've already opened an issue about that: #1036

@sletz
Copy link
Member

sletz commented Jul 17, 2024

Python tool for Max/MSP: there is https://github.com/shakfu/py2max, that I'm using to automatically create the GUI for the Faust ==> RNBO project https://faustdoc.grame.fr/tutorials/rnbo/

Is there an equivalent Python for PD project, that could be used to build a GUI in faust2puredata ?

@agraef
Copy link
Collaborator

agraef commented Jul 17, 2024

Is there an equivalent Python for PD project, that could be used to build a GUI in faust2puredata ?

Not that I know of.

@Spacechild1
Copy link
Author

Is there an equivalent Python for PD project, that could be used to build a GUI in faust2puredata ?

There is https://github.com/grrrr/py, but IIRC it hasn't been updated to Python 3 and doesn't seem to be actively maintained.
There is also a more recent effort: https://github.com/charlesneimog/py4pd

That being said, won't really need a python external for Pd for our purposes. With faust2puredata the Faust code is compiled statically, so the UI (and help patch!) can be generated at build time (as we currently do with faust2pd). For this we can write an ordinary Python script.

@agraef
Copy link
Collaborator

agraef commented Jul 18, 2024

There is also a more recent effort: https://github.com/charlesneimog/py4pd

Interesting. Thanks for pointing to this, I didn't know about it. Seems to be similar to pd-lua in scope (which has been around for a while), but with Python as the scripting language.

But you're right, for faust2puredata we'd just want something which generates a static GUI as a Pd abstraction, and that can be done with just regular scripting, whether in Python or Lua.

@sletz
Copy link
Member

sletz commented Jul 18, 2024

For this we can write an ordinary Python script.

Sure, my point was that a library to help generate the actual PD patch could be used. For faust2rnbo, I wrote the ChatGPT helped rnbo.py script, that uses the py2max library to ease patch generation (since it was my first real Python code ((-;)

@Spacechild1
Copy link
Author

Sure, my point was that a library to helps generate the actual PD patch could be used

Ah, I misunderstood! (I didn't really check the link to https://github.com/shakfu/py2max)

There are indeed comparable Python libraries for Pd, e.g. https://pypi.org/project/puredata-compiler. You are right that this would help a lot with the patch generation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants