Javascript 如何使用JS WebAudioAPI进行节拍检测?
我对使用JavaScriptJavascript 如何使用JS WebAudioAPI进行节拍检测?,javascript,audio,web-audio-api,beat-detection,Javascript,Audio,Web Audio Api,Beat Detection,我对使用JavaScriptWebAudioAPI检测歌曲节拍感兴趣,然后在画布中呈现它们 我可以处理画布部分,但我不是一个喜欢听音频的人,我真的不知道如何用JavaScript制作节拍检测器 我已经尝试了以下步骤,但在我的一生中,无法将每个函数之间的点连接起来,从而生成一个函数程序 我知道我应该给你看一些代码,但老实说,我没有任何代码,我所有的尝试都失败了,相关代码在前面提到的文章中 无论如何,我真的非常感谢一些指导,或者更好的是演示如何使用WebAudioAPI实际检测歌曲节拍 谢谢 需要了
WebAudioAPI
检测歌曲节拍感兴趣,然后在画布中呈现它们
我可以处理画布部分,但我不是一个喜欢听音频的人,我真的不知道如何用JavaScript制作节拍检测器
我已经尝试了以下步骤,但在我的一生中,无法将每个函数之间的点连接起来,从而生成一个函数程序
我知道我应该给你看一些代码,但老实说,我没有任何代码,我所有的尝试都失败了,相关代码在前面提到的文章中
无论如何,我真的非常感谢一些指导,或者更好的是演示如何使用WebAudioAPI
实际检测歌曲节拍
谢谢 需要了解的主要问题是,尽管它提供了大量源代码,但它远不是最终的完整代码。要获得有效的解决方案,您仍然需要一些编码和调试技能 此答案的大部分代码来自参考文章,原始许可适用于适当的地方。 下面是一个使用上述文章描述的函数的简单示例实现
代码包括为答案编写的准备代码:
- 通过网络读取本地文件
- 使用将文件解码为音频数据
- 过滤音频,在本例中使用
- 使用阈值计算峰值
- 分组间隔计数,然后是节奏计数
- 在参考文章中解释了处理背后的逻辑
- 语法可以在相关方法的API文档中引用
audio\u file.onchange=function(){
var file=this.files[0];
var reader=new FileReader();
var context=new(window.AudioContext | | window.webkitadiocontext)();
reader.onload=函数(){
上下文.解码音频数据(reader.result,函数(缓冲区){
制备(缓冲液);
});
};
reader.readAsArrayBuffer(文件);
};
功能准备(缓冲区){
var offlineContext=new OfflineAudioContext(1,buffer.length,buffer.sampleRate);
var source=offlineContext.createBufferSource();
source.buffer=缓冲区;
var filter=offlineContext.createBiquadFilter();
filter.type=“低通”;
source.connect(过滤器);
filter.connect(offlineContext.destination);
source.start(0);
offlineContext.startRendering();
offlineContext.oncomplete=函数(e){
过程(e);
};
}
功能流程(e){
var filteredBuffer=e.renderedBuffer;
//如果要分析两个通道,请稍后使用另一个通道
var data=filteredBuffer.getChannelData(0);
var max=阵列最大值(数据);
var min=arrayMin(数据);
var阈值=最小值+(最大值-最小值)*0.98;
var peaks=getPeaksAtThreshold(数据,阈值);
var intervalCounts=任意类型(峰值)之间的计数间隔;
var tempoCounts=groupNeighborsByTempo(间隔计数);
tempoCounts.sort(函数(a,b){
返回b.count-a.count;
});
if(临时计数长度){
output.innerHTML=tempoCounts[0].tempo;
}
}
// http://tech.beatport.com/2014/web-audio/beat-detection-using-web-audio/
函数getPeaksAtThreshold(数据,阈值){
var peaksArray=[];
变量长度=data.length;
对于(变量i=0;i阈值){
peaksArray.push(i);
//向前跳约1/4s以越过此峰值。
i+=10000;
}
i++;
}
返回峰值阵列;
}
任意类型之间的函数计数间隔(峰值){
var区间计数=[];
峰值。forEach(函数(峰值、指数){
对于(变量i=0;i<10;i++){
var间隔=峰值[指数+i]-峰值;
var foundInterval=intervalCounts.some(函数(intervalCount){
if(intervalCount.interval==interval)返回intervalCount.count++;
});
//附加检查以避免后期处理中出现无限循环
如果(!isNaN(间隔)&&interval!==0&&foundInterval){
间歇推({
间隔:间隔,,
计数:1
});
}
}
});
返回间隔计数;
}
函数组邻居按节拍(间隔计数){
var tempoCounts=[];
forEach(函数(intervalCount){
//把一个音程转换成节奏
var理论平均值=60/(区间数/区间数/44100);
theoreticalTempo=数学圆(theoreticalTempo);
if(theoreticalTempo==0){
返回;
}
//调整节奏以适应90-180 BPM的范围
而(theoreticalTempo<90)theoreticalTempo*=2;
而(theoreticalTempo>180)theoreticalTempo/=2;
var foundTempo=tempoCounts.some(函数(tempoCount){
if(tempoCount.tempo==theory-altempo)返回tempoCount.count+=intervalCount.count;
});
如果(!foundTempo){
临时计数({
节奏:理论上的节奏,
计数:intervalCount.count
});
}
});
返回临时计数;
}
// http://stackoverflow.com/questions/1669190/javascript-min-max-array-values
函数arrayMin(arr){
var len=阵列长度,
最小值=无穷大;
而(len--){
如果(arr[len]max){
max=arr[len];
}
}
返回最大值;
}
最可能的节奏:
我在这里编写了一个教程,展示了如何使用javascript Web Audio API实现这一点
步骤概述
function countFlatLineGroupings(data) {
var groupings = 0;
var newArray = normalizeArray(data);
function getMax(a) {
var m = -Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] > m) {
m = a[i];
}
}
return m;
}
function getMin(a) {
var m = Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] < m) {
m = a[i];
}
}
return m;
}
var max = getMax(newArray);
var min = getMin(newArray);
var count = 0;
var threshold = Math.round((max - min) * 0.2);
for (var i = 0; i < newArray.length; i++) {
if (newArray[i] > threshold && newArray[i + 1] < threshold && newArray[i + 2] < threshold && newArray[i + 3] < threshold && newArray[i + 6] < threshold) {
count++;
}
}
return count;
}
// Count the Groupings
countFlatLineGroupings(lowPassBuffer);
window.lowPassBuffer // Low Pass Array Buffer
window.originalBuffer // Original Non Filtered Array Buffer
function getClip(length, startTime, data) {
var clip_length = length * 44100;
var section = startTime * 44100;
var newArr = [];
for (var i = 0; i < clip_length; i++) {
newArr.push(data[section + i]);
}
return newArr;
}
// Overwrite our array buffer to a 10 second clip starting from 00:10s
window.lowPassFilter = getClip(10, 10, lowPassFilter);
function getSampleClip(data, samples) {
var newArray = [];
var modulus_coefficient = Math.round(data.length / samples);
for (var i = 0; i < data.length; i++) {
if (i % modulus_coefficient == 0) {
newArray.push(data[i]);
}
}
return newArray;
}
// Overwrite our array to down-sampled array.
lowPassBuffer = getSampleClip(lowPassFilter, 300);
function normalizeArray(data) {
var newArray = [];
for (var i = 0; i < data.length; i++) {
newArray.push(Math.abs(Math.round((data[i + 1] - data[i]) * 1000)));
}
return newArray;
}
// Overwrite our array to the normalized array
lowPassBuffer = normalizeArray(lowPassBuffer);
function countFlatLineGroupings(data) {
var groupings = 0;
var newArray = normalizeArray(data);
function getMax(a) {
var m = -Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] > m) {
m = a[i];
}
}
return m;
}
function getMin(a) {
var m = Infinity,
i = 0,
n = a.length;
for (; i != n; ++i) {
if (a[i] < m) {
m = a[i];
}
}
return m;
}
var max = getMax(newArray);
var min = getMin(newArray);
var count = 0;
var threshold = Math.round((max - min) * 0.2);
for (var i = 0; i < newArray.length; i++) {
if (newArray[i] > threshold && newArray[i + 1] < threshold && newArray[i + 2] < threshold && newArray[i + 3] < threshold && newArray[i + 6] < threshold) {
count++;
}
}
return count;
}
// Count the Groupings
countFlatLineGroupings(lowPassBuffer);
var final_tempo = countFlatLineGroupings(lowPassBuffer);
// final_tempo will be 21
final_tempo = final_tempo * 6;
console.log("Tempo: " + final_tempo);
// final_tempo will be 126