soul-lang / SOUL

The SOUL programming language and API
Other
1.71k stars 95 forks source link

Assigning variables to array elements #20

Closed alexrodi closed 4 years ago

alexrodi commented 4 years ago

I've made some very simple changes to the beep example, this code worked on a previous version in the beginning of January.

The assignment of variables to array elements using .at() or [], although not syntactically incorrect and with no compilation errors, don't seem to work

Here is my previous code:

processor Beep
{
    output stream float out;

    let beepLengthSamples  = int (processor.frequency * 1);
    let beepVolume         = 0.1f;
    let oscNumber          = 10;
    let gain               = 1.0f/oscNumber;
    let frequency          = 110.0f;

    struct simpleOSC
    {
        float frequency;
        float phaseIncrement;
        float phase;
    }

    void run()
    {
        simpleOSC[oscNumber] osc;

        for (var i = 0; i<oscNumber; i++){
            simpleOSC thisOsc = osc.at(i);
            thisOsc.phaseIncrement = float (frequency * (i+1) * twoPi * processor.period);
            thisOsc.phase = 0.0;
        }

        loop (beepLengthSamples)
        {
            var result = 0.0f;
            for (var i = 0; i<oscNumber; i++){
                simpleOSC thisOsc = osc.at(i);
                result += sin(thisOsc.phase);
                thisOsc.phase = addModulo2Pi (thisOsc.phase, thisOsc.phaseIncrement);
            }
            out << result * gain;
            advance();
        }
    }
}

And here's a version of the code (no assignment) that does works:

processor Beep
{
    output stream float out;

    let beepLengthSamples  = int (processor.frequency * 1);
    let beepVolume         = 0.1f;
    let oscNumber          = 10;
    let gain               = 1.0f/oscNumber;
    let frequency          = 110.0f;

    struct simpleOSC
    {
        float frequency;
        float phaseIncrement;
        float phase;
    }

    void run()
    {
        simpleOSC[oscNumber] osc;

        for (var i = 0; i<oscNumber; i++){
            osc.at(i).phaseIncrement = float (frequency * (i+1) * twoPi * processor.period);
            osc.at(i).phase = 0.0;
        }

        loop (beepLengthSamples)
        {
            var result = 0.0f;
            for (var i = 0; i<oscNumber; i++){
                result += sin(osc.at(i).phase);
                osc.at(i).phase = addModulo2Pi (osc.at(i).phase, osc.at(i).phaseIncrement);
            }
            out << result * gain;
            advance();
        }
    }
}
julianstorer commented 4 years ago
            simpleOSC thisOsc = osc.at(i);
            thisOsc.phaseIncrement = float (frequency * (i+1) * twoPi * processor.period);
            thisOsc.phase = 0.0;

That's taking a local copy of the object, and then you're modifying the local copy.

At the moment we're avoiding adding syntax to let you declare a local reference, because of scoping edge-cases that we'll need to think through, but it'll be something we add at some point. In the meantime you can use references as function params if you really need to get a reference to something and do a bunch of changes to it in one hit.

Out of interest, what's your language background? It's not a mistake I'd expect a C/C++ programmer to make, but maybe you've done a lot of java or something?

alexrodi commented 4 years ago

Very sparse, I would say :) I have been developing in javascript for some time now, and I've been dabbing in C/C++ lately. My predilect is genExpr...

julianstorer commented 4 years ago

OK, I was just wondering if that's a mistake we'd expect to see often and might need to help people avoid, but I suppose it's no more different to C++ in the copy semantics.

alexrodi commented 4 years ago

Great, this works:

void initOsc(simpleOSC& osc, int index){
        osc.phaseIncrement = float (frequency * (index+1) * twoPi * processor.period);
        osc.phase = 0.0;
    }

    float readOsc(simpleOSC& osc){
        float result = sin(osc.phase);
        osc.phase = addModulo2Pi (osc.phase, osc.phaseIncrement);
        return result;
    }

    void run()
    {
        simpleOSC[oscNumber] osc;

        for (var i = 0; i<oscNumber; i++){
            initOsc(osc.at(i), i);
        }

        loop (beepLengthSamples)
        {
            var result = 0.0f;
            for (var i = 0; i<oscNumber; i++){
                result += readOsc(osc.at(i));
            }
            out << result * gain;
            advance();
        }
    }

Btw, I think the language is amazingly constructed, especially for someone with close-to no experience in C/C++ like me, It's so exciting and I can't wait to get more into it and employ some real dsp routines! Anyway, thanks for the help! :)