Skip to content

Compatibility: Simple Melody App #96

Description

@ksen0

In terms of backwards compatibility, despite some limitations, most common uses should work. All the following examples are from the Simple Melody App tutorial.

1: console logging on osc

// Variable for frequency (middle C).
let myFreq = 262;

// Variable for Oscillator.
let osc;

function setup() {
  createCanvas(400, 400);

  /* Create an Oscillator object with a 
  Frequency defined by the variable myFreq */

  osc = new p5.Oscillator(myFreq);
  console.log(osc.f);
}

function draw() {
  background(220);
}
  • in p5.js v1: console logs 262
  • in p5.js v2 console logs undefined ❌

2: toggling based on osc.started

// Variable for Oscillator.
let osc;

// Middle C frequency.
let myFreq = 262;
function setup() {
  createCanvas(400, 400);
  // Create the Oscillator object.
  osc = new p5.Oscillator(myFreq);
  // console.log(osc.f);
}

function draw() {
  background(220);
}

function mousePressed() {
  // Toggle the note that is playing.
  if (osc.started) {
    osc.stop();
  } else {
    osc.start();
  }
}
  • in p5.js v1: mouse press toggles sound
  • in p5.js v2: mouse press has no effect ❌

3: Overall melody app not working

// Variable for frequency (middle C).
let myFreq = 262;

// Array of frequencies in C Major.
let frequencies = [
  myFreq,
  (myFreq * 9) / 8,
  (myFreq * 5) / 4,
  (myFreq * 4) / 3,
  (myFreq * 3) / 2,
  (myFreq * 5) / 3,
  (myFreq * 15) / 8,
  myFreq * 2,
];

// Melody Object for C Major
let melody = {name: '',
              notesIndex: [],
              tempo: 0
             };


// Empty array for oscillator objects.
let oscillators = [];

// Calculate duration of each note in seconds.
let noteDuration = 60 / melody.tempo;

/* number of notes that can be played (equal to the number of frequencies/oscillators) */
let numNotes = frequencies.length;

//canvas width
let cWidth = 400;

// Tempo selection list (in beats per min).
let tempoList = [
  "100",
  "110",
  "120",
  "130",
  "140",
  "150",
  "160",
  "170",
  "180",
  "190",
  "200",
  "210",
  "220",
  "230",
  "240",
  "250",
  "260",
  "270",
  "280",
  "290",
  "300"
];

// Variable for tempo dropdown.
let tempoSelect;

function setup() {
  createCanvas(cWidth, 400);

  // Initialize oscillators and place in oscillators array.
  for (let freq of frequencies) {
    osc = new p5.Oscillator(freq);
    oscillators.push(osc);
  }
  //set color mode to HSB (better for using notes to color keys)
  colorMode(HSB);

  // Play button.
  let playButton = createButton("🎵 Play your song when you are done! 🎶");
  playButton.position(width * 0.2, 540);
  playButton.mouseClicked(play);

  // Text to prompt users to set tempo
  let p = createP("Step 1: Select a tempo");
  p.style("color", "magenta");
  p.position(10, 415);

  // Tempo dropdown menu.
  tempoSelect = createSelect();
  tempoSelect.position(10, 455);
  tempoSelect.option(0);

  // Add tempos to dropdown options.
  for (let tempo of tempoList) {
    tempoSelect.option(tempo);
  }
  
  // Directions to input text.
let p2 = createP('Step 2: Type a name for your melody and click "Set name"');
p2.style("color", "magenta");
p2.position(10, 465);

  // Name of song input.
    nameInput = createInput("Type a name and set");
  	nameInput.position(10, 500);
  	nameInput.size(200);
  
  // Name button.
let nameButton = createButton('Set name');
nameButton.position(250, 500);
nameButton.mouseClicked(setName);

  // Reset button.
let resetButton = createButton('Reset Melody');
resetButton.position(150, 580);
resetButton.mouseClicked(resetMelody);

}

function draw() {
  background(220);
  
  // Draw and color keys on canvas
  drawMelody();
  
  // Call setTempo() when selected
  tempoSelect.changed(setTempo);
  
  // Display melody name
  fill("magenta")
  textSize(20)
  text(`Melody Name: 
${melody.name}`, 50, 50);
  
  // Display melody name
  fill("magenta")
  textSize(20)
  text(`Tempo: 
${tempoSelect.selected()}`, 300, 50);
}


//update melody object when clicked
function mousePressed() {
    updateMelody();
}


// Starts playing a note at index n in the oscillators array.
function playNote(n) {
  // Starts oscillator if needed.
  if (oscillators[n].started === false) {
    oscillators[n].start();
    // Starts playing the note by increasing the volume with a 0.01 sec fade-in.
    oscillators[n].amp(1, 0.01);
  }

  // Stops playing the note after number of seconds stored in noteDuration * 1000
  setTimeout(stopNote, noteDuration * 1000, n);
}

// Stops playing the note.
function stopNote(n) {
  // Lower oscillator volume to 0.
  oscillators[n].amp(0, 0.01);

  // Stop the oscillator.
  oscillators[n].stop();
}

// Plays the notes in a melody.
function play() {
  // Read each [index, note] in melody.notesIndex
  for (let [index, note] of melody.notesIndex.entries()) {
    // Play each note at scheduled time
    setTimeout(playNote, noteDuration * 1000 * index, note);
  }
  
  //prints index of notes from Major C for melody
  console.log(`${melody.notesIndex}`)
}

//User Interface
function drawMelody() {
  // draw key buttons
  let keyWidth = width / numNotes;

  //Loop for the number of notes available
  for (let i = 0; i < numNotes; i++) {
    //set x for each element
    let x = i * keyWidth;
    let y = keyWidth * 3; // height 3x width

    /*  
    Check if the oscillator[i] has started playing and
    the index for the oscillator (i) matches the value 
    in melody.notesIndex[i]
      */
    if (oscillators[i].started) {
 

      //true: define a local variable h
      //using map(), numNotes and i
      let h = map(i, 0, numNotes, 0, 360);
      // use h in fill to set the color of the button
      fill(h, 100, 100);
    } else {
      fill("white");
    }

    // Draw a rounded rectangle button.
    rect(x, y, keyWidth, keyWidth * 2, 10);
  }
}

// Sets tempo of melody object
function setTempo() {
  // Check that the tempo choice isn’t 0
  if (tempoSelect.selected() !== 0) {
    melody.tempo = tempoSelect.selected();
    noteDuration = 60 / melody.tempo;
  }
}

// Set name of melody.
function setName(){
    melody.name = nameInput.value();
}

//Reset melody object
function resetMelody(){
  // Empty melody object
  melody.name =  "Untitled", 
  melody.notesIndex = [], 
  melody.tempo = 0,
    
  // Reset tempo dropdown
  tempoSelect.selected(0);
      }

//save notes based on rectangles on the screen
function updateMelody() {
  //width of keys
  let keyWidth = width / numNotes;
  
  //Loop for the number of notes available
  for (let i = 0; i < numNotes; i++) {
    //set x and y for each element
    let x = i * keyWidth;
    let y = keyWidth * 3;
  
        /* Check if the mouse is 
        over the key */
        if (mouseX > x && 
            mouseX < x + keyWidth && 
            mouseY > y && 
            mouseY < y + keyWidth * 2) {
          
          //save notes index array
          let notes = melody.notesIndex;
          
          //add new note index to the array
          notes.push(i);
          
          //reassign to melody object
          melody.notesIndex = notes;
          
          //play note at that index
          playNote(i);
        }
      }
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions