ambisonictoolkit / atk-sc3

An extension library for the SuperCollider programming language
GNU General Public License v3.0
75 stars 12 forks source link

why matrix needs to have a numerical value? #132

Open telephon opened 2 years ago

telephon commented 2 years ago

Let's relax the constraint in the Matrix class (MathLib) that values must be numbers:

// just this commenting out
put { arg row, col, val;
        super.at(row).put(col, val)
        /*if( val.isNumber,{
            super.at(row).put(col, val)
        },{
            error("not a number in Matrix-put");this.halt
        });*/
    // put an Array of elements
    }

I can write the following, and to my impression it works correctly.


// prepare
~decoder = FoaDecoderKernel.newUHJ;

(

Ndef(\foa_scene, {
    var sound, angle, azimuth, bformat;
    sound = Decay.ar(Impulse.ar(2.3), 0.05, PinkNoise.ar(1));
    // azimuth -> hard left     = back
    //          centre     = centre
    //          hard right     = back
    azimuth = MouseX.kr(-pi, pi);
    // angle ---> top         = push to plane wave
    //            bottom        = omni-directional
    angle = MouseY.kr(pi/2, 0);
    bformat = FoaEncode.ar(sound, FoaEncoderMatrix.newDirection(azimuth, angle));
});

Ndef(\foa_transformer, {
    var in = Ndef.ar(\foa_scene);
    in // for now, just play out the b-format input
});

Ndef(\foa_decoder, {
    var in = Ndef.ar(\foa_transformer);
    var sound = FoaDecode.ar(in, ~decoder);
    Limiter.ar(sound)
});

Ndef(\foa_decoder).play
);

Should we relax the constraint? Since sclang automatically lifts math operations to UGens, it seems overly narrow.

EDIT: I've made a ticklist for methods that work with UGens, Arrays, and Functions as matrix entries, from inspecting the code. See: https://github.com/supercollider-quarks/MathLib/issues/38

joslloand commented 2 years ago

Hello @telephon,

Hmm... at first I'm surprised that this (quote below) works:

Ndef(\foa_scene, {
    var sound, angle, azimuth, bformat;
    sound = Decay.ar(Impulse.ar(2.3), 0.05, PinkNoise.ar(1));
    // azimuth -> hard left     = back
    //          centre     = centre
    //          hard right     = back
    azimuth = MouseX.kr(-pi, pi);
    // angle ---> top         = push to plane wave
    //            bottom        = omni-directional
    angle = MouseY.kr(pi/2, 0);
    bformat = FoaEncode.ar(sound, FoaEncoderMatrix.newDirection(azimuth, angle));
});

Looking closer at FoaEncoderMatrix:*newDirection, I can see why the above would work given relaxing the Matrix restraint in MathLib.

I'm not sure we could expect this to be the case across the board for all FOA and HOA matrix operations. As you know, for (most) relevant operations we have both matrix and corresponding (p-)UGen implementations.

Just thinking aloud here... two interesting spaces that opening up Matrix could offer:

The latter could be nice, in that MATLAB / SciPy type functionality could be introduced. (@mtmccrea and I have been looking at writing new classes to offer this possibility.) The former could imply refactoring / reducing / replacing current (p-)UGen implementations.

I think we'd want to carefully review the use cases and resulting performance. I am suspicious that there will be a variety of Matrix methods that just won't work... but, I could be wrong.

@mtmccrea, @dyfer, @dmartinp, @joshpar, do you have any thoughts / opinions on the matter?

telephon commented 2 years ago

There are probably some adjustments that will have to be made if all methods should work.

An example:

* { arg that; // return matrix A(m,n) * B(n,r) = AB(m,r)
        var result;

        if ( that.isNumber, {
            ^this.mulNumber(that);
        },{
            ^this.mulMatrix(that);
        });
    }

would have to become:

* { arg that; // return matrix A(m,n) * B(n,r) = AB(m,r)
        var result;

        if ( that.isKindOf(this), {
            ^this.mulMatrix(that);
        },{
            ^this.mulNumber(that);
        });
    }

But this is better anyhow.

The optimal approach would be to write tests (which would be a good idea anyhow for a class so central), and then vary the tests, replacing numbers with their UGen and Signal counterparts.

dyfer commented 2 years ago

Without having worked with Matrix very closely, I'd say that I'd be in favor of removing the number check, since it's better not to have preemptive constrains.

The optimal approach would be to write tests (which would be a good idea anyhow for a class so central), and then vary the tests, replacing numbers with their UGen and Signal counterparts.

This would be ideal, IMO.

Also... I understand this was raised in the context of Atk matrices, but do I understand correctly that we are discussing MathLib's methods here? If so, the discussion should probably be moved there eventually...

telephon commented 2 years ago

Also... I understand this was raised in the context of Atk matrices, but do I understand correctly that we are discussing MathLib's methods here? If so, the discussion should probably be moved there eventually...

Yes. If we get it working correctly with Atk, it is a good start. But discussion should be here: https://github.com/supercollider-quarks/MathLib/issues/38