react-native-audio-api

repository·main·Indexed 21 days ago

https://github.com/software-mansion/react-native-audio-api

A high-performance audio engine for React Native that implements the Web Audio API specification. It enables web-standard audio manipulation techniques in mobile environments and includes a dual-graph architecture to separate high-level graph manipulation from low-level audio processing.

Tokens
73.6K
Snippets
185
Records
302
Agent score
74%

What's inside react-native-audio-api

  1. Overview of React Native Audio API

    main

    React Native Audio API is a high-performance, imperative API designed for processing and synthesizing audio within React Native applications. It is built to bridge the gap in the React Native ecosystem for high-performance audio tasks like creating audio, applying effects, or controlling individual audio parameters.

    Key features include:

    • Web Audio Specification Compliance: The API strictly follows the Web Audio API standard, allowing for a single codebase that works across iOS, Android, and Web (including react-native-web).
    • High Performance: The core is written in C++ for maximum speed and uses modern native APIs like AVFoundation and CoreAudio on iOS, and Oboe on Android.
    • Low Latency: Supports sample-accurate scheduled sound playback, making it suitable for musical applications requiring high rhythmic precision.
    • Advanced Audio Capabilities: Includes modular routing architecture, real-time time-domain and frequency-domain analysis/visualization, BiQuad filters, and support for computational audio synthesis.
  2. What is WorkletAudioContext and when to use it

    main

    WorkletAudioContext is a specialized audio context that runs an audio-processing graph on a dedicated background thread. Unlike a standard AudioContext, it does not route audio to the device speakers; instead, it uses an internal sink where output is discarded.

    Use Cases

    • Worklet Visualization: Driving UI elements (like Reanimated visualizers) from a WorkletNode while actual playback happens in a separate AudioContext.
    • Isolated Processing: Running audio analysis or processing in a self-contained graph that doesn't compete for the hardware audio session.

    Comparison

    ContextOutputRender DriverTypical Use
    AudioContextDevice speakers / headphonesSystem audio callbackPlayback, recording, effects
    WorkletAudioContextInternal sink (discarded)Software timer on a worker threadWorklet visualization, isolated processing
    OfflineAudioContextAudioBufferRenders as fast as possibleOffline bounce / export

    Note: WorkletAudioContext advances in real time at the context sample rate, unlike OfflineAudioContext.

  3. What is an AudioParam?

    main

    An AudioParam is an interface used to control audio node properties (like volume in a GainNode, pan, or frequency) over time. This allows for smooth transitions rather than abrupt changes.

    Key methods for automation include:

    • setValueAtTime(value, time): Sets the parameter to a specific value at a specific time.
    • exponentialRampToValueAtTime(value, time): Smoothly ramps the parameter exponentially toward a target value.
  4. What is an Envelope (ADSR)?

    main

    An envelope describes how a sound's amplitude (volume) changes over time. The standard model is ADSR:

    • Attack: The time taken to ramp from silence to peak volume.
    • Decay: The time taken to fall from peak volume to the sustain level.
    • Sustain: The volume level held while the note is active.
    • Release: The time taken to fade out after the note is released.
  5. What is a WorkletAudioContext?

    main

    A WorkletAudioContext is a dedicated context for worklet graphs that do not require speaker output. It renders on a background thread and discards audio at the destination.

    This allows you to keep visualization or analysis graphs (like RMS meters) separate from your main AudioContext playback session, preventing analysis logic from interfering with actual audio playback.

  6. How to use WorkletSourceNode and WorkletProcessingNode for audio processing

    main

    Use these nodes when you need to perform actual audio processing on the audio path. They invoke callbacks synchronously on a dedicated audio worklet runtime every render quantum (128 frames).

    Node Types:

    • WorkletSourceNode: Use for building custom synthesizers or procedural generators.
    • WorkletProcessingNode: Use for implementing in-graph JavaScript effects, filters, or dynamics processors.

    Critical Performance Warning: These callbacks run on the audio thread. You must keep them short and allocation-free. At 44.1 kHz, you have approximately 2.9 ms to complete the entire callback. If the worklet exceeds this time budget, you will experience audio dropouts or glitches.

  7. Use the AudioListener for 3D spatialization

    main

    The AudioListener interface represents the position and orientation of the listener in a 3D audio scene. It is used by PannerNode objects to spatialize sound relative to the listener's location and direction.

    Key Concepts:

    • Not an AudioNode: AudioListener does not have inputs, outputs, or connect()/disconnect() methods. It only exposes nine AudioParam properties.
    • Accessing the Listener: You do not construct an AudioListener yourself. Instead, every BaseAudioContext exposes a single, read-only listener property.
    • Coordinate System:
      • positionX, positionY, positionZ: The 3D Cartesian coordinates of the listener.
      • forwardX, forwardY, forwardZ: A direction vector representing where the listener is facing (the "nose").
      • upX, upY, upZ: A direction vector representing the top of the listener's head.
    • Constraint: The forward and up vectors must be linearly independent.

    Note on Implementation: As of the current version, PannerNode is not yet implemented, so changes to the AudioListener will not have an audible effect. The interface is provided for future compatibility.

    import { AudioContext } from 'react-native-audio-api';
    
    const ctx = new AudioContext();
    const listener = ctx.listener;
    
    // Move the listener 3 meters along the x axis.
    listener.positionX.value = 3;
    
    // Or automate the movement over time.
    listener.positionX.linearRampToValueAtTime(10, ctx.currentTime + 2);
  8. Integrate with the C++ Extension API

    main

    Extension packages can integrate with react-native-audio-api in C++ using a single public header. To ensure stability and avoid internal dependency issues, you must only include the StableAPI.h header. All necessary types and helpers for extensions are transitively included via this header. Including any other audioapi/... headers is explicitly unsupported and may lead to build failures or instability.

    The only permitted include is:

    #include <audioapi/compatibility/StableAPI.h>
    #include <audioapi/compatibility/StableAPI.h>
  9. Understand the Graph structure and design

    main

    The audio engine uses a dual-graph architecture to separate high-level graph manipulation from low-level audio processing. This ensures that the UI/Main thread can manage the graph structure without blocking the high-priority audio thread.

    Core Components

    • Graph (Graph.hpp): The primary entry point and orchestrator. It provides the high-level public API used to create and manipulate the graph. It manages internal structures including AudioGraph, HostGraph, SPSC, Disposer, and pool capacity.
    • HostGraph (HostGraph.hpp): Manages the graph structure on the main/control thread. It tracks nodes, edges, connections, and cycles. It provides APIs for adding, removing, and connecting nodes.
      • State Synchronization: Every modification in the HostGraph returns an AGEvent (a closure). This closure is sent asynchronously to the audio thread to ensure the AudioGraph eventually reaches the same state as the HostGraph.
      • Cycle Prevention: HostGraph checks for potential cycles before adding edges. It uses NodeHandle to verify if nodes are still active in the AudioGraph to prevent adding edges to orphaned nodes.
    • AudioGraph (AudioGraph.hpp): Responsible for the actual audio processing on the audio thread. It maintains a topological order of nodes and edges and applies AGEvent closures received from the HostGraph to update its state.
    • InputPool (InputPool.hpp): An efficiency-focused component used by AudioGraph to manage edges via a free list. It minimizes memory fragmentation and is designed for high-speed allocation/deallocation on the audio thread. Note: It is not thread-safe and must be used within AudioGraph or its events.
    • NodeHandle (NodeHandle.hpp): A lightweight 32-bit index used to reference nodes within the AudioGraph. These handles should only be used within AGEvent closures to safely reference nodes on the audio thread.
    • Disposer (Disposer.hpp): Manages the destruction of nodes and edges. It uses a worker thread and an SPSC (Single Producer Single Consumer) queue to offload heavy destruction tasks, ensuring the audio thread remains performant.
  10. Configure ChannelCountMode for audio nodes

    main

    The ChannelCountMode type determines how the number of input channels affects the number of output channels in an audio node. You can choose between three modes to control channel up-mixing and clamping:

    • max: The number of channels is equal to the maximum number of channels of all connections. In this mode, channelCount is ignored and only up-mixing occurs.
    • clamped-max: The number of channels is equal to the maximum number of channels of all connections, but it is clamped to the value specified by channelCount (which acts as the maximum permissible value).
    • explicit: The number of channels is strictly defined by the value of channelCount.
  11. Use ConvolverNode for reverb and echo effects

    main

    The ConvolverNode interface implements a linear convolution effect. It is primarily used to apply echo or reverb effects to an audio signal by using an impulse response provided via an AudioBuffer.

    Note on Tail-Time: A ConvolverNode has 'tail-time', meaning it will continue to output non-silent audio even after the input signal has become silent, for the duration of the impulse response buffer.

    Performance Warning: Linear convolution is computationally expensive. If you encounter audio artifacts, consider decreasing the duration of your impulse response buffer.

    // Example conceptual usage
    const convolver = context.createConvolver();
    convolver.buffer = myImpulseResponseBuffer;
    // Connect to audio graph
    source.connect(convolver);
    convolver.connect(context.destination);