0

I have to create a animation Like Google.com Dekstop Mic shows (i.e. scaling of the mic border according to the loudness of voice). I have used the Web Speech API with reference from here (MDN) which shows how we can change the background colour of the webpage using our voice, it work's fine but I want to add Animation Like Google's site( mentioned above).
I have searched a lot to find a way to achieve this animation but I was unable to find this. So I am asking here as this is the best place where I can get my answer :)

Thanks a lot in advance for helping me out with this.

2
  • I'm not sure the volume indication can use the speech recognition API, but you can run 2 process in parallel. MDN has a nice example of volume indication by using audio analyzer -> frequencyBinCount
    – Mosh Feu
    Commented Dec 13, 2021 at 11:43
  • So how can I make the same animation just like Google?? Can you please guide me. Commented Dec 14, 2021 at 7:17

2 Answers 2

2

I'm not expert in this area but I followed the example in MDN and here is the result.

Beside the setup, the key point here is analyser.getByteFrequencyData which gives us the decibel levels.

In order to simplify the code, I took the highest decibel level in the array (Math.max.apply(null, dataArray)) but you can fine tuning it by average or any other calculation you like.

Demo

let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
let distortion = audioCtx.createWaveShaper();
let gainNode = audioCtx.createGain();
let biquadFilter = audioCtx.createBiquadFilter();
let analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;

analyser.fftSize = 256;

const mic = document.querySelector('.mic');
let isListening = false;
let tracks = [];

if (!navigator.mediaDevices.getUserMedia) {
  alert('getUserMedia not supported on your browser!');
}

mic.addEventListener('click', async () => {
  if (!isListening) {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      isListening = true;

      tracks = stream.getTracks();
      source = audioCtx.createMediaStreamSource(stream);
      source.connect(distortion);
      distortion.connect(biquadFilter);
      biquadFilter.connect(gainNode);
      gainNode.connect(analyser);
      analyser.connect(audioCtx.destination);

      requestAnimationFrame(function log() {
        let bufferLength = analyser.frequencyBinCount;
        let dataArray = new Uint8Array(bufferLength);
        analyser.getByteFrequencyData(dataArray);
        const level = Math.max.apply(null, dataArray);
        document.querySelector('#level span').textContent = level;
        mic.style.setProperty('--border', `${level / 5}px`);
        requestAnimationFrame(log);
      });
    } catch (err) {
      console.log('The following gUM error occured: ' + err);
    }
  } else {
    isListening = false;
    tracks.forEach((track) => {
      track.stop();
    });
  }
});
body {
  margin: 0;
  height: 100vh;
  position: relative;
}

.content {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 20px;
}

.mic {
  background: #fff;
  width: 50px;
  height: 50px;
  border: 1px solid #eee;
  border-radius: 100%;
  bottom: 0;
  box-shadow: 0 2px 5px var(--border) rgb(0 0 0 / 10%);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" type="text/css" href="styles.css" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
      integrity="sha512-Fo3rlrZj/k7ujTnHg4CGR2D7kSs0v4LLanw2qksYuRlEzO+tcaEPQogQ0KaoGN26/zrn20ImR1DfuLWnOo7aBA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    />
  </head>
  <body>
    <div class="content">
      <div class="mic">
        <i class="fas fa-microphone"></i>
      </div>
      <div id="level">Level: <span></span></div>
    </div>
    <script src="script.js"></script>
  </body>
</html>
2
  • Thanks for your kind help. Just one problem is there when I turn on the mic in your demo it creates Noise and when I mute the pc speaker no more noise is present. What is the reason behind that can u please tell me? Commented Dec 15, 2021 at 9:05
  • Because there is always a background noise. When the mic is muted, the computer is ignoring every audio input it gets including the noises.
    – Mosh Feu
    Commented Dec 15, 2021 at 10:36
-2
function GoogleMic() 
{
    var mic = $("#mic")
        , mic_anim = $("#mic-animate");

    // Detect API support
    window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition || null;
    if (window.SpeechRecognition === null) {
        mic.hide();
    }
    else {
        var input = $("#cse-search-input")
            , recognizer = new window.SpeechRecognition()
            , recognizing = false;

        // Start recognising
        //recognizer.continuous = true;
        recognizer.onstart = function (event) {
            recognizing = !0;
            mic.hide();
            mic_anim.show();
        }
        recognizer.onend = function () {
            recognizing = !1;
            recognizer.stop();
            mic.show();
            mic_anim.hide();
        };

        recognizer.onresult = function (event)
        {
            for (var i = event.resultIndex; i < event.results.length; i++) {
                if (event.results[i].isFinal) {
                    input.val(event.results[i][0].transcript);
                    // get word values and start your search function here then

                    recognizing = !1;
                    mic.show();
                    mic_anim.hide();
                } else {
                    console.log("Recognition error");
                }
            }
        };
        // Listen for errors
        recognizer.onerror = function () {
            console.log("Recognition denied");
        };

        // Click to speech search
        mic.on("click", function () {
            // Set if we need interim results
            //recognizer.interimResults = false;
            if (recognizing) {
                recognizer.stop();
                recognizing = !1;
                mic.hide();
                mic_anim.show();
            } else {
                recognizer.start();
            }
        });

        // Click to disable speech seach
        mic_anim.on("click", function () {
            recognizer.stop();
        });
    }
}

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.