wish to run a for loop indexing musical notes. runs through forloop without playing notes as expected. have spent a few days reading docs, stack overflow, youtube coding train and still cannot get it to work as expected please help

let notes=["A4","B4","C4","D4"]
function setup() {

  monoSynth = new p5.MonoSynth();
  setTimeout(playStuff,1000)
}

function playStuff(){
  let i=0
  for (i=0;i<notes.length;i++){
    
    monoSynth.play(notes[i], 5, 3, 1 / 6);
    print(i)
    
  }//for i  
}//playStuff

function draw() {
  playStuff()
  noLoop()
}//draw
2

There are 2 best solutions below

0
apodidae On

This demo will play a note every second, one time through the array, using a timer. If you want it to loop repeatedly, delete the noLoop() and insert counter = 0;

var loopTimer = 0;
let interval = 1000;
let notes = ["A4","B4","C4","D4"];
var counter = 0;

function setup() {
  monoSynth = new p5.MonoSynth();
}

function draw() {  
  if(millis() >= loopTimer){
     loopTimer += interval;
     monoSynth.play(notes[counter], 5, 3, 1/6);
    counter++;
     }
  if(counter > 3) {noLoop();}  
}
1
Paul Wheeler On

The setTimeout function is only going to control when the playStuff() function is called, and thus when you start playing notes. Once the playStuff() function is called it will execute as fast as the browser can. Importantly: p5.MonoSynth.play() does not block until the not finishes playing. It simply schedules the note to be played and returns immediately. There are two ways you can achieve the desired timing: 1) Use async/away with a delay to add a time delay to your for loop; 2) Have playStuff take an index argument and only play a single note, but schedule itself to be called again later using setTimeout. I was going to suggest a third option: utilize the third parameter of p5.MonoSynth.play() which is the time from the present when the note should be played. However it seems that you can have only a single un-started note scheduled.

Personally I like option #1 because it doesn't substantially change the structure of the code. However it does have the downside of requiring some understanding of asynchronous programming in JavaScript.

Note: These snippets will not produce any audio, because StackOverflow blocks audio in Stack Snippet iframes

let notes = ["A4", "B4", "C4", "D4"]

let delaySlider;
let durationSlider;

function setup() {
  noCanvas();
  noLoop();
  monoSynth = new p5.MonoSynth();
  let container = createDiv();
  container.style('display', 'flex');
  container.style('align-items', 'flex-start');
  container.style('height', 'fit-content');

  createSpan('Delay: ').parent(container);
  delaySlider = createSlider(1, 20, 2);
  delaySlider.parent(container);
  createSpan('Duration: ').parent(container);
  durationSlider = createSlider(1, 20, 1);
  durationSlider.parent(container);
}

let playing = false;

function mousePressed(e) {
  if (!playing && e.target !== delaySlider.elt && e.target !== durationSlider.elt) {
    playStuff();
  }
}

function asyncDelay(t) {
  return new Promise(res => setTimeout(res, t));
}

async function playStuff() {
  playing = true;
  for (let note of notes) {
    monoSynth.play(note, 5, 0, durationSlider.value() / 6);
    print(note);
    await asyncDelay(delaySlider.value() / 6 * 1000);
  }

  playing = false;
} //playStuff

function draw() {} //draw
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script>

Option #2

let notes = ["A4", "B4", "C4", "D4"]

let delaySlider;
let durationSlider;

function setup() {
  noCanvas();
  noLoop();
  monoSynth = new p5.MonoSynth();
  let container = createDiv();
  container.style('display', 'flex');
  container.style('align-items', 'flex-start');
  container.style('height', 'fit-content');

  createSpan('Delay: ').parent(container);
  delaySlider = createSlider(1, 20, 2);
  delaySlider.parent(container);
  createSpan('Duration: ').parent(container);
  durationSlider = createSlider(1, 20, 1);
  durationSlider.parent(container);
}

let playing = false;

function mousePressed(e) {
  if (!playing && e.target !== delaySlider.elt && e.target !== durationSlider.elt) {
    playStuff(0);
  }
}

function playStuff(noteIndex) {
  playing = true;
  let note = notes[noteIndex];
  monoSynth.play(note, 5, 0, durationSlider.value() / 6);
  print(note);

  if (noteIndex + 1 < notes.length) {
    setTimeout(playStuff, delaySlider.value() / 6 * 1000, noteIndex + 1);
  } else {
    setTimeout(
      () => {
        playing = false;
      },
      delaySlider.value() / 6 * 1000
    );
  }
} //playStuff

function draw() {} //draw
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/addons/p5.sound.min.js"></script>