Simple q. about infinite looping sin

One of those “what’s best practice” questions;

I have a sin looping with a variable speed. Conventionally I’ve seen;

sin(ofGetElapsedTimef() * speed); // speed = 0. to 1.

… but the speed modifier when changed will make the sine move erratically, rather than a smoothly ramping.

Instead I do;

`speedCounter += speed; // speed = 0. to 0.00001
sin(speedCounter);`

After a while though the variable speed starts only working on higher value - my guess is because I’ve hit the limits of decimal points - something like when 0.0000000001 being 1000000000.0

My question then is, should I be looping the float - at 6.28319? - or is there a better way?

I use sin(time) alot for my work and if time gets larger, the value gets “crunchier” as you mention because of floating point precision, as the number gets larger you loose floating point precision.

you can use floating point mod

http://www.cplusplus.com/reference/cmath/fmod/

or something like this:

while (val > M_TWO_PI){ 
    val -= M_TWO_PI;
}
2 Likes

Thanks, much better way of typing 6.28319 :slight_smile:

I came across another problem though;

ofGetElapsedTimef() works well because you have a consistent rate no matter how fast the update or draw functions are running, so instead I’m doing something like;

time = ofGetElapsedTimef();
speedCounter += timestamp - time;
if (speedCounter > M_TWO_PI) speedCounter = 0;
sin(speedCounter);
timestamp = ofGetElapsedTimef();

Here’s what I came up with tonight when creating an oscilloscope;

getValue returns a Hz / clock accurate sine wave
getAll returns a vector of multiple sine values going back in time set (set by int fidelity)

class PerfectSine {
public:
    float frequency = 0;
    float timestamp = 0;
    vector<float> all;
    OscGui offset, freq, amp;
    void setup(ofxDatGui * gui, string name, int maxFreq = 100) {
        offset.setup(gui, name + " offset", "slider", 0, 0, 1); // gui, label, type, value, min, max
        freq.setup(gui, name + " freq", "slider", 20, 0, maxFreq); // gui, label, type, value, min, max
        amp.setup(gui, name + " amp", "slider", 1, 0, 1); // gui, label, type, value, min, max
    }
    float getSine(float elapsed) {
        
        float scaled = elapsed * (M_TWO_PI * freq.getValue());
        frequency = (scaled > M_TWO_PI) ? 0 + (scaled - M_TWO_PI): frequency +  scaled;
        timestamp = ofGetElapsedTimef();
        float sine = sin(frequency) * amp.getValue();
        return sine;
        
    }
    float getValue(float min = -1, float max = 1) {
        
        float elapsed = ofGetElapsedTimef() - timestamp;
        return ofMap(getSine(elapsed), -1, 1, min, max);
        
    }
    
    vector<float> getAll(int fidelity, float min = -1, float max = 1) {
        
        all.clear();
        for (int i = 0; i < fidelity; i ++) {
            float elapsed = (ofGetElapsedTimef() - (i * 0.00001)) - timestamp;
            all.push_back(ofMap(getSine(elapsed), -1, 1, min, max));
        }
        return all;
    }
};

NB. OscGui is a class wrapping in some ofxDatGui sliders

cool ! if it’s helpful note that we also have ofGetLastFrameTime() which tells you the amount of time the last frame took –

if it’s helpful (sorry to get into the weeds!) code like this makes me a little nervous:

time = ofGetElapsedTimef();
speedCounter += timestamp - time;
if (speedCounter > M_TWO_PI) speedCounter = 0;
sin(speedCounter);
timestamp = ofGetElapsedTimef();

because you ask for ofGetElapsedTimef() twice – the values could be different, maybe timestamp = time is better? also this:

if (speedCounter > M_TWO_PI) speedCounter = 0;

isn’t 100% correct if you want to perfectly loop around, it should be:

while (speedCounter > M_TWO_PI) speedCounter -= M_TWO_PI;

anyway, glad this is working out for you!!

Thank you yes, much better way of looping. Also calling ofGetElapsedTimef() was very important - the difference was quite drastic at higher frequencies!