react-web-audio icon indicating copy to clipboard operation
react-web-audio copied to clipboard

Trying to convert class to hook style components

Open wchorski opened this issue 1 year ago • 0 comments

I've taken a wack at trying to convert AudioAnalyser.js to a Hook style Component. I got stuck on one error

The Code

import React, { Component, useRef, useEffect, useState } from 'react';
import AudioVisualiser from './AudioVisualiser';

export const AudioAnalyser = ( { audio } ) => {
  // constructor(props) {
  //   super(props);
  //   this.state = { audioData: new Uint8Array(0) };
  //   this.tick = this.tick.bind(this);
  // }
  const isMounted = useRef()

  const [audioData, setAudioData] = useState(new Uint8Array(0))
  // const [audioContext, setaudioContext] = useState()
  // const [analyser, setAnalyser] = useState()
  // usest
  const audioContext = useRef(null)
  const analyser = useRef(new Uint8Array(0))
  const dataArray = useRef(null)
  const source = useRef(null)
  let rafId = useRef(null)

  useEffect(() => {
    if(!isMounted.current){
      handleMount() // mount logic
      isMounted.current = true 

    } else {
      if(!analyser.current) return 
      tick() // update logic
    }
  
    // return () => {
    //   cancelAnimationFrame(rafId.current);
    //   analyser.current.disconnect();
    //   source.current.disconnect();
    // }
  })
  

  async function handleMount() {
    try {
      // this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
      const newAudCtx = new (window.AudioContext || window.webkitAudioContext)()
      audioContext.current = newAudCtx

      const newAnlyzer = newAudCtx.createAnalyser()
      analyser.current = newAnlyzer

      const newDtArr = new Uint8Array(newAnlyzer.current.frequencyBinCount)
      dataArray.current = newDtArr

      const newSrc = audioContext.current.createMediaStreamSource(audio);
      source.current = newSrc

      newSrc.connect(newAnlyzer)
      const newRafId = requestAnimationFrame(tick())
      rafId.current = newRafId
      
    } catch (error) {
      console.warn('audio analyser mount fail');
    }
  }

  function tick() {
    if(!analyser.current) return 
    analyser.current.getByteTimeDomainData(dataArray.current);
    // setState({ audioData: this.dataArray });
    setAudioData(dataArray.current)
    rafId.current = requestAnimationFrame(tick());
  }



  return <AudioVisualiser audioData={audioData} />
}

export default AudioAnalyser;

The Error

[!error] TypeError: Failed to execute 'getByteTimeDomainData' on 'AnalyserNode': parameter 1 is not of type 'Uint8Array'.

function tick() {
  67 |   if(!analyser.current) return 
> 68 |   analyser.current.getByteTimeDomainData(dataArray.current);
     |                   ^
  69 |   // setState({ audioData: this.dataArray });
  70 |   setAudioData(dataArray.current)
  71 |   rafId.current = requestAnimationFrame(tick());

The Question

can't tell if this is an initialization issue or a order of operations issue. Any guidance on how to correct is greatly appreciated.

wchorski avatar Mar 04 '23 00:03 wchorski