Во-первых, я пытаюсь реализовать этот аккорд алгоритм обнаружения: http://www.music.mcgill.ca/~jason/mumt621/papers5/fujishima_1999.pdfChord Detection Algorithm с Web Audio API
Я первоначально реализован алгоритм, чтобы использовать свой микрофон, но это не сработало. В качестве теста я создал три осциллятора, чтобы сделать 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();
}
Вот мой полный codepen если вы хотите попробовать запустить его самостоятельно. Предупреждение У меня есть useMicrophone установлен на false, поэтому он будет создавать звук с аккордом: https://codepen.io/mapmaps/pen/ONQPpw
Звучит как классный проект, но вы уверены, что вход правильный? Пробовали ли вы с поддельными жестко закодированными входными значениями, чтобы убедиться, что результат в этом случае правильный? –
Не хотите ли вы получать данные с поплавковой частотой вместо данных временной области в буфере? Я также предполагаю, что вы хотите извлечь соответствующий бит из fft-результата для накопления в PCP. Вы только сейчас получаете первое значение. –