diff --git a/.github/workflows/build_web.yml b/.github/workflows/build_web.yml new file mode 100644 index 00000000..111a3743 --- /dev/null +++ b/.github/workflows/build_web.yml @@ -0,0 +1,67 @@ +name: build_web + +on: + push: + pull_request: + +concurrency: + group: build-web-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v5 + with: + submodules: true + fetch-depth: 0 + + - name: install system deps + run: sudo apt-get update && sudo apt-get install -y ninja-build + + - name: setup emsdk + uses: mymindstorm/setup-emsdk@v14 + with: + version: 4.0.23 + actions-cache-folder: emsdk-cache-4.0.23 + + - name: verify EMSDK env + run: | + echo "EMSDK=$EMSDK" + test -n "$EMSDK" + emcc --version + + - name: pin global typescript for emscripten --emit-tsd + run: | + sudo npm i -g typescript@5.9 + which tsc + tsc --version + + - name: configure wasm + run: cmake --preset wasm-release + + - name: build wasm + run: cmake --build --preset wasm-release -j + + - name: setup node + uses: actions/setup-node@v5 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: 'npm' + cache-dependency-path: web/package-lock.json + + # Use the npm version pinned via "packageManager" in web/package.json + # so contributors and CI produce identical lockfile shapes. + - name: enable corepack + run: corepack enable + + - name: install js deps + working-directory: web + run: npm ci + + - name: build js package + working-directory: web + run: npm run build diff --git a/.github/workflows/publish_web.yml b/.github/workflows/publish_web.yml new file mode 100644 index 00000000..19f1ac16 --- /dev/null +++ b/.github/workflows/publish_web.yml @@ -0,0 +1,105 @@ +name: publish_web + +on: + push: + tags: + - 'v*.*.*' + +concurrency: + group: publish-web + cancel-in-progress: false + +jobs: + publish: + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write + steps: + - name: checkout + uses: actions/checkout@v5 + with: + submodules: true + fetch-depth: 0 + + - name: install system deps + run: sudo apt-get update && sudo apt-get install -y ninja-build + + - name: setup emsdk + uses: mymindstorm/setup-emsdk@v14 + with: + version: 4.0.23 + actions-cache-folder: emsdk-cache-4.0.23 + + - name: verify EMSDK env + run: | + echo "EMSDK=$EMSDK" + test -n "$EMSDK" + emcc --version + + - name: pin global typescript for emscripten --emit-tsd + run: | + sudo npm i -g typescript@5.9 + which tsc + tsc --version + + - name: configure wasm + run: cmake --preset wasm-release + + - name: build wasm + run: cmake --build --preset wasm-release -j + + - name: setup node + uses: actions/setup-node@v5 + with: + node-version: '22' + registry-url: 'https://registry.npmjs.org' + cache: 'npm' + cache-dependency-path: web/package-lock.json + + # Use the npm version pinned via "packageManager" in web/package.json + # so contributors and CI produce identical lockfile shapes. + - name: enable corepack + run: corepack enable + + - name: install js deps + working-directory: web + run: npm ci + + - name: derive version + dist-tag + id: meta + run: | + set -euo pipefail + version="${GITHUB_REF_NAME#v}" + if [[ "$version" == *-* ]]; then + tag="next" + else + tag="latest" + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + echo "dist_tag=$tag" >> "$GITHUB_OUTPUT" + echo "Publishing $version under dist-tag $tag" + + - name: stamp package version + working-directory: web + run: npm version "${{ steps.meta.outputs.version }}" --no-git-tag-version --allow-same-version + + - name: build js package + working-directory: web + run: npm run build + + - name: npm publish + working-directory: web + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npm publish --access public --provenance --tag "${{ steps.meta.outputs.dist_tag }}" + + - name: summary + shell: bash + run: | + { + echo "### Anira Web published" + echo "" + echo "- **Version:** \`${{ steps.meta.outputs.version }}\`" + echo "- **dist-tag:** \`${{ steps.meta.outputs.dist_tag }}\`" + } >> "$GITHUB_STEP_SUMMARY" diff --git a/.gitignore b/.gitignore index 39e9772c..f1e9d6e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .idea* *.DS_Store +/build/ +/out/ /build*/ modules/libtorch* modules/onnxruntime* @@ -9,9 +11,16 @@ cmake-build* logs/ results/ venv/ +web/wasm/ +web/dist/ +**/node_modules/** extras/models/stateful-rnn/stateful-lstm/ extras/models/hybrid-nn/GuitarLSTM/ extras/models/cnn/steerable-nafx/ extras/models/model-pool/example-models/ extras/models/third-party/ircam-acids/RAVE/ -extras/**/*.json \ No newline at end of file +extras/**/*.json + +# Auto-generated TypeDoc artifacts for the Anira Web docs (consumed by sphinx-js). +docs/typedoc/node_modules/ +docs/typedoc/package-lock.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f22bc1d..cd1d0dab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,9 +17,25 @@ option(ANIRA_WITH_LIBTORCH "Build with LibTorch backend" ON) option(ANIRA_WITH_ONNXRUNTIME "Build with ONNX Runtime backend" ON) option(ANIRA_WITH_TFLITE "Build with TensorFlow Lite backend" ON) +option(ANIRA_BUILD_WASM "Build WebAssembly module (requires Emscripten toolchain)" OFF) + option(ANIRA_WITH_LOGGING "Enable logging printouts" ON) option(ANIRA_WITH_RTSAN "Enable RealtimeSanitizer (rtan) checks (requires clang 20)" OFF) +if(DEFINED EMSDK_VERSION) + set(DEFINED EMSDK_VERSION ON) + if(ANIRA_WITH_EXAMPLES) + message(FATAL_ERROR "WebAssembly support is not compatible with examples. Please disable ANIRA_WITH_EXAMPLES to build the library with WebAssembly support.") + elseif(ANIRA_WITH_TESTS) + message(FATAL_ERROR "WebAssembly support is not compatible with tests. Please disable ANIRA_WITH_TESTS to build the library with WebAssembly support.") + elseif(ANIRA_WITH_INSTALL) + message(FATAL_ERROR "WebAssembly support is not compatible with install targets. Please disable ANIRA_WITH_INSTALL to build the library with WebAssembly support.") + elseif(ANIRA_WITH_LIBTORCH) + message(FATAL_ERROR "Only the ONNX Runtime backend is supported for WebAssembly. Please set -DANIRA_WITH_LIBTORCH=OFF and enable ANIRA_WITH_ONNXRUNTIME to build the library with WebAssembly support.") + elseif(ANIRA_WITH_TFLITE) + message(FATAL_ERROR "Only the ONNX Runtime backend is supported for WebAssembly. Please set -DANIRA_WITH_TFLITE=OFF and enable ANIRA_WITH_ONNXRUNTIME to build the library with WebAssembly support.") + endif() +endif() # ============================================================================== # Get project version from git # ============================================================================== @@ -27,16 +43,23 @@ option(ANIRA_WITH_RTSAN "Enable RealtimeSanitizer (rtan) checks (requires clang execute_process(COMMAND git describe --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE PROJECT_VERSION_FULL - OUTPUT_STRIP_TRAILING_WHITESPACE) + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE GIT_DESCRIBE_RESULT) execute_process(COMMAND git describe --tags --abbrev=0 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE PROJECT_VERSION_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE) -# Retrive the v from the short version string -string(SUBSTRING ${PROJECT_VERSION_SHORT} 1 -1 PROJECT_VERSION_SHORT) -string(SUBSTRING ${PROJECT_VERSION_FULL} 1 -1 PROJECT_VERSION_FULL) +if(GIT_DESCRIBE_RESULT EQUAL 0 AND PROJECT_VERSION_SHORT) + # Retrieve the v from the short version string + string(SUBSTRING ${PROJECT_VERSION_SHORT} 1 -1 PROJECT_VERSION_SHORT) + string(SUBSTRING ${PROJECT_VERSION_FULL} 1 -1 PROJECT_VERSION_FULL) +else() + set(PROJECT_VERSION_SHORT "0.0.0") + set(PROJECT_VERSION_FULL "0.0.0-unknown") + message(WARNING "git describe failed - no tags found. Using fallback version ${PROJECT_VERSION_SHORT}") +endif() # ============================================================================== # Setup the project @@ -93,6 +116,12 @@ endif () set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) +# Detect Emscripten — must be after project() so CMAKE_CXX_COMPILER is set. +# EMSDK_VERSION is needed by SetupOnnxRuntime.cmake below. +if(ANIRA_BUILD_WASM) + include(cmake/DetectEmscripten.cmake) +endif() + # ============================================================================== # Download and install the selected inference engines # ============================================================================== @@ -202,6 +231,7 @@ target_compile_definitions(${PROJECT_NAME} # Backend-specific definitions $<$:USE_LIBTORCH> $<$:USE_ONNXRUNTIME> + $<$:USE_ANIRA_WEB> $<$:USE_TFLITE> $<$:ENABLE_LOGGING> # Version number @@ -239,7 +269,12 @@ endif() # The onnxruntime library requires PUBLIC linking because otherwise "_OrtGetApiBase" symbol is not found if(ANIRA_WITH_ONNXRUNTIME) - target_link_libraries(${PROJECT_NAME} PUBLIC onnxruntime) + if(EMSDK_VERSION) + target_include_directories(${PROJECT_NAME} PUBLIC ${ANIRA_ONNXRUNTIME_SHARED_LIB_PATH}) + target_link_libraries(${PROJECT_NAME} PUBLIC ${ANIRA_ONNXRUNTIME_SHARED_LIB_PATH}/libonnxruntime_webassembly.a) + else() + target_link_libraries(${PROJECT_NAME} PUBLIC onnxruntime) + endif() endif() if(ANIRA_WITH_TFLITE) @@ -291,3 +326,11 @@ endif() if (ANIRA_WITH_DOCS) add_subdirectory(docs) endif() + +# ============================================================================== +# Build WebAssembly module (optional, requires Emscripten) +# ============================================================================== + +if(ANIRA_BUILD_WASM) + include(cmake/BuildWasm.cmake) +endif() diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 00000000..69d4b5d8 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,120 @@ +{ + "version": 6, + "cmakeMinimumRequired": { + "major": 3, + "minor": 15, + "patch": 0 + }, + "configurePresets": [ + { + "name": "desktop-debug", + "displayName": "Desktop Debug", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/Desktop/Debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "desktop-release", + "displayName": "Desktop Release", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/Desktop/Release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "wasm-debug", + "displayName": "Wasm Debug", + "description": "Build AniraWeb WASM module (debug)", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/Wasm/Debug", + "toolchainFile": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", + "cacheVariables": { + "ANIRA_BUILD_WASM": "ON", + "ANIRA_WITH_LIBTORCH": "OFF", + "ANIRA_WITH_TFLITE": "OFF", + "ANIRA_WITH_ONNXRUNTIME": "ON", + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "wasm-release", + "displayName": "Wasm Release", + "description": "Build AniraWeb WASM module (release)", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/Wasm/Release", + "toolchainFile": "$env{EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake", + "cacheVariables": { + "ANIRA_BUILD_WASM": "ON", + "ANIRA_WITH_LIBTORCH": "OFF", + "ANIRA_WITH_TFLITE": "OFF", + "ANIRA_WITH_ONNXRUNTIME": "ON", + "CMAKE_BUILD_TYPE": "Release" + } + }, + { + "name": "docs", + "displayName": "Documentation", + "description": "Build C++ (Doxygen+Breathe) and Anira Web (TypeDoc+sphinx-js) docs via Sphinx", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/Docs", + "cacheVariables": { + "ANIRA_WITH_DOCS": "ON", + "ANIRA_WITH_LIBTORCH": "OFF", + "ANIRA_WITH_TFLITE": "OFF", + "ANIRA_WITH_ONNXRUNTIME": "OFF", + "CMAKE_BUILD_TYPE": "Release" + } + } + ], + "buildPresets": [ + { + "name": "desktop-debug", + "configurePreset": "desktop-debug", + "configuration": "Debug" + }, + { + "name": "desktop-release", + "configurePreset": "desktop-release", + "configuration": "Release" + }, + { + "name": "wasm-debug", + "configurePreset": "wasm-debug", + "configuration": "Debug", + "description": "Build AniraWeb WASM module (debug)" + }, + { + "name": "wasm-release", + "configurePreset": "wasm-release", + "configuration": "Release", + "description": "Build AniraWeb WASM module (release)" + }, + { + "name": "docs", + "configurePreset": "docs", + "description": "Build the full HTML documentation", + "targets": ["sphinx-docs"] + } + ], + "testPresets": [ + { + "name": "desktop-debug", + "configurePreset": "desktop-debug", + "configuration": "Debug", + "output": { "outputOnFailure": true } + }, + { + "name": "desktop-release", + "configurePreset": "desktop-release", + "configuration": "Release", + "output": { "outputOnFailure": true } + } + ] +} diff --git a/README.md b/README.md index 8facdac5..e79c1e38 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,11 @@ process(float** audio_data, int num_samples) { ## Installation +### C++ Library + Anira can be easily integrated into your CMake project. You can either add anira as a submodule, download the pre-built binaries from the [releases page](https://github.com/anira-project/anira/releases/latest), or build from source. -### Option 1: Add as Git Submodule (Recommended) +#### Option 1: Add as Git Submodule (Recommended) ```bash # Add anira repo as a submodule @@ -86,7 +88,7 @@ add_subdirectory(modules/anira) target_link_libraries(your_target anira::anira) ``` -### Option 2: Use Pre-built Binaries +#### Option 2: Use Pre-built Binaries Download pre-built binaries from the [releases page](https://github.com/anira-project/anira/releases/latest). @@ -105,7 +107,7 @@ find_package(anira REQUIRED) target_link_libraries(your_target anira::anira) ``` -### Option 3: Build from Source +#### Option 3: Build from Source ```bash git clone https://github.com/anira-project/anira.git @@ -115,7 +117,7 @@ cmake --build build --config Release --target anira cmake --install build --prefix /path/to/install/directory ``` -### Build options +### C++ Build Options By default, all three inference engines are installed. You can disable specific backends as needed: @@ -131,6 +133,55 @@ Moreover, the following options are available: - Build anira with documentation: ``-DANIRA_WITH_DOCS=ON`` - Disable the logging system: ``-DANIRA_WITH_LOGGING=OFF`` +### Anira Web (Web / JavaScript) + +Anira is available as the `@anira-project/anira` package for use in web applications: + +```bash +# npm +npm install @anira-project/anira + +# pnpm +pnpm add @anira-project/anira + +# yarn +yarn add @anira-project/anira +``` + +#### Building @anira-project/anira from source + +If you want to build the WASM module and JavaScript bindings yourself, you need to provide your own [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html). The CMake presets expect the `EMSDK` environment variable to be set to the root of your emsdk installation. + +```bash +git clone https://github.com/anira-project/anira.git +cd anira + +export EMSDK=/path/to/your/emsdk + +# Configure and build the WASM module (release) +cmake --preset web-prod +cmake --build --preset web-prod + +# Build the JavaScript package +cd web +npm install +npm run build +``` + +For packaging it locally, use +```bash +npm pack +``` +in the `web` folder, which will create a `.tgz` file that can be installed with npm or yarn. + +Then install the package in your project: + +```bash +npm install path/to/anira/web/anira-project-anira-x.x.x.tgz +``` + +A debug preset is also available via `cmake --preset web` / `cmake --build --preset web`. + ## Examples ### Build in examples diff --git a/cmake/BuildWasm.cmake b/cmake/BuildWasm.cmake new file mode 100644 index 00000000..a0a9ac72 --- /dev/null +++ b/cmake/BuildWasm.cmake @@ -0,0 +1,116 @@ +if(NOT WASM) + message(FATAL_ERROR "Cannot build WASM target without Emscripten toolchain") +endif() + +# ============================================================================== +# AniraWeb WASM target +# ============================================================================== + +set(ANIRA_WASM_TARGET_NAME "AniraWeb") +set(ANIRA_WASM_OUTPUT_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/web/wasm") +message(STATUS "Building AniraWeb WASM module...") + +set(ANIRA_WEB_LICENSES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/web/licenses") + +# Set flags if Debug +if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") + set(ANIRA_WASM_DEBUG_FLAGS "-O0 -gsource-map") +else() + set(ANIRA_WASM_DEBUG_FLAGS "") +endif() + +set(ANIRA_WASM_WRAPPER_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/InferenceThread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/JSPrePostProcessor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/backends/BackendBase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/backends/JSProcessor.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/utils/Buffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/utils/HostConfig.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/utils/RingBuffer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/utils/Vectors.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/InferenceConfig.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/InferenceHandler.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/emscripten-wrappers/PrePostProcessor.cpp +) + +# Static library of WASM wrappers — linkable by AniraWeb and external WASM targets +add_library(anira_wasm_wrappers STATIC ${ANIRA_WASM_WRAPPER_SOURCES}) +target_link_libraries(anira_wasm_wrappers PUBLIC anira::anira) +target_compile_features(anira_wasm_wrappers PUBLIC cxx_std_20) +add_library(anira::wasm_wrappers ALIAS anira_wasm_wrappers) + +set(ANIRA_WASM_LINK_FLAGS "\ + --no-entry \ + --emit-tsd=${ANIRA_WASM_OUTPUT_FOLDER}/${ANIRA_WASM_TARGET_NAME}.d.ts \ + -s STACK_OVERFLOW_CHECK=0 \ + -s IMPORTED_MEMORY=1 \ + -s INITIAL_MEMORY=536870912 \ + -s SHARED_MEMORY=1 \ + -s ALLOW_MEMORY_GROWTH=0 \ + -s MALLOC=emmalloc \ + -s EXPORT_ES6=1 \ + -s MODULARIZE=1 \ + -s ENVIRONMENT=worklet,web \ + -s ASSERTIONS=1 \ + -s NO_DISABLE_EXCEPTION_CATCHING \ + -s STACK_SIZE=33554432 \ + -s EXPORTED_FUNCTIONS='[\"_free\",\"_malloc\"]' \ + -s EXPORT_KEEPALIVE=1 \ + -s EXPORTED_RUNTIME_METHODS='[\"UTF8ToString\",\"HEAPU32\",\"HEAPF32\",\"stackSave\",\"stackRestore\"]' \ + ") + +# CMake requires at least one source file for add_executable. +# This is a --no-entry Emscripten module so there is no main(); +# all symbols come from the linked anira_wasm_wrappers static lib. +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/aniraweb_stub.cpp" "") +add_executable(${ANIRA_WASM_TARGET_NAME} "${CMAKE_CURRENT_BINARY_DIR}/aniraweb_stub.cpp") + +target_link_libraries(${ANIRA_WASM_TARGET_NAME} PUBLIC + -Wl,--whole-archive anira::wasm_wrappers -Wl,--no-whole-archive) +target_compile_features(${ANIRA_WASM_TARGET_NAME} PUBLIC cxx_std_20) + +set_target_properties(${ANIRA_WASM_TARGET_NAME} PROPERTIES + OUTPUT_NAME ${ANIRA_WASM_TARGET_NAME} + LINK_FLAGS "${ANIRA_WASM_DEBUG_FLAGS} ${ANIRA_WASM_LINK_FLAGS}" + RUNTIME_OUTPUT_DIRECTORY ${ANIRA_WASM_OUTPUT_FOLDER} +) + +# ============================================================================== +# Bundle license files from native deps that get statically linked into the +# WASM binary, so the @anira-project/anira npm package can ship them and downstream +# consumers can satisfy their attribution obligations. Tied to the AniraWeb +# build target so it runs as part of the actual wasm build (not at configure +# time, where it would re-fire on every cmake configure regardless of whether +# wasm is being built). +# ============================================================================== +if(ANIRA_WITH_ONNXRUNTIME) + set(_ort_license_dest "${ANIRA_WEB_LICENSES_DIR}/onnxruntime") + set(_ort_license_inputs "") + foreach(_f LICENSE ThirdPartyNotices.txt) + if(EXISTS "${ANIRA_ONNXRUNTIME_SHARED_LIB_PATH}/${_f}") + list(APPEND _ort_license_inputs "${ANIRA_ONNXRUNTIME_SHARED_LIB_PATH}/${_f}") + else() + message(WARNING "ONNX Runtime ${_f} not found at " + "${ANIRA_ONNXRUNTIME_SHARED_LIB_PATH} — Anira Web will ship " + "without it; downstream consumers won't see attribution.") + endif() + endforeach() + + add_custom_command(TARGET ${ANIRA_WASM_TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rm -rf "${_ort_license_dest}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${_ort_license_dest}" + COMMAND ${CMAKE_COMMAND} -E copy ${_ort_license_inputs} "${_ort_license_dest}/" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-PACKAGE.txt" + "${_ort_license_dest}/PACKAGE.txt" + VERBATIM + COMMENT "Bundling ONNX Runtime ${LIBONNXRUNTIME_VERSION} license + ThirdPartyNotices into Anira Web" + ) + + # PACKAGE.txt only depends on configure-time vars (version, etc.), so + # generating it at configure time is safe — it'll be regenerated whenever + # the wasm preset is reconfigured. The actual copy into web/licenses/ + # happens at build time, alongside the heavy LICENSE/ThirdPartyNotices. + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/onnxruntime-PACKAGE.txt" + "name: onnxruntime\nversion: ${LIBONNXRUNTIME_VERSION}\nlicense: MIT\nhomepage: https://github.com/microsoft/onnxruntime\n") +endif() diff --git a/cmake/DetectEmscripten.cmake b/cmake/DetectEmscripten.cmake new file mode 100644 index 00000000..4e316437 --- /dev/null +++ b/cmake/DetectEmscripten.cmake @@ -0,0 +1,14 @@ +if("${CMAKE_CXX_COMPILER}" MATCHES "em\\+\\+") + set(WASM true) + execute_process( + COMMAND ${CMAKE_C_COMPILER} --version + OUTPUT_VARIABLE EMSDK_VERSION_OUTPUT + ) + string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" EMSDK_VERSION "${EMSDK_VERSION_OUTPUT}") + message(STATUS "Emscripten compiler detected: ${EMSDK_VERSION}") + + message(STATUS "Using Emscripten compiler: ${CMAKE_CXX_COMPILER}") + set(CMAKE_EXECUTABLE_SUFFIX ".js") + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -matomics -msimd128 -mbulk-memory -sNO_DISABLE_EXCEPTION_CATCHING") +endif() \ No newline at end of file diff --git a/cmake/SetupOnnxRuntime.cmake b/cmake/SetupOnnxRuntime.cmake index dce4ed2e..c4821709 100644 --- a/cmake/SetupOnnxRuntime.cmake +++ b/cmake/SetupOnnxRuntime.cmake @@ -1,8 +1,13 @@ set(LIBONNXRUNTIME_VERSION 1.19.2) -option(ONNXRUNTIME_ROOTDIR "onnxruntime root dir") -set(ONNXRUNTIME_DIR_NAME "onnxruntime-${LIBONNXRUNTIME_VERSION}-${ANIRA_OPERATING_SYSTEM}-${CMAKE_SYSTEM_PROCESSOR}") -set(ONNXRUNTIME_ROOTDIR ${CMAKE_CURRENT_SOURCE_DIR}/modules/${ONNXRUNTIME_DIR_NAME}) + +if(EMSDK_VERSION) + set(ONNXRUNTIME_DIR_NAME "onnxruntime-${LIBONNXRUNTIME_VERSION}-emsdk-${EMSDK_VERSION}") +else() + set(ONNXRUNTIME_DIR_NAME "onnxruntime-${LIBONNXRUNTIME_VERSION}-${ANIRA_OPERATING_SYSTEM}-${CMAKE_SYSTEM_PROCESSOR}") +endif() + +set(ONNXRUNTIME_ROOTDIR "${CMAKE_CURRENT_SOURCE_DIR}/modules/${ONNXRUNTIME_DIR_NAME}") if(EXISTS ${ONNXRUNTIME_ROOTDIR}/) message(STATUS "ONNX-Runtime library found at ${ONNXRUNTIME_ROOTDIR}") @@ -10,33 +15,38 @@ else() file(MAKE_DIRECTORY ${ONNXRUNTIME_ROOTDIR}/) message(STATUS "ONNX-Runtime library not found - downloading pre-built library.") - if(WIN32) - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-win-x64-${LIBONNXRUNTIME_VERSION}") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "zip") - endif() + if(EMSDK_VERSION) + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnx-v${LIBONNXRUNTIME_VERSION}-emsdk-${EMSDK_VERSION}") + set(LIBONNXRUNTIME_URL "https://github.com/Andonvr/ONNXRuntime-Static-WASM-Builds/releases/download/emsdk-${EMSDK_VERSION}-onnx-v${LIBONNXRUNTIME_VERSION}/onnx-v${LIBONNXRUNTIME_VERSION}-emsdk-${EMSDK_VERSION}.zip") + else() + if(WIN32) + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-win-x64-${LIBONNXRUNTIME_VERSION}") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "zip") + endif() - if(UNIX AND NOT APPLE) - if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-linux-aarch64-${LIBONNXRUNTIME_VERSION}") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") - elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-linux-x64-${LIBONNXRUNTIME_VERSION}") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") - elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-${LIBONNXRUNTIME_VERSION}-Linux-armv7l") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tar.gz") + if(UNIX AND NOT APPLE) + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-linux-aarch64-${LIBONNXRUNTIME_VERSION}") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-linux-x64-${LIBONNXRUNTIME_VERSION}") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-${LIBONNXRUNTIME_VERSION}-Linux-armv7l") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tar.gz") + endif() endif() - endif() - if(UNIX AND APPLE) - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-osx-universal2-${LIBONNXRUNTIME_VERSION}") - set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") - endif() + if(UNIX AND APPLE) + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME "onnxruntime-osx-universal2-${LIBONNXRUNTIME_VERSION}") + set(LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE "tgz") + endif() - if(UNIX AND NOT APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") - set(LIBONNXRUNTIME_URL https://github.com/faressc/onnxruntime-cpp-lib/releases/download/v${LIBONNXRUNTIME_VERSION}/${LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME}.${LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE}) - else() - set(LIBONNXRUNTIME_URL https://github.com/microsoft/onnxruntime/releases/download/v${LIBONNXRUNTIME_VERSION}/${LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME}.${LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE}) + if(UNIX AND NOT APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7l") + set(LIBONNXRUNTIME_URL https://github.com/faressc/onnxruntime-cpp-lib/releases/download/v${LIBONNXRUNTIME_VERSION}/${LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME}.${LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE}) + else() + set(LIBONNXRUNTIME_URL https://github.com/microsoft/onnxruntime/releases/download/v${LIBONNXRUNTIME_VERSION}/${LIB_ONNXRUNTIME_PRE_BUILD_LIB_NAME}.${LIB_ONNXRUNTIME_PRE_BUILD_LIB_TYPE}) + endif() endif() message(STATUS "Downloading: ${LIBONNXRUNTIME_URL}") diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 9fc3c593..3b18a63b 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -12,7 +12,11 @@ if(NOT EXISTS ${DOCS_VENV_DIR}) POST_BUILD COMMAND ${Python3_EXECUTABLE} -m venv ${DOCS_VENV_DIR} COMMAND ${DOCS_VENV_DIR}/bin/pip install --upgrade pip - COMMAND ${DOCS_VENV_DIR}/bin/pip install --quiet sphinx breathe shibuya myst-parser + COMMAND ${DOCS_VENV_DIR}/bin/pip install --quiet sphinx breathe shibuya myst-parser sphinx-js + # Patch sphinx-js bug: redirectPrivateAliases.ts crashes on missing-export + # symbols whose `declarations` is undefined (occurs with TypeDoc >= 0.27). + # Replace `name.declarations![0]` with a guarded read. See pyodide/sphinx-js. + COMMAND bash -c "perl -i -pe 's{const decl = name\\.declarations!\\[0\\];}{const decl = name.declarations?.[0]; if (!decl) continue;}' ${DOCS_VENV_DIR}/lib/python*/site-packages/sphinx_js/js/redirectPrivateAliases.ts" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Creating virtual environment for Sphinx documentation" VERBATIM @@ -53,9 +57,10 @@ add_custom_target(breathe-apidocs -g class,struct -f COMMAND ${CMAKE_COMMAND} -E remove -f ${SPHINX_SOURCE_DIR}/api/struct/structanira_1_1InferenceConfig_1_1Defaults.rst COMMAND ${CMAKE_COMMAND} -E remove -f ${SPHINX_SOURCE_DIR}/api/struct/structanira_1_1SessionElement_1_1ThreadSafeStruct.rst - # Add :allow-dot-graphs: directive to all class and struct files - COMMAND bash -c "find ${SPHINX_SOURCE_DIR}/api/class -name '*.rst' -exec sed -i '/^\\.\\.\\s\\+doxygenclass::/a\\ :allow-dot-graphs:' {} +" - COMMAND bash -c "find ${SPHINX_SOURCE_DIR}/api/struct -name '*.rst' -exec sed -i '/^\\.\\.\\s\\+doxygenstruct::/a\\ :allow-dot-graphs:' {} +" + # Add :allow-dot-graphs: directive to all class and struct files. + # Using perl -i for portability (BSD sed on macOS uses different -i syntax than GNU sed). + COMMAND bash -c "find ${SPHINX_SOURCE_DIR}/api/class -name '*.rst' -exec perl -i -pe 's{^(\\.\\.\\s+doxygenclass::.*\\n)}{$1 :allow-dot-graphs:\\n}' {} +" + COMMAND bash -c "find ${SPHINX_SOURCE_DIR}/api/struct -name '*.rst' -exec perl -i -pe 's{^(\\.\\.\\s+doxygenstruct::.*\\n)}{$1 :allow-dot-graphs:\\n}' {} +" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Breathe using virtual environment" @@ -63,20 +68,65 @@ add_custom_target(breathe-apidocs VERBATIM ) +# --- TypeDoc: generate JSON for the Anira Web TypeScript API ----------------- +# sphinx-js consumes this JSON via the js: domain, producing rendering that +# matches the C++ side (Sphinx domain directives styled by the shibuya theme). +set(TYPEDOC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/typedoc) +set(TYPEDOC_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/typedoc) +set(TYPEDOC_JSON ${TYPEDOC_BUILD_DIR}/typedoc.json) +set(TYPEDOC_NPM_STAMP ${TYPEDOC_BUILD_DIR}/.npm-installed) + +find_program(NPM_EXECUTABLE npm) + +if (NPM_EXECUTABLE) + file(MAKE_DIRECTORY ${TYPEDOC_BUILD_DIR}) + + add_custom_command( + OUTPUT ${TYPEDOC_NPM_STAMP} + COMMAND ${NPM_EXECUTABLE} install --prefix ${TYPEDOC_DIR} + COMMAND ${CMAKE_COMMAND} -E touch ${TYPEDOC_NPM_STAMP} + DEPENDS ${TYPEDOC_DIR}/package.json + COMMENT "Installing TypeDoc into docs/typedoc/node_modules" + VERBATIM + ) + + add_custom_command( + OUTPUT ${TYPEDOC_JSON} + COMMAND ${NPM_EXECUTABLE} exec --prefix ${TYPEDOC_DIR} -- typedoc + --options ${TYPEDOC_DIR}/typedoc.json + --json ${TYPEDOC_JSON} + DEPENDS ${TYPEDOC_NPM_STAMP} ${TYPEDOC_DIR}/typedoc.json + WORKING_DIRECTORY ${TYPEDOC_DIR} + COMMENT "Generating TypeDoc JSON for Anira Web" + VERBATIM + ) + + add_custom_target(typedoc-json DEPENDS ${TYPEDOC_JSON}) +else() + message(WARNING "npm not found - Anira Web API reference will be skipped. Install Node.js to enable it.") + add_custom_target(typedoc-json + COMMAND ${CMAKE_COMMAND} -E echo "Skipping TypeDoc: npm not found" + ) +endif() + # Configure the Sphinx configuration file configure_file(${SPHINX_SOURCE_DIR}/conf.py.in ${SPHINX_BUILD_DIR}/conf.py @ONLY) # Collect all files in SPHINX_SOURCE_DIR as dependencies file(GLOB_RECURSE SPHINX_SOURCE_FILES "${SPHINX_SOURCE_DIR}/*") +# sphinx-js shells out to `typedoc`, so the locally-installed binary in the +# docs/typedoc node_modules must be on PATH when sphinx-build runs. add_custom_target(sphinx-docs - COMMAND ${DOCS_VENV_DIR}/bin/sphinx-build -b html - -c ${SPHINX_BUILD_DIR} - ${SPHINX_SOURCE_DIR} - ${SPHINX_BUILD_DIR}/html + COMMAND ${CMAKE_COMMAND} -E env + "PATH=${TYPEDOC_DIR}/node_modules/.bin:$ENV{PATH}" + ${DOCS_VENV_DIR}/bin/sphinx-build -b html + -c ${SPHINX_BUILD_DIR} + ${SPHINX_SOURCE_DIR} + ${SPHINX_BUILD_DIR}/html WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating HTML documentation with Sphinx using virtual environment" - DEPENDS create_docs_venv doxygen-docs breathe-apidocs ${SPHINX_SOURCE_FILES} + DEPENDS create_docs_venv doxygen-docs breathe-apidocs typedoc-json ${SPHINX_SOURCE_FILES} VERBATIM ) diff --git a/docs/doxygen/Doxyfile.in b/docs/doxygen/Doxyfile.in index eff6a255..f08512a7 100644 --- a/docs/doxygen/Doxyfile.in +++ b/docs/doxygen/Doxyfile.in @@ -653,7 +653,11 @@ INTERNAL_DOCS = NO # Possible values are: SYSTEM, NO and YES. # The default value is: SYSTEM. -CASE_SENSE_NAMES = SYSTEM +# Pinned to NO so generated filenames are deterministic across Linux, macOS and +# Windows. With SYSTEM (the default), Linux produces PascalCase filenames while +# macOS/Windows produce lowercase+underscore -- which causes duplicate stale +# stubs to accumulate when docs are built on more than one platform. +CASE_SENSE_NAMES = NO # If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the diff --git a/docs/sphinx/_static/custom.css b/docs/sphinx/_static/custom.css index d5f9374d..61f1d873 100644 --- a/docs/sphinx/_static/custom.css +++ b/docs/sphinx/_static/custom.css @@ -1,3 +1,14 @@ +/* Strip bullet markers from JS-domain Arguments / parameter lists so + * single-arg and multi-arg callables render with the same flat shape. + * Sphinx's TypedField only collapses single-item lists; the field-list + * cell always emits a
    for >1 args. We hide the + * list affordances here. */ +dl.js > dd > dl.field-list > dd > ul.simple { + list-style: none; + padding-left: 0; + margin-left: 0; +} + /* Bigger class names and functions in the API docs */ dt.sig { position:relative; diff --git a/docs/sphinx/api/class/classanira_1_1BackendBase.rst b/docs/sphinx/api/class/classanira_1_1_backend_base.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1BackendBase.rst rename to docs/sphinx/api/class/classanira_1_1_backend_base.rst diff --git a/docs/sphinx/api/class/classanira_1_1Buffer.rst b/docs/sphinx/api/class/classanira_1_1_buffer.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1Buffer.rst rename to docs/sphinx/api/class/classanira_1_1_buffer.rst diff --git a/docs/sphinx/api/class/classanira_1_1Context.rst b/docs/sphinx/api/class/classanira_1_1_context.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1Context.rst rename to docs/sphinx/api/class/classanira_1_1_context.rst diff --git a/docs/sphinx/api/class/classanira_1_1HighPriorityThread.rst b/docs/sphinx/api/class/classanira_1_1_high_priority_thread.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1HighPriorityThread.rst rename to docs/sphinx/api/class/classanira_1_1_high_priority_thread.rst diff --git a/docs/sphinx/api/class/classanira_1_1InferenceHandler.rst b/docs/sphinx/api/class/classanira_1_1_inference_handler.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1InferenceHandler.rst rename to docs/sphinx/api/class/classanira_1_1_inference_handler.rst diff --git a/docs/sphinx/api/class/classanira_1_1InferenceManager.rst b/docs/sphinx/api/class/classanira_1_1_inference_manager.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1InferenceManager.rst rename to docs/sphinx/api/class/classanira_1_1_inference_manager.rst diff --git a/docs/sphinx/api/class/classanira_1_1InferenceThread.rst b/docs/sphinx/api/class/classanira_1_1_inference_thread.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1InferenceThread.rst rename to docs/sphinx/api/class/classanira_1_1_inference_thread.rst diff --git a/docs/sphinx/api/class/classanira_1_1JsonConfigLoader.rst b/docs/sphinx/api/class/classanira_1_1_json_config_loader.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1JsonConfigLoader.rst rename to docs/sphinx/api/class/classanira_1_1_json_config_loader.rst diff --git a/docs/sphinx/api/class/classanira_1_1LibtorchProcessor.rst b/docs/sphinx/api/class/classanira_1_1_libtorch_processor.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1LibtorchProcessor.rst rename to docs/sphinx/api/class/classanira_1_1_libtorch_processor.rst diff --git a/docs/sphinx/api/class/classanira_1_1MemoryBlock.rst b/docs/sphinx/api/class/classanira_1_1_memory_block.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1MemoryBlock.rst rename to docs/sphinx/api/class/classanira_1_1_memory_block.rst diff --git a/docs/sphinx/api/class/classanira_1_1OnnxRuntimeProcessor.rst b/docs/sphinx/api/class/classanira_1_1_onnx_runtime_processor.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1OnnxRuntimeProcessor.rst rename to docs/sphinx/api/class/classanira_1_1_onnx_runtime_processor.rst diff --git a/docs/sphinx/api/class/classanira_1_1PrePostProcessor.rst b/docs/sphinx/api/class/classanira_1_1_pre_post_processor.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1PrePostProcessor.rst rename to docs/sphinx/api/class/classanira_1_1_pre_post_processor.rst diff --git a/docs/sphinx/api/class/classanira_1_1RingBuffer.rst b/docs/sphinx/api/class/classanira_1_1_ring_buffer.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1RingBuffer.rst rename to docs/sphinx/api/class/classanira_1_1_ring_buffer.rst diff --git a/docs/sphinx/api/class/classanira_1_1SessionElement.rst b/docs/sphinx/api/class/classanira_1_1_session_element.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1SessionElement.rst rename to docs/sphinx/api/class/classanira_1_1_session_element.rst diff --git a/docs/sphinx/api/class/classanira_1_1TFLiteProcessor.rst b/docs/sphinx/api/class/classanira_1_1_t_f_lite_processor.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1TFLiteProcessor.rst rename to docs/sphinx/api/class/classanira_1_1_t_f_lite_processor.rst diff --git a/docs/sphinx/api/class/classanira_1_1benchmark_1_1ProcessBlockFixture.rst b/docs/sphinx/api/class/classanira_1_1benchmark_1_1_process_block_fixture.rst similarity index 100% rename from docs/sphinx/api/class/classanira_1_1benchmark_1_1ProcessBlockFixture.rst rename to docs/sphinx/api/class/classanira_1_1benchmark_1_1_process_block_fixture.rst diff --git a/docs/sphinx/api/struct/structanira_1_1ContextConfig.rst b/docs/sphinx/api/struct/structanira_1_1_context_config.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1ContextConfig.rst rename to docs/sphinx/api/struct/structanira_1_1_context_config.rst diff --git a/docs/sphinx/api/struct/structanira_1_1HostConfig.rst b/docs/sphinx/api/struct/structanira_1_1_host_config.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1HostConfig.rst rename to docs/sphinx/api/struct/structanira_1_1_host_config.rst diff --git a/docs/sphinx/api/struct/structanira_1_1InferenceConfig.rst b/docs/sphinx/api/struct/structanira_1_1_inference_config.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1InferenceConfig.rst rename to docs/sphinx/api/struct/structanira_1_1_inference_config.rst diff --git a/docs/sphinx/api/struct/structanira_1_1_inference_config_1_1_defaults.rst b/docs/sphinx/api/struct/structanira_1_1_inference_config_1_1_defaults.rst new file mode 100644 index 00000000..a57b51cf --- /dev/null +++ b/docs/sphinx/api/struct/structanira_1_1_inference_config_1_1_defaults.rst @@ -0,0 +1,5 @@ +Struct anira::InferenceConfig::Defaults +======================================= + +.. doxygenstruct:: anira::InferenceConfig::Defaults + :allow-dot-graphs: diff --git a/docs/sphinx/api/struct/structanira_1_1InferenceData.rst b/docs/sphinx/api/struct/structanira_1_1_inference_data.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1InferenceData.rst rename to docs/sphinx/api/struct/structanira_1_1_inference_data.rst diff --git a/docs/sphinx/api/struct/structanira_1_1JsonConfigLoader_1_1SingleParameterStruct.rst b/docs/sphinx/api/struct/structanira_1_1_json_config_loader_1_1_single_parameter_struct.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1JsonConfigLoader_1_1SingleParameterStruct.rst rename to docs/sphinx/api/struct/structanira_1_1_json_config_loader_1_1_single_parameter_struct.rst diff --git a/docs/sphinx/api/struct/structanira_1_1LibtorchProcessor_1_1Instance.rst b/docs/sphinx/api/struct/structanira_1_1_libtorch_processor_1_1_instance.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1LibtorchProcessor_1_1Instance.rst rename to docs/sphinx/api/struct/structanira_1_1_libtorch_processor_1_1_instance.rst diff --git a/docs/sphinx/api/struct/structanira_1_1ModelData.rst b/docs/sphinx/api/struct/structanira_1_1_model_data.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1ModelData.rst rename to docs/sphinx/api/struct/structanira_1_1_model_data.rst diff --git a/docs/sphinx/api/struct/structanira_1_1OnnxRuntimeProcessor_1_1Instance.rst b/docs/sphinx/api/struct/structanira_1_1_onnx_runtime_processor_1_1_instance.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1OnnxRuntimeProcessor_1_1Instance.rst rename to docs/sphinx/api/struct/structanira_1_1_onnx_runtime_processor_1_1_instance.rst diff --git a/docs/sphinx/api/struct/structanira_1_1ProcessingSpec.rst b/docs/sphinx/api/struct/structanira_1_1_processing_spec.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1ProcessingSpec.rst rename to docs/sphinx/api/struct/structanira_1_1_processing_spec.rst diff --git a/docs/sphinx/api/struct/structanira_1_1_session_element_1_1_thread_safe_struct.rst b/docs/sphinx/api/struct/structanira_1_1_session_element_1_1_thread_safe_struct.rst new file mode 100644 index 00000000..30f1843f --- /dev/null +++ b/docs/sphinx/api/struct/structanira_1_1_session_element_1_1_thread_safe_struct.rst @@ -0,0 +1,5 @@ +Struct anira::SessionElement::ThreadSafeStruct +============================================== + +.. doxygenstruct:: anira::SessionElement::ThreadSafeStruct + :allow-dot-graphs: diff --git a/docs/sphinx/api/struct/structanira_1_1TFLiteProcessor_1_1Instance.rst b/docs/sphinx/api/struct/structanira_1_1_t_f_lite_processor_1_1_instance.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1TFLiteProcessor_1_1Instance.rst rename to docs/sphinx/api/struct/structanira_1_1_t_f_lite_processor_1_1_instance.rst diff --git a/docs/sphinx/api/struct/structanira_1_1TensorShape.rst b/docs/sphinx/api/struct/structanira_1_1_tensor_shape.rst similarity index 100% rename from docs/sphinx/api/struct/structanira_1_1TensorShape.rst rename to docs/sphinx/api/struct/structanira_1_1_tensor_shape.rst diff --git a/docs/sphinx/conf.py.in b/docs/sphinx/conf.py.in index e184ed5d..fa8011dd 100644 --- a/docs/sphinx/conf.py.in +++ b/docs/sphinx/conf.py.in @@ -21,7 +21,8 @@ extensions = [ 'sphinx.ext.viewcode', 'sphinx.ext.napoleon', 'sphinx.ext.graphviz', - 'myst_parser' + 'myst_parser', + 'sphinx_js', ] # Breathe configuration @@ -33,6 +34,309 @@ breathe_default_members = ('members', 'undoc-members') breathe_domain_by_extension = {"h": "cpp", "hpp": "cpp"} breathe_implementation_filename_extensions = ['.c', '.cc', '.cpp'] +# sphinx-js: render the Anira Web TypeScript API via TypeDoc. +# sphinx-js shells out to the `typedoc` binary on PATH (made available by the +# typedoc-json CMake target). It then parses the resulting JSON so that +# `js:autoclass::` / `js:autofunction::` directives produce Sphinx js-domain +# nodes -- visually matching the cpp-domain output styled by shibuya. +js_language = 'typescript' +js_source_path = '@CMAKE_SOURCE_DIR@/web/src/index.ts' +root_for_relative_js_paths = '@CMAKE_SOURCE_DIR@/web/src' +jsdoc_config_path = '@CMAKE_CURRENT_SOURCE_DIR@/typedoc/typedoc.json' +primary_domain = None # keep both cpp and js domains first-class + +# Monkey-patch sphinx-js so class members render under their short name +# (`getLatency(...)`) instead of the parent-qualified form +# (`InferenceHandler.getLatency(...)`). Upstream hardcodes use_short_name=False +# for members and exposes no flag to override it. We intercept the single +# call site where partial_path is a single element that already contains the +# parent prefix and strip it. +def _patch_sphinx_js_member_short_names(): + """Strip parent-qualified prefixes from sphinx-js member directives. + + sphinx-js emits things like `.. js:function:: InferenceHandler.destroy()` + for class members. We rewrite the partial_path so the directive name + becomes just `destroy`. (Sphinx still adds a visible class prefix on top + of this -- see the second patch below.) + """ + from sphinx_js import renderers + _orig_rst = renderers.JsRenderer.rst + + def rst(self, partial_path, obj, use_short_name=False): + if len(partial_path) == 1 and '.' in partial_path[0]: + partial_path = [partial_path[0].rsplit('.', 1)[-1]] + return _orig_rst(self, partial_path, obj, use_short_name) + + renderers.JsRenderer.rst = rst + +_patch_sphinx_js_member_short_names() + + +def _patch_js_domain_hide_class_prefix(): + """Drop the auto-added `Class.` descclassname from JS member signatures. + + Sphinx's `JSCallable.handle_signature` reads the enclosing js:class from + ref_context and prepends it as a `desc_addname` node, mirroring the + Python domain. We don't want that visual prefix on a per-class page where + the class header is already visible. We let upstream run (so signode + metadata and cross-reference targets stay correct via `fullname`) and + then strip the `desc_addname` children from the signature node. + """ + from sphinx.domains.javascript import JSCallable + from sphinx import addnodes + + _orig = JSCallable.handle_signature + + def handle_signature(self, sig, signode): + result = _orig(self, sig, signode) + for node in list(signode.children): + if isinstance(node, addnodes.desc_addname): + signode.remove(node) + return result + + JSCallable.handle_signature = handle_signature + +_patch_js_domain_hide_class_prefix() + + +def _patch_sphinx_js_drop_exported_from(): + """Suppress sphinx-js's "exported from " line. + + For a single-package barrel-export like @anira-project/anira the source-file path + TypeDoc reports (e.g. `wrappers.utils.HostConfig`) is meaningless to + users, who only ever import from the package root. + """ + from sphinx_js import renderers + + for cls_name in ('AutoClassRenderer', 'AutoFunctionRenderer', 'AutoAttributeRenderer'): + cls = getattr(renderers, cls_name) + _orig_tv = cls._template_vars + def make(orig): + def _template_vars(self, name, obj): + if hasattr(obj, 'exported_from'): + try: + obj.exported_from = None + except Exception: + pass + return orig(self, name, obj) + return _template_vars + cls._template_vars = make(_orig_tv) + +_patch_sphinx_js_drop_exported_from() + + +def _patch_sphinx_js_render_overloads(): + """Render TypeScript overload signatures in the docs. + + sphinx-js (`convertTopLevel.ts`) drops every signature past the first when + converting TypeDoc output to its IR — see the comment block around + `const first_sig = func.signatures![0];`. The Python-side `Function` IR + only carries one params list, so the limitation is structural. + + We work around it by reading `typedoc.json` directly, indexing every + callable that has more than one signature, and appending a fully rendered + ``.. js:function::`` block per extra signature after sphinx-js's + canonical rendering. Each extra block carries its own ``:param X:`` / + ``:type X:`` / ``:returns:`` field list, so every overload shows its own + Arguments / Returns sections in the rendered HTML. + """ + import json + from pathlib import Path + + typedoc_json = Path('@CMAKE_CURRENT_BINARY_DIR@/typedoc/typedoc.json') + if not typedoc_json.exists(): + return + + try: + data = json.loads(typedoc_json.read_text()) + except Exception: + return + + # ---- Type rendering helpers ---- + # Mirror sphinx-js's render_type best-effort. We only need string-quality + # output here; cross-references aren't preserved. + def render_type_node(t): + if t is None: + return '' + if isinstance(t, str): + return t + if not isinstance(t, dict): + return str(t) + kind = t.get('type') + if kind == 'intrinsic': + return t.get('name', '') + if kind == 'reference': + base = t.get('name', '') + args = t.get('typeArguments') or [] + if args: + return f"{base}<{', '.join(render_type_node(a) for a in args)}>" + return base + if kind == 'union': + return ' | '.join(render_type_node(x) for x in t.get('types') or []) + if kind == 'array': + return render_type_node(t.get('elementType')) + '[]' + if kind == 'literal': + v = t.get('value') + return repr(v) if isinstance(v, str) else str(v) + if kind == 'tuple': + return '[' + ', '.join(render_type_node(x) for x in t.get('elements') or []) + ']' + if kind == 'reflection': + # Function types and inline object types — fall back to a name if + # available, else a generic placeholder. + return t.get('name') or 'object' + return t.get('name') or kind or '' + + # ---- Per-signature param/return extraction ---- + def extract_description(comment): + # Reassemble TypeDoc's tokenised summary (mix of 'text' and 'code' + # parts) into a single RST string. Code spans are rendered with their + # original backticks intact so RST inline literals/roles survive. + if not isinstance(comment, dict): + return '' + parts = [] + for p in comment.get('summary') or []: + kind = p.get('kind') + text = p.get('text', '') + if kind == 'code': + # `text` already includes the backticks (e.g. ``foo``). + parts.append(text) + else: + parts.append(text) + return ''.join(parts) + + def extract_signature(sig): + params = [] + for p in sig.get('parameters') or []: + params.append({ + 'name': p.get('name', ''), + 'type': render_type_node(p.get('type')), + 'optional': bool(p.get('flags', {}).get('isOptional')), + 'rest': bool(p.get('flags', {}).get('isRest')), + 'default': p.get('defaultValue'), + }) + return { + 'params': params, + 'returns': render_type_node(sig.get('type')), + 'description': extract_description(sig.get('comment')), + } + + def fmt_formal_params(params): + # Match sphinx-js's `_formal_params`: bare names, `...` prefix for + # rest, `=default` suffix where a default value is present. + formals = [] + for p in params: + name = p['name'] + if p['rest']: + name = '...' + name + if p['default']: + name = f"{name}={p['default']}" + formals.append(name) + return '(' + ', '.join(formals) + ')' + + # Map fully-qualified method names ("ClassName.methodName") to the list of + # *additional* signature dicts (everything past the first signature, since + # sphinx-js already renders signature 0 itself). + extra_overloads: dict[str, list[dict]] = {} + + CONTAINER_KINDS = {128, 256, 2} # Class, Interface, Module + CALLABLE_KINDS = {2048, 64, 512} # Method, Function, Constructor + + def walk(node, parent_name=None): + if isinstance(node, list): + for child in node: + walk(child, parent_name) + return + if not isinstance(node, dict): + return + + name = node.get('name') + kind = node.get('kind') + sigs = node.get('signatures') + + if ( + sigs and isinstance(sigs, list) and len(sigs) > 1 + and kind in CALLABLE_KINDS and parent_name and name + ): + key = f'{parent_name}.{name}' + extra_overloads[key] = [extract_signature(s) for s in sigs[1:]] + + next_parent = name if kind in CONTAINER_KINDS else parent_name + walk(node.get('children') or [], next_parent) + + walk(data, None) + + if not extra_overloads: + return + + # ---- Render an extra overload as a complete .. js:function:: block ---- + # We wrap type strings in sphinx-js's custom `:sphinx_js_type:` role so the + # rendered HTML uses the same `` element as + # the canonical signature — keeping bold/non-italic styling consistent. + def fmt_type(t: str) -> str: + # Backticks inside a role value have to be escaped to keep the role + # parser from terminating early. We don't expect them in our types. + return f':sphinx_js_type:`{t}`' if t else '' + + def render_extra_block(method_name: str, sig: dict) -> str: + params = sig['params'] + formal = fmt_formal_params(params) + lines = [f'.. js:function:: {method_name}{formal}', ''] + description = sig.get('description') or '' + if description.strip(): + # Indent every line into the directive body. Blank lines must + # stay blank (no indent) so RST treats them as paragraph breaks. + for line in description.splitlines(): + lines.append(f' {line}' if line.strip() else '') + lines.append('') + for p in params: + if p['type']: + lines.append(f' :type {p["name"]}: {fmt_type(p["type"])}') + lines.append(f' :param {p["name"]}: ') + if sig['returns'] and sig['returns'] != 'void': + lines.append(f' :returns: {fmt_type(sig["returns"])}') + lines.append('') + return '\n'.join(lines) + + # ---- Patch JsRenderer.rst to append the extra blocks ---- + from sphinx_js import renderers + + _orig_rst = renderers.JsRenderer.rst + + def rst(self, partial_path, obj, use_short_name=False): + result = _orig_rst(self, partial_path, obj, use_short_name) + # Only augment Function IR objects (methods, ctors, free funcs). + from sphinx_js.ir import Function + if not isinstance(obj, Function): + return result + + path = getattr(obj, 'path', None) + segments = list(getattr(path, 'segments', None) or []) + clean = [s.rstrip('.#') for s in segments if s.rstrip('.#')] + candidates = [] + if len(clean) >= 2: + candidates.append(f'{clean[-2]}.{clean[-1]}') + if clean: + candidates.append(clean[-1]) + + extras = None + for key in candidates: + if key in extra_overloads: + extras = extra_overloads[key] + break + if not extras: + return result + + # Use the short method name (last path segment) so the extra block + # matches the canonical one's display style. + method_name = clean[-1] if clean else partial_path[-1] + extra_blocks = [render_extra_block(method_name, sig) for sig in extras] + return result.rstrip() + '\n\n' + '\n'.join(extra_blocks) + '\n' + + renderers.JsRenderer.rst = rst + +_patch_sphinx_js_render_overloads() + + templates_path = ['@SPHINX_SOURCE_DIR@/_templates'] exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'venv'] @@ -65,6 +369,22 @@ html_theme_options = { "url": "usage", "summary": "Detailed usage instructions for Anira" }, + { + "title": "Anira Web API", + "url": "web-api/index", + "children": [ + { + "title": "Class List", + "url": "web-api/reference/classlist", + "summary": "List of all Anira Web classes", + }, + { + "title": "Function List", + "url": "web-api/reference/functionlist", + "summary": "Module-level functions", + }, + ] + }, { "title": "API Documentation", "url": "api/index", diff --git a/docs/sphinx/index.rst b/docs/sphinx/index.rst index a0e760f1..25518267 100644 --- a/docs/sphinx/index.rst +++ b/docs/sphinx/index.rst @@ -21,6 +21,7 @@ Anira Documentation custom_backends examples api/index + web-api/index architecture benchmarking latency diff --git a/docs/sphinx/usage.rst b/docs/sphinx/usage.rst index 0a89c6db..09eabe67 100644 --- a/docs/sphinx/usage.rst +++ b/docs/sphinx/usage.rst @@ -225,6 +225,18 @@ If you want to define a custom context configuration, you can do so by creating // Create an InferenceHandler instance anira::InferenceHandler inference_handler(pp_processor, inference_config, context_config); +You can also opt out of the auto-managed thread pool entirely and supply your own threads. Pass ``0`` to :cpp:struct:`anira::ContextConfig` so the auto-pool stays empty, then create as many threads as you want via :cpp:func:`anira::Context::make_inference_thread`, call ``start()`` on each, and either call ``stop()`` or simply destroy the returned ``unique_ptr`` to tear them down. + +.. code-block:: cpp + + anira::ContextConfig context_config { 0 }; // opt out of the auto-pool + anira::InferenceHandler inference_handler(pp_processor, inference_config, context_config); + + auto thread = anira::Context::make_inference_thread(); + thread->start(); + // ... process audio ... + thread->stop(); // or just let `thread` go out of scope + 4. Get ready for Processing --------------------------- diff --git a/docs/sphinx/web-api/architecture.rst b/docs/sphinx/web-api/architecture.rst new file mode 100644 index 00000000..d4cfb165 --- /dev/null +++ b/docs/sphinx/web-api/architecture.rst @@ -0,0 +1,212 @@ +Architecture +============ + +``Anira Web`` is the WebAssembly distribution of anira: the same C++ +library, compiled to WASM and wrapped in a +TypeScript API. The TypeScript layer's job is to spread that WASM +module across the browser threads anira needs in order to run +real-time inference — a main thread, the audio worklet thread, and one +or more inference worker threads. + +.. code-block:: text + + ┌──────────────────┐ ┌────────────────────┐ ┌──────────────────────┐ + │ Main thread │ │ Inference worker(s)│ │ Audio worklet thread │ + │ │ │ (Web Worker(s)) │ │ │ + │ Setup │ │ │ │ AudioWorklet- │ + │ │ │ Model inference │ │ Processor │ + │ Configuration │◀──▶│ (WASM ONNX, │◀──▶│ Real-time │ + │ │ │ onnxruntime-web, │ │ process() │ + │ UI control │ │ or custom) │ │ Pre/Post-processor │ + └──────────────────┘ └────────────────────┘ └──────────────────────┘ + ▲ ▲ ▲ + └───────────────────────┴──────────────────────────┘ + Shared WebAssembly memory + +The number of inference workers is up to you. Each call to +``aniraWeb.spinUpInferenceWorker()`` spawns a new Web Worker hosting an +``InferenceThread`` — the same primitive anira uses for its desktop +thread pool. One worker is enough for simple models on most machines; spawn more if +you see audio dropouts, so anira can run inference on multiple batches +in parallel. + +All threads share a single ``WebAssembly.Memory`` instance, so +configuration objects, ring buffers, and tensor data live at the same +heap addresses everywhere. Cross-thread coordination uses message +passing for setup and atomics on shared memory for the real-time path. + +Main Thread +----------- + +The main thread is where you set up anira. Calling +``await AniraWeb.create()`` instantiates the WASM module and returns +the ``aniraWeb`` factory; from there you wire up the model, inference +configuration, and pre/post-processing the same way you would in C++. + +The main thread also owns your UI. Non-streamable tensor values +written from here — through ``setInput`` and similar APIs — reach the +model without blocking the audio path, so a slider or toggle can +update the model from frame to frame. + +Inference Worker +---------------- + +``await aniraWeb.spinUpInferenceWorker()`` starts a Web Worker that +owns inference execution. Pulling inference off the audio thread is +what keeps the audio worklet's ``process`` callback real-time-safe +even when a forward pass takes longer than one audio block. + +The worker hosts the inference engine itself, regardless of where that +engine actually runs. ``Anira Web`` ships with two built-in engines: +ONNX Runtime compiled into the WASM module, and ``onnxruntime-web`` on +the JavaScript side (:js:class:`ONNXRuntimeWebBackend`). User-written JS backends +also run on this worker. See :doc:`custom_inference_backends`. + +You can also replace the worker entry point itself: + +.. code-block:: typescript + + await aniraWeb.spinUpInferenceWorker( + new URL('./customInferenceWorker.ts', import.meta.url) + ) + +``spinUpInferenceWorker()`` returns an ``InferenceWorker`` handle. +When you're done with a worker — for instance when reconfiguring or +unloading the model — call ``worker.stop()`` to halt its inference +thread, terminate the underlying ``Worker``, and remove it from +``aniraWeb.getActiveWorkers()``. Workers spun up but never stopped +stay alive for the lifetime of the page. + +Audio Worklet Thread +-------------------- + +The browser's ``AudioWorkletGlobalScope`` runs the audio callback. Anira +ships with a default worklet that handles the common case: a +single-tensor model with in-place stereo or mono I/O. To install it: + +.. code-block:: typescript + + await aniraWeb.registerAudioWorkletForContext(audioContext) + const node = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor + ) + +For models that need more — multi-tensor I/O, a custom processing +buffer size, ``AudioParam`` integration, or a JS pre/post processor — +you provide a custom worklet file. See :doc:`custom_audio_worklets`. + +.. note:: + :js:class:`JSPrePostProcessor` subclasses are constructed on the + audio worklet thread, not on the main thread. Pre- and + post-processing run in the real-time callback, so the JS object that + implements them must live where that callback runs. + +Three Customization Axes +------------------------ + +Most extension work falls into one of three independent categories, +each with its own page: + +1. :doc:`custom_audio_worklets` — extend + :js:class:`AniraAudioWorkletBase` for multi-tensor models + (``processMulti``), custom ``maxBufferSize``, ``AudioParam`` + integration, or to host a custom :js:class:`JSPrePostProcessor`. +2. :doc:`custom_pre_post_processing` — subclass + :js:class:`JSPrePostProcessor` to run JavaScript before and after + inference (windowing, normalization, parameter clamping, etc.). +3. :doc:`custom_inference_backends` — replace the WASM-side runtime with + a JavaScript backend. Built-in options + (:js:class:`JSBackendBase`, :js:class:`ONNXRuntimeWebBackend`) and + user-written backends both run on the inference worker. + +Custom pre/post processing **requires** a custom worklet (because the +subclass must be instantiated on the audio thread); custom worklets and +custom backends are otherwise independent and can be combined freely. + +The JS ↔ WASM Bridge +-------------------- + +C++ objects live in WASM-managed memory and are referenced by raw +numeric pointers. The TypeScript wrappers (``InferenceHandler``, +``PrePostProcessor``, ``BufferF``, …) extend :js:class:`BaseWrapper`, +which holds two fields per instance: ``ptr`` (the C++ pointer) and +``wasmInstance`` (the Emscripten module). Every wrapper method +forwards into a ``__`` C export with ``this.ptr`` as +the first argument. + +Most wrapper APIs accept the union type +``PossiblePointer = T | number``, so you can pass either a wrapper +instance *or* a raw numeric pointer. This avoids forcing an allocation +just to call into the next wrapper — when you already have a pointer +in hand (for example from a worklet message or another wrapper's +``getPointer()``), pass it directly. + +Helpers, all exported from the package root: + ++--------------------------------+----------------------------------------------------------+ +| Helper | Role | ++================================+==========================================================+ +| ``resolvePtr(value)`` | Coerce a ``PossiblePointer`` to a number — returns | +| | ``value`` if it's already numeric, ``value.getPointer()``| +| | if it's a wrapper instance. Use this inside hot loops or | +| | when calling raw WASM exports yourself. | ++--------------------------------+----------------------------------------------------------+ +| ``instance.getPointer()`` | Return the wrapper's underlying C++ pointer as a | +| | number. Symmetric to ``resolvePtr`` for the | +| | wrapper-to-pointer direction. | ++--------------------------------+----------------------------------------------------------+ +| ``instance.wrapPointer(Cls, | Build a wrapper of class ``Cls`` around an existing | +| ptr)`` | pointer, reusing ``this.wasmInstance``. Skips the C++ | +| | constructor — useful for viewing C++ objects you don't | +| | own. | ++--------------------------------+----------------------------------------------------------+ +| ``Cls.createFromPointer( | Static counterpart of ``wrapPointer`` for cases where | +| module, ptr)`` | you don't have an existing wrapper handy (e.g. | +| | reconstructing a ``JSPrePostProcessor`` subclass on the | +| | worklet thread from ``state.prePostProcessorPtr``). | ++--------------------------------+----------------------------------------------------------+ + +.. _lifecycle-and-cleanup: + +Lifecycle and Cleanup +--------------------- + +Wrapper instances expose a ``destroy()`` method that frees the +underlying C++ object via the corresponding ``__destroy`` C +export. JavaScript has no destructors, so the GC won't call this for +you — the C++ memory only goes away when ``destroy()`` runs. For a +long-lived page that loads a model once and keeps inferring, the leak +is harmless (the module stays alive for the session anyway); for apps +that swap models, recreate handlers, or run under a test harness, +``destroy()`` is what you call. + +Not every wrapper needs ``destroy()``, though. Whether a wrapper is +*owning* depends on how it was created: + +* A wrapper from ``new SomeClass(...)`` runs the TS constructor, + which calls ``__create`` and stashes the fresh C++ pointer. + This wrapper is the only handle to that C++ object — calling + ``destroy()`` on it frees the object. +* A wrapper from ``wrapPointer`` or ``createFromPointer`` skips the + TS constructor entirely; it's a view over a C++ object that was + allocated by somebody else (typically another wrapper, or the + inference worker). **Don't call ``destroy()`` on these** — doing so + would free a C++ object that other code is still pointing at. + +For example, ``InferenceConfig.getTensorInputShape()`` returns a +``TensorShapeList`` view; the underlying storage belongs to the +``InferenceConfig``, so you destroy the config, not the view. + +When you do tear down a full setup, free the handler before the +config and processor it references — the handler holds pointers back +into them, so freeing them first leaves it with dangling references: + +.. code-block:: typescript + + inferenceHandler.destroy() // first: holds refs into pp + config + ppProcessor.destroy() + inferenceConfig.destroy() // last among the three + // ProcessingSpec, VectorModelData, VectorTensorShape, etc. can + // then be destroyed in any order. diff --git a/docs/sphinx/web-api/basic_usage.rst b/docs/sphinx/web-api/basic_usage.rst new file mode 100644 index 00000000..55c09da9 --- /dev/null +++ b/docs/sphinx/web-api/basic_usage.rst @@ -0,0 +1,260 @@ +Basic Usage +=========== + +This guide walks through the smallest end-to-end ``Anira Web`` setup: loading +an ONNX model, configuring inference, and wiring it into a Web Audio graph. +The code follows the `simple-gain-stereo demo `_ — a stereo +gain plugin with one streamable audio tensor and one non-streamable scalar +tensor (the gain value). You can run it live alongside this guide. + +The flow follows the same eight steps as the C++ :doc:`../usage` guide. Every +configuration class you know from C++ has a TypeScript equivalent that is +created via the ``aniraWeb`` instance. + +1. Bootstrap +------------ + +Create the ``AniraWeb`` instance and start the inference worker. The +instance owns the WebAssembly module, exposes all factories, and routes +work between threads. + +.. code-block:: typescript + + import { AniraWeb } from '@anira-project/anira' + + const aniraWeb = await AniraWeb.create() + await aniraWeb.spinUpInferenceWorker() + + const audioContext = new AudioContext({ sampleRate: 48000 }) + +.. note:: + ``spinUpInferenceWorker()`` starts the Web Worker that runs model + inference off the audio thread. Without it, no inference will execute. + See :doc:`architecture` for the threading model. + +2. Load the Model +----------------- + +Fetch the model bytes and wrap them in a ``ModelData`` factory. +``ModelData`` accepts either an ``ArrayBuffer`` (built-in WASM backends) or +a URL string (custom JS backends — see :doc:`custom_inference_backends`). + +.. code-block:: typescript + + const res = await fetch('simple-gain-stereo.onnx') + const modelBuffer = await res.arrayBuffer() + + const vectorModelData = aniraWeb.VectorModelData([ + aniraWeb.ModelData(modelBuffer, aniraWeb.InferenceBackend.ONNX), + ]) + +3. Tensor Shapes +---------------- + +Define the input and output tensor shapes. Each ``TensorShapeList`` entry +is one tensor; ``TensorShape`` pairs an input list with an output list. + +.. code-block:: typescript + + const inputShapeList = aniraWeb.TensorShapeList([[1, 2, 512], [1]]) + const outputShapeList = aniraWeb.TensorShapeList([[1, 2, 512], [1]]) + const tensorShape = aniraWeb.TensorShape(inputShapeList, outputShapeList) + const vectorTensorShape = aniraWeb.VectorTensorShape([tensorShape]) + +The model has two tensors: ``[1, 2, 512]`` is a stereo audio tensor +(batch 1, 2 channels, 512 samples per block) and ``[1]`` is the scalar +gain value. + +4. ProcessingSpec +----------------- + +The :js:class:`ProcessingSpec` describes how each tensor is processed. +A streamable tensor (continuous audio) has ``preprocess_input_size`` / +``postprocess_output_size`` greater than zero; a non-streamable tensor +(asynchronous control values) uses ``0`` and is set/read via +``setInput`` / ``getOutput``. + +.. code-block:: typescript + + const preprocessChannels = aniraWeb.VectorSizeT([2, 1]) + const postprocessChannels = aniraWeb.VectorSizeT([2, 1]) + const preprocessSize = aniraWeb.VectorSizeT([512, 0]) // tensor 0 streamable, tensor 1 not + const postprocessSize = aniraWeb.VectorSizeT([512, 0]) + + const processingSpec = aniraWeb.ProcessingSpec( + preprocessChannels, + postprocessChannels, + preprocessSize, + postprocessSize + ) + +5. InferenceConfig +------------------ + +Combine model data, shapes, and the processing spec into an +:js:class:`InferenceConfig`. The remaining positional arguments mirror +the C++ struct: + +.. code-block:: typescript + + const inferenceConfig = aniraWeb.InferenceConfig( + vectorModelData, + vectorTensorShape, + processingSpec, + 5, // max inference time in ms (real-time threshold) + 10, // warm-up iterations + false, // session_exclusive_processor + 0, // blocking_ratio + 1 // num_parallel_processors + ) + +6. PrePostProcessor +------------------- + +For most models the default :js:class:`PrePostProcessor` is enough. +``setInput(value, tensorIndex, sampleIndex)`` writes a non-streamable +input — here the initial gain value: + +.. code-block:: typescript + + const ppProcessor = aniraWeb.PrePostProcessor(inferenceConfig) + ppProcessor.setInput(1, 0, 1) // gain tensor (tensor 1, channel 0) = 1.0 + +If your model needs custom JS-side pre/post-processing, use +:js:class:`JSPrePostProcessor` instead — see +:doc:`custom_pre_post_processing`. + +7. HostConfig and InferenceHandler +---------------------------------- + +The :js:class:`HostConfig` describes the buffer size and sample rate the +host will deliver. Once the handler is constructed, call ``prepare`` to +allocate buffers and ``setInferenceBackend`` to pick the runtime. + +.. code-block:: typescript + + const hostAudioConfig = aniraWeb.HostConfig(128, 48000, false, 0) + + const inferenceHandler = aniraWeb.InferenceHandler(ppProcessor, inferenceConfig) + inferenceHandler.setInferenceBackend(aniraWeb.InferenceBackend.ONNX) + inferenceHandler.prepare(hostAudioConfig) + +.. note:: + The buffer size you pass here is the host buffer size that the audio + worklet will deliver per block (typically ``128`` samples in Web + Audio), not the model's tensor size. + +8. Audio Worklet Wiring +----------------------- + +In the browser, anira's real-time ``process`` callback runs in an +``AudioWorkletNode``. ``registerAudioWorkletForContext`` installs the +worklet module on the given ``AudioContext``; ``configureAudioWorklet`` +returns the connected ``AudioWorkletNode``. + +Calling ``registerAudioWorkletForContext`` with no second argument uses +anira's built-in default worklet, which handles single-tensor in-place +processing automatically. For multi-tensor or custom buffer sizes you +pass a custom worklet URL — see :doc:`custom_audio_worklets`. + +.. code-block:: typescript + + await aniraWeb.registerAudioWorkletForContext(audioContext) + + const inferenceNode = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor + ) + + const audio = new Audio('vibes.mp3') + const sourceNode = audioContext.createMediaElementSource(audio) + sourceNode.connect(inferenceNode).connect(audioContext.destination) + +9. Runtime Control +------------------ + +Non-streamable inputs can be updated from any thread at any time. UI +handlers typically write directly through the ``PrePostProcessor``: + +.. code-block:: typescript + + gainSlider.oninput = () => { + ppProcessor.setInput(parseFloat(gainSlider.value), 0, 1) + } + +The audio worklet thread reads the latest value at the start of each +block. + +Cleanup +------- + +Every Anira Web wrapper exposes a ``destroy()`` method that frees the +underlying C++ object. JavaScript's garbage collector does not call +this for you — if you ``new`` a wrapper and never call ``destroy()``, +the C++ memory leaks for the lifetime of the WebAssembly module. For +single-model apps that load a model once and keep it running, this is +harmless; if your app swaps models, recreates handlers, or runs inside +a long-lived test harness, ``destroy()`` is what you call when you're +done with each wrapper. + +Inference workers are torn down separately. ``spinUpInferenceWorker()`` +returns an ``InferenceWorker`` handle whose ``stop()`` method halts the +inference thread and terminates the underlying Web Worker: + +.. code-block:: typescript + + const worker = await aniraWeb.spinUpInferenceWorker() + // ... use the worker ... + await worker.stop() + +See :doc:`architecture` for the full lifecycle story — which wrappers +need ``destroy()``, which ones don't, and the order to tear them down +in. + +.. _run-inference-in-javascript: + +(Optional) Run Inference in JavaScript +-------------------------------------- + +The flow above runs the model through the WASM-side ONNX Runtime that +ships in anira's WebAssembly module. ``Anira Web`` also bundles a +JavaScript-side engine, :js:class:`ONNXRuntimeWebBackend`, which runs +the model through ``onnxruntime-web``. Two small changes flip the basic setup over to +it: + +* ``ModelData`` takes a **URL string** instead of an ``ArrayBuffer`` — + ``onnxruntime-web`` fetches the model itself. +* You instantiate the backend, register it with ``aniraWeb``, and pass + it to ``InferenceHandler`` as a third argument; the inference + backend is then ``InferenceBackend.CUSTOM``. + +.. code-block:: typescript + + const vectorModelData = aniraWeb.VectorModelData([ + aniraWeb.ModelData( + new URL('/simple-gain-stereo.onnx', window.location.origin).href, + aniraWeb.InferenceBackend.CUSTOM + ), + ]) + + // ... build inferenceConfig, processingSpec, ppProcessor as before ... + + const onnxBackend = aniraWeb.ONNXRuntimeWebBackend(inferenceConfig) + await aniraWeb.registerProcessor(onnxBackend, 'ONNXRuntimeWebBackend') + + const inferenceHandler = aniraWeb.InferenceHandler( + ppProcessor, inferenceConfig, onnxBackend + ) + inferenceHandler.setInferenceBackend(aniraWeb.InferenceBackend.CUSTOM) + +To plug in a different engine — your own JS implementation, a third +JS runtime, or GPU code — see :doc:`custom_inference_backends`. + +Relation to the C++ API +----------------------- + +The TypeScript API mirrors the C++ one: most classes and methods have a +camelCase counterpart with near-identical semantics, so the C++ +:doc:`../usage` guide carries over almost verbatim. See the +:doc:`reference/index` for the full TypeScript surface. diff --git a/docs/sphinx/web-api/custom_audio_worklets.rst b/docs/sphinx/web-api/custom_audio_worklets.rst new file mode 100644 index 00000000..99570284 --- /dev/null +++ b/docs/sphinx/web-api/custom_audio_worklets.rst @@ -0,0 +1,289 @@ +Custom Audio Worklets +===================== + +The default worklet that ships with Anira Web handles the common case: +one streamable tensor, single audio I/O, default ``maxBufferSize``. As +soon as your model wants something more — multiple tensors, a different +processing buffer size, ``AudioParam`` integration, or a JS-side +pre/post-processor — you write your own worklet file by subclassing +:js:class:`AniraAudioWorkletBase`. + +When You Need a Custom Worklet +------------------------------ + +* **Multi-tensor I/O.** Models with more than one streamable input or + output tensor must call ``inferenceHandler.processMulti`` instead of + ``process`` and marshal a ``float***`` pointer structure into WASM + memory. +* **Custom ``maxBufferSize``.** When the model expects a larger + processing block than the default (e.g. 1024 or 2048 samples), pass + ``maxBufferSize`` through ``configureAudioWorklet``'s options. +* **AudioParam integration.** Web Audio's ``AudioParam`` system gives + you sample-accurate, k-rate or a-rate parameter automation — but only + inside a custom worklet that declares ``parameterDescriptors``. +* **Hosting a JSPrePostProcessor subclass.** Custom pre/post-processors + must be instantiated on the audio thread; that requires a worklet + file. See :doc:`custom_pre_post_processing`. + +Skeleton +-------- + +A custom worklet file looks like this: + +.. code-block:: typescript + + // audio-worklet.ts + import { + AniraAudioWorkletBase, + type AniraWorkletState, + } from '@anira-project/anira/workers/worklet-base' + + class MyWorklet extends AniraAudioWorkletBase { + protected async onConfigured(state: AniraWorkletState) { + // One-time setup: build per-tensor pointer structures with + // buildMultiTensorPointers, construct JSPrePostProcessor subclasses, etc. + } + + protected processAudioBlock( + inputs: Float32Array[][], + outputs: Float32Array[][], + state: AniraWorkletState, + bufferSize: number, + parameters: Record + ): void { + // Real-time path: copy inputs into WASM, call processMulti, copy outputs back. + } + } + + registerProcessor('my-worklet', MyWorklet) + +And you register the file by URL and pass the matching +processor name to ``configureAudioWorklet``: + +.. code-block:: typescript + + await aniraWeb.registerAudioWorkletForContext( + audioContext, + new URL('./audio-worklet.ts', import.meta.url) + ) + + const inferenceNode = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor, + 'my-worklet', + { inputChannels: 2, outputChannels: 2 } + ) + +AniraWorkletState +----------------- + +``onConfigured`` and ``processAudioBlock`` both receive an +``AniraWorkletState`` object with everything you need to talk to WASM: + ++----------------------------+---------------------------------------------------------------+ +| Field | Description | ++============================+===============================================================+ +| ``aniraWeb`` | The ``AniraWeb`` instance for this thread. Exposes | +| | ``malloc``, ``getHeapU32``, ``getHeapF32``, | +| | ``getWasmInstance``, factories, etc. | ++----------------------------+---------------------------------------------------------------+ +| ``inferenceHandler`` | The :js:class:`InferenceHandler` proxy. Call | +| | ``processMulti`` (or ``process``) on it from | +| | ``processAudioBlock``. | ++----------------------------+---------------------------------------------------------------+ +| ``prePostProcessorPtr`` | Raw pointer to the C++ ``PrePostProcessor`` instance, used | +| | to construct a :js:class:`JSPrePostProcessor` subclass via | +| | ``createFromPointer``. | ++----------------------------+---------------------------------------------------------------+ +| ``inputBufferPtr`` | ``float**`` pointer arrays — one entry per channel — already | +| ``outputBufferPtr`` | laid out contiguously by ``configureAudioWorklet``. Pass to | +| | ``inferenceHandler.process`` for single-tensor models, or | +| | hand to ``buildMultiTensorPointers`` for multi-tensor splits. | ++----------------------------+---------------------------------------------------------------+ +| ``inputDataBuffer`` | WASM heap offsets for the per-channel scratch buffers the | +| ``outputDataBuffer`` | channel pointers above point into. Each channel occupies | +| | ``maxBufferSize * 4`` bytes, laid out contiguously. | ++----------------------------+---------------------------------------------------------------+ +| ``inputChannelViews`` | ``Float32Array`` views over the per-channel slices of the | +| ``outputChannelViews`` | scratch buffers. Use these to copy audio in and out without | +| | rebuilding views every block. | ++----------------------------+---------------------------------------------------------------+ +| ``ioConfig`` | ``{ maxBufferSize, inputChannels, outputChannels, | +| | inputNodeIndex, outputNodeIndex }``. | ++----------------------------+---------------------------------------------------------------+ +| ``wasmMemory`` | The shared ``WebAssembly.Memory``. Useful when you need a | +| | typed-array view over a custom region of the heap. | ++----------------------------+---------------------------------------------------------------+ + +Helpers on the Base Class +------------------------- + +:js:class:`AniraAudioWorkletBase` provides a few helpers so subclasses +rarely have to touch raw heap offsets: + ++------------------------------------------------+------------------------------------------------+ +| Helper | Purpose | ++================================================+================================================+ +| ``copyAudioInputsToChannels(inputNode, state, | Copy a slice of the host's input channels | +| bufferSize, channelOffset?, channelCount?)`` | into a contiguous range of | +| | ``inputChannelViews``. Missing source channels | +| | are zero-filled. | ++------------------------------------------------+------------------------------------------------+ +| ``copyAudioOutputsFromChannels(outputNode, | Copy a contiguous range of | +| state, samplesProcessed, channelOffset?, | ``outputChannelViews`` back into the host's | +| channelCount?)`` | output channels. | ++------------------------------------------------+------------------------------------------------+ +| ``buildMultiTensorPointers(direction, | Slice the existing ``inputBufferPtr`` / | +| channelsPerTensor)`` | ``outputBufferPtr`` into the ``float***`` | +| | structure ``processMulti`` expects, plus a | +| | ``size_t[numTensors]`` array for the | +| | per-tensor sample counts. Returns | +| | ``{ tensorPtrs, numSamplesPtr }``. | ++------------------------------------------------+------------------------------------------------+ + +In Practice: Multi-Tensor I/O +----------------------------- + +The streaming-gain-stereo demo runs a model with two streamable +tensors: a stereo audio tensor (2 channels) and a single-channel gain +tensor driven by an ``AudioParam``. Because there is more than one +tensor, the worklet has to call ``processMulti`` — which expects +``float***`` for each side (tensor → channels → samples) plus matching +``size_t*`` arrays of per-tensor sample counts. + +The base class already lays out the channel pointers contiguously +behind ``inputBufferPtr`` / ``outputBufferPtr``; +``buildMultiTensorPointers`` only needs the per-tensor channel split to +produce the ``processMulti`` arguments and the per-tensor sample count +buffer: + +.. code-block:: typescript + + const AUDIO_CHANNELS = 2 + const GAIN_CHANNELS = 1 + const NUM_TENSORS = 2 + + class StreamingGainStereo extends AniraAudioWorkletBase { + private inputTensors = { tensorPtrs: 0, numSamplesPtr: 0 } + private outputTensors = { tensorPtrs: 0, numSamplesPtr: 0 } + + static get parameterDescriptors() { + return [{ name: 'gain', defaultValue: 1.0, minValue: 0.0, maxValue: 2.0 }] + } + + protected async onConfigured(_state: AniraWorkletState) { + this.inputTensors = this.buildMultiTensorPointers('input', [AUDIO_CHANNELS, GAIN_CHANNELS]) + this.outputTensors = this.buildMultiTensorPointers('output', [AUDIO_CHANNELS, GAIN_CHANNELS]) + } + } + +In ``processAudioBlock`` use the input/output copy helpers, fill the +gain channel from the ``AudioParam`` (delivered as the fifth argument), +write the per-tensor sample counts, and call ``processMulti``: + +.. code-block:: typescript + + protected processAudioBlock( + inputs: Float32Array[][], + outputs: Float32Array[][], + state: AniraWorkletState, + bufferSize: number, + parameters: Record + ): void { + const { inferenceHandler, ioConfig, inputChannelViews } = state + const heapU32 = state.aniraWeb.getHeapU32() + + const inputNode = inputs[ioConfig.inputNodeIndex] + const outputNode = outputs[ioConfig.outputNodeIndex] + + // Stereo audio into channels 0–1 (the audio tensor). + this.copyAudioInputsToChannels(inputNode, state, bufferSize, 0, AUDIO_CHANNELS) + + // Channel 2 (the gain tensor) is driven by the AudioParam. + const gainParam = parameters.gain + const gainView = inputChannelViews[AUDIO_CHANNELS] + if (gainParam.length === 1) { + gainView.fill(gainParam[0], 0, bufferSize) + } else { + gainView.set(gainParam.subarray(0, bufferSize), 0) + } + + // Both tensors run with the same per-quantum sample count. + for (let i = 0; i < NUM_TENSORS; i++) { + heapU32[this.inputTensors.numSamplesPtr / 4 + i] = bufferSize + heapU32[this.outputTensors.numSamplesPtr / 4 + i] = bufferSize + } + + const resultPtr = inferenceHandler.processMulti( + this.inputTensors.tensorPtrs, + this.inputTensors.numSamplesPtr, + this.outputTensors.tensorPtrs, + this.outputTensors.numSamplesPtr + ) + const samplesProcessed = heapU32[resultPtr / 4] + + // Only the audio tensor is routed back to the Web Audio output. + this.copyAudioOutputsFromChannels(outputNode, state, samplesProcessed, 0, AUDIO_CHANNELS) + } + +The ``AudioParam`` is declared in ``parameterDescriptors`` (as above) +and arrives directly in ``processAudioBlock``'s ``parameters`` argument +— no manual ``process`` override is needed. The ``inferenceNode`` +returned by ``configureAudioWorklet`` exposes the parameter on the JS +side via ``inferenceNode.parameters.get('gain')``. + +.. note:: + The gain tensor is exposed to users as an ``AudioParam``, not as an + audio input — but on the WASM side, anira expects every tensor's + data to live in the contiguous channel layout that the base class + allocates behind ``inputBufferPtr``. So the worklet allocates a + third internal channel as scratch space and materialises the + ``parameters.gain`` values into it on every block. The surrounding + Web Audio node itself stays stereo by passing + ``audioWorkletNodeOptions: { channelCount: 2, outputChannelCount: [2] }`` + in the ``configureAudioWorklet`` options: + + .. code-block:: typescript + + const inferenceNode = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor, + 'streaming-gain-stereo', + { + inputChannels: 3, // 2 audio + 1 scratch for the gain tensor + outputChannels: 3, + audioWorkletNodeOptions: { + channelCount: 2, + outputChannelCount: [2], + }, + } + ) + +In Practice: Custom maxBufferSize +--------------------------------- + +GuitarLSTM expects 2048-sample blocks, far larger than the 128 samples +Web Audio delivers per ``process`` call. ``maxBufferSize`` in the +``configureAudioWorklet`` options propagates into ``ioConfig`` so the +worklet base class allocates buffers of the right size and accumulates +host blocks until the model can run: + +.. code-block:: typescript + + await aniraWeb.registerAudioWorkletForContext( + audioContext, + new URL('./audio-worklet.ts', import.meta.url) + ) + const inferenceNode = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor, + 'guitar-lstm', + { inputChannels: 1, outputChannels: 1, maxBufferSize: 2048 } + ) + +The ``HostConfig`` passed to ``inferenceHandler.prepare`` should still +match Web Audio's per-callback buffer size (``128``); ``maxBufferSize`` +is anira's processing-side block size, not the host-side one. diff --git a/docs/sphinx/web-api/custom_inference_backends.rst b/docs/sphinx/web-api/custom_inference_backends.rst new file mode 100644 index 00000000..0135a875 --- /dev/null +++ b/docs/sphinx/web-api/custom_inference_backends.rst @@ -0,0 +1,171 @@ +Custom Inference Backends +========================= + +``Anira Web`` covers most use cases with the two engines it ships: +the WASM-side ONNX Runtime (the default path in :doc:`basic_usage`) +and ``onnxruntime-web`` on the JS side (see +:ref:`run-inference-in-javascript`). Reach for a custom backend when +neither fits — for example, when you want to run the model through a +different JS runtime, drive a GPU directly, or wire up a stub for +testing. + +A custom backend is a JS class that anira's inference worker invokes +in place of the bundled engine. Writing one takes three steps: + +1. Subclass :js:class:`JSBackendBase` and override ``process``. +2. Bundle that subclass into a custom inference worker so the worker + knows how to construct it. +3. Spin up that custom worker and wire the backend into + :js:class:`InferenceHandler` via ``InferenceBackend.CUSTOM``. + +The `js-copying demo `_ walks through all three +with a passthrough ``JSCopyBackend``; we'll use it as the running +example below. + +Step 1: Implement the Backend +----------------------------- + +Subclass :js:class:`JSBackendBase` and override +``process(inputVecPtr, outputVecPtr)``. Anira hands you two pointers +into WASM memory — one to a ``VectorBufferF`` of input tensors, one to +outputs — and expects you to populate the outputs in place. Use +``wrapPointer`` to view the WASM structures as TypeScript objects. + +.. code-block:: typescript + + // misc/JSCopyBackend.ts + import { JSBackendBase, BufferF, VectorBufferF } from '@anira-project/anira' + + export class JSCopyBackend extends JSBackendBase { + override process(inputVecPtr: number, outputVecPtr: number): void { + const heapF32 = this.wasmInstance.HEAPF32 + const inputVec = this.wrapPointer(VectorBufferF, inputVecPtr) + const outputVec = this.wrapPointer(VectorBufferF, outputVecPtr) + + const tensors = Math.min(inputVec.size(), outputVec.size()) + for (let t = 0; t < tensors; t++) { + const inputBuffer = this.wrapPointer(BufferF, inputVec.get(t)) + const outputBuffer = this.wrapPointer(BufferF, outputVec.get(t)) + + const channels = inputBuffer.getNumChannels() + const inputSamples = inputBuffer.getNumSamples() + const outputSamples = outputBuffer.getNumSamples() + const sampleDiff = inputSamples - outputSamples + + for (let ch = 0; ch < channels; ch++) { + const readOffset = inputBuffer.getReadPointer(ch) >> 2 + const writeOffset = outputBuffer.getWritePointer(ch) >> 2 + for (let i = 0; i < outputSamples; i++) { + heapF32[writeOffset + i] = heapF32[readOffset + i + sampleDiff] + } + } + } + } + } + +Step 2: Bundle Into a Custom Inference Worker +--------------------------------------------- + +The default inference worker that ``spinUpInferenceWorker()`` spawns +doesn't know about your backend class — it only knows the built-ins. +You ship a custom worker file that hands your subclass to anira's +worker runtime: + +.. code-block:: typescript + + // customInferenceWorker.ts + import { setupInferenceWorker } from '@anira-project/anira' + import { JSCopyBackend } from '../misc/JSCopyBackend' + + setupInferenceWorker({ JSCopyBackend }) + +This is a one-line file: ``setupInferenceWorker`` runs anira's worker +loop and registers the constructors you pass it, so the worker can +instantiate the right class when ``registerProcessor`` is called from +the main thread. + +Step 3: Wire It Up +------------------ + +On the main thread, point ``spinUpInferenceWorker`` at the custom +worker file, then follow the usual setup with three additions: the +model is declared as ``InferenceBackend.CUSTOM``, the backend is +instantiated and registered with ``aniraWeb``, and the same instance +is handed to :js:class:`InferenceHandler` as a third argument. + +.. code-block:: typescript + + const customInferenceWorkerUrl = new URL('./customInferenceWorker.ts', import.meta.url) + + const aniraWeb = await AniraWeb.create() + await aniraWeb.spinUpInferenceWorker(customInferenceWorkerUrl) + + const vectorModelData = aniraWeb.VectorModelData([ + aniraWeb.ModelData(modelBuffer, aniraWeb.InferenceBackend.CUSTOM), + ]) + + // Build inferenceConfig, processingSpec, ppProcessor as in basic_usage... + + const jsCopyBackend = new JSCopyBackend(aniraWeb.getWasmInstance(), inferenceConfig) + await aniraWeb.registerProcessor(jsCopyBackend, 'JSCopyBackend') + + const inferenceHandler = aniraWeb.InferenceHandler( + ppProcessor, inferenceConfig, jsCopyBackend + ) + inferenceHandler.setInferenceBackend(aniraWeb.InferenceBackend.CUSTOM) + +``registerProcessor`` ships the backend reference over to the +inference worker so the WASM-side dispatch can call back into it. + +.. note:: + ``ModelData`` accepts either an ``ArrayBuffer`` (the binary form, + shown above) or a URL string. If you pass a URL, anira hands the + string to your backend as-is — your backend decides how to load + it. The built-in :js:class:`ONNXRuntimeWebBackend` uses this to + fetch the model itself; ``modelData.isBinary()`` tells you which + form is in play: + + .. code-block:: typescript + + 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()) + } + +.. warning:: + The custom backend runs on the inference worker thread, not on the + audio worklet thread, so it doesn't block the real-time callback + directly. It still has to finish under the + ``max_inference_time_ms`` set in :js:class:`InferenceConfig`, + otherwise anira will fall back to the previous block's output and + you will hear dropouts. + +Sanity Check: JSBackendBase as a Passthrough +-------------------------------------------- + +If you want to verify the JS-bridge plumbing before committing to a +real backend, instantiate :js:class:`JSBackendBase` directly. It +ships with a trivial WASM-side passthrough ``process`` and a JS hook +that fires for every block — and because it's a built-in, it doesn't +need a custom inference worker: + +.. code-block:: typescript + + const jsBackendBase = aniraWeb.JSBackendBase(inferenceConfig) + await aniraWeb.registerProcessor(jsBackendBase, 'JSBackendBase') + + const inferenceHandler = aniraWeb.InferenceHandler( + ppProcessor, inferenceConfig, jsBackendBase + ) + inferenceHandler.setInferenceBackend(aniraWeb.InferenceBackend.CUSTOM) + +The `js-callback demo `_ does exactly this. diff --git a/docs/sphinx/web-api/custom_pre_post_processing.rst b/docs/sphinx/web-api/custom_pre_post_processing.rst new file mode 100644 index 00000000..f329f7ec --- /dev/null +++ b/docs/sphinx/web-api/custom_pre_post_processing.rst @@ -0,0 +1,176 @@ +Custom Pre- and Post-Processing +=============================== + +When the default :js:class:`PrePostProcessor` doesn't cover what your +model needs — windowing, normalization, parameter smoothing, custom +multi-tensor packing — you subclass :js:class:`JSPrePostProcessor` and +override ``preProcess`` and/or ``postProcess`` in JavaScript. The +`guitar-lstm and steerable-nafx demos `_ +are live examples of this pattern that you can run in the browser. + +.. note:: + This page builds on :doc:`custom_audio_worklets`. A custom + pre/post-processor must be instantiated on the audio worklet thread, + so you always need a small custom worklet file. + +Two-Step Setup +-------------- + +The processor lives in two places. On the **main thread**, you create +a :js:class:`JSPrePostProcessor` from the factory — this tells anira +that pre/post-processing will be handled in JavaScript: + +.. code-block:: typescript + + const ppProcessor = aniraWeb.JSPrePostProcessor(inferenceConfig) + const inferenceHandler = aniraWeb.InferenceHandler(ppProcessor, inferenceConfig) + +On the **audio worklet thread**, you reconstruct the C++ processor as +your subclass and register it. ``createFromPointer`` wraps the existing +C++ instance (``state.prePostProcessorPtr``) so JS overrides hook into +the same object: + +.. code-block:: typescript + + // audio-worklet.ts + import { + AniraAudioWorkletBase, + type AniraWorkletState, + } from '@anira-project/anira/workers/worklet-base' + import { JSPrePostProcessor } from '@anira-project/anira' + + class MyPrePostProcessor extends JSPrePostProcessor { + // overrides go here + } + + class MyWorklet extends AniraAudioWorkletBase { + protected async onConfigured(state: AniraWorkletState) { + const { aniraWeb, prePostProcessorPtr } = state + + const ppProcessor = MyPrePostProcessor.createFromPointer( + aniraWeb.getWasmInstance(), + prePostProcessorPtr + ) + + this.prePostRegistry.set(prePostProcessorPtr, ppProcessor) + } + } + + registerProcessor('my-worklet', MyWorklet) + +What You Can Override +--------------------- + +:js:class:`JSPrePostProcessor` exposes the same hooks as the C++ class: + ++-------------------------------------------------+-----------------------------------------------+ +| Method | When it runs | ++=================================================+===============================================+ +| ``preProcess(ringBuffers, buffers, backend)`` | Before each inference call. Use it to pull | +| | samples from the input ring buffers into the | +| | model's input tensors. | ++-------------------------------------------------+-----------------------------------------------+ +| ``postProcess(buffers, ringBuffers, backend)`` | After each inference call. Use it to push | +| | the model's output tensors into the output | +| | ring buffers. | ++-------------------------------------------------+-----------------------------------------------+ + +Inside an override you can read and write non-streamable tensor values +with ``getInput`` / ``setInput`` / ``getOutput`` / ``setOutput`` (same +semantics as the C++ class — see :doc:`../usage`), and call into raw +WASM exports through ``this.wasmInstance`` for ring-buffer manipulation. + +In Practice: Gain Clamp +----------------------- + +This is the smallest possible custom pre-processor: it clamps the gain +parameter to ``[0, 1]`` before passing it to the C++ pre-processing. + +.. code-block:: typescript + + // audio-worklet.ts + import { + AniraAudioWorkletBase, + type AniraWorkletState, + } from '@anira-project/anira/workers/worklet-base' + import { + JSPrePostProcessor, + type PossiblePointer, + type VectorBufferF, + type VectorRingBuffer, + } from '@anira-project/anira' + + class GainClampPrePostProcessor extends JSPrePostProcessor { + override preProcess( + ringBuffers: PossiblePointer, + buffers: PossiblePointer, + backend: number + ): void { + const gain = this.getInput(0, 1) + this.setInput(Math.min(1.0, gain), 0, 1) + super.preProcess(ringBuffers, buffers, backend) + } + } + + class PrePostProcessorWorklet extends AniraAudioWorkletBase { + protected async onConfigured(state: AniraWorkletState) { + const { aniraWeb, prePostProcessorPtr } = state + const ppProcessor = GainClampPrePostProcessor.createFromPointer( + aniraWeb.getWasmInstance(), + prePostProcessorPtr + ) + this.prePostRegistry.set(prePostProcessorPtr, ppProcessor) + } + } + + registerProcessor('pre-post-processors', PrePostProcessorWorklet) + +The setup is identical to the one on the :doc:`basic_usage` page +except that ``PrePostProcessor`` becomes ``JSPrePostProcessor`` and +``configureAudioWorklet`` is given the processor name: + +.. code-block:: typescript + + const ppProcessor = aniraWeb.JSPrePostProcessor(inferenceConfig) + ppProcessor.setInput(1, 0, 1) + + await aniraWeb.registerAudioWorkletForContext( + audioContext, + new URL('./audio-worklet.ts', import.meta.url) + ) + const inferenceNode = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor, + 'pre-post-processors' + ) + + // The slider sets the raw gain on the main thread; the worklet thread + // clamps it on every block via the override above. + gainSlider.oninput = () => { + ppProcessor.setInput(parseFloat(gainSlider.value), 0, 1) + } + +Pointer Arguments +----------------- + +``preProcess`` and ``postProcess`` receive ``PossiblePointer<...>`` +arguments — either wrapper instances or raw WASM heap addresses. The +:doc:`architecture` page covers the helpers (``resolvePtr``, +``getPointer``, ``wrapPointer``) in full; the short version is to call +``resolvePtr`` to get a numeric pointer, then call the exported WASM +functions on ``this.wasmInstance`` (e.g. ``_vector_ring_buffer_get``, +``_vector_buffer_f_get``, +``_prepostprocessor_pop_samples_from_buffer_window``) to manipulate +buffers in place. The guitar-lstm and steerable-nafx demos show this pattern applied to real windowing +logic. + +.. note:: + Calling the underscore-prefixed exports directly looks unusual at + first, but it's a deliberate performance escape hatch. Wrapping a + pointer into a TypeScript class (``wrapPointer(BufferF, ptr)``, + etc.) allocates a JS object — fine on the main thread, but + unwanted allocation pressure in real-time code that runs every + audio block. The raw exports skip the wrapper entirely, at the + cost of dealing in numeric pointers. Reach for them in real-time + paths; stick with the wrappers everywhere else. diff --git a/docs/sphinx/web-api/index.rst b/docs/sphinx/web-api/index.rst new file mode 100644 index 00000000..d53f0779 --- /dev/null +++ b/docs/sphinx/web-api/index.rst @@ -0,0 +1,22 @@ +Anira Web (TypeScript / WASM) +============================= + +The Anira Web package is a TypeScript wrapper around the Anira C++ +library compiled to WebAssembly via Emscripten. It exposes a large subset +of classes and functions that can be used to run real time inference in the +browser, both with and without the Web Audio API. + +This section is a mix of hand-written guides and an auto-generated API +reference. + +.. toctree:: + :maxdepth: 2 + :caption: Anira Web + + installation_building + basic_usage + architecture + custom_audio_worklets + custom_pre_post_processing + custom_inference_backends + reference/index diff --git a/docs/sphinx/web-api/installation_building.rst b/docs/sphinx/web-api/installation_building.rst new file mode 100644 index 00000000..8de40973 --- /dev/null +++ b/docs/sphinx/web-api/installation_building.rst @@ -0,0 +1,143 @@ +Installation / Building +======================= + +Anira Web is the TypeScript / WebAssembly distribution of Anira. It is +made up of two parts: + +* a WebAssembly module (``AniraWeb.wasm`` + ``AniraWeb.js``) compiled from + the Anira C++ sources via Emscripten, and +* a TypeScript package that wraps the module and exposes a high-level API + for use in the browser (with or without the Web Audio API). + +The sections below cover how to consume the published package, how to +import it in your project, and how to build the WASM module and the +TypeScript package from source. + +Installation +------------ + +Add the package to your project with the package manager of your choice: + +.. code-block:: bash + + npm install @anira-project/anira + pnpm add @anira-project/anira + yarn add @anira-project/anira + bun add @anira-project/anira + +The package ships its WebAssembly artifacts under ``@anira-project/anira/dist/wasm/`` +(``AniraWeb.wasm`` and the Emscripten-generated ``AniraWeb.js`` glue +file). When bundling, make sure the ``.wasm`` file is copied to a path +your runtime can fetch — most modern bundlers (Vite, webpack 5, Rollup +with the right plugins, esbuild) already understand the +``new URL('./file.wasm', import.meta.url)`` references emitted by the +package and will emit the asset automatically. + +Importing +--------- + +The package is published as ESM only. The main entry point re-exports the +high-level API (``AniraWeb``, factories, wrappers, backends, helpers, and +the inference-worker handler): + +.. code-block:: ts + + import { + AniraWeb, + // factories, wrappers, backends, helpers, ... + } from '@anira-project/anira' + +.. _building: + +Building from Source +-------------------- + +Building ``@anira-project/anira`` is a two-stage process: + +1. Cross-compile the Anira C++ library to WebAssembly with Emscripten. + The build outputs ``AniraWeb.wasm``, ``AniraWeb.js`` and + ``AniraWeb.d.ts`` into ``anira/web/wasm/``. +2. Build the TypeScript package, which bundles those artifacts into + ``anira/web/dist/``. + +Both stages are run from a checkout of the Anira repository, so start +by cloning it: + +.. code-block:: bash + + git clone https://github.com/anira-project/anira.git + cd anira + +Prerequisites +~~~~~~~~~~~~~ + +* CMake ≥ 3.15 and Ninja +* The `Emscripten SDK `_ + (``emsdk``) +* Node.js ≥ 18 and a package manager (``npm``, ``pnpm``, ``yarn`` or + ``bun``) + +Activate Emscripten +~~~~~~~~~~~~~~~~~~~ + +.. note:: + We use version 4.0.23 of the Emscripten SDK + + +The CMake presets reference the Emscripten toolchain through the +``$EMSDK`` environment variable, so you must set it. + +.. code-block:: bash + # clone emscripten + git clone https://github.com/emscripten-core/emsdk.git emsdk-4.0.23 + cd emsdk-4.0.23 + + # one-time setup + ./emsdk install 4.0.23 + ./emsdk activate 4.0.23 + + export EMSDK=/path/to/emsdk-4.0.23 + + # sanity-check + echo "$EMSDK" + + +Build the WASM Module +~~~~~~~~~~~~~~~~~~~~~ + +From the ``anira/`` directory (the C++ project root), use the bundled +CMake presets: + +.. code-block:: bash + + # Release build (recommended) + cmake --preset wasm-release + cmake --build --preset wasm-release + + # Debug build + cmake --preset wasm-debug + cmake --build --preset wasm-debug + +The resulting files are written directly into ``anira/web/wasm/``: + +* ``AniraWeb.js`` — Emscripten ES6 module loader +* ``AniraWeb.wasm`` — the compiled module +* ``AniraWeb.d.ts`` — TypeScript declarations emitted by ``--emit-tsd`` + +Build the TypeScript Package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Once ``anira/web/wasm/`` is populated, build the npm package: + +.. code-block:: bash + + cd anira/web + npm install + npm run build # tsc && vite build + # npm run dev # rebuild on changes (vite build --watch) + +The build runs ``tsc`` for type-checking and then ``vite build`` to +produce ESM output in ``anira/web/dist/``. ``vite-plugin-static-copy`` +copies the WASM artifacts from ``wasm/`` into ``dist/wasm/`` so they are +included in the published package. + diff --git a/docs/sphinx/web-api/reference/class/AniraAudioWorkletBase.rst b/docs/sphinx/web-api/reference/class/AniraAudioWorkletBase.rst new file mode 100644 index 00000000..6f5b21d9 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/AniraAudioWorkletBase.rst @@ -0,0 +1,206 @@ +Class AniraAudioWorkletBase +=========================== + +.. note:: + This class is exported from the package's audio-worklet subpath: + ``import { AniraAudioWorkletBase, type AniraWorkletState } from '@anira-project/anira/workers/worklet-base'``. + The subpath isolates the worklet bundle so the main entry point + stays free of references to ``AudioWorkletProcessor``, which only + exists in ``AudioWorkletGlobalScope``. + + See :doc:`../../custom_audio_worklets` for usage + guidance and worked examples. + +.. js:class:: AniraAudioWorkletBase extends AudioWorkletProcessor + + Base class for custom audio worklets that drive an + :js:class:`InferenceHandler`. Subclasses override + :js:meth:`onConfigured` for one-time setup and + :js:meth:`processAudioBlock` for the real-time loop. The class is + wired to the main thread by ``aniraWeb.configureAudioWorklet`` — + the configure handshake populates ``this.aniraState`` and then + invokes ``onConfigured``. + + .. js:attribute:: aniraState + :type: AniraWorkletState | null + + The configuration handed in by the main thread once the + configure handshake completes. ``null`` until the first + ``configure`` message is processed. + + .. js:method:: constructor(options?) + + :param AudioWorkletNodeOptions options: Forwarded to the + ``AudioWorkletProcessor`` super-constructor. Most subclasses + do not need to override the constructor. + + .. js:method:: onConfigured(state) + + Override hook for one-time setup, invoked once after the + configure handshake completes and before the first + ``processAudioBlock`` call. Default implementation is a no-op. + + Typical uses include allocating the ``float***`` pointer + structure for ``processMulti`` (via + :js:meth:`buildMultiTensorPointers`), constructing a + :js:class:`JSPrePostProcessor` subclass with + ``createFromPointer``, or caching frequently-accessed views + onto WASM memory. + + :param AniraWorkletState state: The same state object that will + later be passed to ``processAudioBlock``. + :returns: ``Promise`` + + .. js:method:: processAudioBlock(inputs, outputs, state, bufferSize, parameters) + + Override hook for the real-time path, invoked from + ``process()`` once per audio quantum. The default + implementation copies the host inputs into the WASM scratch + buffers, calls ``inferenceHandler.process`` with + ``inputBufferPtr`` / ``outputBufferPtr``, and copies the + result back to the host outputs — i.e. the single-tensor + in-place case. + + :param inputs: Host input channels (the worklet ``process`` + argument). + :type inputs: Float32Array[][] + :param outputs: Host output channels. + :type outputs: Float32Array[][] + :param AniraWorkletState state: The configured state. + :param number bufferSize: The number of samples in this + quantum (clamped to ``ioConfig.maxBufferSize``). + :param parameters: ``AudioParam`` values for this quantum, + keyed by parameter name. + :type parameters: Record + + .. js:method:: copyAudioInputsToChannels(inputNode, state, bufferSize, channelOffset?, channelCount?) + + Copy a slice of the host's input channels into a contiguous + range of ``state.inputChannelViews``. Missing source channels + are zero-filled. + + :param inputNode: A single host input node (one entry of the + ``inputs`` argument), or ``undefined``. + :type inputNode: Float32Array[] | undefined + :param AniraWorkletState state: The configured state. + :param number bufferSize: Number of samples to copy / fill per + channel. + :param number channelOffset: Index into + ``inputChannelViews`` where copying starts. Defaults to + ``0``. + :param number channelCount: Number of channels to fill. + Defaults to ``inputChannelViews.length - channelOffset``. + + .. js:method:: copyAudioOutputsFromChannels(outputNode, state, samplesProcessed, channelOffset?, channelCount?) + + Copy a contiguous range of ``state.outputChannelViews`` back + into the host's output channels. No-op if no output node is + connected or no samples were produced. + + :param outputNode: A single host output node (one entry of + the ``outputs`` argument), or ``undefined``. + :type outputNode: Float32Array[] | undefined + :param AniraWorkletState state: The configured state. + :param number samplesProcessed: Number of valid samples per + channel. + :param number channelOffset: Index into + ``outputChannelViews`` where copying starts. Defaults to + ``0``. + :param number channelCount: Number of channels to copy. + Defaults to ``outputChannelViews.length - channelOffset``. + + .. js:method:: buildMultiTensorPointers(direction, channelsPerTensor) + + Build the ``float***`` pointer structure that ``processMulti`` + expects, by slicing the existing ``inputBufferPtr`` / + ``outputBufferPtr`` (both already ``float**`` channel-pointer + arrays laid out contiguously by ``configureAudioWorklet``). + Also allocates a ``size_t[numTensors]`` array for the + per-tensor sample counts. + + :param direction: ``'input'`` slices ``inputBufferPtr``; + ``'output'`` slices ``outputBufferPtr``. + :type direction: 'input' | 'output' + :param channelsPerTensor: Per-tensor channel split. For + example, ``[2, 1]`` means tensor 0 owns channels 0–1 and + tensor 1 owns channel 2. + :type channelsPerTensor: number[] + :returns: ``{ tensorPtrs: number, numSamplesPtr: number }`` — + the pointer to pass as the ``float***`` argument to + ``processMulti``, and the pointer to fill with per-tensor + sample counts on each block. + + .. js:method:: process(inputs, outputs, parameters) + + The ``AudioWorkletProcessor.process`` entry point. Clamps the + requested buffer size to ``ioConfig.maxBufferSize`` and + delegates to :js:meth:`processAudioBlock`. Returns silence + until the configure handshake has completed. Subclasses + rarely need to override this; override + :js:meth:`processAudioBlock` instead. + + :param inputs: Host input channels. + :type inputs: Float32Array[][] + :param outputs: Host output channels. + :type outputs: Float32Array[][] + :param parameters: ``AudioParam`` values for this quantum. + :type parameters: Record + :returns: ``true`` (keep the processor alive). + +Type AniraWorkletState +---------------------- + +The configuration the main thread hands to the worklet during the +configure handshake. Exposed read-only on +:js:attr:`AniraAudioWorkletBase.aniraState` and re-passed as the +``state`` argument to :js:meth:`AniraAudioWorkletBase.onConfigured` +and :js:meth:`AniraAudioWorkletBase.processAudioBlock`. + +``aniraWeb`` (:js:class:`AniraWeb`) + The :js:class:`AniraWeb` instance for the worklet thread. + Exposes ``malloc``, ``getHeapU32``, ``getHeapF32``, + ``getWasmInstance``, factories, and so on. + +``inferenceHandler`` (:js:class:`InferenceHandler`) + The :js:class:`InferenceHandler` proxy. Call ``processMulti`` + (or ``process``) on it from ``processAudioBlock``. + +``prePostProcessorPtr`` (number) + Raw pointer to the C++ ``PrePostProcessor`` instance, used to + construct a :js:class:`JSPrePostProcessor` subclass via + ``createFromPointer``. + +``inputBufferPtr`` (number) + ``float**`` channel pointer array, laid out contiguously by + ``configureAudioWorklet``. Pass directly to + ``inferenceHandler.process`` for single-tensor models, or hand + to :js:meth:`AniraAudioWorkletBase.buildMultiTensorPointers` + for multi-tensor splits. + +``outputBufferPtr`` (number) + Same as ``inputBufferPtr`` but for the output side. + +``inputDataBuffer`` (number) + WASM heap offset for the per-channel input scratch buffers. + Each channel occupies ``maxBufferSize * 4`` bytes, laid out + contiguously. + +``outputDataBuffer`` (number) + WASM heap offset for the per-channel output scratch buffers. + +``inputChannelViews`` (``Float32Array[]``) + ``Float32Array`` views over the per-channel slices of the + input scratch buffers. Use these to copy audio in without + rebuilding views every block. + +``outputChannelViews`` (``Float32Array[]``) + ``Float32Array`` views over the per-channel slices of the + output scratch buffers. + +``ioConfig`` (``AudioWorkletIOConfig``) + ``{ maxBufferSize, inputChannels, outputChannels, + inputNodeIndex, outputNodeIndex }``. + +``wasmMemory`` (``WebAssembly.Memory``) + The shared ``WebAssembly.Memory``. Useful when you need a + typed-array view over a custom region of the heap. diff --git a/docs/sphinx/web-api/reference/class/AniraWeb.rst b/docs/sphinx/web-api/reference/class/AniraWeb.rst new file mode 100644 index 00000000..1dfb30b3 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/AniraWeb.rst @@ -0,0 +1,63 @@ +Class AniraWeb +============== + +The package's main entry point. Owns the WebAssembly module, exposes a +factory method per wrapper class, and coordinates the inference +workers and audio worklet integration. Construct one per app via +``await AniraWeb.create()``. + +.. js:autoclass:: AniraWeb.AniraWeb + :short-name: + :members: create, stackRestore, malloc, free, getMemory, getWasmInstance, allocWasmString, registerProcessor, unregisterProcessor, getActiveWorkers, spinUpInferenceWorker, registerAudioWorkletForContext, configureAudioWorklet + +.. js:method:: AniraWeb.getHeapF32() + + Return a ``Float32Array`` view over the WASM module's + ``HEAPF32`` buffer. Useful for reading or writing float32 data at + raw heap offsets. + +.. js:method:: AniraWeb.getHeapU32() + + Return a ``Uint32Array`` view over the WASM module's ``HEAPU32`` + buffer. Useful for reading or writing pointer-sized values at raw + heap offsets — for example the channel pointer arrays referenced + by :js:meth:`AniraAudioWorkletBase.buildMultiTensorPointers`. + +Class Factories +--------------- + +The instance also carries a factory method for every wrapper class. +Each factory takes the same arguments the underlying class +constructor would, but reuses ``aniraWeb``'s WASM instance so you +don't have to thread it through manually: + +.. code-block:: typescript + + const config = aniraWeb.HostConfig(2048, 44100) + // equivalent to: new HostConfig(aniraWeb.getWasmInstance(), 2048, 44100) + +The available factories (each linked to the underlying class +reference) are: + +* :doc:`BufferF` — exposed as ``aniraWeb.Buffer`` +* :doc:`HostConfig` — ``aniraWeb.HostConfig`` +* :doc:`InferenceConfig` — ``aniraWeb.InferenceConfig`` +* :doc:`InferenceHandler` — ``aniraWeb.InferenceHandler`` +* :doc:`JSBackendBase` — ``aniraWeb.JSBackendBase`` +* :doc:`JSPrePostProcessor` — ``aniraWeb.JSPrePostProcessor`` +* :doc:`ModelData` — ``aniraWeb.ModelData`` +* :doc:`ONNXRuntimeWebBackend` — ``aniraWeb.ONNXRuntimeWebBackend`` +* :doc:`PrePostProcessor` — ``aniraWeb.PrePostProcessor`` +* :doc:`ProcessingSpec` — ``aniraWeb.ProcessingSpec`` +* :doc:`RingBuffer` — ``aniraWeb.RingBuffer`` +* :doc:`TensorShape` — ``aniraWeb.TensorShape`` +* ``aniraWeb.TensorShapeList``, ``aniraWeb.VectorBufferF``, + ``aniraWeb.VectorFloat``, ``aniraWeb.VectorInt64T``, + ``aniraWeb.VectorModelData``, ``aniraWeb.VectorRingBuffer``, + ``aniraWeb.VectorSizeT``, ``aniraWeb.VectorTensorShape``, + ``aniraWeb.VectorUnsignedInt``, ``aniraWeb.VectorVectorInt64`` — + thin wrappers over ``std::vector``. +* ``aniraWeb.InferenceBackend`` — the backend enum + (``ONNX``, ``LIBTORCH``, ``TFLITE``, ``CUSTOM``). +* ``aniraWeb.InferenceThread`` — internal scheduler primitive, + rarely used directly. diff --git a/docs/sphinx/web-api/reference/class/BaseWrapper.rst b/docs/sphinx/web-api/reference/class/BaseWrapper.rst new file mode 100644 index 00000000..bb7f6fbd --- /dev/null +++ b/docs/sphinx/web-api/reference/class/BaseWrapper.rst @@ -0,0 +1,6 @@ +Class BaseWrapper +================= + +.. js:autoclass:: BaseWrapper.BaseWrapper + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/BufferF.rst b/docs/sphinx/web-api/reference/class/BufferF.rst new file mode 100644 index 00000000..6ab0826a --- /dev/null +++ b/docs/sphinx/web-api/reference/class/BufferF.rst @@ -0,0 +1,11 @@ +Class BufferF +============= + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.Buffer(...)`` rather than ``new BufferF(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: BufferF.BufferF + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/HostConfig.rst b/docs/sphinx/web-api/reference/class/HostConfig.rst new file mode 100644 index 00000000..875ba7cc --- /dev/null +++ b/docs/sphinx/web-api/reference/class/HostConfig.rst @@ -0,0 +1,11 @@ +Class HostConfig +================ + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.HostConfig(...)`` rather than ``new HostConfig(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: HostConfig.HostConfig + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/InferenceConfig.rst b/docs/sphinx/web-api/reference/class/InferenceConfig.rst new file mode 100644 index 00000000..e78e1a3b --- /dev/null +++ b/docs/sphinx/web-api/reference/class/InferenceConfig.rst @@ -0,0 +1,11 @@ +Class InferenceConfig +===================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.InferenceConfig(...)`` rather than ``new InferenceConfig(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: InferenceConfig.InferenceConfig + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/InferenceHandler.rst b/docs/sphinx/web-api/reference/class/InferenceHandler.rst new file mode 100644 index 00000000..15330599 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/InferenceHandler.rst @@ -0,0 +1,11 @@ +Class InferenceHandler +====================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.InferenceHandler(...)`` rather than ``new InferenceHandler(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: InferenceHandler.InferenceHandler + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/JSBackendBase.rst b/docs/sphinx/web-api/reference/class/JSBackendBase.rst new file mode 100644 index 00000000..814c02f6 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/JSBackendBase.rst @@ -0,0 +1,11 @@ +Class JSBackendBase +=================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.JSBackendBase(...)`` rather than ``new JSBackendBase(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: JSBackendBase.JSBackendBase + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/JSPrePostProcessor.rst b/docs/sphinx/web-api/reference/class/JSPrePostProcessor.rst new file mode 100644 index 00000000..6a27a2ad --- /dev/null +++ b/docs/sphinx/web-api/reference/class/JSPrePostProcessor.rst @@ -0,0 +1,11 @@ +Class JSPrePostProcessor +======================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.JSPrePostProcessor(...)`` rather than ``new JSPrePostProcessor(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: JSPrePostProcessor.JSPrePostProcessor + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/ModelData.rst b/docs/sphinx/web-api/reference/class/ModelData.rst new file mode 100644 index 00000000..a47ef1ca --- /dev/null +++ b/docs/sphinx/web-api/reference/class/ModelData.rst @@ -0,0 +1,11 @@ +Class ModelData +=============== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.ModelData(...)`` rather than ``new ModelData(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: ModelData.ModelData + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/ONNXRuntimeWebBackend.rst b/docs/sphinx/web-api/reference/class/ONNXRuntimeWebBackend.rst new file mode 100644 index 00000000..1750e01e --- /dev/null +++ b/docs/sphinx/web-api/reference/class/ONNXRuntimeWebBackend.rst @@ -0,0 +1,11 @@ +Class ONNXRuntimeWebBackend +=========================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.ONNXRuntimeWebBackend(...)`` rather than ``new ONNXRuntimeWebBackend(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: ONNXRuntimeWebBackend.ONNXRuntimeWebBackend + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/PrePostProcessor.rst b/docs/sphinx/web-api/reference/class/PrePostProcessor.rst new file mode 100644 index 00000000..694c17a7 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/PrePostProcessor.rst @@ -0,0 +1,11 @@ +Class PrePostProcessor +====================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.PrePostProcessor(...)`` rather than ``new PrePostProcessor(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: PrePostProcessor.PrePostProcessor + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/ProcessingSpec.rst b/docs/sphinx/web-api/reference/class/ProcessingSpec.rst new file mode 100644 index 00000000..5aa5e929 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/ProcessingSpec.rst @@ -0,0 +1,11 @@ +Class ProcessingSpec +==================== + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.ProcessingSpec(...)`` rather than ``new ProcessingSpec(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: ProcessingSpec.ProcessingSpec + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/RingBuffer.rst b/docs/sphinx/web-api/reference/class/RingBuffer.rst new file mode 100644 index 00000000..3f052fcf --- /dev/null +++ b/docs/sphinx/web-api/reference/class/RingBuffer.rst @@ -0,0 +1,11 @@ +Class RingBuffer +================ + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.RingBuffer(...)`` rather than ``new RingBuffer(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: RingBuffer.RingBuffer + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/TensorShape.rst b/docs/sphinx/web-api/reference/class/TensorShape.rst new file mode 100644 index 00000000..ea766923 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/TensorShape.rst @@ -0,0 +1,11 @@ +Class TensorShape +================= + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.TensorShape(...)`` rather than ``new TensorShape(...)``. The + factory threads the WASM instance through for you. + +.. js:autoclass:: TensorShape.TensorShape + :short-name: + :members: diff --git a/docs/sphinx/web-api/reference/class/Vectors.rst b/docs/sphinx/web-api/reference/class/Vectors.rst new file mode 100644 index 00000000..db7caf00 --- /dev/null +++ b/docs/sphinx/web-api/reference/class/Vectors.rst @@ -0,0 +1,123 @@ +Class Vectors +============= + +Thin wrappers over ``std::vector`` for the element types anira's +C++ API exposes. Each ``Vector*`` class shares the same surface +(``size``, ``push``, ``get``, ``destroy``) and inherits from +``VectorBase``. + +.. note:: + Construct via the :doc:`AniraWeb` factory in most cases: + ``aniraWeb.VectorSizeT([2, 1])`` rather than + ``new VectorSizeT(...)``. The factory threads the WASM instance + through for you, and most constructors accept a plain JS array as + a convenience initializer. + +Common Surface +-------------- + +Every ``Vector*`` class supports: + +* ``size()`` → ``number`` — element count. +* ``push(value)`` — append one element. Element type depends on the + class (see table below). Object-vector ``push`` accepts either a + wrapper instance or its raw pointer. +* ``get(index)`` — read one element. Primitive vectors return the + element by value; object vectors return a non-owning raw pointer + to the underlying C++ element. +* ``destroy()`` — free the underlying C++ object. See + :ref:`lifecycle-and-cleanup`. + +Most constructors also accept a JS array of initial values that is +pushed eagerly during construction. + +The Vector Family +----------------- + +.. list-table:: + :header-rows: 1 + :widths: 22 30 28 20 + + * - Class + - Underlying C++ type + - Element type + - ``get`` returns + * - ``VectorSizeT`` + - ``std::vector`` + - ``number`` + - ``number`` + * - ``VectorInt64T`` + - ``std::vector`` + - ``bigint`` + - ``bigint`` + * - ``VectorFloat`` + - ``std::vector`` + - ``number`` + - ``number`` + * - ``VectorUnsignedInt`` + - ``std::vector`` + - ``number`` + - ``number`` + * - ``VectorVectorInt64`` + - ``std::vector>`` + - ``VectorInt64T`` / ``number[]`` / pointer + - ``number`` (raw pointer) + * - ``TensorShapeList`` + - alias of ``VectorVectorInt64`` + - same as ``VectorVectorInt64`` + - same as ``VectorVectorInt64`` + * - ``VectorModelData`` + - ``std::vector`` + - :doc:`ModelData` / pointer + - n/a — push-only + * - ``VectorTensorShape`` + - ``std::vector`` + - :doc:`TensorShape` / pointer + - n/a — push-only + * - ``VectorRingBuffer`` + - ``std::vector`` + - :doc:`RingBuffer` / pointer + - ``number`` (raw pointer to the element) + * - ``VectorBufferF`` + - ``std::vector>`` + - :doc:`BufferF` / pointer + - ``number`` (raw pointer to the element) + +``VectorVectorInt64`` accepts several convenience forms during +construction: + +* ``number[][]`` — each inner array is auto-converted to + ``bigint`` and wrapped in a temporary ``VectorInt64T`` that is + destroyed after the inner copy is taken. +* ``bigint[][]`` — same thing, used as-is. +* ``(VectorInt64T | number)[]`` — existing wrapper instances or + raw pointers; the C++ side copies each inner vector. + +``TensorShapeList`` is identical to ``VectorVectorInt64``; it exists +purely so call sites that build tensor shapes read more naturally. + +Typical Use +----------- + +.. code-block:: typescript + + // Primitive vectors initialised from a JS array. + const channels = aniraWeb.VectorSizeT([2, 1]) + const sizes = aniraWeb.VectorSizeT([512, 0]) + + // Object vector: pass wrapper instances directly. + const modelData = aniraWeb.ModelData(modelBuffer, aniraWeb.InferenceBackend.ONNX) + const vectorModelData = aniraWeb.VectorModelData([modelData]) + + // Nested-int64 vector: nested JS array, auto-converted. + const shapes = aniraWeb.TensorShapeList([[1, 2, 512], [1]]) + +VectorBase +---------- + +.. js:autoclass:: Vectors.VectorBase + :short-name: + :members: size + + The abstract base class. Every ``Vector*`` extends this and + exposes the methods listed under "Common Surface" above. diff --git a/docs/sphinx/web-api/reference/classlist.rst b/docs/sphinx/web-api/reference/classlist.rst new file mode 100644 index 00000000..d72906c4 --- /dev/null +++ b/docs/sphinx/web-api/reference/classlist.rst @@ -0,0 +1,7 @@ +Class list +========== + +.. toctree:: + :glob: + + class/* diff --git a/docs/sphinx/web-api/reference/functionlist.rst b/docs/sphinx/web-api/reference/functionlist.rst new file mode 100644 index 00000000..77c98177 --- /dev/null +++ b/docs/sphinx/web-api/reference/functionlist.rst @@ -0,0 +1,36 @@ +Function list +============= + +Module-level free functions exported by ``@anira-project/anira``. + +WASM bootstrap +-------------- + +.. js:autofunction:: createAniraWasm + +.. js:autofunction:: getWasmUrl + +Wrappers +-------- + +.. js:autofunction:: createInferenceBackend + +.. js:autofunction:: resolvePtr + +Workers +------- + +.. js:autofunction:: setupInferenceWorker + +.. js:autofunction:: waitForWorkerMessage + +Helpers +------- + +.. js:autofunction:: randomSample + +.. js:autofunction:: fillBuffer + +.. js:autofunction:: pushBufferToRingbuffer + +.. js:autofunction:: getAniraVersion diff --git a/docs/sphinx/web-api/reference/index.rst b/docs/sphinx/web-api/reference/index.rst new file mode 100644 index 00000000..5f3c32d9 --- /dev/null +++ b/docs/sphinx/web-api/reference/index.rst @@ -0,0 +1,12 @@ +API Reference +============= + +Auto-generated reference for the ``@anira-project/anira`` TypeScript package, +produced from TypeDoc output via ``sphinx-js``. Pages render with the +Sphinx ``js`` domain so styling matches the C++ reference. + +.. toctree:: + :maxdepth: 1 + + classlist + functionlist diff --git a/docs/typedoc/package.json b/docs/typedoc/package.json new file mode 100644 index 00000000..618fe346 --- /dev/null +++ b/docs/typedoc/package.json @@ -0,0 +1,9 @@ +{ + "name": "anira-docs-typedoc", + "private": true, + "description": "TypeDoc dependencies used to generate the Anira Web API JSON consumed by sphinx-js. Kept separate from @anira-project/anira/package.json so docs tooling does not pollute the runtime package.", + "devDependencies": { + "typedoc": "~0.27.9", + "typescript": "~5.7.3" + } +} diff --git a/docs/typedoc/typedoc.json b/docs/typedoc/typedoc.json new file mode 100644 index 00000000..0bf9bbda --- /dev/null +++ b/docs/typedoc/typedoc.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["../../web/src/index.ts"], + "tsconfig": "../../web/tsconfig.json", + "excludeExternals": true, + "excludePrivate": true, + "excludeInternal": true, + "skipErrorChecking": true +} diff --git a/include/anira/ContextConfig.h b/include/anira/ContextConfig.h index 07d464bc..02479695 100644 --- a/include/anira/ContextConfig.h +++ b/include/anira/ContextConfig.h @@ -44,9 +44,14 @@ struct ANIRA_API ContextConfig { * and automatically populates the list of available backends based on compile-time * feature flags. * - * @param num_threads Number of background inference threads to create - * Default: Half of available CPU cores (minimum 1) - * + * @param num_threads Number of background inference threads to create. + * Default: half of available CPU cores (minimum 1). + * Pass 0 to opt out of the auto-managed pool and supply your + * own threads via Context::make_inference_thread() (required on + * WebAssembly, optional on native). When the Context singleton + * already exists, num_threads == 0 leaves any existing pool + * untouched — it signals "no preference," not "shrink to zero." + * * @note The constructor automatically detects and registers available inference * backends based on compile-time definitions (USE_LIBTORCH, USE_ONNXRUNTIME, USE_TFLITE) */ diff --git a/include/anira/InferenceConfig.h b/include/anira/InferenceConfig.h index 60ac72c3..dd0f72a9 100644 --- a/include/anira/InferenceConfig.h +++ b/include/anira/InferenceConfig.h @@ -139,10 +139,15 @@ struct ANIRA_API ModelData { bool operator==(const ModelData& other) const { if (m_size != other.m_size) return false; if (m_backend != other.m_backend) return false; - if (m_model_function != other.m_model_function) return false; if (m_is_binary != other.m_is_binary) return false; - return std::memcmp(m_data, other.m_data, m_size) == 0; + if (m_is_binary) { + // For binary models + return m_data == other.m_data; + } else { + // Compare contents + return std::memcmp(m_data, other.m_data, m_size) == 0; + } } /** diff --git a/include/anira/scheduler/Context.h b/include/anira/scheduler/Context.h index 6068f572..5c38000d 100644 --- a/include/anira/scheduler/Context.h +++ b/include/anira/scheduler/Context.h @@ -222,6 +222,37 @@ class ANIRA_API Context{ */ static moodycamel::ProducerToken& get_producer_token(); + /** + * @brief Get a reference to the static inference queue + * Returns a reference to the global concurrent queue used for inference requests. + * This is used by InferenceThread to pre-allocate a ConsumerToken on the + * main thread, enabling allocation-free dequeue from worker threads. + * @return Reference to the static inference queue + */ + static moodycamel::ConcurrentQueue& get_static_inference_queue(); + + /** + * @brief Factory for a user-owned InferenceThread bound to the static inference queue. + * + * Returns a new InferenceThread whose lifecycle is fully managed by the caller. + * The thread is not started automatically — call start() on the returned object + * to begin processing. The caller must also call stop() (or simply destroy the + * object) before program exit. + * + * This is purely additive: the auto-managed thread pool sized via + * ContextConfig::m_num_threads continues to work unchanged. Users who want full + * control over threading typically construct Context with ContextConfig(0) so + * that no auto-pool threads exist, then create and manage threads themselves + * via this factory. + * + * The returned thread references the static inference queue, which has static + * storage duration — so the thread remains valid even after all sessions and + * the Context singleton itself are released. + * + * @return Unique pointer to a new user-owned InferenceThread. + */ + static std::unique_ptr make_inference_thread(); + private: /** * @brief Gets the next available session ID diff --git a/include/anira/scheduler/InferenceThread.h b/include/anira/scheduler/InferenceThread.h index adc92c24..5ec58d8d 100644 --- a/include/anira/scheduler/InferenceThread.h +++ b/include/anira/scheduler/InferenceThread.h @@ -5,7 +5,9 @@ #include #include +#ifndef __EMSCRIPTEN__ #include "../system/HighPriorityThread.h" +#endif #include "../utils/Buffer.h" #include "SessionElement.h" #include @@ -16,17 +18,30 @@ namespace anira { /** - * @brief High-priority thread class for executing neural network inference operations + * @brief Thread class for executing neural network inference operations. * - * The InferenceThread class extends HighPriorityThread to provide a dedicated thread + * The InferenceThread class provides a dedicated thread * for executing neural network inference operations in real-time audio processing contexts. * It manages a concurrent queue of inference requests and processes them with minimal * latency while maintaining thread safety and real-time performance guarantees. * - * @note This class inherits from HighPriorityThread and automatically manages - * thread priority elevation for optimal real-time performance. + * On native builds, this inherits from HighPriorityThread and owns its own + * OS thread. Under Emscripten there is no owned OS thread — a JS Worker + * drives the loop externally by calling run_loop(), and start()/stop() + * simply flip an atomic flag. This is required because each WASM worker + * instance shares memory with the main instance; spawning OS threads from + * C++ inside a worker would interact badly with the shared allocator. + * + * A moodycamel::ConsumerToken is pre-allocated in the constructor (which + * must run on the thread that owns the allocator — the main WASM instance + * in browser builds). Using an explicit token makes execute() fully + * allocation-free. */ -class ANIRA_API InferenceThread : public HighPriorityThread { +class ANIRA_API InferenceThread +#ifndef __EMSCRIPTEN__ + : public HighPriorityThread +#endif +{ public: /** * @brief Constructor that initializes the inference thread with a task queue @@ -49,15 +64,14 @@ class ANIRA_API InferenceThread : public HighPriorityThread { * inference data structures to process */ InferenceThread(moodycamel::ConcurrentQueue& next_inference); - - /** - * @brief Destructor that ensures proper cleanup of thread resources - * - * Automatically stops the inference thread if it's still running and - * performs cleanup of any remaining inference data or resources. - */ - ~InferenceThread() override; + ~InferenceThread() +#ifndef __EMSCRIPTEN__ + override +#endif + ; + + /** * @brief Executes a single iteration of inference processing * @@ -78,19 +92,31 @@ class ANIRA_API InferenceThread : public HighPriorityThread { */ bool execute(); + /** + * @brief Run the main processing loop with exponential backoff. + * + * Natively, this is invoked by the inherited HighPriorityThread via the + * run() override. Under Emscripten, JS Workers call this directly. + * Returns when should_exit() becomes true. + */ + void run_loop(); + +#ifdef __EMSCRIPTEN__ + // Externally driven lifecycle — the JS Worker owns the thread. + void start(); + void stop(); + bool should_exit() const; + bool is_running() const; +#endif + private: +#ifndef __EMSCRIPTEN__ /** - * @brief Main thread execution loop (overrides HighPriorityThread::run) - * - * Implements the main execution loop for the inference thread. This method - * runs continuously while the thread is active, calling execute() repeatedly - * to process inference requests. The loop includes proper exit condition - * checking and resource cleanup. - * - * @note This method runs on the high-priority thread and should not be - * called directly. Use start() to begin thread execution. + * @brief HighPriorityThread entry point; simply delegates to run_loop(). */ void run() override; +#endif + /** * @brief Performs inference processing for a specific session @@ -134,8 +160,14 @@ class ANIRA_API InferenceThread : public HighPriorityThread { private: moodycamel::ConcurrentQueue& m_next_inference; ///< Reference to the thread-safe queue containing inference requests InferenceData m_inference_data; ///< Current inference data being processed by this thread + moodycamel::ConsumerToken m_consumer_token; + +#ifdef __EMSCRIPTEN__ + std::atomic m_should_exit{false}; + std::atomic m_is_running{false}; +#endif }; } // namespace anira -#endif //ANIRA_INFERENCETHREAD_H \ No newline at end of file +#endif //ANIRA_INFERENCETHREAD_H diff --git a/src/backends/OnnxRuntimeProcessor.cpp b/src/backends/OnnxRuntimeProcessor.cpp index e21af775..e770dbd0 100644 --- a/src/backends/OnnxRuntimeProcessor.cpp +++ b/src/backends/OnnxRuntimeProcessor.cpp @@ -33,7 +33,27 @@ void OnnxRuntimeProcessor::process(std::vector& input, std::vector +#include +#include "anira/InferenceConfig.h" +#include "anira/utils/InferenceBackend.h" + +// ------ InferenceBackend C API ---- + +extern "C" { + +static anira::InferenceBackend to_backend(int value) { + return static_cast(value); +} + +EMSCRIPTEN_KEEPALIVE +int get_inference_backend_onnx() { + return static_cast(anira::InferenceBackend::ONNX); +} + +EMSCRIPTEN_KEEPALIVE +int get_inference_backend_custom() { + return static_cast(anira::InferenceBackend::CUSTOM); +} + +EMSCRIPTEN_KEEPALIVE +const char* anira_get_version() { + return ANIRA_VERSION; +} + +// Debug helper +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_log_debug(uintptr_t ptr) { + auto* config = reinterpret_cast(ptr); + emscripten_log(EM_LOG_CONSOLE, "[InferenceConfig] Debug Info:"); + emscripten_log(EM_LOG_CONSOLE, " - preprocess_input_size[0]: %zu", config->get_preprocess_input_size()[0]); + emscripten_log(EM_LOG_CONSOLE, " - postprocess_output_size[0]: %zu", config->get_postprocess_output_size()[0]); + emscripten_log(EM_LOG_CONSOLE, " - max_inference_time: %f ms", config->m_max_inference_time); + emscripten_log(EM_LOG_CONSOLE, " - warm_up: %zu", config->m_warm_up); + emscripten_log(EM_LOG_CONSOLE, " - num_parallel_processors: %zu", config->m_num_parallel_processors); +} + +// ------ ModelData C API ---- + +EMSCRIPTEN_KEEPALIVE +uintptr_t modeldata_create(uintptr_t data_ptr, size_t size, int backend, const char* name, bool flag) { + return reinterpret_cast( + new anira::ModelData(reinterpret_cast(data_ptr), size, to_backend(backend), name, flag) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t modeldata_create_from_buffer(uintptr_t buffer_ptr, size_t length, int backend) { + void* data = std::malloc(length); + if (!data) { + return 0; + } + + // Copy data from the provided buffer + std::memcpy(data, reinterpret_cast(buffer_ptr), length); + + return reinterpret_cast( + new anira::ModelData(data, length, to_backend(backend), "", true) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t modeldata_create_from_path(const char* model_path, int backend) { + return reinterpret_cast( + new anira::ModelData(model_path, to_backend(backend)) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t modeldata_create_with_function(const char* model_path, int backend, const char* model_function, bool is_binary) { + return reinterpret_cast( + new anira::ModelData(model_path, to_backend(backend), model_function, is_binary) + ); +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t modeldata_get_data_ptr(uintptr_t ptr) { + return reinterpret_cast(reinterpret_cast(ptr)->m_data); +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_set_data_ptr(uintptr_t ptr, uintptr_t data_ptr) { + reinterpret_cast(ptr)->m_data = reinterpret_cast(data_ptr); +} + +EMSCRIPTEN_KEEPALIVE +size_t modeldata_get_size(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_size; +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_set_size(uintptr_t ptr, size_t size) { + reinterpret_cast(ptr)->m_size = size; +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_get_model_function(uintptr_t ptr, char* out_buffer, size_t buffer_size) { + const std::string& func = reinterpret_cast(ptr)->m_model_function; + size_t len = std::min(func.size(), buffer_size - 1); + std::memcpy(out_buffer, func.c_str(), len); + out_buffer[len] = '\0'; +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_set_model_function(uintptr_t ptr, const char* model_function) { + reinterpret_cast(ptr)->m_model_function = model_function; +} + +EMSCRIPTEN_KEEPALIVE +bool modeldata_get_is_binary(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_is_binary; +} + +EMSCRIPTEN_KEEPALIVE +int modeldata_get_backend(uintptr_t ptr) { + return static_cast(reinterpret_cast(ptr)->m_backend); +} + +EMSCRIPTEN_KEEPALIVE +void modeldata_set_is_binary(uintptr_t ptr, bool is_binary) { + reinterpret_cast(ptr)->m_is_binary = is_binary; +} + +EMSCRIPTEN_KEEPALIVE +bool modeldata_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) == *reinterpret_cast(other_ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool modeldata_not_equals(uintptr_t ptr, uintptr_t other_ptr) { + return !(*reinterpret_cast(ptr) == *reinterpret_cast(other_ptr)); +} + +// ------ TensorShape C API ---- + +EMSCRIPTEN_KEEPALIVE +uintptr_t tensorshape_create(uintptr_t input_shape_ptr, size_t input_count, uintptr_t output_shape_ptr, size_t output_count) { + // Cast the vector pointers to the correct type + auto* input_shapes = reinterpret_cast>*>(input_shape_ptr); + auto* output_shapes = reinterpret_cast>*>(output_shape_ptr); + + return reinterpret_cast( + new anira::TensorShape(*input_shapes, *output_shapes) + ); +} + +EMSCRIPTEN_KEEPALIVE +void tensorshape_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool tensorshape_is_universal(uintptr_t ptr) { + return reinterpret_cast(ptr)->is_universal(); +} + +// Returns a non-owning pointer to the input TensorShapeList stored in the TensorShape. +// Valid as long as the TensorShape is alive. +EMSCRIPTEN_KEEPALIVE +uintptr_t tensorshape_get_input_shape(uintptr_t ptr) { + return reinterpret_cast(&reinterpret_cast(ptr)->m_tensor_input_shape); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t tensorshape_get_output_shape(uintptr_t ptr) { + return reinterpret_cast(&reinterpret_cast(ptr)->m_tensor_output_shape); +} + +EMSCRIPTEN_KEEPALIVE +bool tensorshape_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) == *reinterpret_cast(other_ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool tensorshape_not_equals(uintptr_t ptr, uintptr_t other_ptr) { + return !(*reinterpret_cast(ptr) == *reinterpret_cast(other_ptr)); +} + +// ------ ProcessingSpec C API ---- + +EMSCRIPTEN_KEEPALIVE +uintptr_t processingspec_create() { + return reinterpret_cast(new anira::ProcessingSpec()); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t processingspec_create_with_channels(uintptr_t preprocess_channels_ptr, size_t pre_ch_count, uintptr_t postprocess_channels_ptr, size_t post_ch_count) { + auto& preprocess = *reinterpret_cast*>(preprocess_channels_ptr); + auto& postprocess = *reinterpret_cast*>(postprocess_channels_ptr); + return reinterpret_cast(new anira::ProcessingSpec(preprocess, postprocess)); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t processingspec_create_full( + uintptr_t preprocess_ch_ptr, size_t pre_ch_count, + uintptr_t postprocess_ch_ptr, size_t post_ch_count, + uintptr_t preprocess_size_ptr, size_t pre_size_count, + uintptr_t postprocess_size_ptr, size_t post_size_count +) { + auto& preprocess_ch = *reinterpret_cast*>(preprocess_ch_ptr); + auto& postprocess_ch = *reinterpret_cast*>(postprocess_ch_ptr); + auto& preprocess_size = *reinterpret_cast*>(preprocess_size_ptr); + auto& postprocess_size = *reinterpret_cast*>(postprocess_size_ptr); + return reinterpret_cast(new anira::ProcessingSpec(preprocess_ch, postprocess_ch, preprocess_size, postprocess_size)); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t processingspec_create_full_with_latency( + uintptr_t preprocess_ch_ptr, size_t pre_ch_count, + uintptr_t postprocess_ch_ptr, size_t post_ch_count, + uintptr_t preprocess_size_ptr, size_t pre_size_count, + uintptr_t postprocess_size_ptr, size_t post_size_count, + uintptr_t internal_latency_ptr, size_t internal_latency_count +) { + auto& preprocess_ch = *reinterpret_cast*>(preprocess_ch_ptr); + auto& postprocess_ch = *reinterpret_cast*>(postprocess_ch_ptr); + auto& preprocess_size = *reinterpret_cast*>(preprocess_size_ptr); + auto& postprocess_size = *reinterpret_cast*>(postprocess_size_ptr); + auto& internal_latency = *reinterpret_cast*>(internal_latency_ptr); + return reinterpret_cast(new anira::ProcessingSpec(preprocess_ch, postprocess_ch, preprocess_size, postprocess_size, internal_latency)); +} + +EMSCRIPTEN_KEEPALIVE +void processingspec_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool processingspec_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) == *reinterpret_cast(other_ptr); +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_preprocess_input_channels(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_preprocess_input_channels; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_postprocess_output_channels(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_postprocess_output_channels; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_preprocess_input_size(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_preprocess_input_size; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_postprocess_output_size(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_postprocess_output_size; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_internal_model_latency(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_internal_model_latency; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_tensor_input_size(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_tensor_input_size; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t processingspec_get_tensor_output_size(uintptr_t ptr, size_t tensor_index) { + const auto& v = reinterpret_cast(ptr)->m_tensor_output_size; + return tensor_index < v.size() ? v[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +bool processingspec_not_equals(uintptr_t ptr, uintptr_t other_ptr) { + return !(*reinterpret_cast(ptr) == *reinterpret_cast(other_ptr)); +} + +// ------ InferenceConfig C API ---- + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_create() { + return reinterpret_cast(new anira::InferenceConfig()); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_create_full( + uintptr_t model_data_ptrs, size_t model_count, + uintptr_t tensor_shape_ptrs, size_t tensor_count, + uintptr_t processing_spec_ptr, + float max_inference_time, + unsigned int warm_up, + bool session_exclusive_processor, + float blocking_ratio, + unsigned int num_parallel_processors +) { + // Dereference the vector pointers (they point to std::vector objects, not raw arrays) + auto& models = *reinterpret_cast*>(model_data_ptrs); + auto& shapes = *reinterpret_cast*>(tensor_shape_ptrs); + auto& spec = *reinterpret_cast(processing_spec_ptr); + + return reinterpret_cast( + new anira::InferenceConfig(models, shapes, spec, max_inference_time, warm_up, session_exclusive_processor, blocking_ratio, num_parallel_processors) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_create_auto_spec( + uintptr_t model_data_ptrs, size_t model_count, + uintptr_t tensor_shape_ptrs, size_t tensor_count, + float max_inference_time, + unsigned int warm_up, + bool session_exclusive_processor, + float blocking_ratio, + unsigned int num_parallel_processors +) { + auto& models = *reinterpret_cast*>(model_data_ptrs); + auto& shapes = *reinterpret_cast*>(tensor_shape_ptrs); + + return reinterpret_cast( + new anira::InferenceConfig(models, shapes, max_inference_time, warm_up, session_exclusive_processor, blocking_ratio, num_parallel_processors) + ); +} + +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_get_model_path(uintptr_t ptr, int backend, char* out_buffer, size_t buffer_size) { + const std::string& path = reinterpret_cast(ptr)->get_model_path(to_backend(backend)); + size_t len = std::min(path.size(), buffer_size - 1); + std::memcpy(out_buffer, path.c_str(), len); + out_buffer[len] = '\0'; +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_model_data(uintptr_t ptr, int backend) { + return reinterpret_cast( + reinterpret_cast(ptr)->get_model_data(to_backend(backend)) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_tensor_input_size(uintptr_t ptr, size_t tensor_index) { + const std::vector& sizes = reinterpret_cast(ptr)->get_tensor_input_size(); + return tensor_index < sizes.size() ? sizes[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_tensor_output_size(uintptr_t ptr, size_t tensor_index) { + const std::vector& sizes = reinterpret_cast(ptr)->get_tensor_output_size(); + return tensor_index < sizes.size() ? sizes[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_preprocess_input_channels(uintptr_t ptr, size_t tensor_index) { + const std::vector& channels = reinterpret_cast(ptr)->get_preprocess_input_channels(); + return tensor_index < channels.size() ? channels[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_postprocess_output_channels(uintptr_t ptr, size_t tensor_index) { + const std::vector& channels = reinterpret_cast(ptr)->get_postprocess_output_channels(); + return tensor_index < channels.size() ? channels[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_preprocess_input_size(uintptr_t ptr, size_t tensor_index) { + const std::vector& sizes = reinterpret_cast(ptr)->get_preprocess_input_size(); + return tensor_index < sizes.size() ? sizes[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_postprocess_output_size(uintptr_t ptr, size_t tensor_index) { + const std::vector& sizes = reinterpret_cast(ptr)->get_postprocess_output_size(); + return tensor_index < sizes.size() ? sizes[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +size_t inferenceconfig_get_internal_model_latency(uintptr_t ptr, size_t tensor_index) { + const std::vector& latencies = reinterpret_cast(ptr)->get_internal_model_latency(); + return tensor_index < latencies.size() ? latencies[tensor_index] : 0; +} + +EMSCRIPTEN_KEEPALIVE +float inferenceconfig_get_max_inference_time(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_max_inference_time; +} + +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_set_max_inference_time(uintptr_t ptr, float value) { + reinterpret_cast(ptr)->m_max_inference_time = value; +} + +EMSCRIPTEN_KEEPALIVE +unsigned int inferenceconfig_get_warm_up(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_warm_up; +} + +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_set_warm_up(uintptr_t ptr, unsigned int value) { + reinterpret_cast(ptr)->m_warm_up = value; +} + +EMSCRIPTEN_KEEPALIVE +bool inferenceconfig_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) == *reinterpret_cast(other_ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool inferenceconfig_not_equals(uintptr_t ptr, uintptr_t other_ptr) { + return !(*reinterpret_cast(ptr) == *reinterpret_cast(other_ptr)); +} + +EMSCRIPTEN_KEEPALIVE +bool inferenceconfig_is_model_binary(uintptr_t ptr, int backend) { + return reinterpret_cast(ptr)->is_model_binary(to_backend(backend)); +} + +// Returns a non-owning pointer to the universal input TensorShapeList. +// The pointer is valid for as long as the InferenceConfig is alive. +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_tensor_input_shape(uintptr_t ptr) { + const anira::TensorShapeList& shape = reinterpret_cast(ptr)->get_tensor_input_shape(); + return reinterpret_cast(&shape); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_tensor_output_shape(uintptr_t ptr) { + const anira::TensorShapeList& shape = reinterpret_cast(ptr)->get_tensor_output_shape(); + return reinterpret_cast(&shape); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_tensor_input_shape_for_backend(uintptr_t ptr, int backend) { + const anira::TensorShapeList& shape = reinterpret_cast(ptr)->get_tensor_input_shape(to_backend(backend)); + return reinterpret_cast(&shape); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_tensor_output_shape_for_backend(uintptr_t ptr, int backend) { + const anira::TensorShapeList& shape = reinterpret_cast(ptr)->get_tensor_output_shape(to_backend(backend)); + return reinterpret_cast(&shape); +} + +// Returns a non-owning pointer to the underlying TensorShape selected for the given backend. +EMSCRIPTEN_KEEPALIVE +uintptr_t inferenceconfig_get_tensor_shape(uintptr_t ptr, int backend) { + const anira::TensorShape& shape = reinterpret_cast(ptr)->get_tensor_shape(to_backend(backend)); + return reinterpret_cast(&shape); +} + +EMSCRIPTEN_KEEPALIVE +float inferenceconfig_get_blocking_ratio(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_blocking_ratio; +} + +EMSCRIPTEN_KEEPALIVE +void inferenceconfig_set_blocking_ratio(uintptr_t ptr, float value) { + reinterpret_cast(ptr)->m_blocking_ratio = value; +} + +} // extern "C" diff --git a/src/emscripten-wrappers/InferenceHandler.cpp b/src/emscripten-wrappers/InferenceHandler.cpp new file mode 100644 index 00000000..cb8f0757 --- /dev/null +++ b/src/emscripten-wrappers/InferenceHandler.cpp @@ -0,0 +1,194 @@ +#include +#include "anira/InferenceHandler.h" +#include "anira/ContextConfig.h" +#include "anira/utils/InferenceBackend.h" + +// ------ InferenceHandler C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_create(uintptr_t preprocessor_ptr, uintptr_t config_ptr) { + anira::ContextConfig context_config(0); + return reinterpret_cast(new anira::InferenceHandler( + *reinterpret_cast(preprocessor_ptr), + *reinterpret_cast(config_ptr), + context_config + )); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_create_with_custom_processor(uintptr_t preprocessor_ptr, uintptr_t config_ptr, uintptr_t custom_processor_ptr) { + anira::ContextConfig context_config(0); + return reinterpret_cast(new anira::InferenceHandler( + *reinterpret_cast(preprocessor_ptr), + *reinterpret_cast(config_ptr), + *reinterpret_cast(custom_processor_ptr), + context_config + )); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_from_pointer(uintptr_t ptr) { + return ptr; +} + +// Configuration +EMSCRIPTEN_KEEPALIVE +void inferencehandler_set_inference_backend(uintptr_t ptr, int backend) { + reinterpret_cast(ptr)->set_inference_backend( + static_cast(backend) + ); +} + +EMSCRIPTEN_KEEPALIVE +int inferencehandler_get_inference_backend(uintptr_t ptr) { + return static_cast(reinterpret_cast(ptr)->get_inference_backend()); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_prepare(uintptr_t ptr, uintptr_t host_config_ptr) { + auto* host_config = reinterpret_cast(host_config_ptr); + emscripten_log(EM_LOG_CONSOLE, "[InferenceHandler] prepare called with buffer_size=%.2f, sample_rate=%.2f", + host_config->m_buffer_size, host_config->m_sample_rate); + reinterpret_cast(ptr)->prepare( + *host_config + ); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_prepare_with_latency(uintptr_t ptr, uintptr_t host_config_ptr, unsigned int custom_latency, size_t tensor_index) { + reinterpret_cast(ptr)->prepare( + *reinterpret_cast(host_config_ptr), + custom_latency, + tensor_index + ); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_prepare_with_latency_vector(uintptr_t ptr, uintptr_t host_config_ptr, uintptr_t latency_vector_ptr, size_t latency_count) { + std::vector latency_vector; + unsigned int* latencies = reinterpret_cast(latency_vector_ptr); + for (size_t i = 0; i < latency_count; ++i) { + latency_vector.push_back(latencies[i]); + } + reinterpret_cast(ptr)->prepare( + *reinterpret_cast(host_config_ptr), + latency_vector + ); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +size_t inferencehandler_process(uintptr_t ptr, uintptr_t data_ptr, size_t num_samples, size_t tensor_index) { + float* const* data = reinterpret_cast(data_ptr); + return reinterpret_cast(ptr)->process(data, num_samples, tensor_index); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +size_t inferencehandler_process_separate(uintptr_t ptr, uintptr_t input_ptr, size_t num_input_samples, uintptr_t output_ptr, size_t num_output_samples, size_t tensor_index) { + const float* const* input_data = reinterpret_cast(input_ptr); + float* const* output_data = reinterpret_cast(output_ptr); + return reinterpret_cast(ptr)->process(input_data, num_input_samples, output_data, num_output_samples, tensor_index); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_process_multi(uintptr_t ptr, uintptr_t input_ptr, uintptr_t num_input_ptr, uintptr_t output_ptr, uintptr_t num_output_ptr) { + const float* const* const* input_data = reinterpret_cast(input_ptr); + size_t* num_input_samples = reinterpret_cast(num_input_ptr); + float* const* const* output_data = reinterpret_cast(output_ptr); + size_t* num_output_samples = reinterpret_cast(num_output_ptr); + + size_t* result = reinterpret_cast(ptr)->process(input_data, num_input_samples, output_data, num_output_samples); + return reinterpret_cast(result); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +void inferencehandler_push_data(uintptr_t ptr, uintptr_t input_ptr, size_t num_samples, size_t tensor_index) { + const float* const* input_data = reinterpret_cast(input_ptr); + reinterpret_cast(ptr)->push_data(input_data, num_samples, tensor_index); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +void inferencehandler_push_data_multi(uintptr_t ptr, uintptr_t input_ptr, uintptr_t num_samples_ptr) { + const float* const* const* input_data = reinterpret_cast(input_ptr); + size_t* num_input_samples = reinterpret_cast(num_samples_ptr); + reinterpret_cast(ptr)->push_data(input_data, num_input_samples); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +size_t inferencehandler_pop_data(uintptr_t ptr, uintptr_t output_ptr, size_t num_samples, size_t tensor_index) { + float* const* output_data = reinterpret_cast(output_ptr); + return reinterpret_cast(ptr)->pop_data(output_data, num_samples, tensor_index); +} + +// No allocations, but not fully real-time safe due to potential blocking (semaphore wait) +EMSCRIPTEN_KEEPALIVE +size_t inferencehandler_pop_data_blocking(uintptr_t ptr, uintptr_t output_ptr, size_t num_samples, double wait_ms, size_t tensor_index) { + float* const* output_data = reinterpret_cast(output_ptr); + auto now = std::chrono::steady_clock::now(); + auto wait_until = now + std::chrono::milliseconds(static_cast(wait_ms)); + return reinterpret_cast(ptr)->pop_data(output_data, num_samples, wait_until, tensor_index); +} + +// Real-time safe: no allocations, thin wrapper over ANIRA_REALTIME method +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_pop_data_multi(uintptr_t ptr, uintptr_t output_ptr, uintptr_t num_samples_ptr) { + float* const* const* output_data = reinterpret_cast(output_ptr); + size_t* num_output_samples = reinterpret_cast(num_samples_ptr); + size_t* result = reinterpret_cast(ptr)->pop_data(output_data, num_output_samples); + return reinterpret_cast(result); +} + +// No allocations, but not fully real-time safe due to potential blocking (semaphore wait) +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_pop_data_multi_blocking(uintptr_t ptr, uintptr_t output_ptr, uintptr_t num_samples_ptr, double wait_ms) { + float* const* const* output_data = reinterpret_cast(output_ptr); + size_t* num_output_samples = reinterpret_cast(num_samples_ptr); + auto now = std::chrono::steady_clock::now(); + auto wait_until = now + std::chrono::milliseconds(static_cast(wait_ms)); + size_t* result = reinterpret_cast(ptr)->pop_data(output_data, num_output_samples, wait_until); + return reinterpret_cast(result); +} + +// Status and configuration queries +EMSCRIPTEN_KEEPALIVE +unsigned int inferencehandler_get_latency(uintptr_t ptr, size_t tensor_index) { + return reinterpret_cast(ptr)->get_latency(tensor_index); +} + +// Returns pointer to std::vector - caller must cast and copy before the next call +EMSCRIPTEN_KEEPALIVE +uintptr_t inferencehandler_get_latency_vector(uintptr_t ptr) { + thread_local std::vector latencies; + latencies = reinterpret_cast(ptr)->get_latency_vector(); + return reinterpret_cast(&latencies); +} + +EMSCRIPTEN_KEEPALIVE +size_t inferencehandler_get_available_samples(uintptr_t ptr, size_t tensor_index, size_t channel) { + return reinterpret_cast(ptr)->get_available_samples(tensor_index, channel); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_set_non_realtime(uintptr_t ptr, bool non_realtime) { + reinterpret_cast(ptr)->set_non_realtime(non_realtime); +} + +EMSCRIPTEN_KEEPALIVE +void inferencehandler_reset(uintptr_t ptr) { + reinterpret_cast(ptr)->reset(); +} + +} // extern "C" diff --git a/src/emscripten-wrappers/InferenceThread.cpp b/src/emscripten-wrappers/InferenceThread.cpp new file mode 100644 index 00000000..8613ff4c --- /dev/null +++ b/src/emscripten-wrappers/InferenceThread.cpp @@ -0,0 +1,64 @@ +#include +#include "anira/scheduler/Context.h" +#include "anira/scheduler/InferenceThread.h" + +/** + * C API wrapper over anira::InferenceThread for the Emscripten build. + * + * Under __EMSCRIPTEN__, anira::InferenceThread does not inherit from + * HighPriorityThread and does not own an OS thread. JS Workers drive the + * processing loop by calling inference_thread_run_loop(), and start/stop + * just flip an atomic flag inside the class. + * + * inference_thread_create_from_context() MUST be called from the main WASM + * instance (the one that owns the allocator) because the constructor + * pre-allocates a moodycamel::ConsumerToken. Once created, the object + * pointer can be shared with worker instances via postMessage — execute() + * and run_loop() are fully allocation-free and safe to invoke from any + * WASM instance. + */ + +extern "C" { + +EMSCRIPTEN_KEEPALIVE +uintptr_t inference_thread_create_from_context() { + auto& queue = anira::Context::get_static_inference_queue(); + return reinterpret_cast(new anira::InferenceThread(queue)); +} + +EMSCRIPTEN_KEEPALIVE +int inference_thread_execute(uintptr_t ptr) { + return reinterpret_cast(ptr)->execute() ? 1 : 0; +} + +EMSCRIPTEN_KEEPALIVE +void inference_thread_run_loop(uintptr_t ptr) { + reinterpret_cast(ptr)->run_loop(); +} + +EMSCRIPTEN_KEEPALIVE +void inference_thread_stop(uintptr_t ptr) { + reinterpret_cast(ptr)->stop(); +} + +EMSCRIPTEN_KEEPALIVE +void inference_thread_start(uintptr_t ptr) { + reinterpret_cast(ptr)->start(); +} + +EMSCRIPTEN_KEEPALIVE +int inference_thread_should_exit(uintptr_t ptr) { + return reinterpret_cast(ptr)->should_exit() ? 1 : 0; +} + +EMSCRIPTEN_KEEPALIVE +int inference_thread_is_running(uintptr_t ptr) { + return reinterpret_cast(ptr)->is_running() ? 1 : 0; +} + +EMSCRIPTEN_KEEPALIVE +void inference_thread_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +} // extern "C" diff --git a/src/emscripten-wrappers/JSPrePostProcessor.cpp b/src/emscripten-wrappers/JSPrePostProcessor.cpp new file mode 100644 index 00000000..1e8aab30 --- /dev/null +++ b/src/emscripten-wrappers/JSPrePostProcessor.cpp @@ -0,0 +1,87 @@ +#include +#include + +EM_JS(void, process_prepost_js, + (uintptr_t self_ptr, uintptr_t input_ptr, uintptr_t output_ptr, int backend, + int phase), + { + return Module.processPrePost( + self_ptr, + input_ptr, + output_ptr, + backend, + phase + ); + }); + +class JSPrePostProcessor : public anira::PrePostProcessor { +public: + explicit JSPrePostProcessor(anira::InferenceConfig &inference_config) + : anira::PrePostProcessor(inference_config) { + } + + void pre_process(std::vector &input, + std::vector &output, + anira::InferenceBackend current_inference_backend) override { + process_prepost_js(reinterpret_cast(this), + reinterpret_cast(&input), + reinterpret_cast(&output), + static_cast(current_inference_backend), 0); + } + + void post_process(std::vector &input, + std::vector &output, + anira::InferenceBackend current_inference_backend) override { + process_prepost_js(reinterpret_cast(this), + reinterpret_cast(&input), + reinterpret_cast(&output), + static_cast(current_inference_backend), 1); + } + + void wasm_pre_process(std::vector &input, + std::vector &output, + anira::InferenceBackend current_inference_backend) { + PrePostProcessor::pre_process(input, output, current_inference_backend); + } + + void wasm_post_process(std::vector &input, + std::vector &output, + anira::InferenceBackend current_inference_backend) { + PrePostProcessor::post_process(input, output, current_inference_backend); + } +}; + +extern "C" { + +EMSCRIPTEN_KEEPALIVE +uintptr_t jsprepostprocessor_create(uintptr_t inference_config_ptr) { + auto *config = reinterpret_cast(inference_config_ptr); + return reinterpret_cast(new JSPrePostProcessor(*config)); +} + +EMSCRIPTEN_KEEPALIVE +void jsprepostprocessor_wasm_pre_process(uintptr_t self_ptr, uintptr_t input_ptr, + uintptr_t output_ptr, int backend) { + auto *processor = reinterpret_cast(self_ptr); + auto *input = reinterpret_cast *>(input_ptr); + auto *output = reinterpret_cast *>(output_ptr); + processor->wasm_pre_process(*input, *output, + static_cast(backend)); +} + +EMSCRIPTEN_KEEPALIVE +void jsprepostprocessor_wasm_post_process(uintptr_t self_ptr, uintptr_t input_ptr, + uintptr_t output_ptr, int backend) { + auto *processor = reinterpret_cast(self_ptr); + auto *input = reinterpret_cast *>(input_ptr); + auto *output = reinterpret_cast *>(output_ptr); + processor->wasm_post_process(*input, *output, + static_cast(backend)); +} + +EMSCRIPTEN_KEEPALIVE +void jsprepostprocessor_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +} // extern "C" \ No newline at end of file diff --git a/src/emscripten-wrappers/PrePostProcessor.cpp b/src/emscripten-wrappers/PrePostProcessor.cpp new file mode 100644 index 00000000..d3d15294 --- /dev/null +++ b/src/emscripten-wrappers/PrePostProcessor.cpp @@ -0,0 +1,107 @@ +#include +#include "anira/PrePostProcessor.h" +#include "anira/utils/InferenceBackend.h" + +// ------ PrePostProcessor C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t prepostprocessor_create(uintptr_t config_ptr) { + return reinterpret_cast(new anira::PrePostProcessor( + *reinterpret_cast(config_ptr) + )); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t prepostprocessor_from_pointer(uintptr_t ptr) { + return ptr; +} + +// Processing +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_pre_process(uintptr_t ptr, uintptr_t ring_buffers_ptr, uintptr_t buffers_ptr, int backend) { + reinterpret_cast(ptr)->pre_process( + *reinterpret_cast*>(ring_buffers_ptr), + *reinterpret_cast*>(buffers_ptr), + static_cast(backend) + ); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_post_process(uintptr_t ptr, uintptr_t buffers_ptr, uintptr_t ring_buffers_ptr, int backend) { + reinterpret_cast(ptr)->post_process( + *reinterpret_cast*>(buffers_ptr), + *reinterpret_cast*>(ring_buffers_ptr), + static_cast(backend) + ); +} + +// Input/Output configuration +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_set_input(uintptr_t ptr, float value, size_t channel, size_t tensor_index) { + reinterpret_cast(ptr)->set_input(value, tensor_index, channel); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_set_output(uintptr_t ptr, float value, size_t channel, size_t tensor_index) { + reinterpret_cast(ptr)->set_output(value, tensor_index, channel); +} + +EMSCRIPTEN_KEEPALIVE +float prepostprocessor_get_input(uintptr_t ptr, size_t channel, size_t tensor_index) { + return reinterpret_cast(ptr)->get_input(tensor_index, channel); +} + +EMSCRIPTEN_KEEPALIVE +float prepostprocessor_get_output(uintptr_t ptr, size_t channel, size_t tensor_index) { + return reinterpret_cast(ptr)->get_output(tensor_index, channel); +} + +// Buffer operations +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_pop_samples_from_buffer(uintptr_t ptr, uintptr_t ring_buffer_ptr, uintptr_t buffer_ptr, size_t num_samples) { + reinterpret_cast(ptr)->pop_samples_from_buffer( + *reinterpret_cast(ring_buffer_ptr), + *reinterpret_cast(buffer_ptr), + num_samples + ); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_pop_samples_from_buffer_window(uintptr_t ptr, uintptr_t ring_buffer_ptr, uintptr_t buffer_ptr, size_t num_samples, size_t window_size) { + reinterpret_cast(ptr)->pop_samples_from_buffer( + *reinterpret_cast(ring_buffer_ptr), + *reinterpret_cast(buffer_ptr), + num_samples, + window_size + ); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_pop_samples_from_buffer_window_offset(uintptr_t ptr, uintptr_t ring_buffer_ptr, uintptr_t buffer_ptr, size_t num_samples, size_t window_size, size_t offset) { + reinterpret_cast(ptr)->pop_samples_from_buffer( + *reinterpret_cast(ring_buffer_ptr), + *reinterpret_cast(buffer_ptr), + num_samples, + window_size, + offset + ); +} + +EMSCRIPTEN_KEEPALIVE +void prepostprocessor_push_samples_to_buffer(uintptr_t ptr, uintptr_t buffer_ptr, uintptr_t ring_buffer_ptr, size_t num_samples) { + reinterpret_cast(ptr)->push_samples_to_buffer( + *reinterpret_cast(buffer_ptr), + *reinterpret_cast(ring_buffer_ptr), + num_samples + ); +} + +} // extern "C" \ No newline at end of file diff --git a/src/emscripten-wrappers/backends/BackendBase.cpp b/src/emscripten-wrappers/backends/BackendBase.cpp new file mode 100644 index 00000000..4ec0af12 --- /dev/null +++ b/src/emscripten-wrappers/backends/BackendBase.cpp @@ -0,0 +1,22 @@ +#include +#include + +// ------ BackendBase C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t backendbase_create(uintptr_t inference_config_ptr) { + auto* config = reinterpret_cast(inference_config_ptr); + return reinterpret_cast(new anira::BackendBase(*config)); +} + +EMSCRIPTEN_KEEPALIVE +void backendbase_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + + +} // extern "C" + diff --git a/src/emscripten-wrappers/backends/JSProcessor.cpp b/src/emscripten-wrappers/backends/JSProcessor.cpp new file mode 100644 index 00000000..f24ecb85 --- /dev/null +++ b/src/emscripten-wrappers/backends/JSProcessor.cpp @@ -0,0 +1,58 @@ +#include +#include + + +EM_JS(void, process_buffers_js, (uintptr_t self_ptr, uintptr_t input_ptr, uintptr_t output_ptr), { + return Module.processBuffers(self_ptr, input_ptr, output_ptr); +}); + +class JSProcessor : public anira::BackendBase { +public: + JSProcessor(anira::InferenceConfig& inference_config) + : anira::BackendBase(inference_config) {} + + void prepare() override { + + } + + void wasm_process(std::vector& input, std::vector& output, + [[maybe_unused]] std::shared_ptr session) { + // Call BackendBase's process to handle the simple pass-through logic + BackendBase::process(input, output, session); + } + + void process(std::vector& input, std::vector& output, + [[maybe_unused]] std::shared_ptr session) override { + // Call JavaScript to do the processing, passing our own pointer for dispatch + process_buffers_js(reinterpret_cast(this), reinterpret_cast(&input), reinterpret_cast(&output)); + } +}; + + +// ------ JSProcessor C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t jsprocessor_create(uintptr_t inference_config_ptr) { + auto* config = reinterpret_cast(inference_config_ptr); + return reinterpret_cast(new JSProcessor(*config)); +} + +EMSCRIPTEN_KEEPALIVE +void jsprocessor_wasm_process(uintptr_t self_ptr, uintptr_t input_ptr, uintptr_t output_ptr) { + auto* processor = reinterpret_cast(self_ptr); + auto* input = reinterpret_cast*>(input_ptr); + auto* output = reinterpret_cast*>(output_ptr); + processor->wasm_process(*input, *output, nullptr); +} + +EMSCRIPTEN_KEEPALIVE +void jsprocessor_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + + +} // extern "C" + diff --git a/src/emscripten-wrappers/utils/Buffer.cpp b/src/emscripten-wrappers/utils/Buffer.cpp new file mode 100644 index 00000000..07e2e294 --- /dev/null +++ b/src/emscripten-wrappers/utils/Buffer.cpp @@ -0,0 +1,134 @@ +#include +#include "anira/utils/Buffer.h" + +// ------ BufferF C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_create() { + return reinterpret_cast(new anira::BufferF()); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_create_with_size(size_t num_channels, size_t num_samples) { + return reinterpret_cast(new anira::BufferF(num_channels, num_samples)); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +// Properties +EMSCRIPTEN_KEEPALIVE +size_t bufferf_get_num_channels(uintptr_t ptr) { + return reinterpret_cast(ptr)->get_num_channels(); +} + +EMSCRIPTEN_KEEPALIVE +size_t bufferf_get_num_samples(uintptr_t ptr) { + return reinterpret_cast(ptr)->get_num_samples(); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_resize(uintptr_t ptr, size_t num_channels, size_t num_samples) { + reinterpret_cast(ptr)->resize(num_channels, num_samples); +} + +// Pointer access +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_get_read_pointer(uintptr_t ptr, size_t channel) { + return reinterpret_cast( + reinterpret_cast(ptr)->get_read_pointer(channel) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_get_read_pointer_at(uintptr_t ptr, size_t channel, size_t sample_index) { + return reinterpret_cast( + reinterpret_cast(ptr)->get_read_pointer(channel, sample_index) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_get_write_pointer(uintptr_t ptr, size_t channel) { + return reinterpret_cast( + reinterpret_cast(ptr)->get_write_pointer(channel) + ); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_get_write_pointer_at(uintptr_t ptr, size_t channel, size_t sample_index) { + return reinterpret_cast( + reinterpret_cast(ptr)->get_write_pointer(channel, sample_index) + ); +} + +// Array of pointers - writes to provided output array +EMSCRIPTEN_KEEPALIVE +void bufferf_get_array_of_read_pointers(uintptr_t ptr, uintptr_t out_array) { + anira::BufferF* buffer = reinterpret_cast(ptr); + const float* const* ptrs = buffer->get_array_of_read_pointers(); + uintptr_t* out = reinterpret_cast(out_array); + size_t num_channels = buffer->get_num_channels(); + for (size_t i = 0; i < num_channels; ++i) { + out[i] = reinterpret_cast(ptrs[i]); + } +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_get_array_of_write_pointers(uintptr_t ptr, uintptr_t out_array) { + anira::BufferF* buffer = reinterpret_cast(ptr); + float* const* ptrs = buffer->get_array_of_write_pointers(); + uintptr_t* out = reinterpret_cast(out_array); + size_t num_channels = buffer->get_num_channels(); + for (size_t i = 0; i < num_channels; ++i) { + out[i] = reinterpret_cast(ptrs[i]); + } +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t bufferf_data(uintptr_t ptr) { + return reinterpret_cast( + reinterpret_cast(ptr)->data() + ); +} + +// Data manipulation +EMSCRIPTEN_KEEPALIVE +void bufferf_swap_data_with_buffer(uintptr_t ptr, uintptr_t other_ptr) { + reinterpret_cast(ptr)->swap_data( + *reinterpret_cast(other_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_swap_data_with_raw_pointer(uintptr_t ptr, uintptr_t raw_pointer, size_t size) { + float* raw_ptr = reinterpret_cast(raw_pointer); + reinterpret_cast(ptr)->swap_data(raw_ptr, size); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_reset_channel_ptr(uintptr_t ptr) { + reinterpret_cast(ptr)->reset_channel_ptr(); +} + +// Sample access +EMSCRIPTEN_KEEPALIVE +float bufferf_get_sample(uintptr_t ptr, size_t channel, size_t sample_index) { + return reinterpret_cast(ptr)->get_sample(channel, sample_index); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_set_sample(uintptr_t ptr, size_t channel, size_t sample_index, float value) { + reinterpret_cast(ptr)->set_sample(channel, sample_index, value); +} + +EMSCRIPTEN_KEEPALIVE +void bufferf_clear(uintptr_t ptr) { + reinterpret_cast(ptr)->clear(); +} + +} // extern "C" \ No newline at end of file diff --git a/src/emscripten-wrappers/utils/HostConfig.cpp b/src/emscripten-wrappers/utils/HostConfig.cpp new file mode 100644 index 00000000..ead4758a --- /dev/null +++ b/src/emscripten-wrappers/utils/HostConfig.cpp @@ -0,0 +1,97 @@ +#include +#include "anira/utils/HostConfig.h" +#include "anira/InferenceConfig.h" + +// ------ HostConfig C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t hostconfig_create() { + return reinterpret_cast(new anira::HostConfig()); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t hostconfig_create_with_params(float buffer_size, float sample_rate, bool allow_smaller_buffers, size_t tensor_index) { + return reinterpret_cast(new anira::HostConfig(buffer_size, sample_rate, allow_smaller_buffers, tensor_index)); +} + +EMSCRIPTEN_KEEPALIVE +void hostconfig_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +// Property getters +EMSCRIPTEN_KEEPALIVE +float hostconfig_get_buffer_size(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_buffer_size; +} + +EMSCRIPTEN_KEEPALIVE +float hostconfig_get_sample_rate(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_sample_rate; +} + +EMSCRIPTEN_KEEPALIVE +bool hostconfig_get_allow_smaller_buffers(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_allow_smaller_buffers; +} + +EMSCRIPTEN_KEEPALIVE +size_t hostconfig_get_tensor_index(uintptr_t ptr) { + return reinterpret_cast(ptr)->m_tensor_index; +} + +// Property setters +EMSCRIPTEN_KEEPALIVE +void hostconfig_set_buffer_size(uintptr_t ptr, float buffer_size) { + reinterpret_cast(ptr)->m_buffer_size = buffer_size; +} + +EMSCRIPTEN_KEEPALIVE +void hostconfig_set_sample_rate(uintptr_t ptr, float sample_rate) { + reinterpret_cast(ptr)->m_sample_rate = sample_rate; +} + +EMSCRIPTEN_KEEPALIVE +void hostconfig_set_allow_smaller_buffers(uintptr_t ptr, bool allow_smaller_buffers) { + reinterpret_cast(ptr)->m_allow_smaller_buffers = allow_smaller_buffers; +} + +EMSCRIPTEN_KEEPALIVE +void hostconfig_set_tensor_index(uintptr_t ptr, size_t tensor_index) { + reinterpret_cast(ptr)->m_tensor_index = tensor_index; +} + +// Comparison +EMSCRIPTEN_KEEPALIVE +bool hostconfig_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) == *reinterpret_cast(other_ptr); +} + +EMSCRIPTEN_KEEPALIVE +bool hostconfig_not_equals(uintptr_t ptr, uintptr_t other_ptr) { + return *reinterpret_cast(ptr) != *reinterpret_cast(other_ptr); +} + +// Methods +EMSCRIPTEN_KEEPALIVE +float hostconfig_get_relative_buffer_size(uintptr_t ptr, uintptr_t inference_config_ptr, size_t tensor_index, bool input) { + return reinterpret_cast(ptr)->get_relative_buffer_size( + *reinterpret_cast(inference_config_ptr), + tensor_index, + input + ); +} + +EMSCRIPTEN_KEEPALIVE +float hostconfig_get_relative_sample_rate(uintptr_t ptr, uintptr_t inference_config_ptr, size_t tensor_index, bool input) { + return reinterpret_cast(ptr)->get_relative_sample_rate( + *reinterpret_cast(inference_config_ptr), + tensor_index, + input + ); +} + +} // extern "C" diff --git a/src/emscripten-wrappers/utils/RingBuffer.cpp b/src/emscripten-wrappers/utils/RingBuffer.cpp new file mode 100644 index 00000000..bdb7106f --- /dev/null +++ b/src/emscripten-wrappers/utils/RingBuffer.cpp @@ -0,0 +1,63 @@ +#include +#include "anira/utils/RingBuffer.h" + +// ------ RingBuffer C API ---- + +extern "C" { + +// Constructor/Destructor +EMSCRIPTEN_KEEPALIVE +uintptr_t ringbuffer_create() { + return reinterpret_cast(new anira::RingBuffer()); +} + +EMSCRIPTEN_KEEPALIVE +void ringbuffer_destroy(uintptr_t ptr) { + delete reinterpret_cast(ptr); +} + +// Initialization +EMSCRIPTEN_KEEPALIVE +void ringbuffer_initialize_with_positions(uintptr_t ptr, size_t num_channels, size_t num_samples) { + reinterpret_cast(ptr)->initialize_with_positions(num_channels, num_samples); +} + +EMSCRIPTEN_KEEPALIVE +void ringbuffer_clear_with_positions(uintptr_t ptr) { + reinterpret_cast(ptr)->clear_with_positions(); +} + +// Sample operations +EMSCRIPTEN_KEEPALIVE +void ringbuffer_push_sample(uintptr_t ptr, size_t channel, float sample) { + reinterpret_cast(ptr)->push_sample(channel, sample); +} + +EMSCRIPTEN_KEEPALIVE +float ringbuffer_pop_sample(uintptr_t ptr, size_t channel) { + return reinterpret_cast(ptr)->pop_sample(channel); +} + +EMSCRIPTEN_KEEPALIVE +float ringbuffer_get_future_sample(uintptr_t ptr, size_t channel, size_t offset) { + return reinterpret_cast(ptr)->get_future_sample(channel, offset); +} + +EMSCRIPTEN_KEEPALIVE +float ringbuffer_get_past_sample(uintptr_t ptr, size_t channel, size_t offset) { + return reinterpret_cast(ptr)->get_past_sample(channel, offset); +} + +// Status queries +EMSCRIPTEN_KEEPALIVE +size_t ringbuffer_get_available_samples(uintptr_t ptr, size_t channel) { + return reinterpret_cast(ptr)->get_available_samples(channel); +} + +EMSCRIPTEN_KEEPALIVE +size_t ringbuffer_get_available_past_samples(uintptr_t ptr, size_t channel) { + return reinterpret_cast(ptr)->get_available_past_samples(channel); +} + +} // extern "C" + diff --git a/src/emscripten-wrappers/utils/Vectors.cpp b/src/emscripten-wrappers/utils/Vectors.cpp new file mode 100644 index 00000000..d2bf6041 --- /dev/null +++ b/src/emscripten-wrappers/utils/Vectors.cpp @@ -0,0 +1,273 @@ +#include +#include "anira/InferenceConfig.h" +#include "anira/utils/HostConfig.h" +#include "anira/utils/RingBuffer.h" +#include "anira/utils/Buffer.h" + +// ------ Vector C API ---- + +extern "C" { + +// ------ VectorSizeT ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_size_t_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_size_t_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_size_t_push_back(uintptr_t ptr, size_t value) { + reinterpret_cast*>(ptr)->push_back(value); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_size_t_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_size_t_get(uintptr_t ptr, size_t index) { + return (*reinterpret_cast*>(ptr))[index]; +} + +// ------ VectorInt64T ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_int64_t_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_int64_t_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_int64_t_push_back(uintptr_t ptr, int64_t value) { + reinterpret_cast*>(ptr)->push_back(value); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_int64_t_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +int64_t vector_int64_t_get(uintptr_t ptr, size_t index) { + return (*reinterpret_cast*>(ptr))[index]; +} + +// ------ VectorFloat ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_float_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_float_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_float_push_back(uintptr_t ptr, float value) { + reinterpret_cast*>(ptr)->push_back(value); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_float_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +float vector_float_get(uintptr_t ptr, size_t index) { + return (*reinterpret_cast*>(ptr))[index]; +} + +// ------ VectorUnsignedInt ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_unsigned_int_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_unsigned_int_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_unsigned_int_push_back(uintptr_t ptr, unsigned int value) { + reinterpret_cast*>(ptr)->push_back(value); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_unsigned_int_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +unsigned int vector_unsigned_int_get(uintptr_t ptr, size_t index) { + return (*reinterpret_cast*>(ptr))[index]; +} + +// ------ VectorVectorInt64 ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_vector_int64_create() { + return reinterpret_cast(new std::vector>()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_vector_int64_destroy(uintptr_t ptr) { + delete reinterpret_cast>*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_vector_int64_push_back(uintptr_t ptr, uintptr_t inner_vector_ptr) { + reinterpret_cast>*>(ptr)->push_back( + *reinterpret_cast*>(inner_vector_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_vector_int64_size(uintptr_t ptr) { + return reinterpret_cast>*>(ptr)->size(); +} + +// Returns a non-owning pointer to the inner std::vector at `index`. +// Valid only while the outer vector is alive and not resized. +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_vector_int64_get(uintptr_t ptr, size_t index) { + return reinterpret_cast(&(*reinterpret_cast>*>(ptr))[index]); +} + +// ------ VectorModelData ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_model_data_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_model_data_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_model_data_push_back(uintptr_t ptr, uintptr_t model_data_ptr) { + reinterpret_cast*>(ptr)->push_back( + *reinterpret_cast(model_data_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_model_data_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +// ------ VectorTensorShape ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_tensor_shape_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_tensor_shape_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_tensor_shape_push_back(uintptr_t ptr, uintptr_t tensor_shape_ptr) { + reinterpret_cast*>(ptr)->push_back( + *reinterpret_cast(tensor_shape_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_tensor_shape_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +// ------ VectorRingBuffer ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_ring_buffer_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_ring_buffer_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_ring_buffer_push_back(uintptr_t ptr, uintptr_t ring_buffer_ptr) { + reinterpret_cast*>(ptr)->push_back( + *reinterpret_cast(ring_buffer_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_ring_buffer_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_ring_buffer_get(uintptr_t ptr, size_t index) { + return reinterpret_cast(&(*reinterpret_cast*>(ptr))[index]); +} + +// ------ VectorBufferF ---- +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_buffer_f_create() { + return reinterpret_cast(new std::vector()); +} + +EMSCRIPTEN_KEEPALIVE +void vector_buffer_f_destroy(uintptr_t ptr) { + delete reinterpret_cast*>(ptr); +} + +EMSCRIPTEN_KEEPALIVE +void vector_buffer_f_push_back(uintptr_t ptr, uintptr_t buffer_ptr) { + reinterpret_cast*>(ptr)->push_back( + *reinterpret_cast(buffer_ptr) + ); +} + +EMSCRIPTEN_KEEPALIVE +size_t vector_buffer_f_size(uintptr_t ptr) { + return reinterpret_cast*>(ptr)->size(); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t vector_buffer_f_get(uintptr_t ptr, size_t index) { + return reinterpret_cast(&(*reinterpret_cast*>(ptr))[index]); +} + +// ------ BufferF ---- +EMSCRIPTEN_KEEPALIVE +size_t buffer_f_get_num_channels(uintptr_t ptr) { + return reinterpret_cast(ptr)->get_num_channels(); +} + +EMSCRIPTEN_KEEPALIVE +size_t buffer_f_get_num_samples(uintptr_t ptr) { + return reinterpret_cast(ptr)->get_num_samples(); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t buffer_f_get_read_pointer(uintptr_t ptr, size_t channel) { + return reinterpret_cast(reinterpret_cast(ptr)->get_read_pointer(channel)); +} + +EMSCRIPTEN_KEEPALIVE +uintptr_t buffer_f_get_write_pointer(uintptr_t ptr, size_t channel) { + return reinterpret_cast(reinterpret_cast(ptr)->get_write_pointer(channel)); +} + +EMSCRIPTEN_KEEPALIVE +void buffer_f_clear(uintptr_t ptr) { + reinterpret_cast(ptr)->clear(); +} + +} // extern "C" diff --git a/src/scheduler/Context.cpp b/src/scheduler/Context.cpp index 5c270f9c..e2c2c202 100644 --- a/src/scheduler/Context.cpp +++ b/src/scheduler/Context.cpp @@ -23,7 +23,12 @@ std::shared_ptr Context::get_instance(const ContextConfig& context_conf if (m_context->m_context_config.m_enabled_backends != context_config.m_enabled_backends) { LOG_ERROR << "[ERROR] Context already initialized with different backends enabled!" << std::endl; } - if ((unsigned int) m_context->m_thread_pool.size() > context_config.m_num_threads) { + // num_threads == 0 means "I'm opting out of the auto-pool and bringing + // my own threads via Context::make_inference_thread()" — not "shrink + // any existing pool to zero." Skip the resize so a manual-threading + // caller doesn't tear down threads another caller is relying on. + if (context_config.m_num_threads > 0 + && (unsigned int) m_context->m_thread_pool.size() > context_config.m_num_threads) { m_context->new_num_threads(context_config.m_num_threads); m_context->m_context_config.m_num_threads = context_config.m_num_threads; } @@ -66,8 +71,10 @@ std::shared_ptr Context::create_session(PrePostProcessor& pp_pro } if (inference_config.m_num_parallel_processors > (unsigned int) m_thread_pool.size()) { - LOG_INFO << "[WARNING] Session " << session_id << " requested more parallel processors than threads are available in Context. Using number of threads as number of parallel processors." << std::endl; - inference_config.m_num_parallel_processors = (unsigned int) m_thread_pool.size(); + if (!m_thread_pool.empty()) { + LOG_INFO << "[WARNING] Session " << session_id << " requested more parallel processors than threads are available in Context. Using number of threads as number of parallel processors." << std::endl; + inference_config.m_num_parallel_processors = (unsigned int) m_thread_pool.size(); + } } std::shared_ptr session = std::make_shared(session_id, pp_processor, inference_config); @@ -368,6 +375,13 @@ moodycamel::ProducerToken& Context::get_producer_token() { return *m_producer_tokens[index]; } +moodycamel::ConcurrentQueue& Context::get_static_inference_queue() { + return m_next_inference; +} + +std::unique_ptr Context::make_inference_thread() { + return std::make_unique(m_next_inference); +} #ifdef USE_LIBTORCH template void Context::set_processor(std::shared_ptr session, InferenceConfig& inference_config, std::vector>& processors, InferenceBackend backend); diff --git a/src/scheduler/InferenceThread.cpp b/src/scheduler/InferenceThread.cpp index 0f8b6046..c6f015fb 100644 --- a/src/scheduler/InferenceThread.cpp +++ b/src/scheduler/InferenceThread.cpp @@ -4,7 +4,8 @@ namespace anira { InferenceThread::InferenceThread(moodycamel::ConcurrentQueue& next_inference) : - m_next_inference(next_inference) + m_next_inference(next_inference), + m_consumer_token(next_inference) { } @@ -12,7 +13,31 @@ InferenceThread::~InferenceThread() { stop(); } +#ifndef __EMSCRIPTEN__ void InferenceThread::run() { + run_loop(); +} +#else +void InferenceThread::start() { + m_should_exit.store(false, std::memory_order::release); + m_is_running.store(true, std::memory_order::release); +} + +void InferenceThread::stop() { + m_should_exit.store(true, std::memory_order::release); + m_is_running.store(false, std::memory_order::release); +} + +bool InferenceThread::should_exit() const { + return m_should_exit.load(std::memory_order::acquire); +} + +bool InferenceThread::is_running() const { + return m_is_running.load(std::memory_order::acquire); +} +#endif + +void InferenceThread::run_loop() { while (!should_exit()) { constexpr std::array iterations = {4, 32}; // The times for the exponential backoff. The first loop is insteadly trying to acquire the atomic counter. The second loop is waiting for approximately 100ns. Beyond that, the thread will yield and sleep for 100us. @@ -60,7 +85,7 @@ void InferenceThread::exponential_backoff(std::array iterations) { bool InferenceThread::execute() { - if (m_next_inference.try_dequeue(m_inference_data)) { + if (m_next_inference.try_dequeue(m_consumer_token, m_inference_data)) { if (m_inference_data.m_session->m_initialized.load(std::memory_order::acquire)) { do_inference(m_inference_data.m_session, m_inference_data.m_thread_safe_struct); } @@ -133,4 +158,4 @@ void InferenceThread::inference(std::shared_ptr session, std::ve } } -} // namespace anira \ No newline at end of file +} // namespace anira diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8d995c16..fa8cdfa0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,6 +33,7 @@ target_sources(${PROJECT_NAME} PRIVATE utils/test_JsonConfigLoader.cpp scheduler/test_InferenceManager.cpp scheduler/test_SessionElement.cpp + scheduler/test_UserManagedThread.cpp test_WavReader.cpp ) diff --git a/test/scheduler/test_UserManagedThread.cpp b/test/scheduler/test_UserManagedThread.cpp new file mode 100644 index 00000000..9ebc56da --- /dev/null +++ b/test/scheduler/test_UserManagedThread.cpp @@ -0,0 +1,61 @@ +#include +#include + +#include "gtest/gtest.h" +#include + +#include "../../extras/models/hybrid-nn/HybridNNBypassProcessor.h" +#include "../../extras/models/hybrid-nn/HybridNNConfig.h" +#include "../../extras/models/hybrid-nn/HybridNNPrePostProcessor.h" + +#define USER_THREAD_TIMEOUT_S 2 + +using namespace anira; + +// Drives an InferenceHandler with no auto-pool threads — the caller creates +// and manages the InferenceThread that actually runs inference. This is the +// same pattern the wasm build uses under the hood (one JS Worker per +// InferenceThread), now available natively as first-party. +TEST(UserManagedInferenceThread, ProcessesAudioWithoutAutoPool) { + constexpr int buffer_size = 512; + constexpr double sample_rate = 44100.0; + + InferenceConfig inference_config = hybridnn_config; + HybridNNPrePostProcessor pp_processor(inference_config); + HybridNNBypassProcessor bypass_processor(inference_config); + + // Zero auto-pool threads — the user owns the threading. + ContextConfig context_config(0); + + InferenceHandler inference_handler( + pp_processor, inference_config, bypass_processor, context_config); + + auto user_thread = Context::make_inference_thread(); + ASSERT_NE(user_thread, nullptr); + user_thread->start(); + + inference_handler.prepare(HostConfig{buffer_size, sample_rate}); + inference_handler.set_inference_backend(InferenceBackend::CUSTOM); + + BufferF test_buffer(1, buffer_size); + for (size_t i = 0; i < buffer_size; ++i) { + test_buffer.set_sample(0, i, static_cast(i) / buffer_size); + } + + const size_t prev_samples = inference_handler.get_available_samples(0); + inference_handler.process(test_buffer.get_array_of_write_pointers(), buffer_size); + + auto start = std::chrono::system_clock::now(); + while (inference_handler.get_available_samples(0) == prev_samples) { + if (std::chrono::system_clock::now() > + start + std::chrono::duration(USER_THREAD_TIMEOUT_S)) { + FAIL() << "User-managed inference thread did not process the block"; + } + std::this_thread::sleep_for(std::chrono::microseconds(10)); + } + + // stop() joins the underlying std::thread on native builds, so by the + // time it returns the run loop has fully exited. + user_thread->stop(); + ASSERT_FALSE(user_thread->is_running()); +} diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 00000000..66a03d73 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,26 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +tsc-declarations +tsconfig.tsbuildinfo +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/web/.prettierignore b/web/.prettierignore new file mode 100644 index 00000000..afa28ae3 --- /dev/null +++ b/web/.prettierignore @@ -0,0 +1,4 @@ +dist +licenses +node_modules +wasm diff --git a/web/.prettierrc b/web/.prettierrc new file mode 100644 index 00000000..cef45173 --- /dev/null +++ b/web/.prettierrc @@ -0,0 +1,8 @@ +{ + "semi": false, + "trailingComma": "es5", + "singleQuote": true, + "printWidth": 90, + "tabWidth": 2, + "useTabs": false +} diff --git a/web/LICENSE b/web/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/web/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/web/README.md b/web/README.md new file mode 100644 index 00000000..bb8d8c93 --- /dev/null +++ b/web/README.md @@ -0,0 +1,129 @@ +# Anira Web + +The WebAssembly + TypeScript distribution of [**anira**](https://github.com/anira-project/anira) — a real-time neural-network inference library for low-latency audio applications. +Anira Web ships the same C++ library compiled to WebAssembly, wrapped in a TypeScript API that integrates with the Web Audio API. + +📚 **Full documentation:** +[anira-project.github.io/anira/web-api](https://anira-project.github.io/anira/web-api/index.html) + +## Install + +```bash +npm install @anira-project/anira +``` + +The package is published as ESM only and ships its WebAssembly +artifacts under `@anira-project/anira/dist/wasm/`. Modern bundlers (Vite, +webpack 5, Rollup, esbuild) already understand the +`new URL('./file.wasm', import.meta.url)` references emitted by the +package and will copy the asset automatically. + +## Quick example + +Loading an ONNX model and wiring it into a Web Audio graph: + +```ts +import { AniraWeb } from '@anira-project/anira' + +const aniraWeb = await AniraWeb.create() +await aniraWeb.spinUpInferenceWorker() + +const audioContext = new AudioContext({ sampleRate: 48000 }) + +// Load the model +const modelBuffer = await (await fetch('your-model.onnx')).arrayBuffer() +const vectorModelData = aniraWeb.VectorModelData([ + aniraWeb.ModelData(modelBuffer, aniraWeb.InferenceBackend.ONNX), +]) + +// Configure tensors and processing +const tensorShape = aniraWeb.TensorShape( + aniraWeb.TensorShapeList([[1, 2, 512]]), + aniraWeb.TensorShapeList([[1, 2, 512]]) +) +const processingSpec = aniraWeb.ProcessingSpec( + aniraWeb.VectorSizeT([2]), + aniraWeb.VectorSizeT([2]), + aniraWeb.VectorSizeT([512]), + aniraWeb.VectorSizeT([512]) +) +const inferenceConfig = aniraWeb.InferenceConfig( + vectorModelData, + aniraWeb.VectorTensorShape([tensorShape]), + processingSpec, + 5 // max inference time in ms +) + +// Set up the inference handler +const ppProcessor = aniraWeb.PrePostProcessor(inferenceConfig) +const inferenceHandler = aniraWeb.InferenceHandler(ppProcessor, inferenceConfig) +inferenceHandler.setInferenceBackend(aniraWeb.InferenceBackend.ONNX) +inferenceHandler.prepare(aniraWeb.HostConfig(128, 48000)) + +// Wire it into Web Audio +await aniraWeb.registerAudioWorkletForContext(audioContext) +const node = await aniraWeb.configureAudioWorklet( + audioContext, + inferenceHandler, + ppProcessor +) +sourceNode.connect(node).connect(audioContext.destination) +``` + +The full walkthrough — including non-streamable control parameters, the optional `onnxruntime-web` JS-side path, and lifecycle / cleanup — is on the [Basic Usage](https://anira-project.github.io/anira/web-api/basic_usage.html) +page. + +## Documentation + +- [Basic Usage](https://anira-project.github.io/anira/web-api/basic_usage.html) + — minimal end-to-end setup. +- [Architecture](https://anira-project.github.io/anira/web-api/architecture.html) + — the three-thread model (main + audio worklet + inference workers), + the JS ↔ WASM bridge, and the lifecycle / cleanup story. +- [Custom Audio Worklets](https://anira-project.github.io/anira/web-api/custom_audio_worklets.html) + — multi-tensor I/O, custom buffer sizes, `AudioParam` integration. +- [Custom Pre- and Post-Processing](https://anira-project.github.io/anira/web-api/custom_pre_post_processing.html) + — running JS before / after each inference call. +- [Custom Inference Backends](https://anira-project.github.io/anira/web-api/custom_inference_backends.html) + — replacing the WASM-side runtime with a JavaScript backend. +- [API Reference](https://anira-project.github.io/anira/web-api/reference/index.html) + — auto-generated class and function reference. + +## Demos + +A list of demos is available [here](https://anira-project.github.io/anira-web-example). + +## Building from source + +To build Anira Web from source — including cross-compiling the C++ library to WebAssembly — follow the [Installation / Building](https://anira-project.github.io/anira/web-api/installation_building.html#building-from-source) guide. + +## License + +Anira Web itself is distributed under the [Apache License 2.0](https://github.com/anira-project/anira/blob/main/LICENSE). + +### Attribution requirements when redistributing + +The WebAssembly binary statically links **ONNX Runtime** (MIT, © Microsoft) and a number of native libraries (protobuf, abseil, Eigen, flatbuffers, mimalloc, …) whose code ends up in `dist/wasm/AniraWeb.wasm`. If you ship a product that includes `@anira-project/anira`, your distribution must reproduce the corresponding copyright notices and license texts. + +To make this straightforward, the package ships these files in known locations: + +``` +node_modules/@anira-project/anira/ +├── LICENSE # Apache-2.0 for anira / @anira-project/anira +└── dist/licenses/ + └── onnxruntime/ + ├── LICENSE # MIT (ONNX Runtime) + ├── ThirdPartyNotices.txt # ONNX Runtime's transitive deps + └── PACKAGE.txt # name / version / homepage / license +``` + +Each subdirectory under `dist/licenses/` represents one statically-linked native dep that needs attribution. `PACKAGE.txt` is a simple `key: value` manifest you can parse to drive an attribution generator. + +In practice the easiest path is to use a tool like [`rollup-plugin-license`](https://github.com/mjeanroy/rollup-plugin-license) or a similar webpack/esbuild plugin to auto-generate a `THIRD_PARTY_LICENSES.txt` and ship it alongside your build. If you do, point the plugin at: + +- the package's own `LICENSE` (already covered by the plugin's normal dep walk), and +- each subdirectory under `node_modules/@anira-project/anira/dist/licenses/` (these aren't visible to npm-graph-based tools because they describe _native_ code linked into the WASM, not JS deps). + +If you don't use such a tool, copy the files above into your distribution alongside whatever attribution you already do for your other open-source dependencies. + +There is currently no `NOTICE` file shipped by anira itself, so Apache-2.0's NOTICE-propagation clause has nothing to apply. If that ever changes upstream, the file will appear at the package root next to `LICENSE`. diff --git a/web/licenses/onnxruntime/LICENSE b/web/licenses/onnxruntime/LICENSE new file mode 100644 index 00000000..48bc6bb4 --- /dev/null +++ b/web/licenses/onnxruntime/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/web/licenses/onnxruntime/PACKAGE.txt b/web/licenses/onnxruntime/PACKAGE.txt new file mode 100644 index 00000000..8b811484 --- /dev/null +++ b/web/licenses/onnxruntime/PACKAGE.txt @@ -0,0 +1,4 @@ +name: onnxruntime +version: 1.19.2 +license: MIT +homepage: https://github.com/microsoft/onnxruntime diff --git a/web/licenses/onnxruntime/ThirdPartyNotices.txt b/web/licenses/onnxruntime/ThirdPartyNotices.txt new file mode 100644 index 00000000..6a11f414 --- /dev/null +++ b/web/licenses/onnxruntime/ThirdPartyNotices.txt @@ -0,0 +1,6508 @@ +THIRD PARTY SOFTWARE NOTICES AND INFORMATION + +Do Not Translate or Localize + +This software incorporates material from third parties. Microsoft makes certain +open source code available at http://3rdpartysource.microsoft.com, or you may +send a check or money order for US $5.00, including the product name, the open +source component name, and version number, to: + +Source Code Compliance Team +Microsoft Corporation +One Microsoft Way +Redmond, WA 98052 +USA + +Notwithstanding any other terms, you may reverse engineer this software to the +extent required to debug changes to any libraries licensed under the GNU Lesser +General Public License. + +_____ + +Intel Math Kernel Library (Intel MKL) + +Intel Simplified Software License (Version April 2018) + +Copyright (c) 2018 Intel Corporation. + +Use and Redistribution. You may use and redistribute the software (the “Software”), without modification, +provided the following conditions are met: + +* Redistributions must reproduce the above copyright notice and the following terms of use in the Software +and in the documentation and/or other materials provided with the distribution. + +* Neither the name of Intel nor the names of its suppliers may be used to endorse or promote products +derived from this Software without specific prior written permission. + +* No reverse engineering, decompilation, or disassembly of this Software is permitted. + +Limited patent license. Intel grants you a world-wide, royalty-free, non-exclusive license under patents it now +or hereafter owns or controls to make, have made, use, import, offer to sell and sell (“Utilize”) this Software, +but solely to the extent that any such patent is necessary to Utilize the Software alone. The patent license +shall not apply to any combinations which include this software. No hardware per se is licensed hereunder. + +Third party and other Intel programs. “Third Party Programs” are the files listed in the “third-party-programs.txt” +text file that is included with the Software and may include Intel programs under separate license terms. +Third Party Programs, even if included with the distribution of the Materials, are governed by +separate license terms and those license terms solely govern your use of those programs. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. THIS SOFTWARE IS +NOT INTENDED FOR USE IN SYSTEMS OR APPLICATIONS WHERE FAILURE OF THE SOFTWARE +MAY CAUSE PERSONAL INJURY OR DEATH AND YOU AGREE THAT YOU ARE FULLY RESPONSIBLE FOR ANY +CLAIMS, COSTS, DAMAGES, EXPENSES, AND ATTORNEYS’ FEES ARISING OUT OF ANY SUCH USE, +EVEN IF ANY CLAIM ALLEGES THAT INTEL WAS NEGLIGENT REGARDING THE DESIGN OR MANUFACTURE OF +THE MATERIALS. + +LIMITATION OF LIABILITY. IN NO EVENT WILL INTEL BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. YOU AGREE TO INDEMNIFY AND HOLD INTEL HARMLESS AGAINST ANY CLAIMS +AND EXPENSES RESULTING FROM YOUR USE OR UNAUTHORIZED USE OF THE SOFTWARE. + +No support. Intel may make changes to the Software, at any time without notice, and is not obligated to +support, update or provide training for the Software. + +Termination. Intel may terminate your right to use the Software in the event of your breach of this Agreement +and you fail to cure the breach within a reasonable period of time. + +Feedback. Should you provide Intel with comments, modifications, corrections, enhancements or other input +(“Feedback”) related to the Software Intel will be free to use, disclose, reproduce, license or otherwise +distribute or exploit the Feedback in its sole discretion without any obligations or restrictions of any kind, +including without limitation, intellectual property rights or licensing obligations. + +Compliance with laws. You agree to comply with all relevant laws and regulations governing your use, +transfer, import or export (or prohibition thereof) of the Software. + +Governing law. All disputes will be governed by the laws of the United States of America and the State of +Delaware without reference to conflict of law principles and subject to the exclusive jurisdiction of the state or +federal courts sitting in the State of Delaware, and each party agrees that it submits to the personal +jurisdiction and venue of those courts and waives any objections. The United Nations Convention on +Contracts for the International Sale of Goods (1980) is specifically excluded and will not apply to the +Software. + +*Other names and brands may be claimed as the property of others. + +_____ + +protocolbuffers/protobuf + +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +_____ + +madler/zlib + +The deflate format used by zlib was defined by Phil Katz. The deflate and +zlib specifications were written by L. Peter Deutsch. Thanks to all the +people who reported problems and suggested various improvements in zlib; they +are too numerous to cite here. + +Copyright notice: + + (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. + +_____ + +pybind/pybind11 + +Copyright (c) 2016 Wenzel Jakob , All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Please also refer to the file CONTRIBUTING.md, which clarifies licensing of +external contributions to this project including patches, pull requests, etc. + +_____ + +onnx +Open Neural Network Exchange + +Copyright (c) Facebook, Inc. and Microsoft Corporation. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +Eigen + +MPL v2.0 +Mozilla Public License Version 2.0 + + +================================== + +1. Definitions + +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions + +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities + +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation + +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination + +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +_____ + +intel/dnnl + +Copyright 2016-2018 Intel Corporation + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +sub-components: + +xbyak + +Copyright (c) 2007 MITSUNARI Shigeo. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. +Neither the name of the copyright owner nor the names of its contributors may +be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +Microsoft GSL + +Copyright (c) 2015 Microsoft Corporation. All rights reserved. + +This code is licensed under the MIT License (MIT). + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +_____ + +Tensorflow + +Copyright 2018 The TensorFlow Authors. All rights reserved. + +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, +and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by +the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all +other entities that control, are controlled by, or are under common +control with that entity. For the purposes of this definition, +"control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or +otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity +exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation +source, and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but +not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or +Object form, made available under the License, as indicated by a +copyright notice that is included in or attached to the work +(an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including +the original version of the Work and any modifications or additions +to that Work or Derivative Works thereof, that is intentionally +submitted to Licensor for inclusion in the Work by the copyright owner +or by an individual or Legal Entity authorized to submit on behalf of +the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, +and issue tracking systems that are managed by, or on behalf of, the +Licensor for the purpose of discussing and improving the Work, but +excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the +Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +(except as stated in this section) patent license to make, have made, +use, offer to sell, sell, import, and otherwise transfer the Work, +where such license applies only to those patent claims licensable +by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) +with the Work to which such Contribution(s) was submitted. If You +institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work +or a Contribution incorporated within the Work constitutes direct +or contributory patent infringement, then any patent licenses +granted to You under this License for that Work shall terminate +as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You +meet the following conditions: + +(a) You must give any other recipients of the Work or +Derivative Works a copy of this License; and + +(b) You must cause any modified files to carry prominent notices +stating that You changed the files; and + +(c) You must retain, in the Source form of any Derivative Works +that You distribute, all copyright, patent, trademark, and +attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of +the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its +distribution, then any Derivative Works that You distribute must +include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not +pertain to any part of the Derivative Works, in at least one +of the following places: within a NOTICE text file distributed +as part of the Derivative Works; within the Source form or +documentation, if provided along with the Derivative Works; or, +within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents +of the NOTICE file are for informational purposes only and +do not modify the License. You may add Your own attribution +notices within Derivative Works that You distribute, alongside +or as an addendum to the NOTICE text from the Work, provided +that such additional attribution notices cannot be construed +as modifying the License. + +You may add Your own copyright statement to Your modifications and +may provide additional or different license terms and conditions +for use, reproduction, or distribution of Your modifications, or +for any such Derivative Works as a whole, provided Your use, +reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work +by You to the Licensor shall be under the terms and conditions of +this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify +the terms of any separate license agreement you may have executed +with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or +agreed to in writing, Licensor provides the Work (and each +Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied, including, without limitation, any warranties or conditions +of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any +risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, +unless required by applicable law (such as deliberate and grossly +negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, +incidental, or consequential damages of any character arising as a +result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all +other commercial damages or losses), even if such Contributor +has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing +the Work or Derivative Works thereof, You may choose to offer, +and charge a fee for, acceptance of support, warranty, indemnity, +or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only +on Your own behalf and on Your sole responsibility, not on behalf +of any other Contributor, and only if You agree to indemnify, +defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason +of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017, The TensorFlow Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +Microsoft Cognitive Toolkit (CNTK) + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +_____ + +NumPy License + +Copyright (c) 2005, NumPy Developers + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + Neither the name of the NumPy Developers nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +Pytorch / Caffe2 + +From PyTorch: + +Copyright (c) 2016- Facebook, Inc (Adam Paszke) +Copyright (c) 2014- Facebook, Inc (Soumith Chintala) +Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) +Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) +Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) +Copyright (c) 2011-2013 NYU (Clement Farabet) +Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) +Copyright (c) 2006 Idiap Research Institute (Samy Bengio) +Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) + +From Caffe2: + +Copyright (c) 2016-present, Facebook Inc. All rights reserved. + +All contributions by Facebook: +Copyright (c) 2016 Facebook Inc. + +All contributions by Google: +Copyright (c) 2015 Google Inc. +All rights reserved. + +All contributions by Yangqing Jia: +Copyright (c) 2015 Yangqing Jia +All rights reserved. + +All contributions from Caffe: +Copyright(c) 2013, 2014, 2015, the respective contributors +All rights reserved. + +All other contributions: +Copyright(c) 2015, 2016 the respective contributors +All rights reserved. + +Caffe2 uses a copyright model similar to Caffe: each contributor holds +copyright over their contributions to Caffe2. The project versioning records +all such contribution and copyright details. If a contributor wants to further +mark their specific copyright on a particular contribution, they should +indicate their copyright solely in the commit message of the change when it is +committed. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America + and IDIAP Research Institute nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +_____ + +Caffe + +COPYRIGHT + +All contributions by the University of California: +Copyright (c) 2014-2017 The Regents of the University of California (Regents) +All rights reserved. + +All other contributions: +Copyright (c) 2014-2017, the respective contributors +All rights reserved. + +Caffe uses a shared copyright model: each contributor holds copyright over +their contributions to Caffe. The project versioning records all such +contribution and copyright details. If a contributor wants to further mark +their specific copyright on a particular contribution, they should indicate +their copyright solely in the commit message of the change when it is +committed. + +LICENSE + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +CONTRIBUTION AGREEMENT + +By contributing to the BVLC/caffe repository through pull-request, comment, +or otherwise, the contributor releases their content to the +license and copyright terms herein. + +_____ + +The LLVM Compiler Infrastructure + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2017 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +Google Test llvm/utils/unittest/googletest +OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} +pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} +ARM contributions llvm/lib/Target/ARM/LICENSE.TXT +md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h + +_____ + +google/benchmark + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +CONTRIBUTORS + +# People who have agreed to one of the CLAs and can contribute patches. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# +# Names should be added to this file only after verifying that +# the individual or the individual's organization has agreed to +# the appropriate Contributor License Agreement, found here: +# +# https://developers.google.com/open-source/cla/individual +# https://developers.google.com/open-source/cla/corporate +# +# The agreement for individuals can be filled out on the web. +# +# When adding J Random Contributor's name to this file, +# either J's name or J's organization's name should be +# added to the AUTHORS file, depending on whether the +# individual or corporate CLA was used. +# +# Names should be added to this file as: +# Name +# +# Please keep the list sorted. + +Albert Pretorius +Arne Beer +Billy Robert O'Neal III +Chris Kennelly +Christopher Seymour +David Coeurjolly +Deniz Evrenci +Dominic Hamon +Dominik Czarnota +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Federico Ficarelli +Felix Homann +Ismael Jimenez Martinez +Jern-Kuan Leong +JianXiong Zhou +Joao Paulo Magalhaes +John Millikin +Jussi Knuuttila +Kai Wolf +Kishan Kumar +Kaito Udagawa +Lei Xu +Matt Clarkson +Maxim Vafin +Nick Hutchinson +Oleksandr Sochka +Pascal Leroy +Paul Redmond +Pierre Phaneuf +Radoslav Yovchev +Raul Marin +Ray Glover +Robert Guo +Roman Lebedev +Shuo Chen +Tobias Ulvgård +Tom Madams +Yixuan Qiu +Yusuke Suzuki +Zbigniew Skowron + +AUTHORS + +# This is the official list of benchmark authors for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Albert Pretorius +Arne Beer +Carto +Christopher Seymour +David Coeurjolly +Deniz Evrenci +Dirac Research +Dominik Czarnota +Eric Fiselier +Eugene Zhuk +Evgeny Safronov +Federico Ficarelli +Felix Homann +Google Inc. +International Business Machines Corporation +Ismael Jimenez Martinez +Jern-Kuan Leong +JianXiong Zhou +Joao Paulo Magalhaes +Jussi Knuuttila +Kaito Udagawa +Kishan Kumar +Lei Xu +Matt Clarkson +Maxim Vafin +MongoDB Inc. +Nick Hutchinson +Oleksandr Sochka +Paul Redmond +Radoslav Yovchev +Roman Lebedev +Shuo Chen +Steinar H. Gunderson +Stripe, Inc. +Yixuan Qiu +Yusuke Suzuki +Zbigniew Skowron + +_____ + +HalideIR + +Copyright (c) 2016 HalideIR contributors +Copyright (c) 2012-2014 MIT CSAIL, Google Inc., and other contributors +HalideIR is derived from the Halide project. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +_____ + +Distributed Machine Learning Common Codebase + +Copyright (c) 2015 by Contributors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +_____ + +DLPack: Open In Memory Tensor Structure + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 by Contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +HowardHinnant/date + +The source code in this project is released using the MIT License. There is no +global license for the project because each file is licensed individually with +different author names and/or dates. + +If you contribute to this project, please add your name to the license of each +file you modify. If you have already contributed to this project and forgot to +add your name to the license, please feel free to submit a new P/R to add your +name to the license in each file you modified. + +For convenience, here is a copy of the MIT license found in each file except +without author names or dates: + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ + +TVM Open Deep Learning Compiler Stack + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +CONTRIBUTORS + +TVM Contributors +================ +TVM adopts the Apache style model and governs by merit. We believe that it is important to create an inclusive community where everyone can use, +contribute to, and influence the direction of the project. We actively invite contributors who have earned the merit to be part of the development community. + +See the [community structure document](http://docs.tvm.ai/contribute/community.html) for the explanation of community structure and contribution guidelines. + +## Committers +- [Tianqi Chen](https://github.com/tqchen) (PMC) +- [Thierry Moreau](http://homes.cs.washington.edu/~moreau/) +- [Ziheng Jiang](https://github.com/ZihengJiang) +- [Haichen Shen](http://homes.cs.washington.edu/~haichen/) +- [Yizhi Liu](https://github.com/yzhliu) + +## Code Owners +- [Aditya Atluri](https://github.com/adityaatluri) ROCM +- [Leyuan Wang](https://github.com/Laurawly) TOPI +- [Yuwei Hu](https://github.com/Huyuwei) TOPI +- [Zhixun Tan](https://github.com/phisiart) OpenGL/WebGL backend +- [Nick Hynes](https://github.com/nhynes) SGX and secured computing +- [Lianmin Zheng](https://github.com/merrymercy) AutoTVM + +## Reviewers +- [Zhi Chen](https://github.com/zhiics) +- [Xiaoqiang Dan](https://github.com/xqdan) +- [Liangfu Chen](https://github.com/liangfu) +- [Masahiro Masuda](https://github.com/masahi) +- [Kazutaka Morita](https://github.com/kazum) +- [Tatsuya Nishiyama](https://github.com/nishi-t) +- [Pariksheet Pinjari](https://github.com/PariksheetPinjari909) +- [Jared Roesch](https://github.com/jroesch) +- [Siva](https://github.com/srkreddy1238) +- [Siju Samuel](https://github.com/siju-samuel) +- [Alex Weaver](https://github.com/alex-weaver) +- [Yao Wang](https://github.com/kevinthesun) +- [Jian Weng](https://github.com/were) +- [Eddie Yan](https://github.com/eqy) +- [Joshua Z. Zhang](https://github.com/zhreshold) + +## List of Contributors +- [Full List of Contributors](https://github.com/dmlc/tvm/graphs/contributors) + - To contributors: please add your name to the list. +- [Qiao Zhang](https://github.com/zhangqiaorjc) +- [Haolong Zhang](https://github.com/haolongzhangm) +- [Cody Hao Yu](https://github.com/comaniac) +- [Chris Nuernberger](https://github.com/cnuernber) + +_____ + +FreeBSD: getopt.c file + +Copyright (c) 1987, 1993, 1994 +The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the University nor the names of its contributors +may be used to endorse or promote products derived from this software +without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +_____ + + +google/googletest + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +G3log : Asynchronous logger with Dynamic Sinks + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +_____ + +Scikit-learn + +Copyright (c) 2007–2018 The scikit-learn developers. +All rights reserved. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + c. Neither the name of the Scikit-learn Developers nor the names of + its contributors may be used to endorse or promote products + derived from this software without specific prior written + permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +_____ + +google/nsync + +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +google/re2 + +Copyright (c) 2009 The RE2 Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +_____ +onnx/onnx-tensorrt + +MIT License + +Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. +Copyright (c) 2018 Open Neural Network Exchange + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ +nvidia/cutlass + +Copyright (c) 2017 - 2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ +Boost + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + + +_____ + +JDAI-CV/DNNLibrary + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2019] [JD.com Inc. JD AI] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +_____ + +google/flatbuffers + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +_____ + +google/glog + +Copyright (c) 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +A function gettimeofday in utilities.cc is based on + +http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/COPYING&q=GetSystemTimeAsFileTime%20license:bsd + +The license of this code is: + +Copyright (c) 2003-2008, Jouni Malinen and contributors +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +abseil-cpp +https://github.com/abseil/abseil-cpp + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +_____ + +microsoft/wil + +MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE + +_____ + +nlohmann/json + +MIT License + +Copyright (c) 2013-2019 Niels Lohmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ + +dcleblanc/SafeInt + +MIT License + +Copyright (c) 2018 Microsoft + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ +Open MPI + +3-Clause BSD License + +Most files in this release are marked with the copyrights of the +organizations who have edited them. The copyrights below are in no +particular order and generally reflect members of the Open MPI core +team who have contributed code to this release. The copyrights for +code used under license from other parties are included in the +corresponding files. + +Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana + University Research and Technology + Corporation. All rights reserved. +Copyright (c) 2004-2017 The University of Tennessee and The University + of Tennessee Research Foundation. All rights + reserved. +Copyright (c) 2004-2010 High Performance Computing Center Stuttgart, + University of Stuttgart. All rights reserved. +Copyright (c) 2004-2008 The Regents of the University of California. + All rights reserved. +Copyright (c) 2006-2017 Los Alamos National Security, LLC. All rights + reserved. +Copyright (c) 2006-2017 Cisco Systems, Inc. All rights reserved. +Copyright (c) 2006-2010 Voltaire, Inc. All rights reserved. +Copyright (c) 2006-2017 Sandia National Laboratories. All rights reserved. +Copyright (c) 2006-2010 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. +Copyright (c) 2006-2017 The University of Houston. All rights reserved. +Copyright (c) 2006-2009 Myricom, Inc. All rights reserved. +Copyright (c) 2007-2017 UT-Battelle, LLC. All rights reserved. +Copyright (c) 2007-2017 IBM Corporation. All rights reserved. +Copyright (c) 1998-2005 Forschungszentrum Juelich, Juelich Supercomputing + Centre, Federal Republic of Germany +Copyright (c) 2005-2008 ZIH, TU Dresden, Federal Republic of Germany +Copyright (c) 2007 Evergrid, Inc. All rights reserved. +Copyright (c) 2008 Chelsio, Inc. All rights reserved. +Copyright (c) 2008-2009 Institut National de Recherche en + Informatique. All rights reserved. +Copyright (c) 2007 Lawrence Livermore National Security, LLC. + All rights reserved. +Copyright (c) 2007-2017 Mellanox Technologies. All rights reserved. +Copyright (c) 2006-2010 QLogic Corporation. All rights reserved. +Copyright (c) 2008-2017 Oak Ridge National Labs. All rights reserved. +Copyright (c) 2006-2012 Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2009-2015 Bull SAS. All rights reserved. +Copyright (c) 2010 ARM ltd. All rights reserved. +Copyright (c) 2016 ARM, Inc. All rights reserved. +Copyright (c) 2010-2011 Alex Brick . All rights reserved. +Copyright (c) 2012 The University of Wisconsin-La Crosse. All rights + reserved. +Copyright (c) 2013-2016 Intel, Inc. All rights reserved. +Copyright (c) 2011-2017 NVIDIA Corporation. All rights reserved. +Copyright (c) 2016 Broadcom Limited. All rights reserved. +Copyright (c) 2011-2017 Fujitsu Limited. All rights reserved. +Copyright (c) 2014-2015 Hewlett-Packard Development Company, LP. All + rights reserved. +Copyright (c) 2013-2017 Research Organization for Information Science (RIST). + All rights reserved. +Copyright (c) 2017-2018 Amazon.com, Inc. or its affiliates. All Rights + reserved. +Copyright (c) 2018 DataDirect Networks. All rights reserved. +Copyright (c) 2018-2019 Triad National Security, LLC. All rights reserved. + +$COPYRIGHT$ + +Additional copyrights may follow + +$HEADER$ + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer listed + in this license in the documentation and/or other materials + provided with the distribution. + +- Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +The copyright holders provide no reassurances that the source code +provided does not infringe any patent, copyright, or any other +intellectual property rights of third parties. The copyright holders +disclaim any liability to any recipient for claims brought against +recipient by any third party for infringement of that parties +intellectual property rights. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +The Android Open Source Project + +Copyright (C) 2017 The Android Open Source Project +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +------ + +libprotobuf-mutator + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ----- + + openucx/ucx + https://github.com/openucx/ucx + + Copyright (c) 2014-2015 UT-Battelle, LLC. All rights reserved. + Copyright (C) 2014-2020 Mellanox Technologies Ltd. All rights reserved. + Copyright (C) 2014-2015 The University of Houston System. All rights reserved. + Copyright (C) 2015 The University of Tennessee and The University + of Tennessee Research Foundation. All rights reserved. + Copyright (C) 2016-2020 ARM Ltd. All rights reserved. + Copyright (c) 2016 Los Alamos National Security, LLC. All rights reserved. + Copyright (C) 2016-2020 Advanced Micro Devices, Inc. All rights reserved. + Copyright (C) 2019 UChicago Argonne, LLC. All rights reserved. + Copyright (c) 2018-2020 NVIDIA CORPORATION. All rights reserved. + Copyright (C) 2020 Huawei Technologies Co., Ltd. All rights reserved. + Copyright (C) 2016-2020 Stony Brook University. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ----- + + From PyTorch: + + Copyright (c) 2016- Facebook, Inc (Adam Paszke) + Copyright (c) 2014- Facebook, Inc (Soumith Chintala) + Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) + Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) + Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) + Copyright (c) 2011-2013 NYU (Clement Farabet) + Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) + Copyright (c) 2006 Idiap Research Institute (Samy Bengio) + Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) + + From Caffe2: + + Copyright (c) 2016-present, Facebook Inc. All rights reserved. + + All contributions by Facebook: + Copyright (c) 2016 Facebook Inc. + + All contributions by Google: + Copyright (c) 2015 Google Inc. + All rights reserved. + + All contributions by Yangqing Jia: + Copyright (c) 2015 Yangqing Jia + All rights reserved. + + All contributions from Caffe: + Copyright(c) 2013, 2014, 2015, the respective contributors + All rights reserved. + + All other contributions: + Copyright(c) 2015, 2016 the respective contributors + All rights reserved. + + Caffe2 uses a copyright model similar to Caffe: each contributor holds + copyright over their contributions to Caffe2. The project versioning records + all such contribution and copyright details. If a contributor wants to further + mark their specific copyright on a particular contribution, they should + indicate their copyright solely in the commit message of the change when it is + committed. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America + and IDIAP Research Institute nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +_____ + + mpi4py + https://github.com/mpi4py/mpi4py/ + + ======================= + LICENSE: MPI for Python + ======================= + + :Author: Lisandro Dalcin + :Contact: dalcinl@gmail.com + + + Copyright (c) 2019, Lisandro Dalcin. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +_____ +huggingface/transformers + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +_____ +msgpack/msgpack-python + +Copyright (C) 2008-2011 INADA Naoki + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +_____ +lanpa/tensorboardX + +MIT License + +Copyright (c) 2017 Tzu-Wei Huang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +_____ +tensorflow/tensorboard + +Copyright 2017 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017, The TensorFlow Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +_____ + +cerberus + +Cerberus is a lightweight and extensible data validation library for Python. + +ISC License + +Copyright (c) 2012-2016 Nicola Iarocci. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +_____ + +MurmurHash3 + +MIT license + +https://github.com/aappleby/smhasher + +SMHasher is a test suite designed to test the distribution, collision, and +performance properties of non-cryptographic hash functions. +This is the home for the MurmurHash family of hash functions along with the +SMHasher test suite used to verify them. +SMHasher is released under the MIT license. +All MurmurHash versions are public domain software, and the author disclaims all copyright to their code. + +_____ + +gtest-ios-framework + +https://github.com/mestevens/gtest-ios-framework + +Copyright (c) 2013 Matthew Stevens + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +_____ + +DLPack + +https://github.com/dmlc/dlpack + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 by Contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +emsdk + +MIT/Expat license + +https://github.com/emscripten-core/emsdk + +Copyright (c) 2018 Emscripten authors (see AUTHORS in Emscripten) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---------------------------------------------------------------------------- + +This is the MIT/Expat License. For more information see: + +1. http://www.opensource.org/licenses/mit-license.php + +2. http://en.wikipedia.org/wiki/MIT_License + +_____ + +coremltools + +BSD-3-Clause License + +https://github.com/apple/coremltools + +Copyright (c) 2020, Apple Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +© 2021 GitHub, Inc. + +_____ + +react-native + +MIT License + +https://github.com/facebook/react-native + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ + +pytorch/cpuinfo + +BSD 2-Clause "Simplified" License + +https://github.com/pytorch/cpuinfo + +Copyright (c) 2019 Google LLC +Copyright (c) 2017-2018 Facebook Inc. +Copyright (C) 2012-2017 Georgia Institute of Technology +Copyright (C) 2010-2012 Marat Dukhan + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +SQLite Is Public Domain + +All of the code and documentation in SQLite has been dedicated to the public +domain by the authors. All code authors, and representatives of the companies +they work for, have signed affidavits dedicating their contributions to the +public domain and originals of those signed affidavits are stored in a firesafe +at the main offices of Hwaci. Anyone is free to copy, modify, publish, use, +compile, sell, or distribute the original SQLite code, either in source code +form or as a compiled binary, for any purpose, commercial or non-commercial, +and by any means. + +The previous paragraph applies to the deliverable code and documentation in +SQLite - those parts of the SQLite library that you actually bundle and ship +with a larger application. Some scripts used as part of the build process (for +example the "configure" scripts generated by autoconf) might fall under other +open-source licenses. Nothing from these build scripts ever reaches the final +deliverable SQLite library, however, and so the licenses associated with those +scripts should not be a factor in assessing your rights to copy and use the +SQLite library. + +All of the deliverable code in SQLite has been written from scratch. No code +has been taken from other projects or from the open internet. Every line of +code can be traced back to its original author, and all of those authors have +public domain dedications on file. So the SQLite code base is clean and is +uncontaminated with licensed code from other projects. + +_____ + +google/XNNPACK + +BSD License + +For XNNPACK software + +Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. +Copyright 2019 Google LLC + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +google/sentencepiece, https://github.com/google/sentencepiece +(included when statically linked with onnxruntime-extensions) + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +dlfcn-win32/dlfcn-win32 is licensed under the MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +_____ + +The Python Imaging Library (PIL) is + + Copyright © 1997-2011 by Secret Labs AB + Copyright © 1995-2011 by Fredrik Lundh + +Pillow is the friendly PIL fork. It is + + Copyright © 2010-2023 by Alex Clark and contributors + +Like PIL, Pillow is licensed under the open source HPND License: + +By obtaining, using, and/or copying this software and/or its associated +documentation, you agree that you have read, understood, and will comply +with the following terms and conditions: + +Permission to use, copy, modify, and distribute this software and its +associated documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appears in all copies, and that +both that copyright notice and this permission notice appear in supporting +documentation, and that the name of Secret Labs AB or the author not be +used in advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS +SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +_____ + +openssl/openssl, https://github.com/openssl/openssl + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +_____ + +Tencent/rapidjson, https://github.com/Tencent/rapidjson + +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. + +If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. +If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. +A copy of the MIT License is included in this file. + +Other dependencies and licenses: + +Open Source Software Licensed Under the BSD License: +-------------------------------------------------------------------- + +The msinttypes r29 +Copyright (c) 2006-2013 Alexander Chemeris +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Open Source Software Licensed Under the JSON License: +-------------------------------------------------------------------- + +json.org +Copyright (c) 2002 JSON.org +All Rights Reserved. + +JSON_checker +Copyright (c) 2002 JSON.org +All Rights Reserved. + + +Terms of the JSON License: +--------------------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Terms of the MIT License: +-------------------------------------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +_____ + +boostorg/boost, https://github.com/boostorg/boost + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +_____ + +libb64/libb64, https://github.com/libb64/libb64 + +Copyright-Only Dedication (based on United States law) or Public Domain Certification + +The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below. + +A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain. + +Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work. + +Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived. + +_____ + +posix pthread library, https://sourceforge.net/projects/pthreads4w + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +_____ + +Triton Inference Server & Client, https://github.com/triton-inference-server + +Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of NVIDIA CORPORATION nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +microsoft/mimalloc, https://github.com/microsoft/mimalloc + +MIT License + +Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ + +TensorFlow.js + +https://github.com/tensorflow/tfjs + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +—— + +curl/curl + +https://github.com/curl + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (C) Daniel Stenberg, , and many +contributors, see the THANKS file. + +All rights reserved. + +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. + +_____ + +Intel neural-compressor + +https://github.com/intel/neural-compressor + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + ============================================================================ + + Copyright 2016-2019 Intel Corporation + Copyright 2018 YANDEX LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This distribution includes third party software ("third party programs"). + This third party software, even if included with the distribution of + the Intel software, may be governed by separate license terms, including + without limitation, third party license terms, other Intel software license + terms, and open source software license terms. These separate license terms + govern your use of the third party programs as set forth in the + "THIRD-PARTY-PROGRAMS" file. + +_____ + +FlashAttention, https://github.com/Dao-AILab/flash-attention + +BSD 3-Clause License + +Copyright (c) 2022, the respective contributors, as shown by the AUTHORS file. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +_____ + +composable_kernel + +https://github.com/ROCmSoftwarePlatform/composable_kernel + +Copyright (c) 2018- , Advanced Micro Devices, Inc. (Chao Liu, Jing Zhang) +Copyright (c) 2019- , Advanced Micro Devices, Inc. (Letao Qin, Qianfeng Zhang, Liang Huang, Shaojie Wang) +Copyright (c) 2022- , Advanced Micro Devices, Inc. (Anthony Chang, Chunyu Lai, Illia Silin, Adam Osewski, Poyen Chen, Jehandad Khan) +Copyright (c) 2019-2021, Advanced Micro Devices, Inc. (Hanwen Chang) +Copyright (c) 2019-2020, Advanced Micro Devices, Inc. (Tejash Shah) +Copyright (c) 2020 , Advanced Micro Devices, Inc. (Xiaoyan Zhou) +Copyright (c) 2021-2022, Advanced Micro Devices, Inc. (Jianfeng Yan) + +SPDX-License-Identifier: MIT +Copyright (c) 2018-2023, Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +_____ + +neural-speed + +https://github.com/intel/neural-speed + + Apache License + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + ============================================================================ + + Copyright 2016-2019 Intel Corporation + Copyright 2018 YANDEX LLC + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + This distribution includes third party software ("third party programs"). + This third party software, even if included with the distribution of + the Intel software, may be governed by separate license terms, including + without limitation, third party license terms, other Intel software license + terms, and open source software license terms. These separate license terms + govern your use of the third party programs as set forth in the + "THIRD-PARTY-PROGRAMS" file. diff --git a/web/package-lock.json b/web/package-lock.json new file mode 100644 index 00000000..acd0b4d5 --- /dev/null +++ b/web/package-lock.json @@ -0,0 +1,2686 @@ +{ + "name": "@anira-project/anira", + "version": "0.0.1-alpha.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@anira-project/anira", + "version": "0.0.1-alpha.0", + "license": "Apache-2.0", + "dependencies": { + "onnxruntime-web": "^1.19.2" + }, + "devDependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "prettier": "^3.8.3", + "rollup": "^4.60.0", + "typescript": "~5.9.3", + "vite": "^8.0.8", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-static-copy": "^3.2.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.58.7", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.58.7.tgz", + "integrity": "sha512-yK6OycD46gIzLRpj6ueVUWPk1ACSpkN1LBo05gY1qPTylbWyUCanXfH7+VgkI5LJrJoRSQR5F04XuCffCXLOBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.33.8", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1", + "@rushstack/rig-package": "0.7.3", + "@rushstack/terminal": "0.24.0", + "@rushstack/ts-command-line": "5.3.9", + "diff": "~8.0.2", + "minimatch": "10.2.3", + "resolve": "~1.22.1", + "semver": "~7.7.4", + "source-map": "~0.6.1", + "typescript": "5.9.3" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.33.8", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.8.tgz", + "integrity": "sha512-aIcoQggPyer3B6Ze3usz0YWC/oBwUHfRH5ETUsr+oT2BRA6SfTJl7IKPcPZkX4UR+PohowzW4uMxsvjrn8vm+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.1.tgz", + "integrity": "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.18.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", + "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", + "license": "BSD-3-Clause" + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.3.tgz", + "integrity": "sha512-x35CNW/ANXG3hE/EZpRU8MXX1JDN86hBb2wMGAtltkz7pc6cxgjpy1OMMfDosOQ+2hWqIkag/fGok1Yady9nGw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.3.tgz", + "integrity": "sha512-xw3xtkDApIOGayehp2+Rz4zimfkaX65r4t47iy+ymQB2G4iJCBBfj0ogVg5jpvjpn8UWn/+q9tprxleYeNp3Hw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.3.tgz", + "integrity": "sha512-vo6Y5Qfpx7/5EaamIwi0WqW2+zfiusVihKatLvtN1VFVy3D13uERk/6gZLU1UiHRL6fDXqj/ELIeVRGnvcTE1g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.3.tgz", + "integrity": "sha512-D+0QGcZhBzTN82weOnsSlY7V7+RMmPuF1CkbxyMAGE8+ZHeUjyb76ZiWmBlCu//AQQONvxcqRbwZTajZKqjuOw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.3.tgz", + "integrity": "sha512-6HnvHCT7fDyj6R0Ph7A6x8dQS/S38MClRWeDLqc0MdfWkxjiu1HSDYrdPhqSILzjTIC/pnXbbJbo+ft+gy/9hQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.3.tgz", + "integrity": "sha512-KHLgC3WKlUYW3ShFKnnosZDOJ0xjg9zp7au3sIm2bs/tGBeC2ipmvRh/N7JKi0t9Ue20C0dpEshi8WUubg+cnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.3.tgz", + "integrity": "sha512-DV6fJoxEYWJOvaZIsok7KrYl0tPvga5OZ2yvKHNNYyk/2roMLqQAbGhr78EQ5YhHpnhLKJD3S1WFusAkmUuV5g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.3.tgz", + "integrity": "sha512-mQKoJAzvuOs6F+TZybQO4GOTSMUu7v0WdxEk24krQ/uUxXoPTtHjuaUuPmFhtBcM4K0ons8nrE3JyhTuCFtT/w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.3.tgz", + "integrity": "sha512-Whjj2qoiJ6+OOJMGptTYazaJvjOJm+iKHpXQM1P3LzGjt7Ff++Tp7nH4N8J/BUA7R9IHfDyx4DJIflifwnbmIA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.3.tgz", + "integrity": "sha512-4YTNHKqGng5+yiZt3mg77nmyuCfmNfX4fPmyUapBcIk+BdwSwmCWGXOUxhXbBEkFHtoN5boLj/5NON+u5QC9tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.3.tgz", + "integrity": "sha512-SU3kNlhkpI4UqlUc2VXPGK9o886ZsSeGfMAX2ba2b8DKmMXq4AL7KUrkSWVbb7koVqx41Yczx6dx5PNargIrEA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.3.tgz", + "integrity": "sha512-6lDLl5h4TXpB1mTf2rQWnAk/LcXrx9vBfu/DT5TIPhvMhRWaZ5MxkIc8u4lJAmBo6klTe1ywXIUHFjylW505sg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.3.tgz", + "integrity": "sha512-BMo8bOw8evlup/8G+cj5xWtPyp93xPdyoSN16Zy90Q2QZ0ZYRhCt6ZJSwbrRzG9HApFabjwj2p25TUPDWrhzqQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.3.tgz", + "integrity": "sha512-E0L8X1dZN1/Rph+5VPF6Xj2G7JJvMACVXtamTJIDrVI44Y3K+G8gQaMEAavbqCGTa16InptiVrX6eM6pmJ+7qA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.3.tgz", + "integrity": "sha512-oZJ/WHaVfHUiRAtmTAeo3DcevNsVvH8mbvodjZy7D5QKvCefO371SiKRpxoDcCxB3PTRTLayWBkvmDQKTcX/sw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.3.tgz", + "integrity": "sha512-Dhbyh7j9FybM3YaTgaHmVALwA8AkUwTPccyCQ79TG9AJUsMQqgN1DDEZNr4+QUfwiWvLDumW5vdwzoeUF+TNxQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.3.tgz", + "integrity": "sha512-cJd1X5XhHHlltkaypz1UcWLA8AcoIi1aWhsvaWDskD1oz2eKCypnqvTQ8ykMNI0RSmm7NkTdSqSSD7zM0xa6Ig==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.3.tgz", + "integrity": "sha512-DAZDBHQfG2oQuhY7mc6I3/qB4LU2fQCjRvxbDwd/Jdvb9fypP4IJ4qmtu6lNjes6B531AI8cg1aKC2di97bUxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.3.tgz", + "integrity": "sha512-cRxsE8c13mZOh3vP+wLDxpQBRrOHDIGOWyDL93Sy0Ga8y515fBcC2pjUfFwUe5T7tqvTvWbCpg1URM/AXdWIXA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.3.tgz", + "integrity": "sha512-QaWcIgRxqEdQdhJqW4DJctsH6HCmo5vHxY0krHSX4jMtOqfzC+dqDGuHM87bu4H8JBeibWx7jFz+h6/4C8wA5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.3.tgz", + "integrity": "sha512-AaXwSvUi3QIPtroAUw1t5yHGIyqKEXwH54WUocFolZhpGDruJcs8c+xPNDRn4XiQsS7MEwnYsHW2l0MBLDMkWg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.3.tgz", + "integrity": "sha512-65LAKM/bAWDqKNEelHlcHvm2V+Vfb8C6INFxQXRHCvaVN1rJfwr4NvdP4FyzUaLqWfaCGaadf6UbTm8xJeYfEg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.3.tgz", + "integrity": "sha512-EEM2gyhBF5MFnI6vMKdX1LAosE627RGBzIoGMdLloPZkXrUN0Ckqgr2Qi8+J3zip/8NVVro3/FjB+tjhZUgUHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.3.tgz", + "integrity": "sha512-E5Eb5H/DpxaoXH++Qkv28RcUJboMopmdDUALBczvHMf7hNIxaDZqwY5lK12UK1BHacSmvupoEWGu+n993Z0y1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.3.tgz", + "integrity": "sha512-hPt/bgL5cE+Qp+/TPHBqptcAgPzgj46mPcg/16zNUmbQk0j+mOEQV/+Lqu8QRtDV3Ek95Q6FeFITpuhl6OTsAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/node-core-library": { + "version": "5.23.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.23.1.tgz", + "integrity": "sha512-wlKmIKIYCKuCASbITvOxLZXepPbwXvrv7S6ig6XNWFchSyhL/E2txmVXspHY49Wu2dzf7nI27a2k/yV5BA3EiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "~8.18.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.7.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.3.tgz", + "integrity": "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jju": "~1.4.0", + "resolve": "~1.22.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.0.tgz", + "integrity": "sha512-8ZQS4MMaGsv27EXCBiH7WMPkRZrffeDoIevs6z9TM5dzqiY6+Hn4evfK/G+gvgBTjfvfkHIZPQQmalmI2sM4TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.1", + "@rushstack/problem-matcher": "0.2.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.9.tgz", + "integrity": "sha512-GIHqU+sRGQ3LGWAZu1O+9Yh++qwtyNIIGuNbcWHJjBTm2qRez0cwINUHZ+pQLR8UuzZDcMajrDaNbUYoaL/XtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.24.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.19.0" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.34.tgz", + "integrity": "sha512-s9cLyK5mLcvZ4Agva5QgRsQyLKvts9WbU9DB6NqiZkkGEdwmcEiylj5Jbwkp680drF/NNCV8OlAJSe+yMLxaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.34", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.34.tgz", + "integrity": "sha512-EbF/T++k0e2MMZlJsBhzK8Sgwt0HcIPOhzn1CTB/lv6sQcyk+OWf8YeiLxZp3ro7MbbLcAfAJ6sEvjFWuNgUCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.34", + "@vue/shared": "3.5.34" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/language-core/node_modules/brace-expansion": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.34", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.34.tgz", + "integrity": "sha512-24uqU4OIiX29ryC3MeWid/Xf2fa2EFRUVLb77nRhk+UrTVrh/XiGtFAFmJBAtBRbjwNdsPRP+jj/OL27Eg1NDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flatbuffers": { + "version": "25.9.23", + "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz", + "integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==", + "license": "Apache-2.0" + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/guid-typescript": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", + "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/minimatch": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/onnxruntime-common": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.25.1.tgz", + "integrity": "sha512-kKvYQFdos4LWJqhZ+nmKu3NT8NXzw8I5x9fNUKe1rNKcPfNKnYXUtW7JBpcKFsvLtrJashRgVYSbFap4cHxvNg==", + "license": "MIT" + }, + "node_modules/onnxruntime-web": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.25.1.tgz", + "integrity": "sha512-mgs61sJ9m3hLa5jGRr9Pen3kkG00vlxmrcRL6FufYpSWBZKaklo0sotQCq2fLjgDVLnW57jrDcLqzYJNKeZskQ==", + "license": "MIT", + "dependencies": { + "flatbuffers": "^25.1.24", + "guid-typescript": "^1.0.9", + "long": "^5.2.3", + "onnxruntime-common": "1.25.1", + "platform": "^1.3.6", + "protobufjs": "^7.2.4" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "license": "MIT" + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prettier": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/protobufjs": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.6.tgz", + "integrity": "sha512-M71sTMB146U3u0di3yup8iM+zv8yPRNQVr1KK4tyBitl3qFvEGucq/rGDRShD2rsJhtN02RJaJ7j5X5hmy8SJg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.1", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + } + }, + "node_modules/rollup": { + "version": "4.60.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.3.tgz", + "integrity": "sha512-pAQK9HalE84QSm4Po3EmWIZPd3FnjkShVkiMlz1iligWYkWQ7wHYd1PF/T7QZ5TVSD6uSTon5gBVMSM4JfBV+A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.3", + "@rollup/rollup-android-arm64": "4.60.3", + "@rollup/rollup-darwin-arm64": "4.60.3", + "@rollup/rollup-darwin-x64": "4.60.3", + "@rollup/rollup-freebsd-arm64": "4.60.3", + "@rollup/rollup-freebsd-x64": "4.60.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.3", + "@rollup/rollup-linux-arm-musleabihf": "4.60.3", + "@rollup/rollup-linux-arm64-gnu": "4.60.3", + "@rollup/rollup-linux-arm64-musl": "4.60.3", + "@rollup/rollup-linux-loong64-gnu": "4.60.3", + "@rollup/rollup-linux-loong64-musl": "4.60.3", + "@rollup/rollup-linux-ppc64-gnu": "4.60.3", + "@rollup/rollup-linux-ppc64-musl": "4.60.3", + "@rollup/rollup-linux-riscv64-gnu": "4.60.3", + "@rollup/rollup-linux-riscv64-musl": "4.60.3", + "@rollup/rollup-linux-s390x-gnu": "4.60.3", + "@rollup/rollup-linux-x64-gnu": "4.60.3", + "@rollup/rollup-linux-x64-musl": "4.60.3", + "@rollup/rollup-openbsd-x64": "4.60.3", + "@rollup/rollup-openharmony-arm64": "4.60.3", + "@rollup/rollup-win32-arm64-msvc": "4.60.3", + "@rollup/rollup-win32-ia32-msvc": "4.60.3", + "@rollup/rollup-win32-x64-gnu": "4.60.3", + "@rollup/rollup-win32-x64-msvc": "4.60.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", + "license": "MIT" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/vite": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite-plugin-static-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.4.0.tgz", + "integrity": "sha512-ekryzCw0ouAOE8tw4RvVL/dfqguXzumsV3FBKoKso4MQ1MUUrUXtl5RI4KpJQUNGqFEsg9kxl4EvDl02YtA9VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "p-map": "^7.0.4", + "picocolors": "^1.1.1", + "tinyglobby": "^0.2.15" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/sapphi-red" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/web/package.json b/web/package.json new file mode 100644 index 00000000..a6993586 --- /dev/null +++ b/web/package.json @@ -0,0 +1,59 @@ +{ + "name": "@anira-project/anira", + "version": "0.0.1-alpha.2", + "license": "Apache-2.0", + "homepage": "https://github.com/anira-project/anira", + "repository": { + "type": "git", + "url": "https://github.com/anira-project/anira.git", + "directory": "web" + }, + "publishConfig": { + "access": "public" + }, + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./workers/inference-worker": { + "types": "./dist/workers/inference-worker.d.ts", + "import": "./dist/workers/inference-worker.js" + }, + "./workers/audio-worklet": { + "types": "./dist/workers/audio-worklet.d.ts", + "import": "./dist/workers/audio-worklet.js" + }, + "./workers/worklet-base": { + "types": "./dist/workers/worklet-base.d.ts", + "import": "./dist/workers/worklet-base.js" + }, + "./wasm/*": "./dist/wasm/*" + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsc && vite build", + "dev": "vite build --watch", + "format": "prettier . --write" + }, + "devDependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "prettier": "^3.8.3", + "rollup": "^4.60.0", + "typescript": "~5.9.3", + "vite": "^8.0.8", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-static-copy": "^3.2.0" + }, + "dependencies": { + "onnxruntime-web": "^1.19.2" + }, + "packageManager": "npm@11.6.2" +} diff --git a/web/src/AniraWeb.ts b/web/src/AniraWeb.ts new file mode 100644 index 00000000..33ef949e --- /dev/null +++ b/web/src/AniraWeb.ts @@ -0,0 +1,511 @@ +import { JSBackendBase } from './backends' +import { ONNXRuntimeWebBackend } from './backends/ONNXRuntimeWebBackend' +import { + createAniraWasm, + getWasmUrl, + type AniraWasmConfig, + type AniraWasmInstance, +} from './factory' +import { createFactory, type Factory } from './utils' +import type { + AudioWorkletConfigureMessage, + AudioWorkletIOConfig, + DestroyMessage, + InitInferenceWorkerMessage, + RegisterProcessorMessage, + UnregisterProcessorMessage, + StartMessage, +} from './workers/messages' +import { waitForWorkerMessage } from './workers/messages' +import { + BufferF, + HostConfig, + InferenceConfig, + InferenceHandler, + JSPrePostProcessor, + ModelData, + PrePostProcessor, + ProcessingSpec, + RingBuffer, + TensorShape, + TensorShapeList, + VectorBufferF, + VectorFloat, + VectorInt64T, + VectorModelData, + VectorRingBuffer, + VectorSizeT, + VectorTensorShape, + VectorUnsignedInt, + VectorVectorInt64, + createInferenceBackend, + type InferenceBackendValues, +} from './wrappers' +import { resolvePtr, type PossiblePointer } from './wrappers/BaseWrapper' +import { InferenceThread } from './wrappers/system/InferenceThread' + +export type ConfigureAudioWorkletIOOptions = Partial & { + /** + * Overrides for the underlying `AudioWorkletNode` constructor options. + * + * By default, the Web Audio node topology is derived from `inputChannels` / + * `outputChannels` (i.e. `channelCount`, `channelCountMode: 'explicit'`, and + * `outputChannelCount`). When anira's internal buffer shape does not match + * the Web Audio channel layout (e.g. extra scratch channels for auxiliary + * tensors), pass overrides here. Provided fields are merged on top of the + * library defaults. + */ + audioWorkletNodeOptions?: AudioWorkletNodeOptions +} + +export type ProcessorDescriptor = { + backend: JSBackendBase + className: string +} + +export type InferenceWorker = { + worker: Worker + registerProcessor: (descriptor: ProcessorDescriptor) => Promise + unregisterProcessor: (backend: JSBackendBase) => Promise + stop: () => Promise +} + +export class AniraWeb { + protected wasmInstance: AniraWasmInstance + protected memory: WebAssembly.Memory + protected wasmBinary: ArrayBuffer | null = null + private registeredProcessors: ProcessorDescriptor[] = [] + private activeWorkers: InferenceWorker[] = [] + + InferenceBackend: InferenceBackendValues + Buffer: Factory + HostConfig: Factory + InferenceConfig: Factory + InferenceHandler: Factory + JSBackendBase: Factory + ONNXRuntimeWebBackend: Factory + JSPrePostProcessor: Factory + ModelData: Factory + PrePostProcessor: Factory + ProcessingSpec: Factory + RingBuffer: Factory + TensorShape: Factory + InferenceThread: Factory + VectorBufferF: Factory + VectorFloat: Factory + VectorInt64T: Factory + VectorModelData: Factory + VectorRingBuffer: Factory + VectorSizeT: Factory + VectorTensorShape: Factory + VectorUnsignedInt: Factory + VectorVectorInt64: Factory + TensorShapeList: Factory + + private static async initWasm( + config?: AniraWasmConfig & Record, + memory?: WebAssembly.Memory + ) { + const wasmMemory = + memory ?? + new WebAssembly.Memory({ + initial: 8192, + maximum: 8192, + shared: true, + }) + const wasmInstance = await createAniraWasm(wasmMemory, config ?? {}) + return { wasmInstance, wasmMemory } + } + + /** + * Instantiate the WASM module and return a ready-to-use ``AniraWeb``. + * This is the standard entry point — see :doc:`../../basic_usage`. + * + * @param config - Optional Emscripten module overrides plus an + * ``processPrePost`` hook for users running their own JS pre/post + * dispatch outside the registry. Most callers pass nothing. + * @param memory - Optional pre-allocated shared + * ``WebAssembly.Memory``. Used when reusing memory across + * multiple ``AniraWeb`` instances; defaults to a fresh 8192-page + * shared memory. + */ + static async create( + config?: AniraWasmConfig & Record, + memory?: WebAssembly.Memory + ): Promise { + const init = await AniraWeb.initWasm(config, memory) + return new AniraWeb(init.wasmInstance, init.wasmMemory) + } + + constructor(module: AniraWasmInstance, memory: WebAssembly.Memory) { + this.wasmInstance = module + this.memory = memory + + this.InferenceBackend = createInferenceBackend(module) + this.Buffer = createFactory(module, BufferF) + this.HostConfig = createFactory(module, HostConfig) + this.InferenceConfig = createFactory(module, InferenceConfig) + this.InferenceHandler = createFactory(module, InferenceHandler) + this.JSBackendBase = createFactory(module, JSBackendBase) + this.ONNXRuntimeWebBackend = createFactory(module, ONNXRuntimeWebBackend) + this.JSPrePostProcessor = createFactory(module, JSPrePostProcessor) + this.ModelData = createFactory(module, ModelData) + this.PrePostProcessor = createFactory(module, PrePostProcessor) + this.ProcessingSpec = createFactory(module, ProcessingSpec) + this.RingBuffer = createFactory(module, RingBuffer) + this.TensorShape = createFactory(module, TensorShape) + this.InferenceThread = createFactory(module, InferenceThread) + this.VectorBufferF = createFactory(module, VectorBufferF) + this.VectorFloat = createFactory(module, VectorFloat) + this.VectorInt64T = createFactory(module, VectorInt64T) + this.VectorModelData = createFactory(module, VectorModelData) + this.VectorRingBuffer = createFactory(module, VectorRingBuffer) + this.VectorSizeT = createFactory(module, VectorSizeT) + this.VectorTensorShape = createFactory(module, VectorTensorShape) + this.VectorUnsignedInt = createFactory(module, VectorUnsignedInt) + this.VectorVectorInt64 = createFactory(module, VectorVectorInt64) + this.TensorShapeList = createFactory(module, TensorShapeList) + } + + /** + * Restore Emscripten's stack pointer to a previously saved value. + * Used internally when re-entering WASM from a worker thread; rarely + * needed in user code. + */ + stackRestore(ptr: number): void { + this.wasmInstance.stackRestore(ptr) + } + + /** Allocate ``size`` bytes in the WASM heap and return the pointer. */ + malloc(size: number): number { + return this.wasmInstance._malloc(size) + } + + /** Free a pointer previously returned by :js:meth:`malloc`. */ + free(ptr: number): void { + this.wasmInstance._free(ptr) + } + + /** Return the shared ``WebAssembly.Memory`` backing the WASM module. */ + getMemory(): WebAssembly.Memory { + return this.memory + } + + /** + * Return the underlying Emscripten module instance. Use this to call + * raw WASM exports directly when the high-level wrappers don't cover + * what you need. + */ + getWasmInstance(): AniraWasmInstance { + return this.wasmInstance + } + + /** + * Return a ``Float32Array`` view over the WASM module's ``HEAPF32`` + * buffer. Useful for reading or writing float32 data at raw heap + * offsets. + */ + getHeapF32(): Float32Array { + return this.wasmInstance.HEAPF32 + } + + /** + * Return a ``Uint32Array`` view over the WASM module's ``HEAPU32`` + * buffer. Useful for reading or writing pointer-sized values at raw + * heap offsets — for example the channel pointer arrays referenced + * by :js:meth:`AniraAudioWorkletBase.buildMultiTensorPointers`. + */ + getHeapU32(): Uint32Array { + return this.wasmInstance.HEAPU32 + } + + // ---- General utilities ---- + + /** + * Encode ``str`` as a null-terminated UTF-8 string in the WASM + * heap and return the pointer. The caller is responsible for + * :js:meth:`free`-ing the returned pointer when done. + */ + allocWasmString(str: string): number { + const bytes = new TextEncoder().encode(str + '\0') + const ptr = this.wasmInstance._malloc(bytes.length) + new Uint8Array(this.wasmInstance.HEAPU32.buffer, ptr, bytes.length).set(bytes) + return ptr + } + + // ---- Worker & Audio Worklet helpers ---- + + protected async ensureWasmBinary(): Promise { + if (!this.wasmBinary) { + const res = await fetch(getWasmUrl()) + this.wasmBinary = await res.arrayBuffer() + } + return this.wasmBinary + } + + protected static readonly WORKER_STACK_SIZE = 4194304 // 4 MB per worker stack + + protected allocateWorkerStack(): number { + const base = this.malloc(AniraWeb.WORKER_STACK_SIZE) + if (!base) throw new Error('Failed to allocate worker stack') + return base + AniraWeb.WORKER_STACK_SIZE + } + + protected freeWorkerStack(stackTop: number): void { + this.free(stackTop - AniraWeb.WORKER_STACK_SIZE) + } + + /** + * Register a custom JS inference backend so the inference worker + * can dispatch into it. Required for any backend that uses + * ``InferenceBackend.CUSTOM`` — see :doc:`../../custom_inference_backends`. + * The descriptor is also forwarded to all currently-running + * inference workers so they can construct the backend on their side. + */ + async registerProcessor(backend: JSBackendBase, className: string): Promise { + const descriptor: ProcessorDescriptor = { backend, className } + this.registeredProcessors.push(descriptor) + await Promise.all(this.activeWorkers.map((w) => w.registerProcessor(descriptor))) + } + + /** + * Inverse of :js:meth:`registerProcessor`. Removes the descriptor from the + * main-thread registry and instructs all active inference workers to destroy + * and deregister the backend (releasing any resources such as ORT sessions). + */ + async unregisterProcessor(backend: JSBackendBase): Promise { + const idx = this.registeredProcessors.findIndex((d) => d.backend === backend) + if (idx !== -1) this.registeredProcessors.splice(idx, 1) + await Promise.all(this.activeWorkers.map((w) => w.unregisterProcessor(backend))) + } + + /** + * Return the inference workers currently spawned by this + * ``AniraWeb``. The list is updated automatically when + * :js:meth:`spinUpInferenceWorker` adds a worker or + * ``InferenceWorker.stop`` removes one. + */ + getActiveWorkers(): readonly InferenceWorker[] { + return this.activeWorkers + } + + /** + * Spawn a new inference worker (a Web Worker hosting an + * ``InferenceThread``) and return its handle. Inference runs there + * instead of on the audio thread, keeping the audio worklet + * real-time-safe. Spin up multiple workers to run inference on + * multiple batches in parallel — see :doc:`../../architecture`. + * + * @param workerOrUrl - Optional override for the worker entry point. + * Pass a ``URL`` to load a custom worker file (used by user-written + * JS backends, see :doc:`../../custom_inference_backends`), or an + * already-constructed ``Worker`` instance to take ownership of one + * you spawned yourself. Omit to use anira's bundled default worker. + */ + async spinUpInferenceWorker(workerOrUrl?: Worker | URL): Promise { + const inferenceThread = this.InferenceThread() + + const inferenceStackPtr = this.allocateWorkerStack() + let worker: Worker + if (workerOrUrl instanceof Worker) { + worker = workerOrUrl + } else if (workerOrUrl) { + worker = new Worker(workerOrUrl, { type: 'module' }) + } else { + worker = new Worker(new URL('./workers/inference-worker.ts', import.meta.url), { + type: 'module', + }) + } + + worker.postMessage({ + type: 'initInferenceWorker', + wasmMemory: this.memory, + stackPtr: inferenceStackPtr, + threadPtr: inferenceThread.getPointer(), + } satisfies InitInferenceWorkerMessage) + await waitForWorkerMessage(worker, 'ready') + + for (const { backend, className } of this.registeredProcessors) { + worker.postMessage({ + type: 'registerProcessor', + processorPtr: backend.getPointer(), + className, + inferenceConfigPtr: backend.inferenceConfigPtr || undefined, + } satisfies RegisterProcessorMessage) + await waitForWorkerMessage(worker, 'processorRegistered') + } + + inferenceThread.start() + worker.postMessage({ type: 'start' } satisfies StartMessage) + + const inferenceWorker: InferenceWorker = { + worker, + registerProcessor: async (descriptor: ProcessorDescriptor) => { + inferenceThread.stop() + await waitForWorkerMessage(worker, 'stopped') + + worker.postMessage({ + type: 'registerProcessor', + processorPtr: descriptor.backend.getPointer(), + className: descriptor.className, + inferenceConfigPtr: descriptor.backend.inferenceConfigPtr || undefined, + } satisfies RegisterProcessorMessage) + await waitForWorkerMessage(worker, 'processorRegistered') + + inferenceThread.start() + worker.postMessage({ type: 'start' } satisfies StartMessage) + }, + unregisterProcessor: async (backend: JSBackendBase) => { + inferenceThread.stop() + await waitForWorkerMessage(worker, 'stopped') + + worker.postMessage({ + type: 'unregisterProcessor', + processorPtr: backend.getPointer(), + } satisfies UnregisterProcessorMessage) + await waitForWorkerMessage(worker, 'processorUnregistered') + + inferenceThread.start() + worker.postMessage({ type: 'start' } satisfies StartMessage) + }, + stop: async () => { + inferenceThread.stop() + await waitForWorkerMessage(worker, 'stopped') + worker.postMessage({ type: 'destroy' } satisfies DestroyMessage) + inferenceThread.destroy() + this.freeWorkerStack(inferenceStackPtr) + const idx = this.activeWorkers.indexOf(inferenceWorker) + if (idx !== -1) this.activeWorkers.splice(idx, 1) + }, + } + + this.activeWorkers.push(inferenceWorker) + return inferenceWorker + } + + /** + * Install anira's audio worklet module on the given ``AudioContext``. + * Must be called once per context before + * :js:meth:`configureAudioWorklet`. + * + * @param audioContext - The Web Audio context to install the + * worklet on. + * @param workletUrl - Optional URL of a custom worklet file (a + * subclass of :js:class:`AniraAudioWorkletBase`, see + * :doc:`../../custom_audio_worklets`). Omit to use anira's bundled + * default worklet, which handles the simple single-tensor case. + */ + async registerAudioWorkletForContext( + audioContext: AudioContext, + workletUrl?: string | URL + ): Promise { + const url = + workletUrl ?? new URL('./workers/audio-worklet.bundled.js', import.meta.url) + await audioContext.audioWorklet.addModule(url) + } + + /** + * Construct an ``AudioWorkletNode`` wired to ``inferenceHandlerPtr`` + * and ``prePostProcessorPtr`` and complete the configure handshake + * so the worklet is ready to process audio. Allocates the input / + * output scratch buffers in WASM memory and posts them to the + * worklet thread. + * + * @param audioContext - The Web Audio context to attach the node to. + * @param inferenceHandlerPtr - The :js:class:`InferenceHandler` (or + * its raw pointer) that will run inference for this worklet. + * @param prePostProcessorPtr - The :js:class:`PrePostProcessor` + * used during inference. + * @param audioWorkletNodeName - Processor name registered via + * ``registerProcessor`` inside the worklet file. Defaults to + * ``'inference-processor'`` (the bundled default worklet's name). + * @param ioOptions - Channel counts, ``maxBufferSize``, and + * optional ``audioWorkletNodeOptions`` overrides. See + * :doc:`../../custom_audio_worklets` for the multi-tensor and + * custom-buffer-size cases. + * @returns The connected, ready-to-use ``AudioWorkletNode``. + */ + async configureAudioWorklet( + audioContext: AudioContext, + inferenceHandlerPtr: PossiblePointer, + prePostProcessorPtr: PossiblePointer, + audioWorkletNodeName = 'inference-processor', + ioOptions: ConfigureAudioWorkletIOOptions = {} + ): Promise { + const wasmMemory = this.memory + const ioConfig: AudioWorkletIOConfig = { + maxBufferSize: ioOptions.maxBufferSize ?? 1024, + inputNodeIndex: ioOptions.inputNodeIndex ?? 0, + outputNodeIndex: ioOptions.outputNodeIndex ?? 0, + inputChannels: ioOptions.inputChannels ?? 2, + outputChannels: ioOptions.outputChannels ?? 2, + } + + if ( + ioConfig.maxBufferSize <= 0 || + ioConfig.inputChannels <= 0 || + ioConfig.outputChannels <= 0 + ) { + throw new Error( + 'Invalid AudioWorklet IO config: sizes and channel counts must be > 0' + ) + } + + const wasmBinary = await this.ensureWasmBinary() + + const nodeOptions: AudioWorkletNodeOptions = { + channelCount: ioConfig.inputChannels, + channelCountMode: 'explicit', + outputChannelCount: [ioConfig.outputChannels], + ...ioOptions.audioWorkletNodeOptions, + } + const inferenceNode = new AudioWorkletNode( + audioContext, + audioWorkletNodeName, + nodeOptions + ) + const processStackPtr = this.allocateWorkerStack() + const bytesPerChannel = ioConfig.maxBufferSize * Float32Array.BYTES_PER_ELEMENT + + const inputDataBuffer = this.malloc(bytesPerChannel * ioConfig.inputChannels) + const outputDataBuffer = this.malloc(bytesPerChannel * ioConfig.outputChannels) + + const inputBufferPtr = this.malloc(ioConfig.inputChannels * 4) + const outputBufferPtr = this.malloc(ioConfig.outputChannels * 4) + + const inputPtrArray = new Uint32Array( + wasmMemory.buffer, + inputBufferPtr, + ioConfig.inputChannels + ) + const outputPtrArray = new Uint32Array( + wasmMemory.buffer, + outputBufferPtr, + ioConfig.outputChannels + ) + for (let i = 0; i < ioConfig.inputChannels; i++) { + inputPtrArray[i] = inputDataBuffer + i * bytesPerChannel + } + for (let i = 0; i < ioConfig.outputChannels; i++) { + outputPtrArray[i] = outputDataBuffer + i * bytesPerChannel + } + + inferenceNode.port.start() + inferenceNode.port.postMessage({ + type: 'configure', + wasmMemory, + wasmBinary, + stackPtr: processStackPtr, + inferenceHandlerPtr: resolvePtr(inferenceHandlerPtr), + prePostProcessorPtr: resolvePtr(prePostProcessorPtr), + inputBufferPtr, + outputBufferPtr, + inputDataBuffer, + outputDataBuffer, + ioConfig, + } satisfies AudioWorkletConfigureMessage) + + await waitForWorkerMessage(inferenceNode.port, 'ready') + return inferenceNode + } +} diff --git a/web/src/backends/JSBackendBase.ts b/web/src/backends/JSBackendBase.ts new file mode 100644 index 00000000..312b28ab --- /dev/null +++ b/web/src/backends/JSBackendBase.ts @@ -0,0 +1,41 @@ +import type { AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from '../wrappers/BaseWrapper' +import type { InferenceConfig } from '../wrappers/InferenceConfig' + +/** + * TypeScript wrapper for JSBackendBase. + * Each instance is identified by its C++ pointer and carries its own + * `process` implementation that the inference worker dispatches to. + */ +export class JSBackendBase extends BaseWrapper { + /** Pointer to the C++ InferenceConfig used to create this processor. */ + inferenceConfigPtr: number = 0 + + constructor( + wasmInstance: AniraWasmInstance, + inferenceConfig: PossiblePointer + ) { + const configPtr = resolvePtr(inferenceConfig) + super(wasmInstance, wasmInstance._jsprocessor_create(configPtr)) + this.inferenceConfigPtr = configPtr + } + + async init(): Promise { + // Override in subclass if needed + } + + /** + * Destroy this buffer and free memory + */ + destroy(): void { + this._destroy(this.wasmInstance._jsprocessor_destroy) + } + + /** + * Process buffers. Called by the inference worker when C++ invokes the + * JS callback. Override in a subclass to implement custom processing. + */ + process(inputVecPtr: number, outputVecPtr: number): void { + this.wasmInstance._jsprocessor_wasm_process(this.ptr, inputVecPtr, outputVecPtr) + } +} diff --git a/web/src/backends/ONNXRuntimeWebBackend.ts b/web/src/backends/ONNXRuntimeWebBackend.ts new file mode 100644 index 00000000..85e46ab5 --- /dev/null +++ b/web/src/backends/ONNXRuntimeWebBackend.ts @@ -0,0 +1,559 @@ +import { JSBackendBase } from './JSBackendBase' +import { BufferF } from '../wrappers/utils/BufferF' +import { VectorBufferF } from '../wrappers/Vectors' +import { InferenceConfig } from '../wrappers/InferenceConfig' +import { ModelData } from '../wrappers/ModelData' + +// onnxruntime-web 1.19.2 doesn't expose this WASM module factory via its +// package `exports` field. The Vite config aliases this specifier to +// node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs. +import ortWasmFactory from 'onnxruntime-web/ort-wasm-simd-threaded.mjs' +import { createInferenceBackend } from '../wrappers' + +// Shared ORT WASM module — loaded once and reused across all backend instances +// to avoid accumulating WebAssembly.Memory allocations (causes OOM on Safari). +let ortModulePromise: Promise | null = null + +/** + * Minimal type for the ORT WASM Emscripten module instance. + * We use the module directly for synchronous access to the C API. + */ +export interface OrtWasmModule { + _OrtInit(numThreads: number, loggingLevel: number): number + _OrtCreateSessionOptions( + graphOptLevel: number, + enableCpuMemArena: number, + enableMemPattern: number, + executionMode: number, + enableProfiling: number, + profileFilePrefix: number, + logId: number, + logSeverityLevel: number, + logVerbosityLevel: number, + optimizedModelFilePath: number + ): number + _OrtReleaseSessionOptions(handle: number): number + _OrtCreateSession( + modelData: number, + modelDataLength: number, + sessionOptions: number + ): number + _OrtReleaseSession(handle: number): number + _OrtGetInputOutputCount( + sessionHandle: number, + inputCountOffset: number, + outputCountOffset: number + ): number + _OrtGetInputOutputMetadata( + sessionHandle: number, + index: number, + nameOffset: number, + metadataOffset: number + ): number + _OrtCreateTensor( + dataType: number, + data: number, + dataByteLength: number, + dimsOffset: number, + dimsLength: number, + dataLocation: number + ): number + _OrtReleaseTensor(handle: number): number + _OrtRun( + sessionHandle: number, + inputNamesOffset: number, + inputValuesOffset: number, + inputCount: number, + outputNamesOffset: number, + outputCount: number, + outputValuesOffset: number, + runOptionsHandle: number + ): number + _OrtGetTensorData( + tensorHandle: number, + dataTypeOffset: number, + dataOffset: number, + dimsOffset: number, + dimsLengthOffset: number + ): number + _OrtGetLastError(errorCodeOffset: number, errorMessageOffset: number): void + _OrtCreateRunOptions( + logSeverityLevel: number, + logVerbosityLevel: number, + terminate: number, + tag: number + ): number + _OrtReleaseRunOptions(handle: number): number + _OrtFree(ptr: number): number + _malloc(size: number): number + _free(ptr: number): void + stackSave(): number + stackRestore(ptr: number): void + stackAlloc(size: number): number + setValue(ptr: number, value: number, type: string): void + getValue(ptr: number, type: string): number + UTF8ToString(ptr: number): string + HEAPU8: Uint8Array + HEAP32: Int32Array + HEAPU32: Uint32Array + HEAPF32: Float32Array + PTR_SIZE: number +} + +/** Per-input/output metadata stored after session creation. */ +interface TensorMeta { + namePtr: number + dims: number[] + flatSize: number +} + +/** + * ONNX Runtime Web backend implementation. + * Loads the ORT WASM module directly for synchronous inference in the + * process() callback, mirroring the native OnnxRuntimeProcessor. + */ +export class ONNXRuntimeWebBackend extends JSBackendBase { + private ort: OrtWasmModule | null = null + private sessionHandle: number = 0 + private runOptionsHandle: number = 0 + private inputMeta: TensorMeta[] = [] + private outputMeta: TensorMeta[] = [] + + /** + * Async initialization: loads the ORT WASM module, creates an inference + * session from the model binary stored in anira's shared WASM memory. + * Called automatically by the worker handler after processor registration. + */ + async init(): Promise { + const m = this.wasmInstance + const inferenceBackend = createInferenceBackend(m) + const configPtr = this.inferenceConfigPtr + if (!configPtr) { + throw new Error( + 'ONNXRuntimeWebBackend: no inferenceConfigPtr – was the backend registered correctly?' + ) + } + + // --- Extract model binary from anira WASM memory --- + const config = this.wrapPointer(InferenceConfig, configPtr) + const customBackend = inferenceBackend.CUSTOM + const modelDataPtr = config.getModelData(customBackend) + if (!modelDataPtr) { + throw new Error('ONNXRuntimeWebBackend: no model data for CUSTOM backend') + } + + const modelData = this.wrapPointer(ModelData, modelDataPtr) + let modelBytes: Uint8Array + + if (modelData.isBinary()) { + const modelBinaryPtr = modelData.getDataPtr() + const modelSize = modelData.getSize() + modelBytes = new Uint8Array(m.HEAPU32.buffer, modelBinaryPtr, modelSize).slice() + } else { + const pathPtr = modelData.getDataPtr() + const pathLen = modelData.getSize() + const pathBytes = new Uint8Array(m.HEAPU32.buffer, pathPtr, pathLen).slice() + const modelUrl = new TextDecoder().decode(pathBytes) + const response = await fetch(modelUrl) + if (!response.ok) { + throw new Error( + `ONNXRuntimeWebBackend: failed to fetch model from ${modelUrl}: ${response.status}` + ) + } + modelBytes = new Uint8Array(await response.arrayBuffer()) + } + + // --- Load ORT WASM module (shared singleton to avoid repeated memory allocs) --- + ortModulePromise ??= ortWasmFactory({ numThreads: 1 }) as Promise + this.ort = await ortModulePromise + const ort = this.ort + + if (ort._OrtInit(1, 3) !== 0) { + throw new Error('ONNXRuntimeWebBackend: _OrtInit failed') + } + + // --- Create session --- + const sessionOpts = ort._OrtCreateSessionOptions(99, 1, 1, 0, 0, 0, 0, 3, 0, 0) + if (sessionOpts === 0) { + throw new Error('ONNXRuntimeWebBackend: _OrtCreateSessionOptions failed') + } + + const modelOffset = ort._malloc(modelBytes.length) + if (modelOffset === 0) { + throw new Error('ONNXRuntimeWebBackend: ORT _malloc failed for model data') + } + ort.HEAPU8.set(modelBytes, modelOffset) + + this.sessionHandle = ort._OrtCreateSession( + modelOffset, + modelBytes.length, + sessionOpts + ) + ort._free(modelOffset) + ort._OrtReleaseSessionOptions(sessionOpts) + + if (this.sessionHandle === 0) { + const ptrSize = ort.PTR_SIZE + const errStack = ort.stackSave() + const errBuf = ort.stackAlloc(2 * ptrSize) + ort._OrtGetLastError(errBuf, errBuf + ptrSize) + const errCode = Number(ort.getValue(errBuf, ptrSize === 4 ? 'i32' : 'i64')) + const errMsgPtr = Number(ort.getValue(errBuf + ptrSize, '*')) + const errMsg = errMsgPtr ? ort.UTF8ToString(errMsgPtr) : '' + ort.stackRestore(errStack) + throw new Error( + `ONNXRuntimeWebBackend: _OrtCreateSession failed (code=${errCode}): ${errMsg}` + ) + } + + this.runOptionsHandle = ort._OrtCreateRunOptions(2, 0, 0, 0) + if (this.runOptionsHandle === 0) { + throw new Error('ONNXRuntimeWebBackend: _OrtCreateRunOptions failed') + } + + // --- Query input / output metadata --- + const ptrSize = ort.PTR_SIZE + const countStack = ort.stackSave() + const countBuf = ort.stackAlloc(2 * ptrSize) + if ( + ort._OrtGetInputOutputCount(this.sessionHandle, countBuf, countBuf + ptrSize) !== 0 + ) { + ort.stackRestore(countStack) + throw new Error('ONNXRuntimeWebBackend: _OrtGetInputOutputCount failed') + } + const inputCount = Number(ort.getValue(countBuf, ptrSize === 4 ? 'i32' : 'i64')) + const outputCount = Number( + ort.getValue(countBuf + ptrSize, ptrSize === 4 ? 'i32' : 'i64') + ) + ort.stackRestore(countStack) + + this.inputMeta = this.queryMetadata(ort, 0, inputCount) + this.outputMeta = this.queryMetadata(ort, inputCount, outputCount) + + // --- Warm-up inference (non-fatal, matches C++ behaviour) --- + // Skip warm-up when any input has dynamic dims — we can't construct a + // valid concrete shape without actual buffer data. + const hasDynamicDims = this.inputMeta.some((m) => m.dims.includes(-1)) + if (!hasDynamicDims) { + const warmUp = config.getWarmUp() + for (let i = 0; i < warmUp; i++) { + try { + const inputs = this.createZeroInputs() + const outputs = this.runOrt(inputs) + for (const t of outputs) if (t !== 0) ort._OrtReleaseTensor(t) + } catch { + break + } + } + } + } + + override process(inputVecPtr: number, outputVecPtr: number): void { + if (!this.ort || !this.sessionHandle) { + super.process(inputVecPtr, outputVecPtr) + return + } + + const heapF32 = this.wasmInstance.HEAPF32 + const ort = this.ort + const inputVec = this.wrapPointer(VectorBufferF, inputVecPtr) + const outputVec = this.wrapPointer(VectorBufferF, outputVecPtr) + + const numInputBufs = inputVec.size() + const numOutputBufs = outputVec.size() + + const inputTensors: number[] = [] + const allocs: number[] = [] + + try { + // --- Build input tensors from anira buffers --- + for (let i = 0; i < Math.min(numInputBufs, this.inputMeta.length); i++) { + const meta = this.inputMeta[i] + const buf = this.wrapPointer(BufferF, inputVec.get(i)) + const channels = buf.getNumChannels() + const samples = buf.getNumSamples() + const totalFloats = channels * samples + const byteLen = totalFloats * 4 + + const dataOff = ort._malloc(byteLen) + allocs.push(dataOff) + + // Copy channel data linearly into ORT memory + for (let ch = 0; ch < channels; ch++) { + const readPtr = buf.getReadPointer(ch) + const inputOff = readPtr >> 2 + const ortF32 = new Float32Array(ort.HEAPU8.buffer, dataOff, totalFloats) + for (let s = 0; s < samples; s++) { + ortF32[ch * samples + s] = heapF32[inputOff + s] + } + } + + // Resolve dynamic dims (-1) from actual buffer dimensions + const concreteDims = this.resolveDynamicDims(meta.dims, totalFloats) + + const stack = ort.stackSave() + const dimsOff = ort.stackAlloc(concreteDims.length * ort.PTR_SIZE) + for (let d = 0; d < concreteDims.length; d++) { + ort.setValue( + dimsOff + d * ort.PTR_SIZE, + concreteDims[d], + ort.PTR_SIZE === 4 ? 'i32' : 'i64' + ) + } + const tensor = ort._OrtCreateTensor( + 1, + dataOff, + byteLen, + dimsOff, + concreteDims.length, + 1 + ) + ort.stackRestore(stack) + + if (tensor === 0) throw new Error(`Failed to create ORT input tensor ${i}`) + inputTensors.push(tensor) + } + + // --- Run inference --- + const outputs = this.runOrt(inputTensors) + + // --- Copy outputs to anira buffers --- + const ptrSize = ort.PTR_SIZE + for ( + let i = 0; + i < Math.min(numOutputBufs, this.outputMeta.length, outputs.length); + i++ + ) { + const outTensor = outputs[i] + if (outTensor === 0) continue + + const stack = ort.stackSave() + const info = ort.stackAlloc(4 * ptrSize) + ort._OrtGetTensorData( + outTensor, + info, + info + ptrSize, + info + 2 * ptrSize, + info + 3 * ptrSize + ) + const dataPtr = Number(ort.getValue(info + ptrSize, '*')) + ort.stackRestore(stack) + + const outBuf = this.wrapPointer(BufferF, outputVec.get(i)) + const outCh = outBuf.getNumChannels() + const outSamp = outBuf.getNumSamples() + const totalOut = outCh * outSamp + + const ortF32 = new Float32Array(ort.HEAPU8.buffer, dataPtr, totalOut) + for (let ch = 0; ch < outCh; ch++) { + const writePtr = outBuf.getWritePointer(ch) + const writeOff = writePtr >> 2 + for (let s = 0; s < outSamp; s++) { + heapF32[writeOff + s] = ortF32[ch * outSamp + s] + } + } + + ort._OrtReleaseTensor(outTensor) + } + } finally { + for (const t of inputTensors) ort._OrtReleaseTensor(t) + for (const a of allocs) ort._free(a) + } + } + + override destroy(): void { + if (this.ort && this.sessionHandle) { + for (const meta of [...this.inputMeta, ...this.outputMeta]) { + this.ort._OrtFree(meta.namePtr) + } + if (this.runOptionsHandle) { + this.ort._OrtReleaseRunOptions(this.runOptionsHandle) + this.runOptionsHandle = 0 + } + this.ort._OrtReleaseSession(this.sessionHandle) + this.sessionHandle = 0 + } + this.ort = null + this.inputMeta = [] + this.outputMeta = [] + super.destroy() + } + + // ---- private helpers ---- + + /** + * Replace any dynamic dims (-1) with concrete values inferred from the + * total number of elements. Only a single dynamic dim is supported. + */ + private resolveDynamicDims(dims: number[], totalElements: number): number[] { + const dynamicCount = dims.filter((d) => d === -1).length + if (dynamicCount === 0) return dims + + if (dynamicCount > 1) { + throw new Error( + `ONNXRuntimeWebBackend: cannot resolve ${dynamicCount} dynamic dims — at most 1 is supported` + ) + } + + const staticProduct = dims.reduce((a, d) => (d === -1 ? a : a * d), 1) + const inferred = Math.floor(totalElements / staticProduct) + + return dims.map((d) => (d === -1 ? inferred : d)) + } + + private queryMetadata( + ort: OrtWasmModule, + startIndex: number, + count: number + ): TensorMeta[] { + const ptrSize = ort.PTR_SIZE + const result: TensorMeta[] = [] + + for (let i = 0; i < count; i++) { + const stack = ort.stackSave() + let metadataPtr = 0 + try { + const buf = ort.stackAlloc(2 * ptrSize) + if ( + ort._OrtGetInputOutputMetadata( + this.sessionHandle, + startIndex + i, + buf, + buf + ptrSize + ) !== 0 + ) { + throw new Error(`Failed to get metadata for index ${startIndex + i}`) + } + + const namePtr = Number(ort.getValue(buf, '*')) + metadataPtr = Number(ort.getValue(buf + ptrSize, '*')) + + const elementType = ort.HEAP32[metadataPtr >> 2] + if (elementType === 0) { + result.push({ namePtr, dims: [], flatSize: 0 }) + continue + } + + const dimsCount = ort.HEAPU32[(metadataPtr >> 2) + 1] + const dims: number[] = [] + for (let d = 0; d < dimsCount; d++) { + // ORT metadata has two arrays of dimsCount entries each: + // [symbolic name ptrs...][numeric dim values...] + // For dynamic dims, the symbolic name ptr is non-zero and the + // numeric slot is undefined. Use -1 for dynamic dims. + const symbolicNamePtr = Number(ort.getValue(metadataPtr + 8 + d * ptrSize, '*')) + if (symbolicNamePtr !== 0) { + dims.push(-1) + } else { + dims.push( + Number(ort.getValue(metadataPtr + 8 + (d + dimsCount) * ptrSize, '*')) + ) + } + } + + const staticDims = dims.filter((d) => d > 0) + const flatSize = + staticDims.length === dims.length ? staticDims.reduce((a, b) => a * b, 1) : 0 + result.push({ namePtr, dims, flatSize }) + } finally { + ort.stackRestore(stack) + if (metadataPtr !== 0) ort._OrtFree(metadataPtr) + } + } + + return result + } + + private createZeroInputs(): number[] { + const ort = this.ort! + const tensors: number[] = [] + + for (const meta of this.inputMeta) { + // For warm-up, replace dynamic dims (-1) with 1 + const concreteDims = meta.dims.map((d) => (d === -1 ? 1 : d)) + const flatSize = concreteDims.reduce((a, b) => a * b, 1) + const byteLen = flatSize * 4 + const dataOff = ort._malloc(byteLen) + ort.HEAPU8.fill(0, dataOff, dataOff + byteLen) + + const stack = ort.stackSave() + const dimsOff = ort.stackAlloc(concreteDims.length * ort.PTR_SIZE) + for (let d = 0; d < concreteDims.length; d++) { + ort.setValue( + dimsOff + d * ort.PTR_SIZE, + concreteDims[d], + ort.PTR_SIZE === 4 ? 'i32' : 'i64' + ) + } + const tensor = ort._OrtCreateTensor( + 1, + dataOff, + byteLen, + dimsOff, + concreteDims.length, + 1 + ) + ort.stackRestore(stack) + + tensors.push(tensor) + } + + return tensors + } + + private runOrt(inputTensors: number[]): number[] { + const ort = this.ort! + const ptrSize = ort.PTR_SIZE + const inputCount = this.inputMeta.length + const outputCount = this.outputMeta.length + + const stack = ort.stackSave() + const inputNamesOff = ort.stackAlloc(inputCount * ptrSize) + const inputValsOff = ort.stackAlloc(inputCount * ptrSize) + const outputNamesOff = ort.stackAlloc(outputCount * ptrSize) + const outputValsOff = ort.stackAlloc(outputCount * ptrSize) + + for (let i = 0; i < inputCount; i++) { + ort.setValue(inputNamesOff + i * ptrSize, this.inputMeta[i].namePtr, '*') + ort.setValue(inputValsOff + i * ptrSize, inputTensors[i], '*') + } + for (let i = 0; i < outputCount; i++) { + ort.setValue(outputNamesOff + i * ptrSize, this.outputMeta[i].namePtr, '*') + ort.setValue(outputValsOff + i * ptrSize, 0, '*') + } + + const errorCode = ort._OrtRun( + this.sessionHandle, + inputNamesOff, + inputValsOff, + inputCount, + outputNamesOff, + outputCount, + outputValsOff, + this.runOptionsHandle + ) + + const outputs: number[] = [] + for (let i = 0; i < outputCount; i++) { + outputs.push(Number(ort.getValue(outputValsOff + i * ptrSize, '*'))) + } + ort.stackRestore(stack) + + if (errorCode !== 0) { + const errStack = ort.stackSave() + const errBuf = ort.stackAlloc(2 * ptrSize) + ort._OrtGetLastError(errBuf, errBuf + ptrSize) + const errCode = Number(ort.getValue(errBuf, ptrSize === 4 ? 'i32' : 'i64')) + const errMsgPtr = Number(ort.getValue(errBuf + ptrSize, '*')) + const errMsg = errMsgPtr ? ort.UTF8ToString(errMsgPtr) : '' + ort.stackRestore(errStack) + + for (const t of outputs) if (t !== 0) ort._OrtReleaseTensor(t) + throw new Error( + `ONNXRuntimeWebBackend: _OrtRun failed (code=${errCode}): ${errMsg}` + ) + } + + return outputs + } +} diff --git a/web/src/backends/index.ts b/web/src/backends/index.ts new file mode 100644 index 00000000..e549a051 --- /dev/null +++ b/web/src/backends/index.ts @@ -0,0 +1,2 @@ +export { ONNXRuntimeWebBackend } from './ONNXRuntimeWebBackend' +export { JSBackendBase } from './JSBackendBase' diff --git a/web/src/factory.ts b/web/src/factory.ts new file mode 100644 index 00000000..af528e30 --- /dev/null +++ b/web/src/factory.ts @@ -0,0 +1,59 @@ +import AniraWebFactory, { type MainModule } from '../wasm/AniraWeb' + +// Lazy-evaluated so the module can be imported in AudioWorkletGlobalScope +// where URL may not be available. The URLs are only needed on the main thread. +let _jsUrl: string | undefined +let _wasmUrl: string | undefined + +const getJsUrl = () => (_jsUrl ??= new URL('../wasm/AniraWeb.js', import.meta.url).href) +const getWasmUrl = () => + (_wasmUrl ??= new URL('../wasm/AniraWeb.wasm', import.meta.url).href) + +export { getWasmUrl } + +export type AniraWasmConfig = { + processBuffers?: (processorPtr: number, inputPtr: number, outputPtr: number) => void + processPrePost?: ( + prePostProcessorPtr: number, + inputPtr: number, + outputPtr: number, + backend: number, + phase: number + ) => void + wasmBinary?: ArrayBuffer +} + +export type AniraWasmInstance = Omit & { + HEAPF32: Float32Array + HEAPU32: Uint32Array +} + +// Export factory with WASM locateFile override +export const createAniraWasm = async ( + wasmMemory: WebAssembly.Memory, + config?: AniraWasmConfig & Record +): Promise => { + const { processBuffers, processPrePost, wasmBinary, ...rest } = config ?? {} + const out = await AniraWebFactory({ + processBuffers: processBuffers ?? (() => {}), + processPrePost: processPrePost ?? (() => {}), + wasmBinary, + ...rest, + wasmMemory, + locateFile: (path: string) => { + if (path.endsWith('.wasm')) { + return getWasmUrl() + } + if (path.endsWith('.js')) { + return getJsUrl() + } + return path + }, + }) + + return { + ...out, + HEAPF32: out.HEAPF32 as Float32Array, + HEAPU32: out.HEAPU32 as Uint32Array, + } +} diff --git a/web/src/helpers.ts b/web/src/helpers.ts new file mode 100644 index 00000000..c4c47966 --- /dev/null +++ b/web/src/helpers.ts @@ -0,0 +1,62 @@ +import type { AniraWasmInstance } from './factory' +import { BufferF } from './wrappers/utils/BufferF' +import { RingBuffer } from './wrappers/utils/RingBuffer' + +/** + * Mirrors `anira::random_sample()` — uniform sample in [-1.0, 1.0). + */ +export const randomSample = (): number => Math.random() * 2 - 1 + +/** + * Mirrors `anira::fill_buffer(BufferF&)` — overwrites every sample on every + * channel with a fresh `randomSample`. Pure TS; goes through the wrapper + * so it works for any pointer the wrapper owns. + */ +export const fillBuffer = (buffer: BufferF): void => { + const numChannels = buffer.getNumChannels() + const numSamples = buffer.getNumSamples() + for (let i = 0; i < numChannels; i++) { + for (let j = 0; j < numSamples; j++) { + buffer.setSample(i, j, randomSample()) + } + } +} + +/** + * Mirrors `anira::push_buffer_to_ringbuffer(BufferF const&, RingBuffer&)` — + * pushes every sample of every channel into the ring buffer in order. + */ +export const pushBufferToRingbuffer = ( + wasmInstance: AniraWasmInstance, + buffer: BufferF, + ringbuffer: RingBuffer +): void => { + const numChannels = buffer.getNumChannels() + const numSamples = buffer.getNumSamples() + if (numChannels === 0 || numSamples === 0) { + throw new Error('Buffer is empty, cannot push to ring buffer.') + } + const rbPtr = ringbuffer.getPointer() + const rbChannels = wasmInstance._bufferf_get_num_channels(rbPtr) + const rbSamples = wasmInstance._bufferf_get_num_samples(rbPtr) + if (rbChannels === 0 || rbSamples === 0) { + throw new Error('Ring buffer is not initialized, cannot push samples.') + } + for (let i = 0; i < numChannels; i++) { + for (let j = 0; j < numSamples; j++) { + ringbuffer.pushSample(i, buffer.getSample(i, j)) + } + } +} + +/** + * Mirrors `anira::_anira_get_version()` — + * returns the `ANIRA_VERSION` string. + */ +export const getAniraVersion = (wasmInstance: AniraWasmInstance): string => { + const ptr = wasmInstance._anira_get_version() + const view = new Uint8Array(wasmInstance.HEAPU32.buffer, ptr, 256) + let end = 0 + while (end < view.length && view[end] !== 0) end++ + return new TextDecoder().decode(view.subarray(0, end)) +} diff --git a/web/src/index.ts b/web/src/index.ts new file mode 100644 index 00000000..dbe0da0a --- /dev/null +++ b/web/src/index.ts @@ -0,0 +1,20 @@ +export * from './factory' +export * from './AniraWeb' +export * from './wrappers' +export * from './backends' +export * from './workers/inferenceWorkerHandler' +export * from './helpers' + +export { waitForWorkerMessage } from './workers/messages' +export type { + AudioWorkletConfigureMessage, + AudioWorkletIOConfig, + DestroyMessage, + DoneResponse, + InferenceWorkerMessage, + InitInferenceWorkerMessage, + ReadyRespose, + RegisterProcessorMessage, + StartMessage, + StoppedResponse, +} from './workers/messages' diff --git a/web/src/utils.ts b/web/src/utils.ts new file mode 100644 index 00000000..a0de91b4 --- /dev/null +++ b/web/src/utils.ts @@ -0,0 +1,87 @@ +import { type AniraWasmInstance } from './factory' +import { BaseWrapper } from './wrappers' + +/** + * Cascading overload inference: matches the maximum number of distinct + * constructor overloads on `C` (after dropping the leading `wasmInstance` + * parameter) and returns an intersection of call signatures — one per + * overload. Falls through from 6 → 1 so classes with fewer overloads still + * resolve. We can't use `ConstructorParameters` because it only sees the + * last overload, which is why callers like `aniraWeb.ProcessingSpec(a, b, c, d)` + * were rejected with "Expected 5 arguments" even though a 4-arg overload exists. + */ +type OverloadedFactoryFn = C extends { + new (w: AniraWasmInstance, ...a: infer A1): any + new (w: AniraWasmInstance, ...a: infer A2): any + new (w: AniraWasmInstance, ...a: infer A3): any + new (w: AniraWasmInstance, ...a: infer A4): any + new (w: AniraWasmInstance, ...a: infer A5): any + new (w: AniraWasmInstance, ...a: infer A6): any +} + ? ((...args: A1) => R) & + ((...args: A2) => R) & + ((...args: A3) => R) & + ((...args: A4) => R) & + ((...args: A5) => R) & + ((...args: A6) => R) + : C extends { + new (w: AniraWasmInstance, ...a: infer A1): any + new (w: AniraWasmInstance, ...a: infer A2): any + new (w: AniraWasmInstance, ...a: infer A3): any + new (w: AniraWasmInstance, ...a: infer A4): any + new (w: AniraWasmInstance, ...a: infer A5): any + } + ? ((...args: A1) => R) & + ((...args: A2) => R) & + ((...args: A3) => R) & + ((...args: A4) => R) & + ((...args: A5) => R) + : C extends { + new (w: AniraWasmInstance, ...a: infer A1): any + new (w: AniraWasmInstance, ...a: infer A2): any + new (w: AniraWasmInstance, ...a: infer A3): any + new (w: AniraWasmInstance, ...a: infer A4): any + } + ? ((...args: A1) => R) & + ((...args: A2) => R) & + ((...args: A3) => R) & + ((...args: A4) => R) + : C extends { + new (w: AniraWasmInstance, ...a: infer A1): any + new (w: AniraWasmInstance, ...a: infer A2): any + new (w: AniraWasmInstance, ...a: infer A3): any + } + ? ((...args: A1) => R) & ((...args: A2) => R) & ((...args: A3) => R) + : C extends { + new (w: AniraWasmInstance, ...a: infer A1): any + new (w: AniraWasmInstance, ...a: infer A2): any + } + ? ((...args: A1) => R) & ((...args: A2) => R) + : C extends new (w: AniraWasmInstance, ...a: infer A1) => any + ? (...args: A1) => R + : never + +/** A factory function with the wasmInstance pre-bound */ +export type Factory< + C extends new (wasmInstance: AniraWasmInstance, ...args: any[]) => BaseWrapper, +> = OverloadedFactoryFn> & { + fromPointer(ptr: number): InstanceType +} + +export const createFactory = < + C extends new (wasmInstance: AniraWasmInstance, ...args: any[]) => BaseWrapper, +>( + wasmInstance: AniraWasmInstance, + Cls: C +): Factory => { + const factory = (...args: any[]) => new Cls(wasmInstance, ...args) as InstanceType + + factory.fromPointer = (ptr: number): InstanceType => { + const instance = Object.create(Cls.prototype) + instance.wasmInstance = wasmInstance + instance.ptr = ptr + return instance + } + + return factory as Factory +} diff --git a/web/src/vite-env.d.ts b/web/src/vite-env.d.ts new file mode 100644 index 00000000..c7ec1238 --- /dev/null +++ b/web/src/vite-env.d.ts @@ -0,0 +1,11 @@ +/// + +declare module '*.wasm?url' { + const url: string + export default url +} + +declare module 'onnxruntime-web/ort-wasm-simd-threaded.mjs' { + const factory: (config?: Record) => Promise + export default factory +} diff --git a/web/src/workers/audio-worklet.ts b/web/src/workers/audio-worklet.ts new file mode 100644 index 00000000..fb5e93ee --- /dev/null +++ b/web/src/workers/audio-worklet.ts @@ -0,0 +1,5 @@ +import { AniraAudioWorkletBase } from './worklet-base' + +class InferenceWorklet extends AniraAudioWorkletBase {} + +registerProcessor('inference-processor', InferenceWorklet) diff --git a/web/src/workers/inference-worker.ts b/web/src/workers/inference-worker.ts new file mode 100644 index 00000000..0e4cf4bf --- /dev/null +++ b/web/src/workers/inference-worker.ts @@ -0,0 +1,12 @@ +import { setupInferenceWorker } from './inferenceWorkerHandler' + +// Default inference worker with no custom processor classes. +// To use custom JSBackendBase subclasses, create your own worker file: +// +// import { setupInferenceWorker } from './inferenceWorkerHandler' +// import { CustomJSBackend } from './custom-js-backend' +// setupInferenceWorker({ CustomJSBackend }) +// +// Then pass its URL to spinUpInferenceWorker(). + +setupInferenceWorker() diff --git a/web/src/workers/inferenceWorkerHandler.ts b/web/src/workers/inferenceWorkerHandler.ts new file mode 100644 index 00000000..3dc2ecaf --- /dev/null +++ b/web/src/workers/inferenceWorkerHandler.ts @@ -0,0 +1,137 @@ +import { AniraWeb } from '../AniraWeb' +import { ONNXRuntimeWebBackend } from '../backends/ONNXRuntimeWebBackend' +import type { AniraWasmConfig } from '../factory' +import { createFactory } from '../utils' +import type { JSBackendBase } from '../backends' +import type { + InferenceWorkerMessage, + ProcessorRegisteredResponse, + ProcessorUnregisteredResponse, + ReadyRespose, + StoppedResponse, +} from './messages' +import { InferenceThread } from '../wrappers/system/InferenceThread' + +/** + * Map from class name to class constructor. + * The handler uses this to instantiate the correct subclass when + * `className` is provided in a `registerProcessor` message. + */ +type ProcessorClassMap = Record + +type AniraCreateFn = ( + config?: AniraWasmConfig & Record, + memory?: WebAssembly.Memory +) => Promise + +/** + * Set up the inference worker message handler. + * + * Call this at the top level of your worker file, passing any custom + * processor subclasses the worker should know about: + * + * ```ts + * // my-inference-worker.ts + * import { setupInferenceWorker } from './inferenceWorkerHandler' + * import { CustomJSBackend } from '../custom-js-backend' + * + * setupInferenceWorker({ CustomJSBackend }) + * ``` + */ +export const setupInferenceWorker = ( + customProcessorClasses: ProcessorClassMap = {}, + createAnira: AniraCreateFn = (config, memory) => AniraWeb.create(config, memory) +) => { + const processorClasses: ProcessorClassMap = { + ONNXRuntimeWebBackend, + ...customProcessorClasses, + } + let aniraWeb: AniraWeb + let thread: InferenceThread + const processorRegistry = new Map() + + self.onmessage = async (e: MessageEvent) => { + switch (e.data.type) { + case 'initInferenceWorker': { + const { threadPtr, wasmMemory, stackPtr } = e.data + + aniraWeb = await createAnira( + { + processBuffers: ( + processorPtr: number, + inputPtr: number, + outputPtr: number + ) => { + const processor = processorRegistry.get(processorPtr) + if (!processor) { + throw new Error( + `JSProcessor with pointer ${processorPtr} is not registered in this worker. ` + + `Call registerProcessor() before starting inference.` + ) + } + processor.process(inputPtr, outputPtr) + }, + }, + wasmMemory + ) + aniraWeb.stackRestore(stackPtr) + + const t = aniraWeb.InferenceThread.fromPointer(threadPtr) + if (!t) return + thread = t + + postMessage({ type: 'ready' } satisfies ReadyRespose) + break + } + + case 'registerProcessor': { + const { processorPtr, className, inferenceConfigPtr } = e.data + if (!processorRegistry.has(processorPtr)) { + let instance: JSBackendBase + if (className && processorClasses[className]) { + const factory = createFactory( + aniraWeb.getWasmInstance(), + processorClasses[className] + ) + instance = factory.fromPointer(processorPtr) + } else { + instance = aniraWeb.JSBackendBase.fromPointer(processorPtr) + } + if (inferenceConfigPtr) { + instance.inferenceConfigPtr = inferenceConfigPtr + } + await instance.init() + processorRegistry.set(processorPtr, instance) + } + postMessage({ + type: 'processorRegistered', + } satisfies ProcessorRegisteredResponse) + break + } + + case 'unregisterProcessor': { + const { processorPtr } = e.data + const instance = processorRegistry.get(processorPtr) + if (instance) { + instance.destroy() + processorRegistry.delete(processorPtr) + } + postMessage({ + type: 'processorUnregistered', + } satisfies ProcessorUnregisteredResponse) + break + } + + case 'start': { + thread.runLoop() + postMessage({ type: 'stopped' } satisfies StoppedResponse) + break + } + + case 'destroy': { + close() + break + } + } + } +} diff --git a/web/src/workers/messages.ts b/web/src/workers/messages.ts new file mode 100644 index 00000000..f21e3d8b --- /dev/null +++ b/web/src/workers/messages.ts @@ -0,0 +1,130 @@ +// ------------------------------- +// ------ General Messages ------- +// ------------------------------- + +export type InitMessage = { + type: 'init' + wasmMemory: WebAssembly.Memory + stackPtr: number +} + +export type StartMessage = { + type: 'start' +} + +export type DestroyMessage = { + type: 'destroy' +} + +// ------------------------------- +// ------ General Responses ------ +// ------------------------------- + +export type ReadyRespose = { + type: 'ready' +} + +export type StoppedResponse = { + type: 'stopped' +} + +export type DoneResponse = { + type: 'done' +} + +// --------------------------------- +// ------ InferenceWorker Messages -- +// --------------------------------- + +export type InitInferenceWorkerMessage = { + type: 'initInferenceWorker' + wasmMemory: WebAssembly.Memory + stackPtr: number + threadPtr: number +} + +export type RegisterProcessorMessage = { + type: 'registerProcessor' + processorPtr: number + className?: string + inferenceConfigPtr?: number +} + +export type ProcessorRegisteredResponse = { + type: 'processorRegistered' +} + +export type UnregisterProcessorMessage = { + type: 'unregisterProcessor' + processorPtr: number +} + +export type ProcessorUnregisteredResponse = { + type: 'processorUnregistered' +} + +export type InferenceWorkerMessage = + | InitInferenceWorkerMessage + | RegisterProcessorMessage + | UnregisterProcessorMessage + | StartMessage + | DestroyMessage + +// --------------------------------- +// ------ Audio Worklet Messages -- +// --------------------------------- + +export type AudioWorkletIOConfig = { + maxBufferSize: number + inputNodeIndex: number + outputNodeIndex: number + inputChannels: number + outputChannels: number +} + +export type AudioWorkletConfigureMessage = { + type: 'configure' + wasmMemory: WebAssembly.Memory + wasmBinary: ArrayBuffer + stackPtr: number + inferenceHandlerPtr: number + prePostProcessorPtr: number + inputBufferPtr: number + outputBufferPtr: number + inputDataBuffer: number + outputDataBuffer: number + ioConfig: AudioWorkletIOConfig +} + +// --------------------------------- +// ------ Utility Functions -------- +// --------------------------------- + +/** + * Resolve once `worker` posts a message whose `data.type` matches + * `messageType`. The listener is registered for the duration of the + * wait and removed as soon as the matching message arrives. + * + * Used to await the handshake responses (`'ready'`, + * `'processorRegistered'`, `'stopped'`, …) that anira's worker + * runtime emits during setup. Messages whose `type` does not match + * are ignored and left for other listeners. + * + * @param worker - The target worker (or any object with the + * `addEventListener` / `removeEventListener` `'message'` surface). + * @param messageType - Value of `data.type` to wait for. + * @returns A promise that resolves when the matching message is received. + */ +export const waitForWorkerMessage = ( + worker: Pick, + messageType: string +): Promise => { + return new Promise((resolve) => { + const listener = (e: MessageEvent<{ type: string }>) => { + if (e.data.type !== messageType) return + worker.removeEventListener('message', listener) + resolve() + } + worker.addEventListener('message', listener) + }) +} diff --git a/web/src/workers/worklet-base.ts b/web/src/workers/worklet-base.ts new file mode 100644 index 00000000..3e588482 --- /dev/null +++ b/web/src/workers/worklet-base.ts @@ -0,0 +1,272 @@ +import { AniraWeb } from '../AniraWeb' +import type { InferenceHandler, JSPrePostProcessor } from '../wrappers' +import type { + AudioWorkletConfigureMessage, + AudioWorkletIOConfig, + ReadyRespose, +} from './messages' + +export type AniraWorkletState = { + wasmMemory: WebAssembly.Memory + aniraWeb: AniraWeb + inferenceHandler: InferenceHandler + prePostProcessorPtr: number + inputBufferPtr: number + outputBufferPtr: number + inputDataBuffer: number + outputDataBuffer: number + ioConfig: AudioWorkletIOConfig + inputChannelViews: Float32Array[] + outputChannelViews: Float32Array[] +} + +export class AniraAudioWorkletBase extends AudioWorkletProcessor { + protected aniraState: AniraWorkletState | null = null + protected prePostRegistry = new Map() + + private clearOutputs(outputs: Float32Array[][]): void { + for (const outputNode of outputs) { + for (const channel of outputNode) { + channel.fill(0) + } + } + } + + constructor(options?: AudioWorkletNodeOptions) { + super(options) + + this.port.onmessage = async (e: MessageEvent) => { + const message = e.data + if (message.type !== 'configure') return + + const { + inferenceHandlerPtr, + prePostProcessorPtr, + inputBufferPtr, + outputBufferPtr, + inputDataBuffer, + outputDataBuffer, + wasmMemory, + wasmBinary, + stackPtr, + ioConfig, + } = message + + const aniraWeb = await AniraWeb.create( + { + wasmBinary, + processPrePost: ( + prePostProcessorPtr: number, + inputPtr: number, + outputPtr: number, + backend: number, + phase: number + ) => { + const prePostProcessor = this.prePostRegistry.get(prePostProcessorPtr) + if (prePostProcessor) { + if (phase === 0) { + prePostProcessor.preProcess(inputPtr, outputPtr, backend) + return + } + if (phase === 1) { + prePostProcessor.postProcess(inputPtr, outputPtr, backend) + return + } + throw new Error(`Unknown pre/post phase: ${phase}`) + } + + throw new Error( + `JSPrePostProcessor with pointer ${prePostProcessorPtr} is not registered. ` + + `Call this.prePostRegistry.set(prePostProcessorPtr, prePostProcessor) before processing.` + ) + }, + }, + wasmMemory + ) + aniraWeb.stackRestore(stackPtr) + const inferenceHandler = aniraWeb.InferenceHandler.fromPointer(inferenceHandlerPtr) + if (!inferenceHandler) { + console.error('Failed to create inference handler from pointer') + return + } + + const bytesPerChannel = ioConfig.maxBufferSize * Float32Array.BYTES_PER_ELEMENT + const inputChannelViews: Float32Array[] = [] + const outputChannelViews: Float32Array[] = [] + for (let i = 0; i < ioConfig.inputChannels; i++) { + inputChannelViews.push( + new Float32Array( + wasmMemory.buffer, + inputDataBuffer + i * bytesPerChannel, + ioConfig.maxBufferSize + ) + ) + } + for (let i = 0; i < ioConfig.outputChannels; i++) { + outputChannelViews.push( + new Float32Array( + wasmMemory.buffer, + outputDataBuffer + i * bytesPerChannel, + ioConfig.maxBufferSize + ) + ) + } + + this.aniraState = { + wasmMemory, + aniraWeb, + inferenceHandler, + prePostProcessorPtr, + inputBufferPtr, + outputBufferPtr, + inputDataBuffer, + outputDataBuffer, + ioConfig, + inputChannelViews, + outputChannelViews, + } + + await this.onConfigured(this.aniraState) + this.port.postMessage({ type: 'ready' } satisfies ReadyRespose) + } + } + + protected async onConfigured(_state: AniraWorkletState) { + // Hook for subclasses that need one-time setup after configure. + } + + /** + * Copy a slice of `inputNode` channels into a contiguous range of + * `inputChannelViews`. Missing source channels are zero-filled. + */ + protected copyAudioInputsToChannels( + inputNode: Float32Array[] | undefined, + state: AniraWorkletState, + bufferSize: number, + channelOffset = 0, + channelCount = state.inputChannelViews.length - channelOffset + ): void { + const views = state.inputChannelViews + const provided = inputNode?.length ?? 0 + const copyCount = Math.min(provided, channelCount) + for (let ch = 0; ch < copyCount; ch++) { + views[channelOffset + ch].set(inputNode![ch], 0) + } + for (let ch = copyCount; ch < channelCount; ch++) { + views[channelOffset + ch].fill(0, 0, bufferSize) + } + } + + /** + * Copy a contiguous range of `outputChannelViews` back into `outputNode`. + * No-op if no output node is connected or no samples were produced. + */ + protected copyAudioOutputsFromChannels( + outputNode: Float32Array[] | undefined, + state: AniraWorkletState, + samplesProcessed: number, + channelOffset = 0, + channelCount = state.outputChannelViews.length - channelOffset + ): void { + if (!outputNode?.length || samplesProcessed <= 0) return + const views = state.outputChannelViews + const count = Math.min(outputNode.length, channelCount) + for (let ch = 0; ch < count; ch++) { + const src = views[channelOffset + ch] + const dst = outputNode[ch] + const n = Math.min(samplesProcessed, dst.length, state.ioConfig.maxBufferSize) + for (let i = 0; i < n; i++) { + dst[i] = src[i] + } + } + } + + /** + * Build the `float***` pointer structure that `processMulti` expects, by + * slicing the existing `inputBufferPtr` / `outputBufferPtr` (both already + * `float**`s of channel pointers laid out contiguously by + * `configureAudioWorklet`). + * + * `channelsPerTensor` describes how the contiguous channel range is split + * across tensors — e.g. `[2, 1]` means tensor 0 owns channels 0–1 and + * tensor 1 owns channel 2. Also allocates a `size_t[numTensors]` array + * for per-tensor sample counts. + */ + protected buildMultiTensorPointers( + direction: 'input' | 'output', + channelsPerTensor: number[] + ): { tensorPtrs: number; numSamplesPtr: number } { + const state = this.aniraState + if (!state) { + throw new Error('buildMultiTensorPointers called before configure') + } + const { aniraWeb } = state + const baseBufferPtr = + direction === 'input' ? state.inputBufferPtr : state.outputBufferPtr + const heapU32 = aniraWeb.getHeapU32() + const numTensors = channelsPerTensor.length + + const tensorPtrs = aniraWeb.malloc(numTensors * 4) + let channelOffset = 0 + for (let i = 0; i < numTensors; i++) { + heapU32[tensorPtrs / 4 + i] = baseBufferPtr + channelOffset * 4 + channelOffset += channelsPerTensor[i] + } + const numSamplesPtr = aniraWeb.malloc(numTensors * 4) + return { tensorPtrs, numSamplesPtr } + } + + protected processAudioBlock( + inputs: Float32Array[][], + outputs: Float32Array[][], + state: AniraWorkletState, + bufferSize: number, + _parameters: Record + ): void { + const { inferenceHandler, inputBufferPtr, outputBufferPtr, ioConfig } = state + const inputNode = inputs[ioConfig.inputNodeIndex] + const outputNode = outputs[ioConfig.outputNodeIndex] + + if (outputNode && outputNode.length > 0) { + for (let ch = 0; ch < outputNode.length; ch++) { + outputNode[ch].fill(0) + } + } + + this.copyAudioInputsToChannels(inputNode, state, bufferSize) + + const samplesProcessed = inferenceHandler.process( + inputBufferPtr, + bufferSize, + outputBufferPtr, + bufferSize, + 0 + ) + + this.copyAudioOutputsFromChannels(outputNode, state, samplesProcessed) + } + + process( + inputs: Float32Array[][], + outputs: Float32Array[][], + parameters: Record + ): boolean { + if (!this.aniraState) { + // AudioWorklet process() can run before the async configure handshake finishes. + this.clearOutputs(outputs) + return true + } + + const outputNode = outputs[this.aniraState.ioConfig.outputNodeIndex] + const inputNode = inputs[this.aniraState.ioConfig.inputNodeIndex] + const requestedBufferSize = outputNode?.[0]?.length || inputNode?.[0]?.length || 0 + const bufferSize = Math.min( + requestedBufferSize, + this.aniraState.ioConfig.maxBufferSize + ) + if (bufferSize === 0) return true + + this.processAudioBlock(inputs, outputs, this.aniraState, bufferSize, parameters) + return true + } +} diff --git a/web/src/worklet.d.ts b/web/src/worklet.d.ts new file mode 100644 index 00000000..df517ad0 --- /dev/null +++ b/web/src/worklet.d.ts @@ -0,0 +1,21 @@ +// https://github.com/microsoft/TypeScript/issues/28308#issuecomment-650802278 +interface AudioWorkletProcessor { + readonly port: MessagePort + process( + inputs: Float32Array[][], + outputs: Float32Array[][], + parameters: Record + ): boolean +} + +declare var AudioWorkletProcessor: { + prototype: AudioWorkletProcessor + new (options?: AudioWorkletNodeOptions): AudioWorkletProcessor +} + +declare function registerProcessor( + name: string, + processorCtor: (new (options?: AudioWorkletNodeOptions) => AudioWorkletProcessor) & { + parameterDescriptors?: AudioParamDescriptor[] + } +): void diff --git a/web/src/wrappers/BaseWrapper.ts b/web/src/wrappers/BaseWrapper.ts new file mode 100644 index 00000000..161f7bb7 --- /dev/null +++ b/web/src/wrappers/BaseWrapper.ts @@ -0,0 +1,57 @@ +import type { AniraWasmInstance } from '../factory' + +/** Accepts either a raw WASM pointer or a wrapper instance. */ +export type PossiblePointer = T | number + +/** Resolve a `PossiblePointer` to a raw numeric pointer. */ +export const resolvePtr = (value: PossiblePointer): number => { + return typeof value === 'number' ? value : value.getPointer() +} + +export abstract class BaseWrapper { + protected ptr: number + protected wasmInstance: AniraWasmInstance + + constructor(module: AniraWasmInstance, ptr: PossiblePointer) { + this.wasmInstance = module + this.ptr = resolvePtr(ptr) + } + + getPointer(): number { + return this.ptr + } + + /** + * Wrap a raw WASM pointer as an instance of a wrapper class, + * reusing this instance's wasmInstance. + */ + wrapPointer( + Cls: new (wasmInstance: AniraWasmInstance, ...args: any[]) => T, + ptr: number + ): T { + const instance = Object.create(Cls.prototype) as T + instance.wasmInstance = this.wasmInstance + instance.ptr = ptr + return instance + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + abstract destroy(): void + + static createFromPointer( + this: new (module: AniraWasmInstance, ptr: number) => T, + module: AniraWasmInstance, + ptr: number + ): T { + const out = Object.create(this.prototype) + out.wasmInstance = module + out.ptr = ptr + return out + } + + protected _destroy(func: (ptr: number) => void) { + if (!this.ptr) return + func(this.ptr) + this.ptr = 0 + } +} diff --git a/web/src/wrappers/InferenceBackend.ts b/web/src/wrappers/InferenceBackend.ts new file mode 100644 index 00000000..6ddcb8f2 --- /dev/null +++ b/web/src/wrappers/InferenceBackend.ts @@ -0,0 +1,15 @@ +import type { AniraWasmInstance } from '../factory' + +export interface InferenceBackendValues { + readonly ONNX: number + readonly CUSTOM: number +} + +export const createInferenceBackend = ( + wasmInstance: AniraWasmInstance +): InferenceBackendValues => { + return Object.freeze({ + ONNX: wasmInstance._get_inference_backend_onnx(), + CUSTOM: wasmInstance._get_inference_backend_custom(), + }) +} diff --git a/web/src/wrappers/InferenceConfig.ts b/web/src/wrappers/InferenceConfig.ts new file mode 100644 index 00000000..4e9e50e7 --- /dev/null +++ b/web/src/wrappers/InferenceConfig.ts @@ -0,0 +1,308 @@ +import type { AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' +import type { VectorModelData, VectorTensorShape } from './Vectors' +import { TensorShapeList } from './Vectors' +import { ProcessingSpec } from './ProcessingSpec' +import { TensorShape } from './TensorShape' + +/** + * Mirrors `anira::InferenceConfig::Defaults` from the C++ header — *with one + * deliberate deviation*: `numParallelProcessors` defaults to + * `navigator.hardwareConcurrency` (full count), not `hardware_concurrency / 2`. + * + * On the web, parallel inference is driven by JS workers the user spins up + * via `AniraWeb.spinUpInferenceWorker`; the library does not own a + * native thread pool. `num_parallel_processors` decides how many backend + * processor instances the session pre-allocates — i.e. the upper bound on + * concurrent inferences. Setting it lower than the worker count causes the + * extra workers to serialise on processor locks; setting it higher just + * costs a bit of memory. Defaulting to the full hardware-concurrency value + * keeps users out of the "silently serialised" trap; pass an explicit value + * if you know your worker count. + */ +export const InferenceConfigDefaults = { + warmUp: 0, + sessionExclusiveProcessor: false, + blockingRatio: 0, + numParallelProcessors: Math.max(1, globalThis.navigator?.hardwareConcurrency ?? 1), +} as const + +/** + * TypeScript wrapper for anira::InferenceConfig + * Thread-safe C API wrapper + */ +export class InferenceConfig extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + modelDataVector: PossiblePointer, + tensorShapeVector: PossiblePointer, + processingSpec: PossiblePointer, + maxInferenceTime: number, + warmUp?: number, + sessionExclusiveProcessor?: boolean, + blockingRatio?: number, + numParallelProcessors?: number + ) + constructor( + wasmInstance: AniraWasmInstance, + modelDataVector: PossiblePointer, + tensorShapeVector: PossiblePointer, + maxInferenceTime: number, + warmUp?: number, + sessionExclusiveProcessor?: boolean, + blockingRatio?: number, + numParallelProcessors?: number + ) + constructor( + wasmInstance: AniraWasmInstance, + modelDataVector: PossiblePointer, + tensorShapeVector: PossiblePointer, + processingSpecOrMaxInferenceTime: PossiblePointer | number, + arg4?: number | boolean, + arg5?: number | boolean, + arg6?: number | boolean, + arg7?: number, + arg8?: number + ) { + const modelDataVectorPtr = resolvePtr(modelDataVector) + const tensorShapeVectorPtr = resolvePtr(tensorShapeVector) + const modelCount = wasmInstance._vector_model_data_size(modelDataVectorPtr) + const tensorCount = wasmInstance._vector_tensor_shape_size(tensorShapeVectorPtr) + + // Disambiguation: the auto-spec overload's 4th arg is `maxInferenceTime` (a + // raw number). The full-spec overload's 4th arg is a `ProcessingSpec` + // wrapper instance (PossiblePointer accepts a number too, but we require an + // instance here so the two overloads can be told apart at runtime). + const isFullSpec = processingSpecOrMaxInferenceTime instanceof ProcessingSpec + + if (isFullSpec) { + const processingSpecPtr = resolvePtr( + processingSpecOrMaxInferenceTime as PossiblePointer + ) + const maxInferenceTime = arg4 as number + const warmUp = (arg5 as number | undefined) ?? InferenceConfigDefaults.warmUp + const sessionExclusiveProcessor = + (arg6 as unknown as boolean | undefined) ?? + InferenceConfigDefaults.sessionExclusiveProcessor + const blockingRatio = + (arg7 as number | undefined) ?? InferenceConfigDefaults.blockingRatio + const numParallelProcessors = + (arg8 as number | undefined) ?? InferenceConfigDefaults.numParallelProcessors + + super( + wasmInstance, + wasmInstance._inferenceconfig_create_full( + modelDataVectorPtr, + modelCount, + tensorShapeVectorPtr, + tensorCount, + processingSpecPtr, + maxInferenceTime, + warmUp, + sessionExclusiveProcessor ? 1 : 0, + blockingRatio, + numParallelProcessors + ) + ) + } else { + const maxInferenceTime = processingSpecOrMaxInferenceTime as number + const warmUp = (arg4 as number | undefined) ?? InferenceConfigDefaults.warmUp + const sessionExclusiveProcessor = + (arg5 as boolean | undefined) ?? InferenceConfigDefaults.sessionExclusiveProcessor + const blockingRatio = + (arg6 as number | undefined) ?? InferenceConfigDefaults.blockingRatio + const numParallelProcessors = + (arg7 as number | undefined) ?? InferenceConfigDefaults.numParallelProcessors + + super( + wasmInstance, + wasmInstance._inferenceconfig_create_auto_spec( + modelDataVectorPtr, + modelCount, + tensorShapeVectorPtr, + tensorCount, + maxInferenceTime, + warmUp, + sessionExclusiveProcessor ? 1 : 0, + blockingRatio, + numParallelProcessors + ) + ) + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._inferenceconfig_destroy) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_model_path`. */ + getModelPath(backend: number): string { + const bufferSize = 1024 + const buffer = this.wasmInstance._malloc(bufferSize) + try { + this.wasmInstance._inferenceconfig_get_model_path( + this.ptr, + backend, + buffer, + bufferSize + ) + const view = new Uint8Array(this.wasmInstance.HEAPU32.buffer, buffer, bufferSize) + let end = 0 + while (end < bufferSize && view[end] !== 0) end++ + return new TextDecoder().decode(view.subarray(0, end)) + } finally { + this.wasmInstance._free(buffer) + } + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_model_data`. */ + getModelData(backend: number): number { + return this.wasmInstance._inferenceconfig_get_model_data(this.ptr, backend) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::is_model_binary`. */ + isModelBinary(backend: number): boolean { + return this.wasmInstance._inferenceconfig_is_model_binary(this.ptr, backend) === 1 + } + + /** + * Mirrors :cpp:func:`anira::InferenceConfig::get_tensor_input_shape`. + * + * Returns a non-owning `TensorShapeList` view into the config's + * universal (or per-backend) input shape. Do **not** call `.destroy()` on it + * — the underlying storage belongs to the `InferenceConfig`. + */ + getTensorInputShape(backend?: number): TensorShapeList { + const ptr = + backend === undefined + ? this.wasmInstance._inferenceconfig_get_tensor_input_shape(this.ptr) + : this.wasmInstance._inferenceconfig_get_tensor_input_shape_for_backend( + this.ptr, + backend + ) + return this.wrapPointer(TensorShapeList, ptr) + } + + /** + * Mirrors :cpp:func:`anira::InferenceConfig::get_tensor_output_shape`. + * + * Returns a non-owning `TensorShapeList` view. See + * `getTensorInputShape` for ownership notes. + */ + getTensorOutputShape(backend?: number): TensorShapeList { + const ptr = + backend === undefined + ? this.wasmInstance._inferenceconfig_get_tensor_output_shape(this.ptr) + : this.wasmInstance._inferenceconfig_get_tensor_output_shape_for_backend( + this.ptr, + backend + ) + return this.wrapPointer(TensorShapeList, ptr) + } + + /** + * Mirrors :cpp:func:`anira::InferenceConfig::get_tensor_shape`. + * + * Returns a non-owning `TensorShape` view selected for `backend` + * (falling back to the universal shape if no backend-specific shape is + * registered). Do **not** call `.destroy()` on it. + */ + getTensorShape(backend: number): TensorShape { + const ptr = this.wasmInstance._inferenceconfig_get_tensor_shape(this.ptr, backend) + return this.wrapPointer(TensorShape, ptr) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_tensor_input_size`. */ + getTensorInputSize(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_tensor_input_size(this.ptr, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_tensor_output_size`. */ + getTensorOutputSize(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_tensor_output_size( + this.ptr, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_preprocess_input_channels`. */ + getPreprocessInputChannels(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_preprocess_input_channels( + this.ptr, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_postprocess_output_channels`. */ + getPostprocessOutputChannels(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_postprocess_output_channels( + this.ptr, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_preprocess_input_size`. */ + getPreprocessInputSize(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_preprocess_input_size( + this.ptr, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_postprocess_output_size`. */ + getPostprocessOutputSize(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_postprocess_output_size( + this.ptr, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceConfig::get_internal_model_latency`. */ + getInternalModelLatency(tensorIndex: number = 0): number { + return this.wasmInstance._inferenceconfig_get_internal_model_latency( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_max_inference_time` field. */ + getMaxInferenceTime(): number { + return this.wasmInstance._inferenceconfig_get_max_inference_time(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_max_inference_time` field. */ + setMaxInferenceTime(value: number): void { + this.wasmInstance._inferenceconfig_set_max_inference_time(this.ptr, value) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_warm_up` field. */ + getWarmUp(): number { + return this.wasmInstance._inferenceconfig_get_warm_up(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_warm_up` field. */ + setWarmUp(value: number): void { + this.wasmInstance._inferenceconfig_set_warm_up(this.ptr, value) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_blocking_ratio` field. */ + getBlockingRatio(): number { + return this.wasmInstance._inferenceconfig_get_blocking_ratio(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::InferenceConfig::m_blocking_ratio` field. */ + setBlockingRatio(value: number): void { + this.wasmInstance._inferenceconfig_set_blocking_ratio(this.ptr, value) + } + + equals(other: PossiblePointer): boolean { + return this.wasmInstance._inferenceconfig_equals(this.ptr, resolvePtr(other)) === 1 + } + + notEquals(other: PossiblePointer): boolean { + return ( + this.wasmInstance._inferenceconfig_not_equals(this.ptr, resolvePtr(other)) === 1 + ) + } +} diff --git a/web/src/wrappers/InferenceHandler.ts b/web/src/wrappers/InferenceHandler.ts new file mode 100644 index 00000000..149a4a73 --- /dev/null +++ b/web/src/wrappers/InferenceHandler.ts @@ -0,0 +1,232 @@ +import { type AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' +import type { InferenceConfig } from './InferenceConfig' +import type { PrePostProcessor } from './PrePostProcessor' +import type { HostConfig } from './utils/HostConfig' + +/** + * TypeScript wrapper for anira::InferenceHandler + * Thread-safe C API wrapper + */ +export class InferenceHandler extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + preprocessor: PossiblePointer, + config: PossiblePointer, + customProcessor?: PossiblePointer + ) { + const preprocessorPtr = resolvePtr(preprocessor) + const configPtr = resolvePtr(config) + if (customProcessor) { + super( + wasmInstance, + wasmInstance._inferencehandler_create_with_custom_processor( + preprocessorPtr, + configPtr, + resolvePtr(customProcessor) + ) + ) + } else { + super( + wasmInstance, + wasmInstance._inferencehandler_create(preprocessorPtr, configPtr) + ) + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._inferencehandler_destroy) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::set_inference_backend`. */ + setInferenceBackend(backend: number): void { + this.wasmInstance._inferencehandler_set_inference_backend(this.ptr, backend) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::get_inference_backend`. */ + getInferenceBackend(): number { + return this.wasmInstance._inferencehandler_get_inference_backend(this.ptr) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::prepare() `. */ + prepare(hostConfig: PossiblePointer): void + /** Mirrors :cpp:func:`anira::InferenceHandler::prepare() `. */ + prepare( + hostConfig: PossiblePointer, + customLatency: number, + tensorIndex?: number + ): void + /** Mirrors :cpp:func:`anira::InferenceHandler::prepare() )>`. */ + prepare(hostConfig: PossiblePointer, customLatency: Uint32Array): void + prepare( + hostConfig: PossiblePointer, + customLatency?: number | Uint32Array, + tensorIndex?: number + ): void { + const hostConfigPtr = resolvePtr(hostConfig) + if (customLatency === undefined) { + this.wasmInstance._inferencehandler_prepare(this.ptr, hostConfigPtr) + return + } + if (typeof customLatency === 'number') { + this.wasmInstance._inferencehandler_prepare_with_latency( + this.ptr, + hostConfigPtr, + customLatency, + tensorIndex ?? 0 + ) + return + } + const latencyPtr = this.wasmInstance._malloc(customLatency.length * 4) + this.wasmInstance.HEAPU32.set(customLatency, latencyPtr / 4) + this.wasmInstance._inferencehandler_prepare_with_latency_vector( + this.ptr, + hostConfigPtr, + latencyPtr, + customLatency.length + ) + this.wasmInstance._free(latencyPtr) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::process() `. */ + process(dataPtr: number, numSamples: number, tensorIndex?: number): number + /** Mirrors :cpp:func:`anira::InferenceHandler::process() `. */ + process( + inputPtr: number, + numInputSamples: number, + outputPtr: number, + numOutputSamples: number, + tensorIndex?: number + ): number + process(a: number, b: number, c?: number, d?: number, e?: number): number { + // Discriminator: the separate-buffers overload always passes outputPtr at + // position 4 (`d`). When `d` is undefined we're in the in-place form. + if (d === undefined) { + return this.wasmInstance._inferencehandler_process(this.ptr, a, b, c ?? 0) + } + return this.wasmInstance._inferencehandler_process_separate( + this.ptr, + a, + b, + c!, + d, + e ?? 0 + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::process() ` (multi-tensor overload). */ + processMulti( + inputPtr: number, + numInputPtr: number, + outputPtr: number, + numOutputPtr: number + ): number { + return this.wasmInstance._inferencehandler_process_multi( + this.ptr, + inputPtr, + numInputPtr, + outputPtr, + numOutputPtr + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::push_data() `. */ + pushData(inputPtr: number, numSamples: number, tensorIndex: number = 0): void { + this.wasmInstance._inferencehandler_push_data( + this.ptr, + inputPtr, + numSamples, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::push_data() ` (multi-tensor overload). */ + pushDataMulti(inputPtr: number, numSamplesPtr: number): void { + this.wasmInstance._inferencehandler_push_data_multi(this.ptr, inputPtr, numSamplesPtr) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::pop_data() ` (non-blocking). */ + popData(outputPtr: number, numSamples: number, tensorIndex: number = 0): number { + return this.wasmInstance._inferencehandler_pop_data( + this.ptr, + outputPtr, + numSamples, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::pop_data() ` (blocking with timeout). */ + popDataBlocking( + outputPtr: number, + numSamples: number, + waitMs: number, + tensorIndex: number = 0 + ): number { + return this.wasmInstance._inferencehandler_pop_data_blocking( + this.ptr, + outputPtr, + numSamples, + waitMs, + tensorIndex + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::pop_data() ` (multi-tensor, non-blocking). */ + popDataMulti(outputPtr: number, numSamplesPtr: number): number { + return this.wasmInstance._inferencehandler_pop_data_multi( + this.ptr, + outputPtr, + numSamplesPtr + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::pop_data() ` (multi-tensor, blocking with timeout). */ + popDataMultiBlocking(outputPtr: number, numSamplesPtr: number, waitMs: number): number { + return this.wasmInstance._inferencehandler_pop_data_multi_blocking( + this.ptr, + outputPtr, + numSamplesPtr, + waitMs + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::get_latency`. */ + getLatency(tensorIndex: number = 0): number { + return this.wasmInstance._inferencehandler_get_latency(this.ptr, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::get_latency_vector`. */ + getLatencyVector(): number[] { + const vectorPtr = this.wasmInstance._inferencehandler_get_latency_vector(this.ptr) + + const dataPtr = this.wasmInstance.HEAPU32[vectorPtr / 4] + const endPtr = this.wasmInstance.HEAPU32[vectorPtr / 4 + 1] + const size = (endPtr - dataPtr) / 4 // size in elements (uint32) + + const result: number[] = [] + for (let i = 0; i < size; i++) { + result.push(this.wasmInstance.HEAPU32[dataPtr / 4 + i]) + } + return result + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::get_available_samples`. */ + getAvailableSamples(tensorIndex: number, channel: number = 0): number { + return this.wasmInstance._inferencehandler_get_available_samples( + this.ptr, + tensorIndex, + channel + ) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::set_non_realtime`. */ + setNonRealtime(nonRealtime: boolean): void { + this.wasmInstance._inferencehandler_set_non_realtime(this.ptr, nonRealtime ? 1 : 0) + } + + /** Mirrors :cpp:func:`anira::InferenceHandler::reset`. */ + reset(): void { + this.wasmInstance._inferencehandler_reset(this.ptr) + } +} diff --git a/web/src/wrappers/JSPrePostProcessor.ts b/web/src/wrappers/JSPrePostProcessor.ts new file mode 100644 index 00000000..579ac944 --- /dev/null +++ b/web/src/wrappers/JSPrePostProcessor.ts @@ -0,0 +1,59 @@ +import type { AniraWasmInstance } from '../factory' +import { PrePostProcessor } from './PrePostProcessor' +import type { InferenceConfig } from './InferenceConfig' +import { resolvePtr, type PossiblePointer } from './BaseWrapper' +import type { VectorBufferF, VectorRingBuffer } from './Vectors' + +// TODO: Hybrid ppprocessor testen +/** + * TypeScript wrapper for JSPrePostProcessor. + * Each instance is identified by its C++ pointer and carries its own + * pre/post implementation that the inference worker dispatches to. + */ +export class JSPrePostProcessor extends PrePostProcessor { + constructor( + wasmInstance: AniraWasmInstance, + inferenceConfig: PossiblePointer + ) { + super(wasmInstance, inferenceConfig, wasmInstance._jsprepostprocessor_create) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + override destroy(): void { + this._destroy(this.wasmInstance._jsprepostprocessor_destroy) + } + + /** + * Called by the inference worker when C++ invokes the JS callback. + * Override in a subclass to implement custom preprocessing. + */ + override preProcess( + ringBuffers: PossiblePointer, + buffers: PossiblePointer, + backend: number + ): void { + this.wasmInstance._jsprepostprocessor_wasm_pre_process( + this.ptr, + resolvePtr(ringBuffers), + resolvePtr(buffers), + backend + ) + } + + /** + * Called by the inference worker when C++ invokes the JS callback. + * Override in a subclass to implement custom postprocessing. + */ + override postProcess( + buffers: PossiblePointer, + ringBuffers: PossiblePointer, + backend: number + ): void { + this.wasmInstance._jsprepostprocessor_wasm_post_process( + this.ptr, + resolvePtr(buffers), + resolvePtr(ringBuffers), + backend + ) + } +} diff --git a/web/src/wrappers/ModelData.ts b/web/src/wrappers/ModelData.ts new file mode 100644 index 00000000..d35f957d --- /dev/null +++ b/web/src/wrappers/ModelData.ts @@ -0,0 +1,82 @@ +import { type AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' + +/** + * TypeScript wrapper for anira::ModelData + * Thread-safe C API wrapper + */ +export class ModelData extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + bufferOrPath: ArrayBuffer | string, + backend: number + ) { + if (bufferOrPath instanceof ArrayBuffer) { + const buffer = bufferOrPath + + const bufferPtr = wasmInstance._malloc(buffer.byteLength) + const heapView = new Uint8Array( + wasmInstance.HEAPU32.buffer, + bufferPtr, + buffer.byteLength + ) + heapView.set(new Uint8Array(buffer)) + + const ptr = wasmInstance._modeldata_create_from_buffer( + bufferPtr, + buffer.byteLength, + backend + ) + + wasmInstance._free(bufferPtr) + super(wasmInstance, ptr) + } else { + const modelPath = bufferOrPath + + const pathPtr = wasmInstance._malloc(modelPath.length + 1) + const heapView = new Uint8Array( + wasmInstance.HEAPU32.buffer, + pathPtr, + modelPath.length + 1 + ) + heapView.set(new TextEncoder().encode(modelPath + '\0')) + + const ptr = wasmInstance._modeldata_create_from_path(pathPtr, backend) + wasmInstance._free(pathPtr) + super(wasmInstance, ptr) + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._modeldata_destroy) + } + + /** Mirrors the :cpp:member:`anira::ModelData::m_size` field. */ + getSize(): number { + return this.wasmInstance._modeldata_get_size(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::ModelData::m_is_binary` field. */ + isBinary(): boolean { + return this.wasmInstance._modeldata_get_is_binary(this.ptr) !== 0 + } + + /** Mirrors the :cpp:member:`anira::ModelData::m_backend` field. */ + getBackend(): number { + return this.wasmInstance._modeldata_get_backend(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::ModelData::m_data` field. */ + getDataPtr(): number { + return this.wasmInstance._modeldata_get_data_ptr(this.ptr) + } + + equals(other: PossiblePointer): boolean { + return this.wasmInstance._modeldata_equals(this.ptr, resolvePtr(other)) === 1 + } + + notEquals(other: PossiblePointer): boolean { + return this.wasmInstance._modeldata_not_equals(this.ptr, resolvePtr(other)) === 1 + } +} diff --git a/web/src/wrappers/PrePostProcessor.ts b/web/src/wrappers/PrePostProcessor.ts new file mode 100644 index 00000000..20683fd0 --- /dev/null +++ b/web/src/wrappers/PrePostProcessor.ts @@ -0,0 +1,148 @@ +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' +import type { AniraWasmInstance } from '../factory' +import type { InferenceConfig } from './InferenceConfig' +import type { RingBuffer } from './utils/RingBuffer' +import type { BufferF } from './utils/BufferF' +import type { VectorBufferF, VectorRingBuffer } from './Vectors' + +/** + * TypeScript wrapper for anira::PrePostProcessor + * Thread-safe C API wrapper + */ +export class PrePostProcessor extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + config: PossiblePointer, + createFn?: (configPtr: number) => number + ) { + const configPtr = resolvePtr(config) + const creator = createFn ?? wasmInstance._prepostprocessor_create + super(wasmInstance, creator(configPtr)) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._prepostprocessor_destroy) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::pre_process`. */ + preProcess( + ringBuffers: PossiblePointer, + buffers: PossiblePointer, + backend: number + ): void { + this.wasmInstance._prepostprocessor_pre_process( + this.ptr, + resolvePtr(ringBuffers), + resolvePtr(buffers), + backend + ) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::post_process`. */ + postProcess( + buffers: PossiblePointer, + ringBuffers: PossiblePointer, + backend: number + ): void { + this.wasmInstance._prepostprocessor_post_process( + this.ptr, + resolvePtr(buffers), + resolvePtr(ringBuffers), + backend + ) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::set_input`. */ + setInput(value: number, channel: number, tensorIndex: number): void { + this.wasmInstance._prepostprocessor_set_input(this.ptr, value, channel, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::set_output`. */ + setOutput(value: number, channel: number, tensorIndex: number): void { + this.wasmInstance._prepostprocessor_set_output(this.ptr, value, channel, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::get_input`. */ + getInput(channel: number, tensorIndex: number): number { + return this.wasmInstance._prepostprocessor_get_input(this.ptr, channel, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::get_output`. */ + getOutput(channel: number, tensorIndex: number): number { + return this.wasmInstance._prepostprocessor_get_output(this.ptr, channel, tensorIndex) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::pop_samples_from_buffer() `. */ + popSamplesFromBuffer( + ringBuffer: PossiblePointer, + buffer: PossiblePointer, + numSamples: number + ): void + /** Mirrors :cpp:func:`anira::PrePostProcessor::pop_samples_from_buffer() `. */ + popSamplesFromBuffer( + ringBuffer: PossiblePointer, + buffer: PossiblePointer, + numNewSamples: number, + numOldSamples: number + ): void + /** Mirrors :cpp:func:`anira::PrePostProcessor::pop_samples_from_buffer() `. */ + popSamplesFromBuffer( + ringBuffer: PossiblePointer, + buffer: PossiblePointer, + numNewSamples: number, + numOldSamples: number, + offset: number + ): void + popSamplesFromBuffer( + ringBuffer: PossiblePointer, + buffer: PossiblePointer, + a: number, + b?: number, + c?: number + ): void { + const rbPtr = resolvePtr(ringBuffer) + const bufPtr = resolvePtr(buffer) + if (b === undefined) { + this.wasmInstance._prepostprocessor_pop_samples_from_buffer( + this.ptr, + rbPtr, + bufPtr, + a + ) + return + } + if (c === undefined) { + this.wasmInstance._prepostprocessor_pop_samples_from_buffer_window( + this.ptr, + rbPtr, + bufPtr, + a, + b + ) + return + } + this.wasmInstance._prepostprocessor_pop_samples_from_buffer_window_offset( + this.ptr, + rbPtr, + bufPtr, + a, + b, + c + ) + } + + /** Mirrors :cpp:func:`anira::PrePostProcessor::push_samples_to_buffer`. */ + pushSamplesToBuffer( + buffer: PossiblePointer, + ringBuffer: PossiblePointer, + numSamples: number + ): void { + this.wasmInstance._prepostprocessor_push_samples_to_buffer( + this.ptr, + resolvePtr(buffer), + resolvePtr(ringBuffer), + numSamples + ) + } +} diff --git a/web/src/wrappers/ProcessingSpec.ts b/web/src/wrappers/ProcessingSpec.ts new file mode 100644 index 00000000..879f4123 --- /dev/null +++ b/web/src/wrappers/ProcessingSpec.ts @@ -0,0 +1,165 @@ +import { type AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' +import { VectorSizeT } from './Vectors' + +/** + * TypeScript wrapper for anira::ProcessingSpec + * Thread-safe C API wrapper + */ +export class ProcessingSpec extends BaseWrapper { + constructor(wasmInstance: AniraWasmInstance) + constructor( + wasmInstance: AniraWasmInstance, + preprocessChannels: PossiblePointer, + postprocessChannels: PossiblePointer + ) + constructor( + wasmInstance: AniraWasmInstance, + preprocessChannels: PossiblePointer, + postprocessChannels: PossiblePointer, + preprocessSize: PossiblePointer, + postprocessSize: PossiblePointer + ) + constructor( + wasmInstance: AniraWasmInstance, + preprocessChannels: PossiblePointer, + postprocessChannels: PossiblePointer, + preprocessSize: PossiblePointer, + postprocessSize: PossiblePointer, + internalModelLatency: PossiblePointer + ) + constructor( + wasmInstance: AniraWasmInstance, + preprocessChannels?: PossiblePointer, + postprocessChannels?: PossiblePointer, + preprocessSize?: PossiblePointer, + postprocessSize?: PossiblePointer, + internalModelLatency?: PossiblePointer + ) { + if (preprocessChannels === undefined || postprocessChannels === undefined) { + super(wasmInstance, wasmInstance._processingspec_create()) + return + } + + const preChPtr = resolvePtr(preprocessChannels) + const postChPtr = resolvePtr(postprocessChannels) + const preChCount = wasmInstance._vector_size_t_size(preChPtr) + const postChCount = wasmInstance._vector_size_t_size(postChPtr) + + if (preprocessSize === undefined || postprocessSize === undefined) { + super( + wasmInstance, + wasmInstance._processingspec_create_with_channels( + preChPtr, + preChCount, + postChPtr, + postChCount + ) + ) + return + } + + const preSizePtr = resolvePtr(preprocessSize) + const postSizePtr = resolvePtr(postprocessSize) + const preSizeCount = wasmInstance._vector_size_t_size(preSizePtr) + const postSizeCount = wasmInstance._vector_size_t_size(postSizePtr) + + if (internalModelLatency === undefined) { + super( + wasmInstance, + wasmInstance._processingspec_create_full( + preChPtr, + preChCount, + postChPtr, + postChCount, + preSizePtr, + preSizeCount, + postSizePtr, + postSizeCount + ) + ) + return + } + + const latencyPtr = resolvePtr(internalModelLatency) + const latencyCount = wasmInstance._vector_size_t_size(latencyPtr) + super( + wasmInstance, + wasmInstance._processingspec_create_full_with_latency( + preChPtr, + preChCount, + postChPtr, + postChCount, + preSizePtr, + preSizeCount, + postSizePtr, + postSizeCount, + latencyPtr, + latencyCount + ) + ) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._processingspec_destroy) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_preprocess_input_channels` field. */ + getPreprocessInputChannels(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_preprocess_input_channels( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_postprocess_output_channels` field. */ + getPostprocessOutputChannels(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_postprocess_output_channels( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_preprocess_input_size` field. */ + getPreprocessInputSize(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_preprocess_input_size( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_postprocess_output_size` field. */ + getPostprocessOutputSize(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_postprocess_output_size( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_internal_model_latency` field. */ + getInternalModelLatency(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_internal_model_latency( + this.ptr, + tensorIndex + ) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_tensor_input_size` field. */ + getTensorInputSize(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_tensor_input_size(this.ptr, tensorIndex) + } + + /** Mirrors the :cpp:member:`anira::ProcessingSpec::m_tensor_output_size` field. */ + getTensorOutputSize(tensorIndex: number = 0): number { + return this.wasmInstance._processingspec_get_tensor_output_size(this.ptr, tensorIndex) + } + + equals(other: PossiblePointer): boolean { + return this.wasmInstance._processingspec_equals(this.ptr, resolvePtr(other)) === 1 + } + + notEquals(other: PossiblePointer): boolean { + return this.wasmInstance._processingspec_not_equals(this.ptr, resolvePtr(other)) === 1 + } +} diff --git a/web/src/wrappers/TensorShape.ts b/web/src/wrappers/TensorShape.ts new file mode 100644 index 00000000..7f8d04a7 --- /dev/null +++ b/web/src/wrappers/TensorShape.ts @@ -0,0 +1,63 @@ +import { type AniraWasmInstance } from '../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from './BaseWrapper' +import { TensorShapeList } from './Vectors' + +/** + * TypeScript wrapper for anira::TensorShape + * Thread-safe C API wrapper + */ +export class TensorShape extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + inputShapeListOrPtr: PossiblePointer, + outputShapeListOrPtr: PossiblePointer + ) { + const inputShapeList = resolvePtr(inputShapeListOrPtr) + const outputShapeList = resolvePtr(outputShapeListOrPtr) + const inputCount = wasmInstance._vector_vector_int64_size(inputShapeList) + const outputCount = wasmInstance._vector_vector_int64_size(outputShapeList) + super( + wasmInstance, + wasmInstance._tensorshape_create( + inputShapeList, + inputCount, + outputShapeList, + outputCount + ) + ) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._tensorshape_destroy) + } + + /** Mirrors :cpp:func:`anira::TensorShape::is_universal`. */ + isUniversal(): boolean { + return this.wasmInstance._tensorshape_is_universal(this.ptr) === 1 + } + + /** + * Mirrors the :cpp:member:`anira::TensorShape::m_tensor_input_shape` field. + */ + getTensorInputShape(): TensorShapeList { + const ptr = this.wasmInstance._tensorshape_get_input_shape(this.ptr) + return this.wrapPointer(TensorShapeList, ptr) + } + + /** + * Mirrors the :cpp:member:`anira::TensorShape::m_tensor_output_shape` field. + */ + getTensorOutputShape(): TensorShapeList { + const ptr = this.wasmInstance._tensorshape_get_output_shape(this.ptr) + return this.wrapPointer(TensorShapeList, ptr) + } + + equals(other: PossiblePointer): boolean { + return this.wasmInstance._tensorshape_equals(this.ptr, resolvePtr(other)) === 1 + } + + notEquals(other: PossiblePointer): boolean { + return this.wasmInstance._tensorshape_not_equals(this.ptr, resolvePtr(other)) === 1 + } +} diff --git a/web/src/wrappers/Vectors.ts b/web/src/wrappers/Vectors.ts new file mode 100644 index 00000000..d86e0bd8 --- /dev/null +++ b/web/src/wrappers/Vectors.ts @@ -0,0 +1,320 @@ +import { type AniraWasmInstance } from '../factory' +import { BaseWrapper, resolvePtr } from './BaseWrapper' + +// ============================================================ +// Abstract base for all vector wrappers +// ============================================================ + +/** + * Base class shared by every typed vector wrapper. + */ +export abstract class VectorBase extends BaseWrapper { + /** Number of elements in the vector */ + abstract size(): number +} + +// ============================================================ +// Primitive vectors +// ============================================================ + +/** + * Wrapper for `std::vector` + */ +export class VectorSizeT extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, values?: number[]) { + super(wasmInstance, wasmInstance._vector_size_t_create()) + if (values) for (const v of values) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_size_t_destroy) + } + + size(): number { + return this.wasmInstance._vector_size_t_size(this.ptr) + } + + push(value: number): void { + this.wasmInstance._vector_size_t_push_back(this.ptr, value) + } + + get(index: number): number { + return this.wasmInstance._vector_size_t_get(this.ptr, index) + } +} + +/** + * Wrapper for `std::vector` + */ +export class VectorInt64T extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, values?: bigint[]) { + super(wasmInstance, wasmInstance._vector_int64_t_create()) + if (values) for (const v of values) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_int64_t_destroy) + } + + size(): number { + return this.wasmInstance._vector_int64_t_size(this.ptr) + } + + push(value: bigint): void { + this.wasmInstance._vector_int64_t_push_back(this.ptr, value) + } + + get(index: number): bigint { + return this.wasmInstance._vector_int64_t_get(this.ptr, index) as bigint + } +} + +/** + * Wrapper for `std::vector` + */ +export class VectorFloat extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, values?: number[]) { + super(wasmInstance, wasmInstance._vector_float_create()) + if (values) for (const v of values) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_float_destroy) + } + + size(): number { + return this.wasmInstance._vector_float_size(this.ptr) + } + + push(value: number): void { + this.wasmInstance._vector_float_push_back(this.ptr, value) + } + + get(index: number): number { + return this.wasmInstance._vector_float_get(this.ptr, index) + } +} + +/** + * Wrapper for `std::vector` + */ +export class VectorUnsignedInt extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, values?: number[]) { + super(wasmInstance, wasmInstance._vector_unsigned_int_create()) + if (values) for (const v of values) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_unsigned_int_destroy) + } + + size(): number { + return this.wasmInstance._vector_unsigned_int_size(this.ptr) + } + + push(value: number): void { + this.wasmInstance._vector_unsigned_int_push_back(this.ptr, value) + } + + get(index: number): number { + return this.wasmInstance._vector_unsigned_int_get(this.ptr, index) + } +} + +// ============================================================ +// Nested / composite vectors +// ============================================================ + +/** + * Wrapper for `std::vector>` (a.k.a. `TensorShapeList`) + * + * Accepts several convenience forms in the constructor: + * - `number[][]` — each inner array is auto-converted to bigint + * - `bigint[][]` — used as-is + * - `(VectorInt64T | number)[]` — existing wrapper objects or raw pointers + * + * The C++ side copies each inner vector, so temporaries can be freed + * independently. + */ +export class VectorVectorInt64 extends VectorBase { + constructor( + wasmInstance: AniraWasmInstance, + items?: number[][] | bigint[][] | (VectorInt64T | number)[] + ) { + super(wasmInstance, wasmInstance._vector_vector_int64_create()) + if (!items) return + + for (const v of items) { + if (Array.isArray(v)) { + // number[] or bigint[] — wrap in a temporary VectorInt64T + const inner = new VectorInt64T( + wasmInstance, + (v as (number | bigint)[]).map((d) => (typeof d === 'bigint' ? d : BigInt(d))) + ) + this.push(inner) + inner.destroy() + } else { + // VectorInt64T instance or raw pointer + this.push(v) + } + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_vector_int64_destroy) + } + + size(): number { + return this.wasmInstance._vector_vector_int64_size(this.ptr) + } + + push(item: VectorInt64T | number): void { + const innerPtr = resolvePtr(item) + this.wasmInstance._vector_vector_int64_push_back(this.ptr, innerPtr) + } + + /** + * Get a non-owning pointer to the inner `VectorInt64T` at `index`. + * The returned pointer is valid only while this vector is alive and not + * resized. + */ + get(index: number): number { + return this.wasmInstance._vector_vector_int64_get(this.ptr, index) + } +} + +/** + * Alias matching the C++ typedef `anira::TensorShapeList` + * (`std::vector>`). + * + * Identical to `VectorVectorInt64` — provided for readability + * when working with tensor shapes. + */ +export class TensorShapeList extends VectorVectorInt64 {} + +// ============================================================ +// Object vectors (push copies the pointed-to object) +// ============================================================ + +/** + * Wrapper for `std::vector` + * + * `push` accepts a `BaseWrapper` (e.g. `ModelData`) or a raw pointer. + */ +export class VectorModelData extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, items?: (BaseWrapper | number)[]) { + super(wasmInstance, wasmInstance._vector_model_data_create()) + if (items) for (const v of items) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_model_data_destroy) + } + + size(): number { + return this.wasmInstance._vector_model_data_size(this.ptr) + } + + push(item: BaseWrapper | number): void { + this.wasmInstance._vector_model_data_push_back(this.ptr, resolvePtr(item)) + } +} + +/** + * Wrapper for `std::vector` + * + * `push` accepts a `BaseWrapper` (e.g. `TensorShape`) or a raw pointer. + */ +export class VectorTensorShape extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, items?: (BaseWrapper | number)[]) { + super(wasmInstance, wasmInstance._vector_tensor_shape_create()) + if (items) for (const v of items) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_tensor_shape_destroy) + } + + size(): number { + return this.wasmInstance._vector_tensor_shape_size(this.ptr) + } + + push(item: BaseWrapper | number): void { + this.wasmInstance._vector_tensor_shape_push_back(this.ptr, resolvePtr(item)) + } +} + +/** + * Wrapper for `std::vector` + * + * `push` accepts a `BaseWrapper` (e.g. `RingBuffer`) or a raw pointer. + */ +export class VectorRingBuffer extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, items?: (BaseWrapper | number)[]) { + super(wasmInstance, wasmInstance._vector_ring_buffer_create()) + if (items) for (const v of items) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_ring_buffer_destroy) + } + + size(): number { + return this.wasmInstance._vector_ring_buffer_size(this.ptr) + } + + push(item: BaseWrapper | number): void { + this.wasmInstance._vector_ring_buffer_push_back(this.ptr, resolvePtr(item)) + } + + /** + * Get a non-owning pointer to the element at `index`. + * The returned pointer is valid only while this vector is alive. + */ + get(index: number): number { + return this.wasmInstance._vector_ring_buffer_get(this.ptr, index) + } +} + +/** + * Wrapper for `std::vector` + * + * `push` accepts a `BaseWrapper` (e.g. `BufferF`) or a raw pointer. + * `get` returns the raw WASM pointer to the element at `index` + * (a non-owning reference — do **not** free it). + */ +export class VectorBufferF extends VectorBase { + constructor(wasmInstance: AniraWasmInstance, items?: (BaseWrapper | number)[]) { + super(wasmInstance, wasmInstance._vector_buffer_f_create()) + if (items) for (const v of items) this.push(v) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._vector_buffer_f_destroy) + } + + size(): number { + return this.wasmInstance._vector_buffer_f_size(this.ptr) + } + + push(item: BaseWrapper | number): void { + this.wasmInstance._vector_buffer_f_push_back(this.ptr, resolvePtr(item)) + } + + /** + * Get a non-owning pointer to the element at `index`. + * The returned pointer is valid only while this vector is alive. + */ + get(index: number): number { + return this.wasmInstance._vector_buffer_f_get(this.ptr, index) + } +} diff --git a/web/src/wrappers/index.ts b/web/src/wrappers/index.ts new file mode 100644 index 00000000..8fbb7e73 --- /dev/null +++ b/web/src/wrappers/index.ts @@ -0,0 +1,25 @@ +export { BaseWrapper, resolvePtr, type PossiblePointer } from './BaseWrapper' +export { createInferenceBackend, type InferenceBackendValues } from './InferenceBackend' +export { InferenceConfig } from './InferenceConfig' +export { InferenceHandler } from './InferenceHandler' +export { JSPrePostProcessor } from './JSPrePostProcessor' +export { ModelData } from './ModelData' +export { PrePostProcessor } from './PrePostProcessor' +export { ProcessingSpec } from './ProcessingSpec' +export { TensorShape } from './TensorShape' +export { BufferF } from './utils/BufferF' +export { HostConfig } from './utils/HostConfig' +export { RingBuffer } from './utils/RingBuffer' +export { + TensorShapeList, + VectorBase, + VectorBufferF, + VectorFloat, + VectorInt64T, + VectorModelData, + VectorRingBuffer, + VectorSizeT, + VectorTensorShape, + VectorUnsignedInt, + VectorVectorInt64, +} from './Vectors' diff --git a/web/src/wrappers/system/InferenceThread.ts b/web/src/wrappers/system/InferenceThread.ts new file mode 100644 index 00000000..9746e106 --- /dev/null +++ b/web/src/wrappers/system/InferenceThread.ts @@ -0,0 +1,43 @@ +import { type AniraWasmInstance } from '../../factory' +import { BaseWrapper } from '../BaseWrapper' + +export class InferenceThread extends BaseWrapper { + constructor(wasmInstance: AniraWasmInstance) { + super(wasmInstance, wasmInstance._inference_thread_create_from_context()) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._inference_thread_destroy) + } + + /** Mirrors :cpp:func:`anira::InferenceThread::execute`. */ + execute(): boolean { + return this.wasmInstance._inference_thread_execute(this.ptr) === 1 + } + + /** Mirrors :cpp:func:`anira::InferenceThread::run_loop`. */ + runLoop(): void { + this.wasmInstance._inference_thread_run_loop(this.ptr) + } + + /** Mirrors :cpp:func:`anira::InferenceThread::stop`. */ + stop(): void { + this.wasmInstance._inference_thread_stop(this.ptr) + } + + /** Mirrors :cpp:func:`anira::InferenceThread::start`. */ + start(): void { + this.wasmInstance._inference_thread_start(this.ptr) + } + + /** Mirrors :cpp:func:`anira::InferenceThread::should_exit`. */ + shouldExit(): boolean { + return this.wasmInstance._inference_thread_should_exit(this.ptr) === 1 + } + + /** Mirrors :cpp:func:`anira::InferenceThread::is_running`. */ + isRunning(): boolean { + return this.wasmInstance._inference_thread_is_running(this.ptr) === 1 + } +} diff --git a/web/src/wrappers/utils/BufferF.ts b/web/src/wrappers/utils/BufferF.ts new file mode 100644 index 00000000..ddb9ee96 --- /dev/null +++ b/web/src/wrappers/utils/BufferF.ts @@ -0,0 +1,142 @@ +import type { AniraWasmInstance } from '../../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from '../BaseWrapper' + +/** + * TypeScript wrapper for anira::BufferF + * Thread-safe C API wrapper + */ +export class BufferF extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + numChannels?: number, + numSamples?: number + ) { + if (numChannels !== undefined && numSamples !== undefined) { + super(wasmInstance, wasmInstance._bufferf_create_with_size(numChannels, numSamples)) + } else { + super(wasmInstance, wasmInstance._bufferf_create()) + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._bufferf_destroy) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_num_channels`. */ + getNumChannels(): number { + return this.wasmInstance._bufferf_get_num_channels(this.ptr) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_num_samples`. */ + getNumSamples(): number { + return this.wasmInstance._bufferf_get_num_samples(this.ptr) + } + + /** Mirrors :cpp:func:`anira::Buffer::resize`. */ + resize(numChannels: number, numSamples: number): void { + this.wasmInstance._bufferf_resize(this.ptr, numChannels, numSamples) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_read_pointer() `. */ + getReadPointer(channel: number): number + /** Mirrors :cpp:func:`anira::Buffer::get_read_pointer() `. */ + getReadPointer(channel: number, sampleIndex: number): number + getReadPointer(channel: number, sampleIndex?: number): number { + if (sampleIndex === undefined) { + return this.wasmInstance._bufferf_get_read_pointer(this.ptr, channel) + } + return this.wasmInstance._bufferf_get_read_pointer_at(this.ptr, channel, sampleIndex) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_write_pointer() `. */ + getWritePointer(channel: number): number + /** Mirrors :cpp:func:`anira::Buffer::get_write_pointer() `. */ + getWritePointer(channel: number, sampleIndex: number): number + getWritePointer(channel: number, sampleIndex?: number): number { + if (sampleIndex === undefined) { + return this.wasmInstance._bufferf_get_write_pointer(this.ptr, channel) + } + return this.wasmInstance._bufferf_get_write_pointer_at(this.ptr, channel, sampleIndex) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_array_of_read_pointers`. */ + getArrayOfReadPointers(): number[] { + const numChannels = this.getNumChannels() + const outArray = this.wasmInstance._malloc(numChannels * 4) // 4 bytes per pointer + this.wasmInstance._bufferf_get_array_of_read_pointers(this.ptr, outArray) + + const result: number[] = [] + const view = new Uint32Array(this.wasmInstance.HEAPU32.buffer, outArray, numChannels) + for (let i = 0; i < numChannels; i++) { + result.push(view[i]) + } + + this.wasmInstance._free(outArray) + return result + } + + /** Mirrors :cpp:func:`anira::Buffer::get_array_of_write_pointers`. */ + getArrayOfWritePointers(): number[] { + const numChannels = this.getNumChannels() + const outArray = this.wasmInstance._malloc(numChannels * 4) // 4 bytes per pointer + this.wasmInstance._bufferf_get_array_of_write_pointers(this.ptr, outArray) + + const result: number[] = [] + const view = new Uint32Array(this.wasmInstance.HEAPU32.buffer, outArray, numChannels) + for (let i = 0; i < numChannels; i++) { + result.push(view[i]) + } + + this.wasmInstance._free(outArray) + return result + } + + /** Mirrors :cpp:func:`anira::Buffer::data`. */ + data(): number { + return this.wasmInstance._bufferf_data(this.ptr) + } + + /** Mirrors :cpp:func:`anira::Buffer::swap_data() `. */ + swapData(other: PossiblePointer): void + /** Mirrors :cpp:func:`anira::Buffer::swap_data() `. */ + swapData(rawPointer: number, size: number): void + swapData(otherOrRawPointer: PossiblePointer | number, size?: number): void { + // The single-arg overload accepts either a `BufferF` instance or a raw + // pointer to a `BufferF`; the two-arg overload accepts a raw float buffer + // pointer plus its element count. Distinguishing via arg count is + // unambiguous. + if (size === undefined) { + this.wasmInstance._bufferf_swap_data_with_buffer( + this.ptr, + resolvePtr(otherOrRawPointer as PossiblePointer) + ) + return + } + this.wasmInstance._bufferf_swap_data_with_raw_pointer( + this.ptr, + otherOrRawPointer as number, + size + ) + } + + /** Mirrors :cpp:func:`anira::Buffer::reset_channel_ptr`. */ + resetChannelPtr(): void { + this.wasmInstance._bufferf_reset_channel_ptr(this.ptr) + } + + /** Mirrors :cpp:func:`anira::Buffer::get_sample`. */ + getSample(channel: number, sampleIndex: number): number { + return this.wasmInstance._bufferf_get_sample(this.ptr, channel, sampleIndex) + } + + /** Mirrors :cpp:func:`anira::Buffer::set_sample`. */ + setSample(channel: number, sampleIndex: number, value: number): void { + this.wasmInstance._bufferf_set_sample(this.ptr, channel, sampleIndex, value) + } + + /** Mirrors :cpp:func:`anira::Buffer::clear`. */ + clear(): void { + this.wasmInstance._bufferf_clear(this.ptr) + } +} diff --git a/web/src/wrappers/utils/HostConfig.ts b/web/src/wrappers/utils/HostConfig.ts new file mode 100644 index 00000000..4af8766b --- /dev/null +++ b/web/src/wrappers/utils/HostConfig.ts @@ -0,0 +1,121 @@ +import type { AniraWasmInstance } from '../../factory' +import { BaseWrapper, type PossiblePointer, resolvePtr } from '../BaseWrapper' +import type { InferenceConfig } from '../InferenceConfig' + +/** + * TypeScript wrapper for anira::HostConfig + * Thread-safe C API wrapper + */ +export class HostConfig extends BaseWrapper { + constructor( + wasmInstance: AniraWasmInstance, + bufferSize?: number, + sampleRate?: number, + allowSmallerBuffers?: boolean, + tensorIndex?: number + ) { + if ( + bufferSize !== undefined && + sampleRate !== undefined && + allowSmallerBuffers !== undefined && + tensorIndex !== undefined + ) { + super( + wasmInstance, + wasmInstance._hostconfig_create_with_params( + bufferSize, + sampleRate, + allowSmallerBuffers ? 1 : 0, + tensorIndex + ) + ) + } else { + super(wasmInstance, wasmInstance._hostconfig_create()) + } + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._hostconfig_destroy) + } + + // Property getters + + /** Mirrors the :cpp:member:`anira::HostConfig::m_buffer_size` field. */ + get bufferSize(): number { + return this.wasmInstance._hostconfig_get_buffer_size(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_sample_rate` field. */ + get sampleRate(): number { + return this.wasmInstance._hostconfig_get_sample_rate(this.ptr) + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_allow_smaller_buffers` field. */ + get allowSmallerBuffers(): boolean { + return this.wasmInstance._hostconfig_get_allow_smaller_buffers(this.ptr) === 1 + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_tensor_index` field. */ + get tensorIndex(): number { + return this.wasmInstance._hostconfig_get_tensor_index(this.ptr) + } + + // Property setters + + /** Mirrors the :cpp:member:`anira::HostConfig::m_buffer_size` field. */ + set bufferSize(value: number) { + this.wasmInstance._hostconfig_set_buffer_size(this.ptr, value) + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_sample_rate` field. */ + set sampleRate(value: number) { + this.wasmInstance._hostconfig_set_sample_rate(this.ptr, value) + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_allow_smaller_buffers` field. */ + set allowSmallerBuffers(value: boolean) { + this.wasmInstance._hostconfig_set_allow_smaller_buffers(this.ptr, value ? 1 : 0) + } + + /** Mirrors the :cpp:member:`anira::HostConfig::m_tensor_index` field. */ + set tensorIndex(value: number) { + this.wasmInstance._hostconfig_set_tensor_index(this.ptr, value) + } + + equals(other: PossiblePointer): boolean { + return this.wasmInstance._hostconfig_equals(this.ptr, resolvePtr(other)) === 1 + } + + notEquals(other: PossiblePointer): boolean { + return this.wasmInstance._hostconfig_not_equals(this.ptr, resolvePtr(other)) === 1 + } + + /** Mirrors :cpp:func:`anira::HostConfig::get_relative_buffer_size`. */ + getRelativeBufferSize( + inferenceConfig: PossiblePointer, + tensorIndex: number, + input: boolean = true + ): number { + return this.wasmInstance._hostconfig_get_relative_buffer_size( + this.ptr, + resolvePtr(inferenceConfig), + tensorIndex, + input ? 1 : 0 + ) + } + + /** Mirrors :cpp:func:`anira::HostConfig::get_relative_sample_rate`. */ + getRelativeSampleRate( + inferenceConfig: PossiblePointer, + tensorIndex: number, + input: boolean = true + ): number { + return this.wasmInstance._hostconfig_get_relative_sample_rate( + this.ptr, + resolvePtr(inferenceConfig), + tensorIndex, + input ? 1 : 0 + ) + } +} diff --git a/web/src/wrappers/utils/RingBuffer.ts b/web/src/wrappers/utils/RingBuffer.ts new file mode 100644 index 00000000..56774a38 --- /dev/null +++ b/web/src/wrappers/utils/RingBuffer.ts @@ -0,0 +1,61 @@ +import type { AniraWasmInstance } from '../../factory' +import { BaseWrapper } from '../BaseWrapper' + +/** + * TypeScript wrapper for anira::RingBuffer + * Thread-safe C API wrapper + */ +export class RingBuffer extends BaseWrapper { + constructor(wasmInstance: AniraWasmInstance) { + super(wasmInstance, wasmInstance._ringbuffer_create()) + } + + /** Free the underlying C++ object. See :ref:`lifecycle-and-cleanup` for when to call this. */ + destroy(): void { + this._destroy(this.wasmInstance._ringbuffer_destroy) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::initialize_with_positions`. */ + initializeWithPositions(numChannels: number, numSamples: number): void { + this.wasmInstance._ringbuffer_initialize_with_positions( + this.ptr, + numChannels, + numSamples + ) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::clear_with_positions`. */ + clearWithPositions(): void { + this.wasmInstance._ringbuffer_clear_with_positions(this.ptr) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::push_sample`. */ + pushSample(channel: number, sample: number): void { + this.wasmInstance._ringbuffer_push_sample(this.ptr, channel, sample) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::pop_sample`. */ + popSample(channel: number): number { + return this.wasmInstance._ringbuffer_pop_sample(this.ptr, channel) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::get_future_sample`. */ + getFutureSample(channel: number, offset: number): number { + return this.wasmInstance._ringbuffer_get_future_sample(this.ptr, channel, offset) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::get_past_sample`. */ + getPastSample(channel: number, offset: number): number { + return this.wasmInstance._ringbuffer_get_past_sample(this.ptr, channel, offset) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::get_available_samples`. */ + getAvailableSamples(channel: number): number { + return this.wasmInstance._ringbuffer_get_available_samples(this.ptr, channel) + } + + /** Mirrors :cpp:func:`anira::RingBuffer::get_available_past_samples`. */ + getAvailablePastSamples(channel: number): number { + return this.wasmInstance._ringbuffer_get_available_past_samples(this.ptr, channel) + } +} diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 00000000..5dece95d --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "moduleResolution": "bundler", + "skipLibCheck": true, + + "composite": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "rootDir": "src", + "outDir": "dist", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 00000000..9163551d --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,209 @@ +import path from 'path' +import { defineConfig, type Plugin } from 'vite' +import { rollup } from 'rollup' +import dts from 'vite-plugin-dts' +import { viteStaticCopy } from 'vite-plugin-static-copy' + +function watchWasm() { + return { + name: 'watch-wasm', + buildStart() { + this.addWatchFile(path.resolve(__dirname, 'wasm')) + }, + } +} + +/** + * Prevents Vite's library-mode build from inlining `new URL(path, import.meta.url)` + * references as base64 data URLs. Instead, the built output keeps the `new URL()` + * pattern with corrected paths pointing to the built entry points, so that a + * consumer's app-mode Vite build can detect them (e.g. for worker bundling). + */ +function preserveWorkerUrls(): Plugin { + // Map source-level paths to their built entry point paths in dist/ + const rewrites: Array<{ sourcePath: string; builtEntry: string }> = [ + { + sourcePath: './workers/inference-worker.ts', + builtEntry: 'workers/inference-worker.js', + }, + { + sourcePath: './workers/audio-worklet.bundled.js', + builtEntry: 'workers/audio-worklet.bundled.js', + }, + { + sourcePath: '../wasm/AniraWeb.js', + builtEntry: 'wasm/AniraWeb.js', + }, + { + sourcePath: '../wasm/AniraWeb.wasm', + builtEntry: 'wasm/AniraWeb.wasm', + }, + ] + + return { + name: 'preserve-worker-urls', + enforce: 'pre', + + // In transform (pre): wrap the path in String() so Vite's + // assetImportMetaUrl plugin won't match it (requires a plain literal). + transform(code) { + let result = code + let modified = false + for (const { sourcePath } of rewrites) { + const needle = `new URL('${sourcePath}', import.meta.url)` + if (result.includes(needle)) { + result = result.replace( + needle, + `new URL(String('${sourcePath}'), import.meta.url)` + ) + modified = true + } + } + return modified ? result : null + }, + + // In renderChunk: replace String('source-path') with the correct + // literal path to the built entry, restoring the standard new URL() form. + renderChunk(code, chunk) { + let result = code + let modified = false + for (const { sourcePath, builtEntry } of rewrites) { + const pattern = new RegExp( + `String\\(["']${sourcePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}["']\\)`, + 'g' + ) + if (!pattern.test(result)) continue + const chunkDir = path.dirname(chunk.fileName) + let relPath = path.posix.relative(chunkDir, builtEntry) + if (!relPath.startsWith('.')) relPath = './' + relPath + result = result.replace( + new RegExp( + `String\\(["']${sourcePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}["']\\)`, + 'g' + ), + `'${relPath}'` + ) + modified = true + } + return modified ? result : null + }, + } +} + +/** + * After the main library build, re-bundles the audio worklet entry point into + * a single self-contained JS file with all dependencies inlined (except WASM + * externals). AudioWorklet's addModule() can't resolve ES module imports, so + * the file loaded by addModule must be fully self-contained. + */ +function bundleAudioWorklet(): Plugin { + return { + name: 'bundle-audio-worklet', + async closeBundle() { + const distDir = path.resolve(__dirname, 'dist') + const workletEntry = path.resolve(distDir, 'workers/audio-worklet.js') + + // Stub out new URL() asset references that the AudioWorkletGlobalScope + // can't resolve (no URL constructor). The worklet receives wasmBinary + // via postMessage, so these URLs are never used at runtime. + const stubWasmUrls = { + name: 'stub-wasm-urls', + renderChunk(code: string) { + const result = code.replace( + /new URL\(["'][^"']*["'],\s*import\.meta\.url\)\.href/g, + '""' + ) + return result !== code ? result : null + }, + } + + const bundle = await rollup({ + input: workletEntry, + plugins: [stubWasmUrls], + }) + await bundle.write({ + file: path.resolve(distDir, 'workers/audio-worklet.bundled.js'), + format: 'es', + inlineDynamicImports: true, + }) + await bundle.close() + }, + } +} + +export default defineConfig({ + base: './', + resolve: { + alias: [ + // onnxruntime-web 1.19.2 does not expose ort-wasm-simd-threaded.mjs + // in its package `exports`; resolve it directly from dist/. + { + find: 'onnxruntime-web/ort-wasm-simd-threaded.mjs', + replacement: path.resolve( + __dirname, + 'node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.mjs' + ), + }, + ], + }, + plugins: [ + preserveWorkerUrls(), + bundleAudioWorklet(), + watchWasm(), + viteStaticCopy({ + targets: [ + { src: 'wasm/*.wasm', dest: 'wasm' }, + { src: 'wasm/*.js', dest: 'wasm' }, + // Attribution for native deps statically linked into the WASM binary + // (populated by cmake/BuildWasm.cmake from the downloaded prebuilt). + { src: 'licenses/*', dest: 'licenses' }, + ], + }), + dts({ + include: ['src/**/*'], + outDir: 'dist', + }), + ], + build: { + lib: { + entry: { + index: path.resolve(__dirname, 'src/index.ts'), + 'workers/inference-worker': path.resolve( + __dirname, + 'src/workers/inference-worker.ts' + ), + 'workers/audio-worklet': path.resolve(__dirname, 'src/workers/audio-worklet.ts'), + 'workers/worklet-base': path.resolve(__dirname, 'src/workers/worklet-base.ts'), + }, + formats: ['es'], + }, + minify: false, + target: 'esnext', + outDir: 'dist', + rollupOptions: { + external: (id) => { + // Externalize both WASM files and emscripten-generated JS wrappers + if (id.includes('/wasm/')) return true + if (id.endsWith('.wasm')) return true + return false + }, + output: { + entryFileNames: '[name].js', + chunkFileNames: 'shared/[name]-[hash].js', + paths: (id) => { + // Rewrite paths for wasm imports to be relative to the dist folder + if (id.includes('/wasm/')) { + return id.replace(/.*\/wasm\//, './wasm/') + } + return id + }, + }, + }, + }, + // This is a known issue when using WebAssembly with Vite 5.x + // Need to specify `optimizeDeps.exclude` to NPM packages that uses WebAssembly + // See: https://github.com/vitejs/vite/issues/8427 + optimizeDeps: { + exclude: ['onnxruntime-web'], + }, +})