在 p5.js 中使用 for 循环索引音符仅播放单个音符。尽管有 setTimeout,但仍会执行 for 循环。不会按预期播放

发布于 2025-01-12 19:15:54 字数 443 浏览 0 评论 0原文

希望运行 for 循环索引音符。运行 forloop 而不按预期演奏音符。花了几天时间阅读文档、堆栈溢出、youtube 编码训练,但仍然无法使其按预期工作,请帮忙

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绝情姑娘 2025-01-19 19:15:55

setTimeout 函数仅控制何时调用 playStuff() 函数,从而控制何时开始演奏音符。一旦调用 playStuff() 函数,它将与浏览器一样快地执行。重要的是:p5.MonoSynth.play() 不会阻塞直到播放完毕。它只是安排要播放的音符并立即返回。有两种方法可以实现所需的计时: 1) 使用带有延迟的 async/away 为 for 循环添加时间延迟; 2) 让 playStuff 接受索引参数并仅播放单个音符,但安排其自身稍后使用 setTimeout 再次调用。我打算建议第三个选项:利用 p5.MonoSynth.play() 的第三个参数,这是从现在开始播放音符的时间。然而,您似乎只能安排一个未开始的笔记。

就我个人而言,我喜欢选项#1,因为它不会实质性地改变代码的结构。然而,它确实有一个缺点,即需要对 JavaScript 中的异步编程有一定的了解。

注意:这些代码片段不会产生任何音频,因为 StackOverflow 会阻止 Stack Snippet iframe 中的音频

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>

奢欲 2025-01-19 19:15:55

该演示将使用计时器每秒在数组中播放一次音符。如果你想让它重复循环,删除 noLoop() 并插入 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();}  
}

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();}  
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文