Javascript 基于Web音频API的和弦检测算法

Javascript 基于Web音频API的和弦检测算法,javascript,algorithm,web-audio-api,audio-processing,audio,Javascript,Algorithm,Web Audio Api,Audio Processing,Audio,首先,我尝试实现这个和弦检测算法: 我最初实现了使用麦克风的算法,但没有成功。作为测试,我创建了三个振荡器来制作c弦,但算法仍然不起作用。我想我应该只看到C、E和G的数字更高,但我看到所有音符的数字。我的算法实现有问题吗?或者它是我的N,fref,还是fs值 下面是一段包含重要部分的代码: // Set audio Context window.AudioContext = window.AudioContext || window.webkitAudioContext; var media

首先,我尝试实现这个和弦检测算法:

我最初实现了使用麦克风的算法,但没有成功。作为测试,我创建了三个振荡器来制作c弦,但算法仍然不起作用。我想我应该只看到C、E和G的数字更高,但我看到所有音符的数字。我的算法实现有问题吗?或者它是我的N,fref,还是fs值

下面是一段包含重要部分的代码:

// Set audio Context
window.AudioContext = window.AudioContext || window.webkitAudioContext;

var mediaStreamSource = null;
var analyser = null;
var N = 4096;//8192;//2048; // Samples of Sound
var bufferLen = null;
var buffer = null;
var PCP = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // Pitch Class Profiles
var fref = 261.63; // Reference frequency middle C (C4)
// fref = 65.4; // Reference frequency C2
// fref = 440.0; // Reference frequency A4
var audioContext = new AudioContext();
var fs = audioContext.sampleRate; // Retrieve sampling rate. Usually 48KHz
var useMicrophone = false;

navigator.mediaDevices.getUserMedia(constraints)
  .then(function(stream) {
    // Create an analyzer node to process the audio
    analyser = audioContext.createAnalyser();
    analyser.fftSize = N;
    bufferLen = N / 2;
    //bufferLen = analyser.frequencyBinCount;
    console.log( 'bufferLen = ' + bufferLen );
    buffer = new Float32Array(bufferLen);

    if ( useMicrophone ) {
      // Create an AudioNode from the stream.
      mediaStreamSource = audioContext.createMediaStreamSource(stream);
      // Connect it to the destination.
      mediaStreamSource.connect(analyser);
    }
    else {
      // As a test, feed a C chord directly into the analyzer
      // C4, E4, G4
      var freqs = [261.63, 329.63, 392.00];
      for( var i=0; i < freqs.length; i++) {
        var o = audioContext.createOscillator();
        var g = audioContext.createGain(); //Create Gain Node
        o.frequency.value = freqs[i];
        o.connect(g);
        g.gain.value = 0.25;
        g.connect( audioContext.destination );
        g.connect( analyser );
        o.start(0);
        //setTimeout(function(s) {s.stop(0)}, 1000, o);
      }
    }

    // Call algorithm every 50 ms
    setInterval(function() {
      pcpAlg();
    }, 50);
  })
  .catch(function(err) {
    console.log(err.name + ": " + err.message);
  });

function pcpAlg() {
  analyser.getFloatTimeDomainData(buffer);
  //analyser.getFloatFrequencyData( buffer );
  // Reset PCP
  PCP = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  // M(0)=-1 so we don't have to start at 0
  for (var l = 1; l < bufferLen; l++) { // l = 0,1,...,[(N/2) - 1]
    // Calculate M(l)
    var ML = Math.round(12 * Math.log2( (fs * (l / N) ) / fref ) ) % 12; //
    //console.log( ML );
    if (ML >= 0 && ML <= 11) {
      PCP[ML] += Math.pow( Math.abs( buffer[l] ), 2 );
    }
  }

  // Display Data on UI and also try to determine if the sound is a C or F chord
  displayAndCategorize();
}
//设置音频上下文
window.AudioContext=window.AudioContext | | window.webkitadiocontext;
var mediaStreamSource=null;
var分析仪=零;
var N=4096//8192;//2048; // 声音样本
var bufferLen=null;
var buffer=null;
变量PCP=[0,0,0,0,0,0,0,0,0,0,0,0];//沥青等级剖面图
var fref=261.63;//参考频率中间值C(C4)
//fref=65.4;//参考频率C2
//fref=440.0;//参考频率A4
var audioContext=新的audioContext();
var fs=audioContext.sampleRate;//检索采样率。通常为48KHz
var=false;
navigator.mediaDevices.getUserMedia(约束)
.then(函数(流){
//创建analyzer节点以处理音频
Analyzer=audioContext.createAnalyzer();
分析仪.fftSize=N;
bufferLen=N/2;
//bufferLen=分析仪频率B计数;
log('bufferLen='+bufferLen);
buffer=新的Float32Array(bufferLen);
如果(使用麦克风){
//从流中创建AudioNode。
mediaStreamSource=audioContext.createMediaStreamSource(流);
//将其连接到目的地。
mediaStreamSource.connect(分析仪);
}
否则{
//作为测试,将C弦直接输入分析仪
//C4、E4、G4
风险值频率=[261.63329.63392.00];
对于(变量i=0;i如果(ML>=0&&ML问题在于1999年的一篇论文中的算法。您似乎在使用FFT计算幅值峰值,这是一种粗略的频谱频率估计器,而不是音高检测器/估计器。复调和弦估计是一项更为困难/复杂的任务。请在此查找有关复调和弦最新算法的研究论文ic提取:

听起来像是一个很酷的项目,但你确定输入是正确的吗?你有没有尝试过用假硬编码输入值来检查这种情况下的输出是否正确?你不想得到浮点频率数据而不是缓冲区中的时域数据吗?我还假设你想从fft结果中提取适当的bin to累加到PCP中。您当前只获取第一个时间值。我不确定是否有足够的知识将其标记为正确。我在1999年的论文中选择实现该算法,因为它似乎是我能够实现的,并且它声称是一个和弦检测算法。这两篇论文中也引用了该算法:和Wi在1999年的论文中,有他的算法检测和弦的输出。也许他在论文中遗漏了什么?