Anira

repository·main·Indexed 42 days ago

https://github.com/anira-project/anira

A high-performance C++ library for real-time safe neural network inference in audio applications. It provides a deterministic runtime with minimal latency and supports multiple backends including ONNXRuntime, LibTorch, LiteRT, TensorFlow Lite, and ExecuTorch. Anira is cross-platform, supporting macOS, Linux, Windows, Android, iOS, and WebAssembly via the @anira-project/anira npm package.

Tokens
143.8K
Snippets
302
Records
495
Agent score
52%

What's inside Anira

  1. Overview of Anira core classes and structures

    main

    Anira provides several key components to integrate real-time audio processing with machine learning models:

    • anira::InferenceHandler: The primary interface for interacting with the library. It manages audio processing and inference for the real-time thread, offloading the actual inference to a thread pool and updating real-time thread buffers with the processed audio.
    • anira::InferenceConfig: A configuration structure used to define model specifics (e.g., input/output shape, maximum inference time). This must be provided when constructing an InferenceHandler.
    • anira::PrePostProcessor: A class used to define processing steps that occur before and after inference. You can use the default implementation or inherit from this class to implement custom logic.
    • anira::HostConfig: A structure used to define host-level settings, specifically buffer size and sample rate.
    • anira::ContextConfig (Optional): A configuration structure that defines global behavior across all Anira instances. This includes thread pool settings (number of threads and anira::WaitStrategy) and the global anira::LogLevel for Anira and its backends.
  2. Overview of Anira Web (TypeScript / WASM)

    main
    Anira Web is a TypeScript wrapper around the Anira C++ library, compiled to WebAssembly via Emscripten. It allows developers to perform real-time inference directly in the browser. The package supports inference both with and without the Web Audio API, exposing a large subset of the core C++ classes and functions for web environments.
  3. Overview of Anira

    main

    Anira is a high-performance C++ library designed for the real-time safe integration of neural network inference within audio applications. It bridges the gap between advanced neural network architectures and real-time audio processing by providing a deterministic runtime.

    Key features include:

    • Real-time Safe Execution: Ensures deterministic runtimes for audio.
    • Thread Pool Management: Uses a static thread pool to prevent oversubscription.
    • Minimal Latency: Optimized for low-latency audio processing.
    • Built-in Benchmarking: Tools to evaluate neural network performance.
    • Multi-Backend Support: Integrates with LibTorch, ONNXRuntime, LiteRT, TensorFlow Lite, and ExecuTorch.
    • Cross-Platform: Supports macOS, Linux, Windows, Android, iOS, and WebAssembly (browser).
  4. Supported platforms and neural network frameworks in anira

    main

    Anira is designed for real-time neural network inference in audio applications and supports the following environments:

    Supported Platforms:

    • macOS
    • Linux
    • Windows
    • Architectures: x86_64, ARM64, and ARM7

    Supported Inference Backends:

    • LibTorch
    • ONNX Runtime
    • TensorFlow Lite

    Custom backends can be integrated as needed.

  5. What is anira and how does it handle neural network inference?

    main

    anira is a C++ library for real-time audio applications that integrate neural network inference. It provides a high-performance, real-time safe execution environment designed for deterministic runtimes.

    Core Architecture:

    • Unified Interface: Uses the anira::InferenceHandler class to provide a single interface for multiple industry-standard engines, including LibTorch, ONNXRuntime, and TensorFlow Lite.
    • Real-time Safety: Inference is executed outside the audio thread using a static thread pool. This prevents inference execution from blocking the audio thread, ensuring the application remains responsive and deterministic.
    • Parallelism: Leverages multiple CPU cores for efficient parallel inference.
    • Latency Management: Automatically calculates minimum required latency based on the anira::InferenceConfig struct. If processing exceeds the latency threshold, anira compensates for missing frames to maintain synchronized audio processing.
  6. Configure Anira Contracts (Hard vs Async)

    main

    Anira uses anira::Contract to define the execution model. This is a std::variant<anira::Hard, anira::Async>.

    • anira::Hard: A plain aggregate. It includes a double wait_ratio = 0 field. Use this for strict real-time requirements.
    • anira::Async: A plain aggregate for asynchronous execution.

    Contracts are minted at the prepare stage. While the C++ wrapper provides type-level support, the underlying C layer enforces these via ANIRA_ERROR_WRONG_CONTRACT if the contract type does not match the stage requirements.

    anira::Contract contract = anira::Hard{.wait_ratio = 0.5};
  7. Handle model data loading in custom backends

    main

    When creating ModelData, you can provide either an ArrayBuffer (binary) or a URL string. If you provide a URL, your custom backend is responsible for fetching and loading the model.

    You can check the format using modelData.isBinary():

    • If isBinary() is true: Use modelData.getDataPtr() and modelData.getSize() to access the data in WASM memory.
    • If isBinary() is false: The data is a URL string. You must decode it from WASM memory and then fetch the actual model bytes.
    if (modelData.isBinary()) {
      const ptr = modelData.getDataPtr()
      const size = modelData.getSize()
      modelBytes = new Uint8Array(wasm.HEAPU32.buffer, ptr, size).slice()
    } else {
      const pathBytes = new Uint8Array(
        wasm.HEAPU32.buffer,
        modelData.getDataPtr(),
        modelData.getSize()
      ).slice()
      const modelUrl = new TextDecoder().decode(pathBytes)
      modelBytes = new Uint8Array(await (await fetch(modelUrl)).arrayBuffer())
    }
  8. Understand the Anira v3 C ABI export and visibility rules

    main

    The Anira v3 C ABI uses the ANIRA_API macro to manage symbol visibility and linking. This ensures that only intended functions are exported when building the library and that consumers can correctly import them.

    Visibility and Exporting

    • On Linux/Unix (GCC/Clang): Symbols are exported using __attribute__((visibility("default"))). A version script (e.g., tanh_set_export_allowlist) is used to restrict exports to the anira_* namespace.
    • On Windows (PE/COFF): The macro uses __declspec(dllexport) when building the library and __declspec(dllimport) when being consumed by a client. dllexport acts as the allowlist for exported symbols.
    • Internal/Embedding: When used within an embedding plugin, ANIRA_API may be defined as empty to keep symbols hidden.

    Linking Behavior

    • Static Consumers: Consumers link against the exported symbols defined by the ANIRA_API macro.
    • Build Interface: The project uses $<BUILD_INTERFACE> in CMake to manage how objects are absorbed and linked during the build process.
    /* Typical macro expansion logic for ANIRA_API */
    #if defined(ANIRA_BUILDING)
      define ANIRA_API __attribute__((visibility("default"))) 
      /* or __declspec(dllexport) on Windows */
    #else
      define ANIRA_API __attribute__((visibility("default"))) 
      /* or __declspec(dllimport) on Windows */
    #endif
  9. Understand Inference Slots and memory allocation

    main

    An 'inference slot' represents the number of inferences that are submitted but not yet collected. The number of slots $S$ determines how many thread-safe structures a session allocates.

    To ensure a anira::InferenceHandler::reset is wait-free and never drops a hop, the session allocates twice the number of required slots ($2S$). This allows one pool to drain in-flight inferences while a fresh schedule uses a new pool of structures.

  10. Manage WebGPU device ownership

    main

    Anira v3 manages its own WebGPU implementation via a pinned Dawn revision.

    • Anira-Owned: If you use the native Dawn path, Anira creates/owns the WGPUInstance, WGPUDevice, and WGPUQueue.
    • Borrowed: If your host application already has a WebGPU renderer, you can borrow its device by setting ANIRA_OWNERSHIP_BORROWED in the WebGPU description. Anira will then use your existing device/queue.
    • Engine Integration (e.g., ORT): Engines should not bring their own Dawn. They should receive Anira's DawnProcTable and device handles via a proc table to ensure they are using the same underlying implementation.

    Note: On Emscripten, set_webgpu returns ANIRA_ERROR_NOT_SUPPORTED. Browser-based WebGPU is handled as an asynchronous JS backend in future versions.

  11. Manage Tensor Memory and Ownership in Anira v3

    main

    Anira v3 uses specific C types for tensor management to ensure predictable memory layouts and ownership rules:

    • Types: Use anira_tensor, anira_memory_handle, and anira_sync_token.
    • Initialization: Factories are named following the pattern anira_tensor_init_*.
    • Ownership Rule: For tensors returned by allocate_* functions, the caller is responsible for calling free_tensor. Anira does not automatically release these tensors.
    • Lifecycle: A common pattern is one submit = one release. Never use the release mechanism for allocate_* calls; use the dedicated free functions instead.
  12. Understand the Anira v3 C ABI Data Tiers

    main

    Anira v3 categorizes C ABI data into three tiers to balance performance, stability, and extensibility:

    1. Tier-1 RT PODs: Fixed-layout, versioned by ABI major only. These are used for high-performance runtime operations (e.g., anira_tensor, anira_sync_token, anira_error). They are designed for lock-free FIFOs or value-initialization and do not support size changes within a major version.
    2. Config Objects: Opaque handles managed via scalar setters and getters (e.g., anira_machine_config, anira_model_config). The internal layout is hidden from the ABI, making this the safest model for growth.
    3. Tier-2 Descriptors: Handed to setters once or filled by enumerators (e.g., anira_log_desc, anira_backend_desc). These use a uint32_t struct_size field at the start to allow tail growth. The library reads/fills only up to the minimum of the provided struct_size and the library's internal size.