You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PyScript中借助AudioContext动态创建并播放音频?

使用AudioContext实现动态连续音频流并集成到PyScript

一、核心JavaScript实现步骤

1. 初始化AudioContext与全局变量

先定义全局变量存储波形数据,完成AudioContext初始化:

const audio = new AudioContext({
  latencyHint: "interactive",
  sampleRate: 44100,
});

// 存储1秒波形数据(44100个浮点数)
let waveformData = new Float32Array(44100);
// 记录当前播放的采样位置,实现循环播放
let currentSamplePos = 0;

2. 创建音频处理器实现连续播放

使用ScriptProcessorNode实时填充音频输出,实现波形循环播放:

// 创建处理器,缓冲区大小设为4096(平衡延迟与性能)
const processor = audio.createScriptProcessor(4096, 0, 1);

processor.onaudioprocess = function(e) {
  const outputBuffer = e.outputBuffer.getChannelData(0);
  const outputLength = outputBuffer.length;

  // 循环读取波形数据填充输出缓冲区
  for (let i = 0; i < outputLength; i++) {
    outputBuffer[i] = waveformData[currentSamplePos];
    currentSamplePos = (currentSamplePos + 1) % 44100;
  }
};

// 将处理器连接到系统音频输出
processor.connect(audio.destination);

3. 实现波形更新函数

定义函数接收新的44100长度浮点数向量,替换当前波形:

function updateWaveform(newWaveform) {
  if (newWaveform.length !== 44100) {
    console.error("波形数据必须包含44100个采样点");
    return;
  }
  waveformData = newWaveform;
  // 重置播放位置(可选,也可继续当前进度)
  currentSamplePos = 0;
}

二、集成到PyScript示例

PyScript可直接调用JavaScript函数,实现Python生成波形、JS播放的联动。以下是完整示例:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
  <script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head>
<body>
  <input type="range" id="freqSlider" min="220" max="660" value="440" step="1">
  <p>当前频率: <span id="freqDisplay">440</span> Hz</p>

  <script>
    // 嵌入核心JavaScript代码
    const audio = new AudioContext({
      latencyHint: "interactive",
      sampleRate: 44100,
    });

    let waveformData = new Float32Array(44100);
    let currentSamplePos = 0;

    const processor = audio.createScriptProcessor(4096, 0, 1);

    processor.onaudioprocess = function(e) {
      const outputBuffer = e.outputBuffer.getChannelData(0);
      const outputLength = outputBuffer.length;

      for (let i = 0; i < outputLength; i++) {
        outputBuffer[i] = waveformData[currentSamplePos];
        currentSamplePos = (currentSamplePos + 1) % 44100;
      }
    };

    processor.connect(audio.destination);

    function updateWaveform(newWaveform) {
      if (newWaveform.length !== 44100) {
        console.error("波形数据必须包含44100个采样点");
        return;
      }
      waveformData = newWaveform;
      currentSamplePos = 0;
    }
  </script>

  <py-script>
    from js import document, updateWaveform, Float32Array
    import math

    def update_wave(e):
        # 获取滑块数值
        freq = int(document.getElementById("freqSlider").value)
        document.getElementById("freqDisplay").innerText = str(freq)
        
        # 生成1秒正弦波数据
        sample_rate = 44100
        new_wave = Float32Array(sample_rate)
        for i in range(sample_rate):
            new_wave[i] = math.sin(2 * math.pi * freq * i / sample_rate)
        
        # 调用JS函数更新波形
        updateWaveform(new_wave)

    # 绑定滑块变动事件
    document.getElementById("freqSlider").addEventListener("input", update_wave)
  </py-script>
</body>
</html>

关键说明

  • PyScript通过from js import ...导入JS全局对象与函数,直接传递生成的波形数据。
  • 滑块事件可选择在JS或PyScript中绑定,按需调整逻辑位置。
  • 浏览器安全策略要求音频播放需用户交互触发,可添加按钮调用audio.resume()避免自动播放被拦截。

注意事项

  • ScriptProcessorNode虽已标记为弃用,但目前主流浏览器仍支持;如需更现代方案,可使用AudioWorklet(实现复杂度更高)。
  • 波形数据取值范围需控制在[-1, 1],超出会导致音频失真。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:01:36