From 56f0f58911152880941427fbfce20512fee16bd9 Mon Sep 17 00:00:00 2001 From: maciejmakowski2003 Date: Tue, 17 Mar 2026 16:52:51 +0100 Subject: [PATCH 1/8] feat: ai slop long files playback node --- .../AudioVisualizer/AudioVisualizer.tsx | 113 +++++++----------- .../BaseAudioContextHostObject.cpp | 18 +++ .../HostObjects/BaseAudioContextHostObject.h | 1 + .../sources/AudioFileSourceNodeHostObject.cpp | 15 +++ .../sources/AudioFileSourceNodeHostObject.h | 22 ++++ .../cpp/audioapi/core/BaseAudioContext.cpp | 8 ++ .../cpp/audioapi/core/BaseAudioContext.h | 3 + .../core/sources/AudioFileSourceNode.cpp | 108 +++++++++++++++++ .../core/sources/AudioFileSourceNode.h | 46 +++++++ .../common/cpp/audioapi/types/NodeOptions.h | 4 + packages/react-native-audio-api/src/api.ts | 1 + .../src/core/AudioFileSourceNode.ts | 9 ++ .../src/core/BaseAudioContext.ts | 5 + .../react-native-audio-api/src/interfaces.ts | 3 + 14 files changed, 289 insertions(+), 67 deletions(-) create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioFileSourceNodeHostObject.cpp create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioFileSourceNodeHostObject.h create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioFileSourceNode.cpp create mode 100644 packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioFileSourceNode.h create mode 100644 packages/react-native-audio-api/src/core/AudioFileSourceNode.ts diff --git a/apps/common-app/src/examples/AudioVisualizer/AudioVisualizer.tsx b/apps/common-app/src/examples/AudioVisualizer/AudioVisualizer.tsx index 731aba9c9..8e6960e88 100644 --- a/apps/common-app/src/examples/AudioVisualizer/AudioVisualizer.tsx +++ b/apps/common-app/src/examples/AudioVisualizer/AudioVisualizer.tsx @@ -2,9 +2,8 @@ import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, View } from 'react-native'; import { AnalyserNode, - AudioBuffer, - AudioBufferSourceNode, AudioContext, + AudioFileSourceNode, } from 'react-native-audio-api'; import { Button, Container } from '../../components'; @@ -13,13 +12,13 @@ import FreqTimeChart from './FreqTimeChart'; const FFT_SIZE = 512; -const URL = - 'https://software-mansion.github.io/react-native-audio-api/audio/music/example-music-02.mp3'; +const AUDIO_URL = + 'https://upload.wikimedia.org/wikipedia/commons/9/91/Dl1bajkiwisdr.ddns.net_2026-02-02T18_39_07Z_4625.00_usb.wav'; const AudioVisualizer: React.FC = () => { const [isPlaying, setIsPlaying] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [audioBuffer, setAudioBuffer] = useState(null); + const [arrayBuffer, setArrayBuffer] = useState(null); const [times, setTimes] = useState( new Uint8Array(FFT_SIZE).fill(127) @@ -28,90 +27,70 @@ const AudioVisualizer: React.FC = () => { new Uint8Array(FFT_SIZE / 2).fill(0) ); - const [startTime, setStartTime] = useState(0); - const [offset, setOffset] = useState(0); - const audioContextRef = useRef(null); const analyserRef = useRef(null); - const bufferSourceRef = useRef(null); - - const handlePlayPause = () => { - if (isPlaying) { - const stopTime = audioContextRef.current!.currentTime; - bufferSourceRef.current?.stop(stopTime); - setOffset((prev) => prev + stopTime - startTime); - } else { - if (!audioContextRef.current || !analyserRef.current) { - return; - } - - if (!audioBuffer) { - fetchAudioBuffer(); - } - - bufferSourceRef.current = audioContextRef.current.createBufferSource(); - bufferSourceRef.current.buffer = audioBuffer; - bufferSourceRef.current.connect(analyserRef.current); - - setStartTime(audioContextRef.current.currentTime); - bufferSourceRef.current.start(startTime, offset); - - requestAnimationFrame(draw); - } - - setIsPlaying((prev) => !prev); - }; + const fileSourceRef = useRef(null); + const animFrameRef = useRef(0); const draw = () => { if (!analyserRef.current) { return; } - const timesArrayLength = analyserRef.current.fftSize; - const frequencyArrayLength = analyserRef.current.frequencyBinCount; - - const timesArray = new Uint8Array(timesArrayLength); + const timesArray = new Uint8Array(analyserRef.current.fftSize); analyserRef.current.getByteTimeDomainData(timesArray); setTimes(timesArray); - const freqsArray = new Uint8Array(frequencyArrayLength); + const freqsArray = new Uint8Array(analyserRef.current.frequencyBinCount); analyserRef.current.getByteFrequencyData(freqsArray); setFreqs(freqsArray); - requestAnimationFrame(draw); + // animFrameRef.current = requestAnimationFrame(draw); }; - const fetchAudioBuffer = async () => { - setIsLoading(true); - - const buffer = await fetch(URL) - .then((response) => response.arrayBuffer()) - .then((arrayBuffer) => - audioContextRef.current!.decodeAudioData(arrayBuffer) - ) - .catch((error) => { - console.error('Error decoding audio data source:', error); - return null; - }); + const handlePlayPause = () => { + if (!audioContextRef.current || !analyserRef.current || !arrayBuffer) { + return; + } - setAudioBuffer(buffer); + if (isPlaying) { + fileSourceRef.current?.stop(audioContextRef.current.currentTime); + fileSourceRef.current = null; + cancelAnimationFrame(animFrameRef.current); + } else { + fileSourceRef.current = audioContextRef.current.createAudioFileSource( + arrayBuffer + ); + fileSourceRef.current.connect(audioContextRef.current.destination); + fileSourceRef.current.start(audioContextRef.current.currentTime); + // animFrameRef.current = requestAnimationFrame(draw); + } - setIsLoading(false); + setIsPlaying((prev) => !prev); }; useEffect(() => { - if (!audioContextRef.current) { - audioContextRef.current = new AudioContext(); - } - - if (!analyserRef.current) { - analyserRef.current = new AnalyserNode(audioContextRef.current, { fftSize: FFT_SIZE, smoothingTimeConstant: 0.2 }); - analyserRef.current.connect(audioContextRef.current.destination); - } + audioContextRef.current = new AudioContext(); + analyserRef.current = new AnalyserNode(audioContextRef.current, { + fftSize: FFT_SIZE, + smoothingTimeConstant: 0.2, + }); + // analyserRef.current.connect(audioContextRef.current.destination); - fetchAudioBuffer(); + setIsLoading(true); + fetch(AUDIO_URL) + .then((response) => response.arrayBuffer()) + .then((buffer) => { + setArrayBuffer(buffer); + setIsLoading(false); + }) + .catch((error) => { + console.error('Error fetching audio:', error); + setIsLoading(false); + }); return () => { + cancelAnimationFrame(animFrameRef.current); audioContextRef.current?.close(); }; }, []); @@ -138,8 +117,8 @@ const AudioVisualizer: React.FC = () => { }}>