GameOfLife / Unit-Lib

The Unit Library is a system that provides high level abstractions on top of the SuperCollider language.
25 stars 6 forks source link

easier creation of uchains where the same mono unit is repeated n times to process a multichannel input of n channels #36

Closed miguel-negrao closed 10 years ago

miguel-negrao commented 10 years ago

Currently I do stuff like:

var fx = UChain(*([0,0,totalDuration+5,
    [\groupIn, [\bus, 20]]]++numChan.collect{ |i|
    [\highPass, [\u_i_ar_0_bus, i, \u_o_ar_0_bus, i, \freq, [\envelope, [\env, env]]]] }++
[[\output, [\numChannels, numChan]]]
)).ugroup_('default')
.addAction_('addToTail');

It would be nice if there was a special syntax or class to automate this, and if the guis for those multiple copies would present them as if they were just one, since if we think of this as just one fx, then you want all those units to have the same settings.

woutersnoei commented 10 years ago

Hi Miguel,

that would be nice indeed. In the GUI it is done so easily, so why not in code. I have two ideas: 1 - starting an array with a number (integer) would replicate every unit that comes after it by that number, and increase all i/o buses by one. Syntax would be like this:

UChain(*[0,0,totalDuration+5,
    [\groupIn, [\bus, 20]], 
    [ numChan, [ \highPass, [ \freq, [\envelope, [\env, env]] ] ] ],
    [\output, [\numChannels, numChan]]
]);

2 - a bit harder to make, but easier on the eyes; every Unit would have a possible \numChannels key. If it is not defined by the def (like in case of \output) it would render itself into an array of U's when not 1. I.e.:

UChain(*[0,0,totalDuration+5,
    [\groupIn, [\bus, 20]], 
    [ \highPass, [ \freq, [\envelope, [\env, env]], \numChannels, numChan ] ],
    [\output, [\numChannels, numChan]]
]);

The latter would need to be dealth with within U, perhaps pointing to a temporary MultiU or UArray, which would need to be unpacked by the UChain (or not).

Btw in the example you gave the GUI will automatically create a MassEditU GUI for the whole group of highPass. This happens always if more then one U's of the same def are placed next to each other.

miguel-negrao commented 10 years ago

Hi Wouter,

Option 1 seems fairly easy to implement. Option 2 is more work but would be quite more convenient, so I would vote for number 2 (but well, this is a do-ocracy... :-) ). I think in this case the MassEditU gui is not very usefull because most often you want the exact same settings for all the channels, and that's not doable with the range sliders.

For my own phD library I have a similar issue. I have a class MUChain which makes n copies of a uchain. I made a special gui for it which just presents one slider together with a button to open a plot to see the underlying values (in case they are changed by code or from umods) and another button to update the plot or not (to save cpu) . This was done by subclassing MassUEdit and changing

massEditSpec = argSpec.spec.immEditSpec( values );

Then I had to also subclass ArrayControlSpec and change the makeView method.

+ Object {

    immEditSpec { |...args|
        ^this.massEditSpec(*args)
    }

    *immEditSpec { |...args|
        ^this.massEditSpec(*args)
    }

}
+ ControlSpec {

    asImmArrayControlSpec { ^ImmArrayControlSpec.newFrom( this ) }

    immEditSpec { |inArray|
        ^this.asImmArrayControlSpec.default_( inArray );
    }

}

The gui for this

UChain(ImmU([U(\sine), U(\sine)])).gui

looks like captura de ecra de 2014-02-10 14 56 53

Perhaps we could subclass MassEditU to MultiChannelU and do something similar ? Although, I just tested and doing UChain(MassEditU([U(\sine), U(\sine)])).prepareAndStart only plays one sine, so it's not actually functional to play multiple things at the same time...

woutersnoei commented 10 years ago

Hi Miguel,

ah ok, but if the single value thing is hard to do from MassEdit, that is what actually needs to be fixed. I was thinking along the line of having a second fader squeezed in the space of the range slider, which would be a normal fader. Moving that fader would move the center of the range-slider, double clicking or moving it to one of the outer bounds would flatten the range. That way both multi-value and single value unit sets could be edited from the same gui. Haven't gotten to implementing this yet, but it would be much simpler and more convenient, as both modes of editing would be available in a single GUI.

woutersnoei commented 10 years ago

on topic; thinking about option 1 a bit more that may actually be my favourite. We could invent a simple multichannel expansion syntax, which would also allow for example arrays and maybe small functions to set individual parameters of the multiple U's. This could be implemented via MassEditU, where we could make a new *generate method perhaps which could be called internally by UChain at creation. MassEditU already has some things built-in to intelligently know if an arg is meant to be an array, or is in fact an array of args that should be spread among the units.

woutersnoei commented 10 years ago

ok, just added a mean slider to the mass edit gui. The upper part of the range slider now acts as a mean slider. Moving it moves the whole range, double clicking sets the range to a single value.

miguel-negrao commented 10 years ago

Ok, just pulled, the new mean slider is quite nice ! :-)

The way I understood option 1 was that the the units would be generated in the UChain#new method but would be concatenated with the rest of the list on both sides, such that after creation time they would just be a number of perfectly normal repeated units. That would mean that after creation time you wouldn't be able to easily set the value of them by code with .set for instance (would have to select them out of the array first). Is this what you are proposing ?

My ClusterBasic class also does "intelligently know if an arg is meant to be an array, or is in fact an array of args that should be spread among the units.", just in case it's usefull. See expandArray in https://github.com/miguel-negrao/Cluster/blob/master/ClusterBasic.sc

The way I see it, for this specific situation, what I would be after would be that the array of units would really behave in every way as if they were really just one unit, indeed as if the synthdef had a 'numChannels' argument which was changing the the structure of the synthdef internally (just wrote about that on the list today :-) ). What about having this be a special type of U ( UX ? as in U x 8) which would create n synths internally and then would set the in/out controls accordingly. In the args it would have all the u_i_ar_j_bus, u_o_ar_j_bus, with j in [0, (n-1)], but then internally it would smartly pass the right parameters to each synth, so : u_i_ar_1_bus would be passed to u_i_ar_0_bus of synth number 2 u_i_ar_2_bus would be passed to u_2_ar_0_bus of synth number 3 etc

Maybe this would be too convoluted... just brainstorming... :-)