如何在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
相关产品推荐
相关产品推荐

