You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于Audio Web API实现网页循环工作站的录制循环功能技术问询

Hey there! Let's tackle this loop recording feature you need for your web-based looper station. Here's a practical, step-by-step solution that integrates seamlessly with your existing code:

Key Concepts to Implement

We'll use MediaRecorder to capture the microphone input, convert the recorded blob to an AudioBuffer, and then use AudioBufferSourceNode with the loop flag enabled to create continuous playback. We'll also manage state to toggle between recording and playback modes cleanly.

Full Integrated Code

Here's how to update your code to add the loop recording functionality:

window.AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
let mediaStreamSource;
let inputgain;
let outputgain;
let isRecording = false;
let mediaRecorder;
let recordedChunks = [];
let loopSourceNode = null;

// Initialize microphone and audio nodes
async function initMicrophone() {
  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaStreamSource = audioContext.createMediaStreamSource(stream)
    inputgain = audioContext.createGain()
    outputgain = audioContext.createGain()
    
    // Base audio chain: Mic → Input Gain → Output Gain → Speakers
    mediaStreamSource.connect(inputgain)
    inputgain.connect(outputgain)
    outputgain.connect(audioContext.destination)
    
    // Set up MediaRecorder for capturing audio
    mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm; codecs=opus' });
    
    // Collect recorded data chunks
    mediaRecorder.ondataavailable = (e) => {
      if (e.data.size > 0) {
        recordedChunks.push(e.data);
      }
    };
    
    // Process recorded data when recording stops
    mediaRecorder.onstop = async () => {
      const audioBlob = new Blob(recordedChunks, { type: 'audio/webm' });
      const arrayBuffer = await audioBlob.arrayBuffer();
      const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
      
      // Create a loopable playback node
      loopSourceNode = audioContext.createBufferSource();
      loopSourceNode.buffer = audioBuffer;
      loopSourceNode.loop = true; // Enable continuous looping
      loopSourceNode.connect(outputgain);
      loopSourceNode.start(); // Start playback immediately
      
      // Reset chunk array for next recording
      recordedChunks = [];
    };
  } catch (err) {
    console.error('Failed to access microphone:', err);
  }
}

// Toggle recording/playback with a button
document.getElementById('recordBtn').addEventListener('click', async () => {
  // Resume AudioContext if it's suspended (browser security requirement)
  if (audioContext.state === 'suspended') {
    await audioContext.resume();
  }
  
  if (!isRecording) {
    // Stop existing loop if present before starting new recording
    if (loopSourceNode) {
      loopSourceNode.stop();
      loopSourceNode = null;
    }
    
    isRecording = true;
    mediaRecorder.start();
    inputgain.connect(outputgain); // Let user hear their live input
    document.getElementById('recordBtn').textContent = 'Stop Recording';
  } else {
    isRecording = false;
    mediaRecorder.stop();
    inputgain.disconnect(outputgain); // Disable live input monitoring during loop playback
    document.getElementById('recordBtn').textContent = 'Start Recording';
  }
});

// Initialize on page load
initMicrophone();

Important Notes

  • Browser MIME Type Support: The audio/webm; codecs=opus format is widely supported, but you can check compatibility with MediaRecorder.isTypeSupported('your-mime-type') if you run into issues.
  • AudioContext Suspension: Browsers automatically suspend AudioContext until a user interaction (like a button click) occurs—this code handles resuming it when the button is pressed.
  • Clean Resource Management: We stop and discard old loop nodes when starting a new recording to avoid memory leaks and overlapping audio.
  • Input Monitoring: We disconnect the input gain from the output when playing loops to prevent feedback or live input mixing with the recorded loop.

内容的提问来源于stack exchange,提问作者corsiin

火山引擎 最新活动