localbuf vs buffer sendtrig issue

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

localbuf vs buffer sendtrig issue

Fredrik Olofsson
hi list,
something must have changed between sc3.6.5 and 3.7 in the way synthdefs are built.  it could very well be my user error but i thought i'd post my findings here in case it's a real bug.
the first example is using LocalBuf and it is working as expected on all versions i tried (osx sc365, sc37, sc38, sc39b1).  i get four separate SendTrig ugens listed in the dump.

the issue arise in the second example.  there instead of a LocalBuf i have a Buffer object.  now sc37, sc38, sc39b1 all create an incorrect working synthdef with only one SendTrig.  under the old sc365 it's fine and posting four sendtrigs though.

any ideas of what this could be?  optimisation gone wrong?  bug?  or am i just doing something weird?

//this work for all sc versions
(
s.waitForBoot{
l= 8;
SynthDef(\avTrk, {|in= 0, t_trig= 0|
var z= In.ar(in, 1);
var chain= FFT(LocalBuf(l), z);
Array.fill(l.div(2), {|i|
var a= Unpack1FFT(chain, l, i, 0);
var b= Demand.kr(chain>=0, 0, a);
SendTrig.kr(t_trig, i, b);
});
}).dumpUGens;
};
)

//this _only work under the old 3.6.5 - incorrect with sc versions >=3.7
(
s.waitForBoot{
l= 8;
b.free; b= Buffer.alloc(s, l, 1);
s.sync;
SynthDef(\avTrk, {|in= 0, t_trig= 0|
var z= In.ar(in, 1);
var chain= FFT(b, z);
Array.fill(l.div(2), {|i|
var a= Unpack1FFT(chain, l, i, 0);
var b= Demand.kr(chain>=0, 0, a);
SendTrig.kr(t_trig, i, b);
});
}).dumpUGens;
};
)

//--sc365 (correct)
[ 0_TrigControl, control, nil ]
[ 1_Control, control, nil ]
[ 2_In, audio, [ 1_Control[0] ] ]
[ 3_FFT, control, [ 0, 2_In[0], 0.5, 0, 1, 0 ] ]
[ 4_Unpack1FFT, demand, [ 3_FFT, 8, 0, 0 ] ]
[ 5_>=, control, [ 3_FFT, 0 ] ]
[ 6_Demand, control, [ 5_>=, 0, 4_Unpack1FFT ] ]
[ 7_SendTrig, control, [ 0_TrigControl[0], 0, 6_Demand[0] ] ]
[ 8_Unpack1FFT, demand, [ 3_FFT, 8, 1, 0 ] ]
[ 9_>=, control, [ 3_FFT, 0 ] ]
[ 10_Demand, control, [ 9_>=, 0, 8_Unpack1FFT ] ]
[ 11_SendTrig, control, [ 0_TrigControl[0], 1, 10_Demand[0] ] ]
[ 12_Unpack1FFT, demand, [ 3_FFT, 8, 2, 0 ] ]
[ 13_>=, control, [ 3_FFT, 0 ] ]
[ 14_Demand, control, [ 13_>=, 0, 12_Unpack1FFT ] ]
[ 15_SendTrig, control, [ 0_TrigControl[0], 2, 14_Demand[0] ] ]
[ 16_Unpack1FFT, demand, [ 3_FFT, 8, 3, 0 ] ]
[ 17_>=, control, [ 3_FFT, 0 ] ]
[ 18_Demand, control, [ 17_>=, 0, 16_Unpack1FFT ] ]
[ 19_SendTrig, control, [ 0_TrigControl[0], 3, 18_Demand[0] ] ]

//--sc3.7 and above (incorrect)
[ 0_TrigControl, control, nil ]
[ 1_Control, control, nil ]
[ 2_In, audio, [ 1_Control[0] ] ]
[ 3_FFT, control, [ 0, 2_In[0], 0.5, 0, 1, 0 ] ]
[ 4_Unpack1FFT, demand, [ 3_FFT, 8, 0, 0 ] ]
[ 5_Unpack1FFT, demand, [ 3_FFT, 8, 1, 0 ] ]
[ 6_Unpack1FFT, demand, [ 3_FFT, 8, 2, 0 ] ]
[ 7_Unpack1FFT, demand, [ 3_FFT, 8, 3, 0 ] ]
[ 8_>=, control, [ 3_FFT, 0 ] ]
[ 9_Demand, control, [ 8_>=, 0, 7_Unpack1FFT ] ]
[ 10_SendTrig, control, [ 0_TrigControl[0], 3, 9_Demand[0] ] ]
[ 11_BufFrames, scalar, [ 0 ] ]
[ 12_BufFrames, scalar, [ 0 ] ]
[ 14_BufFrames, scalar, [ 0 ] ]
[ 14_BufFrames, scalar, [ 0 ] ]


  #|
  |#

Reply | Threaded
Open this post in threaded view
|

Re: localbuf vs buffer sendtrig issue

jamshark70-2
---- On Wed, 03 Jan 2018 05:18:29 +0800 <[hidden email]> wrote ----
> hi list,something must have changed between sc3.6.5 and 3.7 in the way synthdefs are built.  it could very well be my user error but i thought i'd post my findings here in case it's a real bug.the first example is using LocalBuf and it is working as expected on all versions i tried (osx sc365, sc37, sc38, sc39b1).  i get four separate SendTrig ugens listed in the dump.
> the issue arise in the second example.  there instead of a LocalBuf i have a Buffer object.  now sc37, sc38, sc39b1 all create an incorrect working synthdef with only one SendTrig.  under the old sc365 it's fine and posting four sendtrigs though.
> any ideas of what this could be?  optimisation gone wrong?  bug?  or am i just doing something weird?

Real bug.

Starting with 3.7, we create copies of PV units whose output is split into multiple chains. ("Starting with 3.7" = why you didn't see it in 3.6.5.)

In your hardcoded buffer example, we are doing this for "chain >= 0" -- which is not really necessary, because "chain >= 0" is not modifying the buffer contents (whereas, say, multiple parallel PV_Scramble units *do* modify them).

It seems, if the FFT is using a LocalBuf, the PV_Copy units are preserved, but if it's a hardcoded buffer object (your case) or a bufnum input, the PV_Copy units are optimized out and their entire chains along with them. Why that is, I don't know yet.

                directDescendants = buildSynthDef.children.select ({ |child|
                        var inputs;
                        child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: {

This logic needs to exclude non-PV UGens from directDescendants, I think, maybe "child.isKindOf(PV_ChainUGen) and: { ... }".

hjh


_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Reply | Threaded
Open this post in threaded view
|

Re: localbuf vs buffer sendtrig issue

jamshark70-2
---- On Wed, 03 Jan 2018 09:25:05 +0800 <[hidden email]> wrote ----
>         directDescendants = buildSynthDef.children.select ({ |child|
>             var inputs;
>             child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: {
>  
> This logic needs to exclude non-PV UGens from directDescendants, I think, maybe "child.isKindOf(PV_ChainUGen) and: { ... }".

Confirmed, this revision does keep all the >=, Demands and SendTrigs.

        addCopiesIfNeeded {
                var directDescendants, frames, buf, copy;
                // find UGens that have me as an input
                directDescendants = buildSynthDef.children.select ({ |child|
                        var inputs;
                        child.isKindOf(WidthFirstUGen) and: {
                                child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: {
                                        inputs = child.inputs;
                                        inputs.notNil and: { inputs.includes(this) }
                                }
                        }
                });
                ...
        }

I don't know if there are other ramifications but I don't see why we need to copy for non-width-first downstream units. It seems there was an assumption that a PV unit will only ever plug into another PV unit, but there are legitimate cases to poach a PV unit for its trigger.

We can remove "and: { child.isKindOf(Unpack1FFT).not }" b/c Unpack1FFT is not width-first.

hjh


_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/
Reply | Threaded
Open this post in threaded view
|

Re: localbuf vs buffer sendtrig issue

Fredrik Olofsson
thank you for commenting and confirming James.
and your corrected code works great afaict.
_f

> 3 jan. 2018 kl. 04:16 skrev [hidden email]:
>
> ---- On Wed, 03 Jan 2018 09:25:05 +0800 <[hidden email]> wrote ----
>>        directDescendants = buildSynthDef.children.select ({ |child|
>>            var inputs;
>>            child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: {
>>
>> This logic needs to exclude non-PV UGens from directDescendants, I think, maybe "child.isKindOf(PV_ChainUGen) and: { ... }".
>
> Confirmed, this revision does keep all the >=, Demands and SendTrigs.
>
> addCopiesIfNeeded {
> var directDescendants, frames, buf, copy;
> // find UGens that have me as an input
> directDescendants = buildSynthDef.children.select ({ |child|
> var inputs;
> child.isKindOf(WidthFirstUGen) and: {
> child.isKindOf(PV_Copy).not and: { child.isKindOf(Unpack1FFT).not } and: {
> inputs = child.inputs;
> inputs.notNil and: { inputs.includes(this) }
> }
> }
> });
> ...
> }
>
> I don't know if there are other ramifications but I don't see why we need to copy for non-width-first downstream units. It seems there was an assumption that a PV unit will only ever plug into another PV unit, but there are legitimate cases to poach a PV unit for its trigger.
>
> We can remove "and: { child.isKindOf(Unpack1FFT).not }" b/c Unpack1FFT is not width-first.
>
> hjh
>
>
> _______________________________________________
> sc-dev mailing list
>
> info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
> archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
> search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/


  #|
     fredrikolofsson.com     musicalfieldsforever.com
  |#


_______________________________________________
sc-dev mailing list

info (subscription, etc.): http://www.birmingham.ac.uk/facilities/ea-studios/research/supercollider/mailinglist.aspx
archive: http://www.listarc.bham.ac.uk/marchives/sc-dev/
search: http://www.listarc.bham.ac.uk/lists/sc-dev/search/