JSFiddle - React, Tailwind, and code Playground

by soulwire

HTML

<button id="start">
Start
</button>

JavaScript

class AdvancedSpeechDetector {
  constructor(callback) {
    this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
    this.analyser = this.audioContext.createAnalyser();
    this.microphone = null;
    this.scriptProcessor = null;
    this.callback = callback;
    this.analyser.fftSize = 1024; // Frequency resolution
    this.smoothingTimeConstant = 0.3; // Smoother transitions
  }

  async start() {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      this.microphone = this.audioContext.createMediaStreamSource(stream);
      this.scriptProcessor = this.audioContext.createScriptProcessor(2048, 1, 1);

      this.microphone.connect(this.analyser);
      this.analyser.connect(this.scriptProcessor);
      this.scriptProcessor.connect(this.audioContext.destination);

      this.scriptProcessor.onaudioprocess = (event) => {
        const inputData = event.inputBuffer.getChannelData(0);
        const volume = this.calculateRMS(inputData);
        const zcr = this.calculateZeroCrossingRate(inputData);
        const speechPresence = this.analyzeFrequency();

        // Decide if speech is present based on multiple factors
        const isSpeaking = volume > 0.02 && zcr > 200 && speechPresence;
        this.callback(isSpeaking);
      };
    } catch (error) {
      console.error("Error accessing microphone:", error);
    }
  }

  stop() {
    if (this.scriptProcessor) this.scriptProcessor.disconnect();
    if (this.microphone) this.microphone.disconnect();
  }

  calculateRMS(samples) {
    let sum = 0;
    for (let i = 0; i < samples.length; i++) {
      sum += samples[i] * samples[i];
    }
    return Math.sqrt(sum / samples.length);
  }

  calculateZeroCrossingRate(samples) {
    let crossings = 0;
    for (let i = 1; i < samples.length; i++) {
      if ((samples[i - 1] < 0 && samples[i] > 0) || (samples[i - 1] > 0 && samples[i] < 0)) {
        crossings++;
      }
    }
    return crossings;
  }

 ...