0

I am trying to capture the Sound Frequency value from the Device Microphone from a Web Browser, utilizing the Web Audio API. The Instructions only covers how to play a sound file and manipulate its output, ect.

I need to listen to a Humming Sound from a person and figure out the Sound frequency, which I will then convert to a musical note. I need to build an array with all the frequencies that are generated from a Single Musical Note that I play from a digital Piano keyboard. I will then get the mode of all the frequencies to get the actual Musical note.

I am able to display the frequency and notes that I detect onto the Console.log(), however, I am not able to build the array, get the mode, and then clear-out the array when I play a new note. My array remains active because the code is on an event listening mode and remains active to listen for the next note.

This is my code:

var arrayList = [];
function getModes(array) {

    var frequency = []; // array of frequency.
    var maxFreq = 0; // holds the max frequency.
    var modes = [];

    for (var i in array) {
        frequency[array[i]] = (frequency[array[i]] || 0) + 1; // increment frequency.

        if (frequency[array[i]] > maxFreq) { // is this frequency > max so far ?
            maxFreq = frequency[array[i]]; // update max.
        }
    }

    for (var k in frequency) {
        if (frequency[k] == maxFreq) {
            modes.push(k);
        }
    }

    return modes;
}


function updatePitch(time) {
    
    var cycles = new Array;
    analyser.getFloatTimeDomainData(buf);
    var ac = autoCorrelate(buf, audioContext.sampleRate);
    // TODO: Paint confidence meter on canvasElem here.

    if (DEBUGCANVAS) {  // This draws the current waveform, useful for debugging
        waveCanvas.clearRect(0, 0, 512, 256);
        waveCanvas.strokeStyle = "red";
        waveCanvas.beginPath();
        waveCanvas.moveTo(0, 0);
        waveCanvas.lineTo(0, 256);
        waveCanvas.moveTo(128, 0);
        waveCanvas.lineTo(128, 256);
        waveCanvas.moveTo(256, 0);
        waveCanvas.lineTo(256, 256);
        waveCanvas.moveTo(384, 0);
        waveCanvas.lineTo(384, 256);
        waveCanvas.moveTo(512, 0);
        waveCanvas.lineTo(512, 256);
        waveCanvas.stroke();
        waveCanvas.strokeStyle = "black";
        waveCanvas.beginPath();
        waveCanvas.moveTo(0, buf[0]);

        for (var i = 1; i < 512; i++) {
            waveCanvas.lineTo(i, 128 + (buf[i] * 128));
        }
        waveCanvas.stroke();
    }

    if (ac == -1) {
        detectorElem.className = "vague";
        pitchElem.innerText = "--";
        noteElem.innerText = "-";
        detuneElem.className = "";
        detuneAmount.innerText = "--";
    } else {
        detectorElem.className = "confident";
        pitch = ac;
        pitchElem.innerText = Math.round(pitch);
        var note = noteFromPitch(pitch);


        // Here is where I am converting the frequency to a note letter
        var noteString = noteStrings[note % 12];
        console.log(noteString);

        // This is where I am building the array range with the notes that I find
        // I have a nice array, but it keeps building and I do not know how to clear it for 
        // the next session.

        if (note >=36 && note <= 96) {      
            if (arrayList) {
                arrayList.push(noteString);
            }
            console.log(noteString);
        }
        else {
            console.log("not note");
            var MyNote = getModes(arrayList)
            noteElem.innerHTML = MyNote;
            arrayList = [];
            
        }

        //  This function remains active and continues to listen for the next not to 
        //  generate and new note letter
        
        var detune = centsOffFromPitch(pitch, note);
        if (detune == 0) {
            detuneElem.className = "";
            detuneAmount.innerHTML = "--";
        } else {
            if (detune < 0)
                detuneElem.className = "flat";
            else
                detuneElem.className = "sharp";
            detuneAmount.innerHTML = Math.abs(detune);
        }
    }
    
    if (!window.requestAnimationFrame)
        window.requestAnimationFrame = window.webkitRequestAnimationFrame;
    rafID = window.requestAnimationFrame(updatePitch);
}

How do I clear the array and use a new array when I play a new note? thank you for the support...

Johnny
  • 819
  • 1
  • 10
  • 24
  • `arrayList = []`? – Barmar Feb 24 '22 at 18:40
  • I wish it was that simple... I am doing this already in the else statement. – Johnny Feb 24 '22 at 18:59
  • I guess the `if` condition isn't correct to determine whether it's a new note. – Barmar Feb 24 '22 at 19:00
  • 1
    There are plenty of examples on the internet. For instance, https://webaudioapi.com/samples/microphone/ shows a sample of using the microphone. – Heretic Monkey Feb 24 '22 at 20:22
  • You may want to read [Why is using "for...in" for array iteration a bad idea?](https://stackoverflow.com/q/500504/215552) – Heretic Monkey Feb 24 '22 at 20:24
  • 1
    It's not clear what the issue is. You've not shown where `arrayList` is defined, but setting it equal to an empty array will do just that, unless there is a race condition and something else pushes to the array while that happens. There are ways of countering that, mainly through using a managing class that brokers access to an underlying array. – Heretic Monkey Feb 24 '22 at 20:32

0 Answers0