skip to Main Content

I am a bit struggling to create a sound from a buffer object with Tone.js

It should be simple, but I am in unfamiliar territory. And increasingly unuseful suggestions from chatGPT discombobulated me very.

Here is the code (I know the code is a bit messy. Sorry for that, I couldn’t make it even simplified)

import React, { useEffect, useState } from 'react';
import * as Tone from 'tone';

function AudioPlayer() {
  const [isPlaying, setIsPlaying] = useState(false);
  const chunkSize = 1024;
  const bufferArray = new Float32Array(chunkSize);
  const sampleRate = 16384;
  let t = 0;
  let x = 0;
  const context = Tone.context;
  const buffer = context.createBuffer(1, chunkSize, sampleRate);
// const source = context.createBufferSource(); <= do I really need this!
  const player = new Tone.Player(buffer).toDestination();

  useEffect(() => {

    while (isPlaying){
      for (let i = 0; i < chunkSize; i++) {
        bufferArray[i] = Math.sin(2 * Math.PI * 440 * x);
        t++;
        x = t / sampleRate;
      }
      // buffer.fromArray(bufferArray); <= is there a simple method that just override on buffer? 
    }

    
  }, [isPlaying]);

  const handlePlayClick = async () => {
    setIsPlaying(true);
    player.start()
    
  };

  const handleStopClick = () => {
    setIsPlaying(false);
    player.stop()
  };

  return (
    <div>
      {!isPlaying && (
        <button onClick={handlePlayClick}>Play</button>
      )}
      {isPlaying && (
        <button onClick={handleStopClick}>Stop</button>
      )}
    </div>
  );
}

export default AudioPlayer;


I just want to fill the buffer(bufferArray[chunkSize]) and override the bufferArray and play it continuously.

2

Answers


  1. Chosen as BEST ANSWER

    Here is an answer -not quite, but works- for the question that I asked.

    import React, { useEffect, useState } from 'react';
    
    function AudioPlayer() {
      const [isPlaying, setIsPlaying] = useState(false);
      const [audioCtx, setAudioCtx] = useState(false);
      const [oscillator, setOscillator] = useState(null);
      // const audioDataArray = [-1, 1]//[...Array(4)].map(e => Math.random(-1, 1));
      const [audioDataArray, setAudioDataArray] = useState([-1, 1]);
    
      useEffect(() => {
        // Create an oscillator and set the waveform to the custom audio data array
        if (!isPlaying){
          const ac = new AudioContext();
          setAudioCtx(ac)
          const oscillator = ac.createOscillator();
          const real = new Float32Array(audioDataArray);
          const imag = new Float32Array(audioDataArray.length).fill(0);
          const wave = ac.createPeriodicWave(real, imag);
          oscillator.setPeriodicWave(wave);
          console.log(oscillator)
          oscillator.connect(ac.destination);
          setOscillator(oscillator);
        }
    
      }, [isPlaying]);
    
      useEffect(() => {
        // Update the audio data array with new random values every 100 milliseconds
        const intervalId = setInterval(() => {
          const newAudioDataArray = [...Array(4)].map(e => Math.random(-1, 1));
          setAudioDataArray(newAudioDataArray);
        }, 100);
    
        return () => {
          clearInterval(intervalId);
        };
      }, []);
    
      const handlePlayClick = () => {
        if (!isPlaying && oscillator) {
          setIsPlaying(true);
          oscillator.start();
        }
      };
    
      const handleStopClick = () => {
        if (isPlaying && oscillator) {
          setIsPlaying(false);
          oscillator.stop();
          oscillator.disconnect();
          setOscillator(null);
        }
      };
    
      const handleUpdateClick = () => {
        if (oscillator) {
          const real = new Float32Array(audioDataArray);
          const imag = new Float32Array(audioDataArray.length).fill(0);
          const wave = audioCtx.createPeriodicWave(real, imag);
          oscillator.setPeriodicWave(wave);
        }
      };
    
      return (
        <div>
          <button onClick={handlePlayClick}>Play</button>
          <button onClick={handleStopClick}>Stop</button>
          <button onClick={handleUpdateClick}>Update Waveform</button>
        </div>
      );
    }
    
    export default AudioPlayer;
    

  2. I have close to zero idea what I’m doing and I’m not sure I understand the question, but I played around a bit; does the following help at all?:

    const sampleRate = 16384;
    
    const get_audio_buffer = () => {
      return Tone.context.createBuffer(
        1,
        sampleRate,
        sampleRate
      );
    };
    
    const populate_audio_buffer = (buffer) => {
      const nowBuffering = buffer.getChannelData(0);
      
      for(let i = 0; i < buffer.length; i++) {
        nowBuffering[i] = Math.sin(2 * Math.PI * i * 440 / sampleRate);
      }
    };
    
    function AudioPlayer() {
      const [isPlaying, setIsPlaying] = React.useState(false);
      const player = React.useRef(null);
      
      if(!player.current) {
        const buffer = get_audio_buffer();
        populate_audio_buffer(buffer);
        
        player.current = new Tone.Player(buffer).toDestination();
        player.current.loop = true;
      }
    
      const handlePlayClick = () => {
        setIsPlaying(true);
        player.current.start();
      };
    
      const handleStopClick = () => {
        setIsPlaying(false);
        player.current.stop();
      };
    
      return (
        <div>
          {!isPlaying && (
            <button onClick={handlePlayClick}>Play</button>
          )}
          {isPlaying && (
            <button onClick={handleStopClick}>Stop</button>
          )}
        </div>
      );
    }
    
    const root = ReactDOM.createRoot(document.getElementById('app'));
    root.render(<AudioPlayer />);
    <script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
    <script crossorigin src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.min.js"></script>
    
    <div id="app"></div>

    Things I looked at:

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search