为彼此独立工作的按钮重用一个功能?

Reusing a function for buttons that work independently of each other?

我正在尝试使用 P5.js 创建类似于音频循环器的东西——也就是说,您录制一段音频,它作为循环播放给您,然后您可以录制其他片段一起播放的音频来创作歌曲。

我想出了如何录制音频、循环播放和停止循环的方法,但我不确定重复该功能的最佳方法,以便它可以用于独立于彼此录制单独的音频文件,因为我想录制多个循环。

我对 P5.js 还是很陌生,所以可能有一种简单的方法可以做到这一点——任何想法都有帮助!总的来说,如果您对如何实现整个项目(音频循环器)有任何想法,我很乐意听取他们的意见。

这是我的代码:

let mic, recorder, soundFile, button;

let state = 0;

function setup() {
  createCanvas(windowWidth, windowHeight);
  background(200);
  mic = new p5.AudioIn();
  mic.start();
  recorder = new p5.SoundRecorder();
  recorder.setInput(mic);
  soundFile = new p5.SoundFile();

  button = createButton("record");

  button.size(200, 100);
  button.style("font-family", "Bodoni");
  button.style("font-size", "48px");

  button.position(10, 10, 10);
  button.mouseClicked(loopRecord);
}


// this is the looper
function loopRecord() {
  if (state === 0 && mic.enabled) {
    recorder.record(soundFile);

    background(255, 0, 0);
    state++;
  } else if (state === 1) {
    recorder.stop();

    background(0, 255, 0);
    state++;
  } else if (state === 2) {
    soundFile.loop();
    state++;
  } else if (state === 3) {
    soundFile.stop();
    state++;
  } else if (state === 4) {
    state === 0;
  }
} 

您应该以某种方式构建您的数据,以便每个按钮都有自己的状态(以及其他不应是全局的但对每个循环都是唯一的参数)。

这里是一个使用轨道对象数组的示例: https://editor.p5js.org/RemyDekor/sketches/gM75vBYmk

我也把代码复制过来

let mic

// this array will be filled afterwards
let tracksArray = [];

function setup() {
  createCanvas(400, 400);
  background(200);
  
  // we need only one mic (it is still global)
  mic = new p5.AudioIn();
  mic.start();
  
  // we call a function that creates a custom "track" object and puts it in the tracksArray (which you could use for some other things, but is currently un-used)
  createTrack();
  
  // we create a button that call the same function when we click on it
  const addTrackButton = createButton("add track");
  addTrackButton.mouseClicked(createTrack)
  addTrackButton.position(10, 10)
}

// We now use names (strings) instead of abstract numbers to set the state of the track
function handleTrackButtonClick(trackObject) {
  if (trackObject.state === "idle" && mic.enabled) {
    trackObject.recorder.record(trackObject.soundFile);
    background(255, 0, 0);
  
    trackObject.state = "recording";
    console.dir(trackObject.button.elt.innerText = "[recording..]");
    
  } else if (trackObject.state === "recording") {
    trackObject.recorder.stop();
    background(0, 255, 0);
    
    trackObject.state = "stopped";
    console.dir(trackObject.button.elt.innerText = "play");
  
  } else if (trackObject.state === "stopped") {
    trackObject.soundFile.loop();
    
    trackObject.state = "playing";
    console.dir(trackObject.button.elt.innerText = "[playing..] stop")
    
  } else if (trackObject.state === "playing") {
    trackObject.soundFile.stop();
    
    trackObject.state = "stopped";
    console.dir(trackObject.button.elt.innerText = "[stopped..] play")
  }
}


function createTrack() {
  const newButton = createButton("record");
  newButton.style("font-family", "Bodoni");
  newButton.style("font-size", "48px");
  // we do not position this button anymore, and use the "flow" of the html document
  newButton.style("display", "block");
  
  // this is the "track" object we create, and we attach the previously global parameters/states on it
  const newTrackObject = {
    button: newButton,
    state: "idle",
    recorder: new p5.SoundRecorder(),
    soundFile: new p5.SoundFile()
  };
  
  newButton.mouseClicked(function() {
     handleTrackButtonClick(newTrackObject)
  });
  
  newTrackObject.recorder.setInput(mic);
  
  tracksArray.push(newTrackObject);
}