faust icon indicating copy to clipboard operation
faust copied to clipboard

attach'ed hbargraph is removed if first bus gets terminated

Open Jikstra opened this issue 3 years ago • 9 comments

Example code: process = _, (2.0 <: _, hbargraph("test", 0, 5) : attach) : _,!; Diagram: Screenshot_20220819_123440

Expected: I would expect that an attached signal is getting exposed to the ui, even if it gets later on terminated Actual: attached signal is getting removed, even if it's part of the diagram

But not exposed in ui: Screenshot_20220819_123538

Jikstra avatar Aug 19 '22 10:08 Jikstra

The SVG diagram is a bit misleading here: in this cas the compiler actually remove the attached part and generates this C++ code:

virtual void compute(int count, FAUSTFLOAT** RESTRICT inputs, FAUSTFLOAT** RESTRICT outputs) {
        FAUSTFLOAT* input0 = inputs[0];
	FAUSTFLOAT* output0 = outputs[0];
	for (int i0 = 0; i0 < count; i0 = i0 + 1) {
		output0[i0] = FAUSTFLOAT(float(input0[i0]));
	}
}

sletz avatar Aug 19 '22 12:08 sletz

Yes, attach must attach to a signal that survives. It would be nice to have a primitive that works like you expected, e.g., hbargraph("test", 0, 5) : persist.

josmithiii avatar Aug 21 '22 20:08 josmithiii

Yes, attach must attach to a signal that survives. It would be nice to have a primitive that works like you expected, e.g., hbargraph("test", 0, 5) : persist.

Yes I think something like this would be really helpful. Would this be hard to implement? I tried looking for where the logic for attach is defined, buuuut after the 5th page of search results i gave up :D

Jikstra avatar Aug 22 '22 00:08 Jikstra

Read the attach primitive documentation again: https://faustdoc.grame.fr/manual/syntax/#attach-primitive. Since your program finally compute an output, you should be able to use if in the attach expression right?

sletz avatar Aug 22 '22 06:08 sletz

Read the attach primitive documentation again: https://faustdoc.grame.fr/manual/syntax/#attach-primitive. Since your program finally compute an output, you should be able to use if in the attach expression right?

I'm currently writing a mixer with peak/dbmeter. It has 4 stereo buses for the channel, but they get terminated once they got mixxed down for the main output. So those signals don't survive, and also the attach primitive doesn't. Probably I stumbled on this problem because I did the db metering after the mixdown, maybe it would survive if i would do it before the mixdown. But anyways, I worked around this by keeping all the buses, as I write the interaction with the jack audio api myself, i can hide them there. I think now that it's clear that this is the intended behaviour of attach, It's more about an persist primitive would be helpful for faust and if it's possible to implement.

Jikstra avatar Aug 22 '22 10:08 Jikstra

But you need to get the result of peak/dbmeter in a bargraph right? Why cant you attach them to the signal which is then mixe to main output ? Any "simplest" piece of code that should the problem?

sletz avatar Aug 22 '22 10:08 sletz

But you need to get the result of peak/dbmeter in a bargraph right? Why cant you attach them to the signal which is then mixe to main output ? Any "simplest" piece of code that should the problem?

As I said, I guess I could make it work somehow, doing the metering before the mixdown. But my code would look something like this:

_,_ <: _,_,_,_  : _,_ (_,_:>_) : _, (_, (_metering : hbargraph(...)) : attach) : _,_

With a possible persist primtive

_,_ <: _,_,_,_  : _,_ (_,_:>_:metering:hbargraph(...):persist:!) : _,_

With persist i think it's more clear what happens. With attach it's why 2 inputs? What is the sense of feeding the right channel into it?

Jikstra avatar Aug 22 '22 11:08 Jikstra

Coincidentally, I just wrote a library to solve this problem: https://github.com/nuchi/faust-tap-library/

Actually I wanted something slightly different than a persist primitive — I wanted to route deeply nested signals to output without manually dealing with crossings, but when I saw this issue it was only a few extra lines to add persist functionality.

The name ("tap.lib") comes from tapping a delay line.

Please make sure to look at the "Limitations" section in the readme, there are some situations that it can't handle.

Example code:

tap = library("tap.lib");

A(k) = *(k);

complicatedExpression = _,_,_,_ : (
        (A(1) <: _,(hbargraph("first", 0, 1) : tap.T1)),
         A(2),
         A(3),
        (A(4) <: _,(hbargraph("second", 0, 1) : tap.T2)),
         A(5)
    ) ~ (_,_,_,_,_ :> _ <: _,tap.T3)
      : si.block(5)
      ;
process = tap.persist(
    tap.extract(complicatedExpression, tap.T3),
    (tap.T1, tap.T2)
);

Resulting block diagram: persist

EDIT: Your example:

process = _, (2.0 <: _, hbargraph("test", 0, 5) : attach) : _,!;

would be written like the following, assuming I understand correctly (I think you want a signal going straight through, and then a constant signal 2 feeding directly into an hbargraph which doesn't interact with the first signal):

tap = library("tap.lib");
process =  tap.persist(
    (_, (2.0 : hbargraph("test", 0, 5) : tap.T1) : _)
    // or just (_, (2.0 : hbargraph("test", 0, 5) : tap.T1))
    , tap.T1
);

nuchi avatar Aug 23 '22 03:08 nuchi

Nice! I've often needed such taps

josmithiii avatar Aug 23 '22 04:08 josmithiii