使用JavaScript播放PCM16时的饱和声音
Saturated sound when playing PCM16 with JavaScript
我正在尝试用AudioContext
对象播放原始PCM16缓冲区。声音确实在播放,但以一种非常饱和的方式播放。
问题可能来自于将无符号16位整数转换为[-1.0;1.0]浮点,但我认为我所做的没有任何问题。
我在下面做了一个最小的html样本,以便于复制。output.raw
文件可以通过以下命令从MP3文件中获得:
MP3FILE=myfile.mp3
ffmpeg -i $MP3FILE -f s16le -ac 1 -acodec pcm_s16le output.raw
我使用Linux Chromium Version 38.0.2125.111 (290379) (64-bit)
。
谢谢你的帮助!
EDIT:直接加载PCM32(s32le)样本会出现同样的问题。
<html>
<head>
</head>
<body>
<script>
var oReq = new XMLHttpRequest();
oReq.open("GET", "output.raw", true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var context = new window.AudioContext();
var pcm16Buffer = new Uint16Array(oReq.response);
var frameCount = pcm16Buffer.length;
var channels = 1;
var buffer = context.createBuffer(channels, frameCount, context.sampleRate);
for (var channel = 0; channel < channels; ++channel) {
var channelBuffer = buffer.getChannelData(channel);
for (var i = 0; i < frameCount; ++i) {
channelBuffer[i] = pcm16Buffer[i] * 2 / 65535 - 1;
}
}
var source = context.createBufferSource();
source.buffer = buffer;
source.connect(context.destination);
source.start();
};
function run() {
oReq.send();
}
</script>
<a href="javascript:run()">run</a>
</body>
</html>
答案:将PCM16转换为PCM32的上述循环是不正确的,因为它不能正确地转换2的补码。
您正在使用ffmpeg输出有符号的16位数据,但随后您正在通过Uint16Array
类型的数组在JavaScript中读取它,该数组是无符号的16位数。这不会在文件中为您提供-32k到+32k的值,这些值被转移到0到64k;值存储在二的补码中,因此负值将显示为较大的正值。主要需要做的是将pcm16Buffer
更改为Int16Array
。
转换为浮点可以是一个简单的
channelBuffer[i] = pcm16Buffer[i] / 32768;
Web Audio API只能呈现PCM缓冲区,因此无论音频源自何处,进程最终都必须提供该格式。首先,使用Audacity等其他工具验证您的输入文件是否正常。以下是一个输入WAV文件,它在渲染之前从中提取原始PCM缓冲区。
<html>
<head>
</head>
<body>
<script>
var audio_context, gain_node, source_node;
var chosen_audio_file_url = "output_2.wav";
// log if an error occurs
function on_error(e) {
console.log("ERROR - " + e);
}
try {
window.AudioContext = window.AudioContext ||
window.webkitAudioContext ||
window.mozAudioContext ||
window.oAudioContext ||
window.msAudioContext;
audio_context = new AudioContext();
console.log("cool audio context established");
} catch (e) {
alert("Web Audio API is not supported by this browser");
}
gain_node = audio_context.createGain(); // Declare gain node
gain_node.connect(audio_context.destination); // Connect gain node to speakers
source_node = audio_context.createBufferSource();
source_node.connect(gain_node);
var request = new XMLHttpRequest();
request.open('GET', chosen_audio_file_url, true);
request.responseType = 'arraybuffer';
// When loaded decode the data
request.onload = function() {
// decode the data
audio_context.decodeAudioData(request.response, function(buffer) {
console.log(chosen_audio_file_url, ' ... buffer.length ', buffer.length);
source_node.buffer = buffer;
source_node.start(0);
// ---
}, on_error);
}
function run() {
request.send();
}
</script>
<a href="javascript:run()">run</a>
</body>
</html>
如果您需要更多,请告诉我们
您试图从无符号转换为有符号,但您的代码没有做任何可能更改符号的事情。首先,通过减去32767将无符号的16位(0-65536)转换为带符号(-32767到32767)。然后除以32767,缩放到-1.0到1.0。此外,请确保您的除法是浮点除法。
channelBuffer[i] = (pcm16Buffer[i]-32767) / 32767.0;
- 如何在javascript中一个声音文件接一个声音地播放
- 使用javascript播放声音
- 如何检测网页中的更改并使用Javascript播放声音
- 无法使用JavaScript在iPhone上播放声音,但可以在Android上播放
- 在javascript中将声音转换为字节数组
- 为一个声音元素数组创建一个音频对象jquery,javascript
- 是否可以用javascript或任何脚本语言在浏览器或扬声器中录制播放的声音
- Javascript自动播放声音文件,单击其中一个按钮时停止
- javascript播放的声音不适用于chrome for android
- 播放连续的声音,用HTML5和javascript构建一个音频句子
- 在后台播放带有javascript的声音
- 如何在JavaScript中检测声音的频率
- 我的JavaScript声音在Windows XP中无法播放
- 使用类似 Javascript 的 matlab 播放声音
- Chrome for iOS 中的 JavaScript 可以播放声音吗?
- Javascript播放声音会导致“NPObject上的错误调用方法”
- Javascript中的空间(2D)声音
- 用javascript停止html声音
- 我如何在按钮点击上播放随机声音?JavaScript
- 播放声音Javascript或HTML