Help with metronome

Hi there - I'm not a coder, I just happened to land myself in a coding class in college and I'm super lost for my project. trying to make a metronome that changes according to BPM. Basically there should be a slider and the ellipse should flash according to the value (BPM) that the slider is at. Can anyone fix my code? I've been guessing and checking all morning. Thanks!

var bpm = 120; var minute = 60000; var interval = minute / bpm; var time; var beats = 0; //var Slider; var timer;

var s;

function setup() { createCanvas(300, 300); fill(255, 0, 0); noStroke();

time = millis(); //timer = createP('timer'); setInterval(drawEllipse, 500);

// create slider Slider = createSlider(0, 120) Slider.position(20, 20); }

function drawEllipse(){ //if (millis() - time > interval){ var s = Slider.value(); ellipse(width/2, height/2, 50, 50);

// beats ++; // time = millis(); //setInterval(drawEllipse, 60000/s);

}

//}

function draw() {

background(255);

text(s, 40, 50);

}

Answers

  • Check the forum guide on formatting code ;)

    In this case I'll let you off as the code is just about short enough to make sense of.

    You have several problems here:

    1. minute is a p5js method so can't be used as a variable name.
    2. keep things simple: instead of using setInterval use the existing draw loop
    3. keep things simple: if the slider value represents bpm then use the slider to set bpm directly and don't create a separate 's' variable
    4. don't access slider.value() repeatedly - this is potentially bad for performance: the createSlider example does not follow good practice here! Instead use the changed() method to update the relevant variable only when the slider changes.

    I can post working code later; but since this is an assignment you should have a go at implementing the above suggestions and posting your attempt first :-B

    A tip on getting things working: when in doubt use print(variableName) at relevant points in your code (though avoid doing this in draw if possible) to check the value of the specified variable is as expected. The output will display in the console (in p5 editor or hit F12 in your browser). The console will also report any errors in your code.

    I'm not a coder

    No-one is born a coder; but pretty much anyone can be one if they apply themselves: it's just something you learn; like any language...

  • I understand everything you're saying but I still can't get it to work

  • Have a go. Post your updated code and we can point you in the right direction ;)

  • `var bpm = 120; var minuteyo = 60000; var interval = minuteyo / bpm; var time; var beats = 0; //var Slider; var timer;

    function setup() { createCanvas(300, 300); fill(255, 0, 0); noStroke();

    time = millis(); timer = createP('timer');

    // create slider Slider = createSlider(0, 120) Slider.position(20, 20); }

    function draw(){ if (millis() - time > interval){

    ellipse(width/2, height/2, 50, 50);
    

    beats ++; time = millis();

    } Slider.value = bpm; text(Slider.value, 40, 50);

    background(255);

    }

    `

    I never learned how to use the changed function and don't totally understand it. How would I go about communicating that bpm is the slider value?

  • any help? sorry the code is formatted weirdly again it didn't look like that would happen before i posted it

  • OK - so you're obviously struggling - even with the 'Check the forum guide on formatting code ' :P

    I've added some comments to your code below:

    var bpm = 120; 
    var minuteyo = 60000; 
    var interval = minuteyo / bpm; 
    var time; 
    var beats = 0; 
    var slider; 
    var timer;
    
    function setup() { 
        createCanvas(300, 300); 
        fill(255, 0, 0); 
        noStroke();
    
        time = millis();
    
        // is this the label for the slider??? See below.
        timer = createP('timer');
    
        // create slider
        Slider = createSlider(0, 120);
        // In practice this does something very crude
        // and isn't in any way attached to the label (above?):
        Slider.position(20, 20); 
    }
    
    function draw(){ 
        if (millis() - time > interval){
    
            ellipse(width/2, height/2, 50, 50);
            beats ++; 
            time = millis();
    
        } 
    
        // You're still trying to check slider value in draw!!!
        // AND you've got this backwards: here you 
        // appear to try to SET the value of the slider
        // to bpm!!!
        Slider.value = bpm; 
    
        text(Slider.value, 40, 50);
    
    background(255);
    
    }
    
  • edited April 2016

    OK - now for some almost working code. I've left a couple of 'fill the gaps' and not being 100% sure of everything you want to achieve I've removed a couple of things from your code that seemed unnecessary in a demo ;)

    Your attempt didn't include a changed() event; which is key to making it more straightforward to deal with slider input efficiently:

    var bpm = 120;
    // you can't use 'minute' here:
    var myMinute = 60000; 
    var interval = myMinute / bpm; 
    var time; 
    var slider; 
    
    
    function setup() { 
        createCanvas(300, 300); 
        fill(255, 0, 0); 
        noStroke();
    
        // record start time
        time = millis();
    
        // create slider 
        slider = createSlider(60, 240, bpm);
    
        // *** register event listener ***
        // the 'sliderChanged' function (further below) will  
        // run when the slider value is changed by the user
        slider.changed(sliderChanged);
    }
    
    // no need for setInterval: draw is running in a permanent loop
    function draw() {
        background(255);
        text(bpm, 40, 50);
    
        if (millis() - time > interval){ 
            ellipse(width/2, height/2, 50, 50);
            //reset time here
            // [fill the gap]
        }
    
    }
    
    // - - - - - - - - - - - - - - - - - - //
    
    
    // it's more efficient to set the value of s 
    // like this; rather than repeatedly 
    // calling slider.value() - e.g. in draw()
    function sliderChanged() {
        // Set the value of bpm to the slider value
        bpm = slider.value();
        // debug: output value of bpm to console
        print(bpm);
    
        //recalculate interval here
        // [fill the gap]
    }
    

    Once you've filled the gaps this should work - more or less; but you'll find there's a slight problem to your approach: with the above the ellipse is only drawn on each 'beat' for a single frame: i.e. you barely see it.

    A better approach is to change the size of the ellipse so it grows to a certain size and then resets to 0 when the timer resets. There are different ways to achieve this; but I'll leave that to you to try ;)

  • I even figured out the growing ellipse by adapting some old code of mine - but now the "recalculate bpm" thing is throwing me off

  • edited April 2016

    Sorry: that should have said recalculate interval (had bpm stuck in my head); then it might make more sense ;)

    I'll fix my post

Sign In or Register to comment.