commit 4d20931eccd53887b09acaa8819e9a20fb9cdef4 Author: Kar l5 Date: Tue Jun 17 15:53:01 2025 +0530 init diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7f3e2e0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:22.04 + +WORKDIR /app + +# Install dependencies +RUN apt-get update && apt-get install -y \ + python3 \ + python3-pip \ + ffmpeg \ + cmake \ + build-essential \ + libsdl2-dev \ + libsdl2-ttf-dev \ + && rm -rf /var/lib/apt/lists/* + +# Copy whisper.cpp +COPY whisper.cpp-1.5.2 /app/whisper.cpp + +# Build whisper.cpp +RUN cd whisper.cpp && \ + mkdir -p build && \ + cd build && \ + cmake .. && \ + make -j$(nproc) + +# Copy API files +COPY app.py requirements.txt /app/ + +# Install Python dependencies +RUN pip install -r requirements.txt + +# Create data directory +RUN mkdir /data + +# Expose port +EXPOSE 4004 + +# Run the application +CMD ["python3", "app.py"] diff --git a/app.py b/app.py new file mode 100644 index 0000000..1d59eec --- /dev/null +++ b/app.py @@ -0,0 +1,75 @@ +from flask import Flask, request, jsonify +import os +import uuid +import subprocess +from werkzeug.utils import secure_filename + +app = Flask(__name__) +UPLOAD_FOLDER = '/data' +ALLOWED_EXTENSIONS = {'wav', 'mp3', 'ogg', 'flac'} + +def allowed_file(filename): +return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS + +@app.route('/stt', methods=['POST']) +def transcribe(): +if 'audio' not in request.files: +return jsonify({"error": "No audio file provided"}), 400 + +file = request.files['audio'] +if file.filename == '': +return jsonify({"error": "Empty filename"}), 400 + +if not file or not allowed_file(file.filename): +return jsonify({"error": "Invalid file type"}), 400 + +try: +# Generate unique filename +file_id = str(uuid.uuid4()) +orig_ext = secure_filename(file.filename).rsplit('.', 1)[1].lower() +orig_path = os.path.join(UPLOAD_FOLDER, f"{file_id}.{orig_ext}") +wav_path = os.path.join(UPLOAD_FOLDER, f"{file_id}.wav") +output_base = os.path.join(UPLOAD_FOLDER, file_id) + +# Save original file +file.save(orig_path) + +# Convert to WAV if needed +if orig_ext != 'wav': +subprocess.run([ +'ffmpeg', '-i', orig_path, +'-ar', '16000', '-ac', '1', '-c:a', 'pcm_s16le', wav_path +], check=True) +os.remove(orig_path) +audio_path = wav_path +else: +audio_path = orig_path + +# Run whisper.cpp +subprocess.run([ +'/app/whisper.cpp/build/bin/main', +'-m', '/app/whisper.cpp/models/ggml-base.bin', +'-f', audio_path, +'-otxt', '-of', output_base +], check=True) + +# Read output +output_file = f"{output_base}.txt" +with open(output_file, 'r') as f: +transcription = f.read() + +# Cleanup +for f in [orig_path, wav_path, audio_path, output_file]: +if os.path.exists(f): +os.remove(f) + +return jsonify({"text": transcription.strip()}) + +except subprocess.CalledProcessError as e: +return jsonify({"error": f"Whisper processing failed: {e.stderr}"}), 500 +except Exception as e: +return jsonify({"error": str(e)}), 500 + +if __name__ == '__main__': +os.makedirs(UPLOAD_FOLDER, exist_ok=True) +app.run(host='0.0.0.0', port=4004) diff --git a/data/out.wav b/data/out.wav new file mode 100644 index 0000000..307f88b Binary files /dev/null and b/data/out.wav differ diff --git a/data/rec.wav b/data/rec.wav new file mode 100644 index 0000000..1c009dc Binary files /dev/null and b/data/rec.wav differ diff --git a/data/rec3.wav b/data/rec3.wav new file mode 100644 index 0000000..0227476 Binary files /dev/null and b/data/rec3.wav differ diff --git a/whisper.cpp-1.5.2/.devops/cublas.Dockerfile b/whisper.cpp-1.5.2/.devops/cublas.Dockerfile new file mode 100644 index 0000000..ae3da75 --- /dev/null +++ b/whisper.cpp-1.5.2/.devops/cublas.Dockerfile @@ -0,0 +1,28 @@ +ARG UBUNTU_VERSION=22.04 + +# This needs to generally match the container host's environment. +ARG CUDA_VERSION=11.7.1 + +# Target the CUDA build image +ARG BASE_CUDA_DEV_CONTAINER=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} + +FROM ${BASE_CUDA_DEV_CONTAINER} as build + +# Unless otherwise specified, we make a fat build. +ARG CUDA_DOCKER_ARCH=all + +RUN apt-get update && \ + apt-get install -y build-essential git cmake + +WORKDIR /app + +COPY . . + +# Set nvcc architecture +ENV CUDA_DOCKER_ARCH=${CUDA_DOCKER_ARCH} +# Enable cuBLAS +ENV WHISPER_CUBLAS=1 + +RUN make + +ENTRYPOINT ["/app/main"] diff --git a/whisper.cpp-1.5.2/.github/workflows/bindings-go.yml b/whisper.cpp-1.5.2/.github/workflows/bindings-go.yml new file mode 100644 index 0000000..13f1950 --- /dev/null +++ b/whisper.cpp-1.5.2/.github/workflows/bindings-go.yml @@ -0,0 +1,22 @@ +name: Bindings Tests (Go) +on: + push: + paths: + - bindings/go/** + - whisper.h + pull_request: + paths: + - bindings/go/** + - whisper.h + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: '^1.19' + - uses: actions/checkout@v1 + - run: | + cd bindings/go + make test diff --git a/whisper.cpp-1.5.2/.github/workflows/bindings-ruby.yml b/whisper.cpp-1.5.2/.github/workflows/bindings-ruby.yml new file mode 100644 index 0000000..902dfe6 --- /dev/null +++ b/whisper.cpp-1.5.2/.github/workflows/bindings-ruby.yml @@ -0,0 +1,22 @@ +name: Bindings Tests (Ruby) +on: + push: + paths: + - bindings/ruby/** + - whisper.h + pull_request: + paths: + - bindings/ruby/** + - whisper.h + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + steps: + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.0' + - uses: actions/checkout@v1 + - run: | + cd bindings/ruby/ext + ruby extconf.rb && make diff --git a/whisper.cpp-1.5.2/.github/workflows/build.yml b/whisper.cpp-1.5.2/.github/workflows/build.yml new file mode 100644 index 0000000..5d254a7 --- /dev/null +++ b/whisper.cpp-1.5.2/.github/workflows/build.yml @@ -0,0 +1,493 @@ +name: CI +on: [push, pull_request] + +env: + ubuntu_image: "ubuntu:22.04" + +jobs: + ubuntu-latest: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential libsdl2-dev + make + make stream' + + macOS-latest: + runs-on: macOS-latest + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Dependencies + run: | + brew update + brew install sdl2 + + - name: Build + run: | + make + make stream + + freeBSD-latest: + runs-on: macos-12 + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Build + uses: cross-platform-actions/action@v0.15.0 + with: + operating_system: freebsd + version: '13.2' + run: | + sudo pkg update + sudo pkg install -y gmake sdl2 + gmake + gmake stream + + ubuntu-latest-gcc: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + build: [Debug, Release] + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential cmake libsdl2-dev + cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} + make + ctest -L gh --output-on-failure' + + ubuntu-latest-clang: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + build: [Debug, Release] + arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y clang + apt install -y clang build-essential cmake libsdl2-dev + cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang + make + ctest -L gh --output-on-failure' + + ubuntu-latest-gcc-sanitized: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + sanitizer: [ADDRESS, THREAD, UNDEFINED] + arch: [linux/amd64] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Build ${{ matrix.arch }} + run: | + docker run --platform ${{ matrix.arch }} --rm \ + -v ${{ github.workspace }}:/workspace \ + -w /workspace ${{ env.ubuntu_image }} /bin/sh -c ' + set -e + apt update + apt install -y build-essential cmake + cmake . -DCMAKE_BUILD_TYPE=Debug -DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON + make + ctest -L gh --output-on-failure' + + windows: + runs-on: windows-latest + + strategy: + matrix: + build: [Release] + arch: [Win32, x64] + sdl2: [ON] + include: + - arch: Win32 + s2arc: x86 + jnaPath: win32-x86 + - arch: x64 + s2arc: x64 + jnaPath: win32-x86-64 + - sdl2: ON + s2ver: 2.26.0 + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1 + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DWHISPER_SDL2=${{ matrix.sdl2 }} + + - name: Build + run: | + cd ./build + msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload dll + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.jnaPath }}_whisper.dll + path: build/bin/${{ matrix.build }}/whisper.dll + + - name: Upload binaries + if: matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v1 + with: + name: whisper-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + windows-blas: + runs-on: windows-latest + + strategy: + matrix: + build: [Release] + arch: [Win32, x64] + blas: [ON] + sdl2: [ON] + include: + - arch: Win32 + obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x86.zip + s2arc: x86 + - arch: x64 + obzip: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.25/OpenBLAS-0.3.25-x64.zip + s2arc: x64 + - sdl2: ON + s2ver: 2.26.0 + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1 + + - name: Fetch OpenBLAS + if: matrix.blas == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO blas.zip ${{ matrix.obzip }} + 7z x blas.zip -oblas -y + copy blas/include/cblas.h . + copy blas/include/openblas_config.h . + echo "OPENBLAS_PATH=$env:GITHUB_WORKSPACE/blas" >> $env:GITHUB_ENV + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DWHISPER_OPENBLAS=${{ matrix.blas }} + -DCMAKE_LIBRARY_PATH="$env:OPENBLAS_PATH/lib" + -DWHISPER_SDL2=${{ matrix.sdl2 }} + + - name: Build + run: | + cd ./build + msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }} + + - name: Copy libopenblas.dll + if: matrix.blas == 'ON' + run: copy "$env:OPENBLAS_PATH/bin/libopenblas.dll" build/bin/${{ matrix.build }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload binaries + if: matrix.blas == 'ON' && matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v1 + with: + name: whisper-blas-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + windows-cublas: + runs-on: windows-latest + + strategy: + matrix: + build: [Release] + arch: [x64] + cublas: [ON] + sdl2: [ON] + cuda-toolkit: [12.2.0, 11.8.0] + include: + - arch: x64 + s2arc: x64 + - sdl2: ON + s2ver: 2.26.0 + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Add msbuild to PATH + uses: microsoft/setup-msbuild@v1 + + - name: Install CUDA Toolkit + id: cuda-toolkit + uses: Jimver/cuda-toolkit@v0.2.11 + with: + cuda: '${{ matrix.cuda-toolkit }}' + + - name: Fetch SDL2 and set SDL2_DIR + if: matrix.sdl2 == 'ON' + run: | + C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip + 7z x sdl2.zip + echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV + + - name: Configure + run: > + cmake -S . -B ./build -A ${{ matrix.arch }} + -DCMAKE_BUILD_TYPE=${{ matrix.build }} + -DWHISPER_CUBLAS=1 + + - name: Build ${{ matrix.cuda-toolkit }} + run: | + cd ./build + cmake --build . --config ${{ matrix.build }} + + - name: Copy CUDA DLLs + run: > + Copy-Item -PassThru + -Path "${{ steps.cuda-toolkit.outputs.CUDA_PATH }}/bin/*.dll" + -Include cudart64_*,cublas64_*,cublasLt64_* + -Destination build/bin/${{ matrix.build }} + + - name: Copy SDL2.dll + if: matrix.sdl2 == 'ON' + run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }} + + - name: Upload binaries + if: matrix.sdl2 == 'ON' + uses: actions/upload-artifact@v1 + with: + name: whisper-cublas-${{ matrix.cuda-toolkit }}-bin-${{ matrix.arch }} + path: build/bin/${{ matrix.build }} + + emscripten: + runs-on: ubuntu-latest + + strategy: + matrix: + build: [Release] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Setup emsdk + uses: mymindstorm/setup-emsdk@v12 + + - name: Verify + run: emcc -v + + - name: Build + run: | + emcmake cmake . -DCMAKE_BUILD_TYPE=${{ matrix.build }} + make + + ios: + runs-on: macos-latest + + strategy: + matrix: + build: [Release] + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Configure + run: | + cp models/for-tests-ggml-base.en.bin models/ggml-base.en.bin + mkdir models/ggml-base.en-encoder.mlmodelc + + - name: Build objc example + run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphonesimulator build + + - name: Build swiftui example + run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphonesimulator build + + android: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Install Java + uses: actions/setup-java@v3 + with: + distribution: zulu + java-version: 17 + + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + + - name: Build + run: | + cd examples/whisper.android + ./gradlew assembleRelease --no-daemon + + android_java: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: set up JDK 11 + uses: actions/setup-java@v3 + with: + java-version: '11' + distribution: 'temurin' + cache: gradle + + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + with: + api-level: 30 + build-tools-version: 30.0.3 + + - name: Build + run: | + cd examples/whisper.android.java + chmod +x ./gradlew + ./gradlew assembleRelease + + java: + needs: [ 'windows' ] + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Java + uses: actions/setup-java@v1 + with: + java-version: 17 + + - name: Download Windows lib + uses: actions/download-artifact@v3 + with: + name: win32-x86-64_whisper.dll + path: bindings/java/build/generated/resources/main/win32-x86-64 + + - name: Build + run: | + models\download-ggml-model.cmd tiny.en + cd bindings/java + chmod +x ./gradlew + ./gradlew build + + - name: Upload jar + uses: actions/upload-artifact@v3 + with: + name: whispercpp.jar + path: bindings/java/build/libs/whispercpp-*.jar + + - name: Publish package + if: ${{ github.ref == 'refs/heads/master' }} + uses: gradle/gradle-build-action@v2.4.2 + with: + arguments: publish + build-root-directory: bindings/java + env: + MAVEN_USERNAME: ${{ secrets.JIRA_USER }} + MAVEN_PASSWORD: ${{ secrets.JIRA_PASS }} + PGP_SECRET: ${{ secrets.GPG_PRIVATE_KEY }} + PGP_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + + quantize: + runs-on: ubuntu-latest + + steps: + - name: Clone + uses: actions/checkout@v3 + + - name: Test quantize + run: | + ./models/download-ggml-model.sh tiny.en + make quantize + ./quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0 diff --git a/whisper.cpp-1.5.2/.github/workflows/examples.yml b/whisper.cpp-1.5.2/.github/workflows/examples.yml new file mode 100644 index 0000000..ddaf5e9 --- /dev/null +++ b/whisper.cpp-1.5.2/.github/workflows/examples.yml @@ -0,0 +1,48 @@ +name: Examples Tests +on: + push: + paths: + - examples/addon.node/** + - whisper.h + pull_request: + paths: + - examples/addon.node/** + - whisper.h + +jobs: + addon_node-ubuntu-latest: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 16.x, 18.x ] + steps: + - name: Clone + uses: actions/checkout@v1 + + - name: Dependencies + run: | + sudo apt-get update + sudo apt-get install build-essential + sudo apt-get install cmake + sudo apt-get install libsdl2-dev + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + + - name: Install package.json dependencies + working-directory: ./examples/addon.node + run: npm install + + - name: Compile addon.node + run: npx cmake-js compile -T whisper-addon -B Release + + - name: Download test model + run: | + bash ./models/download-ggml-model.sh base.en + - name: Test + run: | + cd examples/addon.node + npm run test diff --git a/whisper.cpp-1.5.2/.gitignore b/whisper.cpp-1.5.2/.gitignore new file mode 100644 index 0000000..30fca39 --- /dev/null +++ b/whisper.cpp-1.5.2/.gitignore @@ -0,0 +1,61 @@ +*.o +*.a +.cache/ +.coreml/ +.test/ +.vs/ +.vscode/ +.DS_Store + +build/ +build-coreml/ +build-em/ +build-debug/ +build-release/ +build-rwdi/ +build-static/ +build-cublas/ +build-no-accel/ +build-sanitize-addr/ +build-sanitize-thread/ + +# SPM +.build/ +.swiftpm +*.metallib + +/main +/stream +/command +/talk +/talk-llama +/bench +/quantize +/server +/lsp + +arm_neon.h +sync.sh +libwhisper.a +libwhisper.so +compile_commands.json + +examples/arm_neon.h +examples/whisper.objc/whisper.objc.xcodeproj/xcshareddata +examples/whisper.objc/whisper.objc.xcodeproj/xcuserdata/ +examples/whisper.objc/whisper.objc.xcodeproj/project.xcworkspace/xcuserdata + +extra/bench-gg.txt + +models/*.mlmodel +models/*.mlmodelc +models/*.mlpackage +bindings/java/.gradle/ +bindings/java/.idea/ +.idea/ + +benchmark_results.csv +cmake-build-debug/ +.cxx/ +.gradle/ +local.properties \ No newline at end of file diff --git a/whisper.cpp-1.5.2/.gitmodules b/whisper.cpp-1.5.2/.gitmodules new file mode 100644 index 0000000..94d7ce1 --- /dev/null +++ b/whisper.cpp-1.5.2/.gitmodules @@ -0,0 +1,3 @@ +[submodule "bindings/ios"] + path = bindings/ios + url = https://github.com/ggerganov/whisper.spm diff --git a/whisper.cpp-1.5.2/CMakeLists.txt b/whisper.cpp-1.5.2/CMakeLists.txt new file mode 100644 index 0000000..03e6bd0 --- /dev/null +++ b/whisper.cpp-1.5.2/CMakeLists.txt @@ -0,0 +1,565 @@ +cmake_minimum_required (VERSION 3.5) + +project(whisper.cpp VERSION 1.5.2) + +# Add path to modules +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + set(WHISPER_STANDALONE ON) + include(GitVars) + include(BuildTypes) + + # configure project version + if (EXISTS "${CMAKE_SOURCE_DIR}/bindings/ios/Makefile-tmpl") + configure_file(${CMAKE_SOURCE_DIR}/bindings/ios/Makefile-tmpl ${CMAKE_SOURCE_DIR}/bindings/ios/Makefile @ONLY) + endif() + configure_file(${CMAKE_SOURCE_DIR}/bindings/javascript/package-tmpl.json ${CMAKE_SOURCE_DIR}/bindings/javascript/package.json @ONLY) +else() + set(WHISPER_STANDALONE OFF) +endif() + +if (EMSCRIPTEN) + set(BUILD_SHARED_LIBS_DEFAULT OFF) + + option(WHISPER_WASM_SINGLE_FILE "whisper: embed WASM inside the generated whisper.js" ON) +else() + if (MINGW) + set(BUILD_SHARED_LIBS_DEFAULT OFF) + else() + set(BUILD_SHARED_LIBS_DEFAULT ON) + endif() +endif() + +# options + +if (APPLE) + set(WHISPER_METAL_DEFAULT ON) +else() + set(WHISPER_METAL_DEFAULT OFF) +endif() + +option(BUILD_SHARED_LIBS "whisper: build shared libs" ${BUILD_SHARED_LIBS_DEFAULT}) + +option(WHISPER_ALL_WARNINGS "whisper: enable all compiler warnings" ON) +option(WHISPER_ALL_WARNINGS_3RD_PARTY "whisper: enable all compiler warnings in 3rd party libs" OFF) + +option(WHISPER_SANITIZE_THREAD "whisper: enable thread sanitizer" OFF) +option(WHISPER_SANITIZE_ADDRESS "whisper: enable address sanitizer" OFF) +option(WHISPER_SANITIZE_UNDEFINED "whisper: enable undefined sanitizer" OFF) + +option(WHISPER_BUILD_TESTS "whisper: build tests" ${WHISPER_STANDALONE}) +option(WHISPER_BUILD_EXAMPLES "whisper: build examples" ${WHISPER_STANDALONE}) + +option(WHISPER_SDL2 "whisper: support for libSDL2" OFF) + +option(WHISPER_NO_AVX "whisper: disable AVX" OFF) +option(WHISPER_NO_AVX2 "whisper: disable AVX2" OFF) +option(WHISPER_NO_FMA "whisper: disable FMA" OFF) +option(WHISPER_NO_F16C "whisper: disable F16c" OFF) + +option(WHISPER_OPENVINO "whisper: support for OpenVINO" OFF) + +if (APPLE) + option(WHISPER_NO_ACCELERATE "whisper: disable Accelerate framework" OFF) + option(WHISPER_METAL "whisper: use Metal" ${WHISPER_METAL_DEFAULT}) + option(WHISPER_METAL_NDEBUG "whisper: disable Metal debugging" OFF) + option(WHISPER_COREML "whisper: enable Core ML framework" OFF) + option(WHISPER_COREML_ALLOW_FALLBACK "whisper: allow non-CoreML fallback" OFF) +else() + option(WHISPER_BLAS "whisper: use BLAS libraries" OFF) + option(WHISPER_BLAS_VENDOR "whisper: BLAS library vendor" Generic) + option(WHISPER_OPENBLAS "whisper: prefer OpenBLAS" OFF) + option(WHISPER_CUBLAS "whisper: support for cuBLAS" OFF) + option(WHISPER_HIPBLAS "whisper: support for hipBLAS" OFF) + option(WHISPER_CLBLAST "whisper: use CLBlast" OFF) +endif() + +option(WHISPER_PERF "whisper: enable perf timings" OFF) + +# sanitizers + +if (NOT MSVC) + if (WHISPER_SANITIZE_THREAD) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") + endif() + + if (WHISPER_SANITIZE_ADDRESS) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") + endif() + + if (WHISPER_SANITIZE_UNDEFINED) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") + endif() +endif() + +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffast-math") +#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native") + +# dependencies + +find_package(Threads REQUIRED) + +# on APPLE +if (APPLE) + # include Accelerate framework + if (NOT WHISPER_NO_ACCELERATE) + find_library(ACCELERATE_FRAMEWORK Accelerate) + + if (ACCELERATE_FRAMEWORK) + message(STATUS "Accelerate framework found") + + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} ${ACCELERATE_FRAMEWORK}) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_USE_ACCELERATE) + else() + message(FATAL_ERROR "Accelerate framework not found") + endif() + endif() + + if (WHISPER_METAL) + find_library(FOUNDATION_LIBRARY Foundation REQUIRED) + find_library(METAL_FRAMEWORK Metal REQUIRED) + find_library(METALKIT_FRAMEWORK MetalKit REQUIRED) + + if (METAL_FRAMEWORK) + message(STATUS "Metal framework found") + + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} + ${FOUNDATION_LIBRARY} + ${METAL_FRAMEWORK} + ${METALKIT_FRAMEWORK} + ) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_USE_METAL) + + if (WHISPER_METAL_NDEBUG) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_METAL_NDEBUG) + endif() + else() + message(FATAL_ERROR "Metal framework not found") + endif() + + set(GGML_SOURCES_METAL ggml-metal.m ggml-metal.h) + + # copy ggml-metal.metal to bin directory + configure_file(ggml-metal.metal bin/ggml-metal.metal COPYONLY) + endif() + + if (WHISPER_COREML) + find_library(FOUNDATION_FRAMEWORK Foundation) + find_library(COREML_FRAMEWORK CoreML) + + if (COREML_FRAMEWORK) + message(STATUS "CoreML framework found") + + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DWHISPER_USE_COREML) + else() + message(FATAL_ERROR "CoreML framework not found") + endif() + + if (WHISPER_COREML_ALLOW_FALLBACK) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DWHISPER_COREML_ALLOW_FALLBACK) + endif() + endif() +endif() + +if (WHISPER_OPENBLAS) + set(WHISPER_BLAS_VENDOR "OpenBLAS") + set(WHISPER_BLAS ON) +endif() + +if (WHISPER_BLAS) + if (WIN32) + if(DEFINED ENV{OPENBLAS_PATH}) + set(BLAS_LIBRARIES $ENV{OPENBLAS_PATH}/lib/libopenblas.dll.a) + message(STATUS "Libraries ${BLAS_LIBRARIES}") + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_USE_OPENBLAS) + include_directories($ENV{OPENBLAS_PATH}/include) + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} ${BLAS_LIBRARIES}) + else () + message(FATAL_ERROR "BLAS library was not found. Environment variable OPENBLAS_PATH not defined.") + endif () + else () + set(BLA_STATIC 1) + set(BLA_VENDOR ${WHISPER_BLAS_VENDOR}) + set(BLA_SIZEOF_INTEGER 8) + set(BLA_PREFER_PKGCONFIG 1) + find_package(BLAS) + + if(BLAS_FOUND) + message(STATUS "BLAS compatible library found") + message(STATUS "Libraries ${BLAS_LIBRARIES}") + find_path(BLAS_INCLUDE_DIRS cblas.h /usr/include/openblas /usr/local/include/openblas $ENV{BLAS_HOME}/include) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_USE_OPENBLAS) + include_directories(${BLAS_INCLUDE_DIRS}) + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} ${BLAS_LIBRARIES}) + else() + message(FATAL_ERROR "BLAS library was not found") + endif() + endif () +endif () + +if (WHISPER_CUBLAS) + cmake_minimum_required(VERSION 3.17) + + find_package(CUDAToolkit) + + if (CUDAToolkit_FOUND) + message(STATUS "cuBLAS found") + + enable_language(CUDA) + + set(GGML_SOURCES_CUDA ggml-cuda.cu ggml-cuda.h) + + add_compile_definitions(GGML_USE_CUBLAS) + + if (WHISPER_STATIC) + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} CUDA::cudart_static CUDA::cublas_static CUDA::cublasLt_static) + else() + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} CUDA::cudart CUDA::cublas CUDA::cublasLt) + endif() + + else() + message(FATAL_ERROR "cuBLAS not found") + endif() +endif() + + +if (WHISPER_HIPBLAS) + list(APPEND CMAKE_PREFIX_PATH /opt/rocm) + if (NOT ${CMAKE_C_COMPILER_ID} MATCHES "Clang") + message(WARNING "Only LLVM is supported for HIP, hint: CC=/opt/rocm/llvm/bin/clang") + endif() + if (NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") + message(WARNING "Only LLVM is supported for HIP, hint: CXX=/opt/rocm/llvm/bin/clang++") + endif() + + find_package(hip) + find_package(hipblas) + find_package(rocblas) + + if (${hipblas_FOUND} AND ${hip_FOUND}) + message(STATUS "HIP and hipBLAS found") + add_compile_definitions(GGML_USE_HIPBLAS GGML_USE_CUBLAS) + add_library(ggml-rocm OBJECT ggml-cuda.cu ggml-cuda.h) + set_property(TARGET ggml-rocm PROPERTY POSITION_INDEPENDENT_CODE ON) + set_source_files_properties(ggml-cuda.cu PROPERTIES LANGUAGE CXX) + target_link_libraries(ggml-rocm PRIVATE hip::device PUBLIC hip::host roc::rocblas roc::hipblas) + + if (WHISPER_STATIC) + message(FATAL_ERROR "Static linking not supported for HIP/ROCm") + endif() + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} ggml-rocm) + else() + message(FATAL_ERROR "hipBLAS or HIP not found. Try setting CMAKE_PREFIX_PATH=/opt/rocm") + endif() +endif() + +if (WHISPER_CLBLAST) + find_package(CLBlast) + if (CLBlast_FOUND) + message(STATUS "CLBlast found") + + set(GGML_SOURCES_OPENCL ggml-opencl.cpp ggml-opencl.h) + + add_compile_definitions(GGML_USE_CLBLAST) + + set(WHISPER_EXTRA_LIBS ${WHISPER_EXTRA_LIBS} clblast) + else() + message(FATAL_ERROR "CLBlast not found") + endif() +endif() + +if( WHISPER_OPENVINO ) + find_package(OpenVINO REQUIRED COMPONENTS Runtime) +endif() + +# compiler flags + +if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo") +endif () + +if (WHISPER_ALL_WARNINGS) + if (NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ + -Wall \ + -Wextra \ + -Wpedantic \ + -Wshadow \ + -Wcast-qual \ + -Wstrict-prototypes \ + -Wpointer-arith \ + -Wno-unused-function \ + ") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ + -Wall \ + -Wextra \ + -Wpedantic \ + -Wcast-qual \ + ") + else() + # todo : msvc + endif() +endif() + +if (NOT MSVC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=vla") + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-math-errno -ffinite-math-only -funsafe-math-optimizations") +endif() + +message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") + +if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64") + message(STATUS "ARM detected") +elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ppc64le") + message(STATUS "PowerPC detected") +else() + message(STATUS "x86 detected") + if (MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /utf-8") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8") + if(NOT WHISPER_NO_AVX2) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX2") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /arch:AVX2") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:AVX2") + else() + if(NOT WHISPER_NO_AVX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:AVX") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /arch:AVX") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:AVX") + endif() + endif() + else() + if (EMSCRIPTEN) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + else() + if(NOT WHISPER_NO_AVX) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx") + endif() + if(NOT WHISPER_NO_AVX2) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx2") + endif() + if(NOT WHISPER_NO_FMA) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfma") + endif() + if(NOT WHISPER_NO_F16C) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mf16c") + endif() + endif() + endif() +endif() + +# +# POSIX conformance +# + +# clock_gettime came in POSIX.1b (1993) +# CLOCK_MONOTONIC came in POSIX.1-2001 / SUSv3 as optional +# posix_memalign came in POSIX.1-2001 / SUSv3 +# M_PI is an XSI extension since POSIX.1-2001 / SUSv3, came in XPG1 (1985) +add_compile_definitions(_XOPEN_SOURCE=600) + +# Somehow in OpenBSD whenever POSIX conformance is specified +# some string functions rely on locale_t availability, +# which was introduced in POSIX.1-2008, forcing us to go higher +if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + remove_definitions(-D_XOPEN_SOURCE=600) + add_compile_definitions(_XOPEN_SOURCE=700) +endif() + +# Data types, macros and functions related to controlling CPU affinity +# are available on Linux through GNU extensions in libc +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + add_compile_definitions(_GNU_SOURCE) +endif() + +# RLIMIT_MEMLOCK came in BSD, is not specified in POSIX.1, +# and on macOS its availability depends on enabling Darwin extensions +# similarly on DragonFly, enabling BSD extensions is necessary +if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + add_compile_definitions(_DARWIN_C_SOURCE) +endif() +if (CMAKE_SYSTEM_NAME MATCHES "DragonFly") + add_compile_definitions(_DARWIN_C_SOURCE) +endif() + +# alloca is a non-standard interface that is not visible on BSDs when +# POSIX conformance is specified, but not all of them provide a clean way +# to enable it in such cases +if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + add_compile_definitions(__BSD_VISIBLE) +endif() +if (CMAKE_SYSTEM_NAME MATCHES "NetBSD") + add_compile_definitions(_NETBSD_SOURCE) +endif() +if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD") + add_compile_definitions(_BSD_SOURCE) +endif() + +if (WHISPER_PERF) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DGGML_PERF) +endif() + +# +# whisper.coreml - Core ML support +# + +if (WHISPER_COREML) + set(TARGET whisper.coreml) + + add_library(${TARGET} + coreml/whisper-encoder.h + coreml/whisper-encoder.mm + coreml/whisper-encoder-impl.h + coreml/whisper-encoder-impl.m + ) + + include(DefaultTargetOptions) + + target_include_directories(${TARGET} PUBLIC + . + ) + + target_link_libraries(${TARGET} PRIVATE ${FOUNDATION_FRAMEWORK} ${COREML_FRAMEWORK}) + + set_target_properties(${TARGET} PROPERTIES + COMPILE_FLAGS "-fobjc-arc" + ) +endif() + +if (WHISPER_OPENVINO) + set(TARGET whisper.openvino) + + add_library(${TARGET} OBJECT + openvino/whisper-openvino-encoder.h + openvino/whisper-openvino-encoder.cpp + ) + + target_include_directories(${TARGET} PUBLIC + . + ) + + set_property(TARGET ${TARGET} PROPERTY POSITION_INDEPENDENT_CODE ON) + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -DWHISPER_USE_OPENVINO) + + target_link_libraries(${TARGET} PRIVATE openvino::runtime) +endif() + +# +# whisper - this is the main library of the project +# + +set(TARGET whisper) + +add_library(${TARGET} + ggml.h + ggml.c + ggml-alloc.h + ggml-alloc.c + ggml-backend.h + ggml-backend.c + ggml-quants.h + ggml-quants.c + ${GGML_SOURCES_METAL} + ${GGML_SOURCES_CUDA} + ${GGML_SOURCES_OPENCL} + whisper.h + whisper.cpp + ) + +include(DefaultTargetOptions) + +target_include_directories(${TARGET} PUBLIC + . + ) + +if (WHISPER_COREML) + target_link_libraries(${TARGET} PRIVATE whisper.coreml) +endif() + +if (WHISPER_OPENVINO) + target_link_libraries(${TARGET} PRIVATE whisper.openvino) +endif() + +if (MSVC) + target_link_libraries(${TARGET} PRIVATE ${WHISPER_EXTRA_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + + set(WHISPER_EXTRA_FLAGS ${WHISPER_EXTRA_FLAGS} -D_CRT_SECURE_NO_WARNINGS) +else() + target_link_libraries(${TARGET} PRIVATE m ${WHISPER_EXTRA_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +endif() + +if (BUILD_SHARED_LIBS) + target_link_libraries(${TARGET} PUBLIC + ${CMAKE_DL_LIBS} + ) + + target_compile_definitions(${TARGET} PUBLIC + WHISPER_SHARED + GGML_SHARED + ) + + target_compile_definitions(${TARGET} PRIVATE + WHISPER_BUILD + GGML_BUILD + ) + + if (WHISPER_METAL) + # TODO: I think this should make ggml-metal.m "see" the ggml-metal.metal file from the "bin" directory + # but for some reason it does not work here like it does in llama.cpp + set_target_properties(${TARGET} PROPERTIES RESOURCE "${CMAKE_CURRENT_SOURCE_DIR}/ggml-metal.metal") + endif() +endif() + +if (GGML_SOURCES_CUDA) + message(STATUS "GGML CUDA sources found, configuring CUDA architecture") + set_property(TARGET whisper PROPERTY CUDA_ARCHITECTURES OFF) + set_property(TARGET whisper PROPERTY CUDA_SELECT_NVCC_ARCH_FLAGS "Auto") +endif() + +if (EMSCRIPTEN) + set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "-msimd128") +endif() + +target_compile_definitions(${TARGET} PUBLIC + ${WHISPER_EXTRA_FLAGS} + ) + +set_target_properties(${TARGET} PROPERTIES PUBLIC_HEADER "ggml.h;whisper.h") + +include(GNUInstallDirs) + +install(TARGETS ${TARGET} + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib/static + RUNTIME DESTINATION bin + RESOURCE DESTINATION bin + PUBLIC_HEADER DESTINATION include + ) + +# +# bindings +# + +add_subdirectory(bindings) + +# +# programs, examples and tests +# + +if (WHISPER_BUILD_TESTS AND NOT CMAKE_JS_VERSION) + enable_testing() + add_subdirectory(tests) +endif () + +if (WHISPER_BUILD_EXAMPLES) + add_subdirectory(examples) +endif() diff --git a/whisper.cpp-1.5.2/LICENSE b/whisper.cpp-1.5.2/LICENSE new file mode 100644 index 0000000..76f67ef --- /dev/null +++ b/whisper.cpp-1.5.2/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Georgi Gerganov + +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/whisper.cpp-1.5.2/Makefile b/whisper.cpp-1.5.2/Makefile new file mode 100644 index 0000000..b1f5b7c --- /dev/null +++ b/whisper.cpp-1.5.2/Makefile @@ -0,0 +1,448 @@ +default: main bench quantize server + +ifndef UNAME_S +UNAME_S := $(shell uname -s) +endif + +ifndef UNAME_P +UNAME_P := $(shell uname -p) +endif + +ifndef UNAME_M +UNAME_M := $(shell uname -m) +endif + +ifndef NVCC_VERSION + ifeq ($(call,$(shell which nvcc))$(.SHELLSTATUS),0) + NVCC_VERSION := $(shell nvcc --version | egrep -o "V[0-9]+.[0-9]+.[0-9]+" | cut -c2-) + endif +endif + +CCV := $(shell $(CC) --version | head -n 1) +CXXV := $(shell $(CXX) --version | head -n 1) + +# Mac OS + Arm can report x86_64 +# ref: https://github.com/ggerganov/whisper.cpp/issues/66#issuecomment-1282546789 +ifeq ($(UNAME_S),Darwin) + ifneq ($(UNAME_P),arm) + SYSCTL_M := $(shell sysctl -n hw.optional.arm64) + ifeq ($(SYSCTL_M),1) + # UNAME_P := arm + # UNAME_M := arm64 + warn := $(warning Your arch is announced as x86_64, but it seems to actually be ARM64. Not fixing that can lead to bad performance. For more info see: https://github.com/ggerganov/whisper.cpp/issues/66\#issuecomment-1282546789) + endif + endif +endif + +# +# Compile flags +# + +CFLAGS = -I. -O3 -DNDEBUG -std=c11 -fPIC +CXXFLAGS = -I. -I./examples -O3 -DNDEBUG -std=c++11 -fPIC +LDFLAGS = + +# clock_gettime came in POSIX.1b (1993) +# CLOCK_MONOTONIC came in POSIX.1-2001 / SUSv3 as optional +# posix_memalign came in POSIX.1-2001 / SUSv3 +# M_PI is an XSI extension since POSIX.1-2001 / SUSv3, came in XPG1 (1985) +CFLAGS += -D_XOPEN_SOURCE=600 +CXXFLAGS += -D_XOPEN_SOURCE=600 + +# Somehow in OpenBSD whenever POSIX conformance is specified +# some string functions rely on locale_t availability, +# which was introduced in POSIX.1-2008, forcing us to go higher +ifeq ($(UNAME_S),OpenBSD) + CFLAGS += -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 + CXXFLAGS += -U_XOPEN_SOURCE -D_XOPEN_SOURCE=700 +endif + +# Data types, macros and functions related to controlling CPU affinity +# are available on Linux through GNU extensions in libc +ifeq ($(UNAME_S),Linux) + CFLAGS += -D_GNU_SOURCE + CXXFLAGS += -D_GNU_SOURCE +endif + +# RLIMIT_MEMLOCK came in BSD, is not specified in POSIX.1, +# and on macOS its availability depends on enabling Darwin extensions +# similarly on DragonFly, enabling BSD extensions is necessary +ifeq ($(UNAME_S),Darwin) + CFLAGS += -D_DARWIN_C_SOURCE + CXXFLAGS += -D_DARWIN_C_SOURCE +endif +ifeq ($(UNAME_S),DragonFly) + CFLAGS += -D__BSD_VISIBLE + CXXFLAGS += -D__BSD_VISIBLE +endif + +# alloca is a non-standard interface that is not visible on BSDs when +# POSIX conformance is specified, but not all of them provide a clean way +# to enable it in such cases +ifeq ($(UNAME_S),FreeBSD) + CFLAGS += -D__BSD_VISIBLE + CXXFLAGS += -D__BSD_VISIBLE +endif +ifeq ($(UNAME_S),NetBSD) + CFLAGS += -D_NETBSD_SOURCE + CXXFLAGS += -D_NETBSD_SOURCE +endif +ifeq ($(UNAME_S),OpenBSD) + CFLAGS += -D_BSD_SOURCE + CXXFLAGS += -D_BSD_SOURCE +endif + +# OS specific +# TODO: support Windows +ifeq ($(filter $(UNAME_S),Linux Darwin DragonFly FreeBSD NetBSD OpenBSD Haiku),$(UNAME_S)) + CFLAGS += -pthread + CXXFLAGS += -pthread +endif + +# Architecture specific +# TODO: probably these flags need to be tweaked on some architectures +# feel free to update the Makefile for your architecture and send a pull request or issue +ifeq ($(UNAME_M),$(filter $(UNAME_M),x86_64 i686 amd64)) + ifeq ($(UNAME_S),Darwin) + CPUINFO_CMD := sysctl machdep.cpu.features machdep.cpu.leaf7_features + else ifeq ($(UNAME_S),Linux) + CPUINFO_CMD := cat /proc/cpuinfo + else ifneq (,$(filter MINGW32_NT% MINGW64_NT%,$(UNAME_S))) + CPUINFO_CMD := cat /proc/cpuinfo + else ifneq (,$(filter DragonFly FreeBSD,$(UNAME_S))) + CPUINFO_CMD := grep Features /var/run/dmesg.boot + else ifeq ($(UNAME_S),Haiku) + CPUINFO_CMD := sysinfo -cpu + endif + + ifdef CPUINFO_CMD + AVX_M := $(shell $(CPUINFO_CMD) | grep -iwE 'AVX|AVX1.0') + ifneq (,$(AVX_M)) + CFLAGS += -mavx + CXXFLAGS += -mavx + endif + + AVX2_M := $(shell $(CPUINFO_CMD) | grep -iw 'AVX2') + ifneq (,$(AVX2_M)) + CFLAGS += -mavx2 + CXXFLAGS += -mavx2 + endif + + FMA_M := $(shell $(CPUINFO_CMD) | grep -iw 'FMA') + ifneq (,$(FMA_M)) + CFLAGS += -mfma + CXXFLAGS += -mfma + endif + + F16C_M := $(shell $(CPUINFO_CMD) | grep -iw 'F16C') + ifneq (,$(F16C_M)) + CFLAGS += -mf16c + CXXFLAGS += -mf16c + endif + + SSE3_M := $(shell $(CPUINFO_CMD) | grep -iwE 'PNI|SSE3') + ifneq (,$(SSE3_M)) + CFLAGS += -msse3 + CXXFLAGS += -msse3 + endif + + SSSE3_M := $(shell $(CPUINFO_CMD) | grep -iw 'SSSE3') + ifneq (,$(SSSE3_M)) + CFLAGS += -mssse3 + CXXFLAGS += -mssse3 + endif + endif +endif + +ifneq ($(filter ppc64%,$(UNAME_M)),) + POWER9_M := $(shell grep "POWER9" /proc/cpuinfo) + ifneq (,$(findstring POWER9,$(POWER9_M))) + CFLAGS += -mpower9-vector + endif + # Require c++23's std::byteswap for big-endian support. + ifeq ($(UNAME_M),ppc64) + CXXFLAGS += -std=c++23 -DGGML_BIG_ENDIAN + endif +endif + +ifndef WHISPER_NO_ACCELERATE + # Mac M1 - include Accelerate framework + ifeq ($(UNAME_S),Darwin) + CFLAGS += -DGGML_USE_ACCELERATE + LDFLAGS += -framework Accelerate + endif +endif + +ifdef WHISPER_COREML + CXXFLAGS += -DWHISPER_USE_COREML + LDFLAGS += -framework Foundation -framework CoreML + +ifdef WHISPER_COREML_ALLOW_FALLBACK + CXXFLAGS += -DWHISPER_COREML_ALLOW_FALLBACK +endif +endif + +ifndef WHISPER_NO_METAL + ifeq ($(UNAME_S),Darwin) + WHISPER_METAL := 1 + + CFLAGS += -DGGML_USE_METAL + CXXFLAGS += -DGGML_USE_METAL + LDFLAGS += -framework Foundation -framework Metal -framework MetalKit + endif +endif + +ifdef WHISPER_OPENBLAS + CFLAGS += -DGGML_USE_OPENBLAS -I/usr/local/include/openblas -I/usr/include/openblas + LDFLAGS += -lopenblas +endif + +ifdef WHISPER_CUBLAS + ifeq ($(shell expr $(NVCC_VERSION) \>= 11.6), 1) + CUDA_ARCH_FLAG=native + else + CUDA_ARCH_FLAG=all + endif + + CFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include -I/opt/cuda/include -I$(CUDA_PATH)/targets/$(UNAME_M)-linux/include + CXXFLAGS += -DGGML_USE_CUBLAS -I/usr/local/cuda/include -I/opt/cuda/include -I$(CUDA_PATH)/targets/$(UNAME_M)-linux/include + LDFLAGS += -lcublas -lculibos -lcudart -lcublasLt -lpthread -ldl -lrt -L/usr/local/cuda/lib64 -L/opt/cuda/lib64 -L$(CUDA_PATH)/targets/$(UNAME_M)-linux/lib + WHISPER_OBJ += ggml-cuda.o + NVCC = nvcc + NVCCFLAGS = --forward-unknown-to-host-compiler -arch=$(CUDA_ARCH_FLAG) + +ggml-cuda.o: ggml-cuda.cu ggml-cuda.h + $(NVCC) $(NVCCFLAGS) $(CXXFLAGS) -Wno-pedantic -c $< -o $@ +endif + +ifdef WHISPER_HIPBLAS + ROCM_PATH ?= /opt/rocm + HIPCC ?= $(ROCM_PATH)/bin/hipcc + GPU_TARGETS ?= $(shell $(ROCM_PATH)/llvm/bin/amdgpu-arch) + CFLAGS += -DGGML_USE_HIPBLAS -DGGML_USE_CUBLAS + CXXFLAGS += -DGGML_USE_HIPBLAS -DGGML_USE_CUBLAS + LDFLAGS += -L$(ROCM_PATH)/lib -Wl,-rpath=$(ROCM_PATH)/lib + LDFLAGS += -lhipblas -lamdhip64 -lrocblas + HIPFLAGS += $(addprefix --offload-arch=,$(GPU_TARGETS)) + WHISPER_OBJ += ggml-cuda.o + +ggml-cuda.o: ggml-cuda.cu ggml-cuda.h + $(HIPCC) $(CXXFLAGS) $(HIPFLAGS) -x hip -c -o $@ $< +endif + +ifdef WHISPER_CLBLAST + CFLAGS += -DGGML_USE_CLBLAST + CXXFLAGS += -DGGML_USE_CLBLAST + LDFLAGS += -lclblast + ifeq ($(UNAME_S),Darwin) + LDFLAGS += -framework OpenCL + else + LDFLAGS += -lOpenCL + endif + WHISPER_OBJ += ggml-opencl.o + +ggml-opencl.o: ggml-opencl.cpp ggml-opencl.h + $(CXX) $(CXXFLAGS) -c $< -o $@ +endif + +ifdef WHISPER_GPROF + CFLAGS += -pg + CXXFLAGS += -pg +endif + +ifneq ($(filter aarch64%,$(UNAME_M)),) + CFLAGS += -mcpu=native + CXXFLAGS += -mcpu=native +endif + +ifneq ($(filter armv6%,$(UNAME_M)),) + # 32-bit Raspberry Pi 1, 2, 3 + CFLAGS += -mfpu=neon -mfp16-format=ieee -mno-unaligned-access +endif + +ifneq ($(filter armv7%,$(UNAME_M)),) + # 32-bit ARM, for example on Armbian or possibly raspbian + #CFLAGS += -mfpu=neon -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access + #CXXFLAGS += -mfpu=neon -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access + + # 64-bit ARM on 32-bit OS, use these (TODO: auto-detect 64-bit) + CFLAGS += -mfpu=neon-fp-armv8 -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access + CXXFLAGS += -mfpu=neon-fp-armv8 -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access +endif + +ifneq ($(filter armv8%,$(UNAME_M)),) + # Raspberry Pi 4 + CFLAGS += -mfpu=neon-fp-armv8 -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access + CXXFLAGS += -mfpu=neon-fp-armv8 -mfp16-format=ieee -funsafe-math-optimizations -mno-unaligned-access +endif + +# +# Print build information +# + +$(info I whisper.cpp build info: ) +$(info I UNAME_S: $(UNAME_S)) +$(info I UNAME_P: $(UNAME_P)) +$(info I UNAME_M: $(UNAME_M)) +$(info I CFLAGS: $(CFLAGS)) +$(info I CXXFLAGS: $(CXXFLAGS)) +$(info I LDFLAGS: $(LDFLAGS)) +$(info I CC: $(CCV)) +$(info I CXX: $(CXXV)) +$(info ) + +# +# Build library +# + +ggml.o: ggml.c ggml.h ggml-cuda.h + $(CC) $(CFLAGS) -c $< -o $@ + +ggml-alloc.o: ggml-alloc.c ggml.h ggml-alloc.h + $(CC) $(CFLAGS) -c $< -o $@ + +ggml-backend.o: ggml-backend.c ggml.h ggml-backend.h + $(CC) $(CFLAGS) -c $< -o $@ + +ggml-quants.o: ggml-quants.c ggml.h ggml-quants.h + $(CC) $(CFLAGS) -c $< -o $@ + +WHISPER_OBJ += ggml.o ggml-alloc.o ggml-backend.o ggml-quants.o + +whisper.o: whisper.cpp whisper.h ggml.h ggml-cuda.h + $(CXX) $(CXXFLAGS) -c $< -o $@ + +ifndef WHISPER_COREML +WHISPER_OBJ += whisper.o +else +whisper-encoder.o: coreml/whisper-encoder.mm coreml/whisper-encoder.h + $(CXX) -O3 -I . -fobjc-arc -c coreml/whisper-encoder.mm -o whisper-encoder.o + +whisper-encoder-impl.o: coreml/whisper-encoder-impl.m coreml/whisper-encoder-impl.h + $(CXX) -O3 -I . -fobjc-arc -c coreml/whisper-encoder-impl.m -o whisper-encoder-impl.o + +WHISPER_OBJ += whisper.o whisper-encoder.o whisper-encoder-impl.o +endif + +ifdef WHISPER_METAL +ggml-metal.o: ggml-metal.m ggml-metal.h + $(CC) $(CFLAGS) -c $< -o $@ + +WHISPER_OBJ += ggml-metal.o +endif + +libwhisper.a: $(WHISPER_OBJ) + $(AR) rcs libwhisper.a $(WHISPER_OBJ) + +libwhisper.so: $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) -shared -o libwhisper.so $(WHISPER_OBJ) $(LDFLAGS) + +clean: + rm -f *.o main stream command talk talk-llama bench quantize server lsp libwhisper.a libwhisper.so + +# +# Examples +# + +CC_SDL=`sdl2-config --cflags --libs` + +SRC_COMMON = examples/common.cpp examples/common-ggml.cpp +SRC_COMMON_SDL = examples/common-sdl.cpp + +main: examples/main/main.cpp $(SRC_COMMON) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/main/main.cpp $(SRC_COMMON) $(WHISPER_OBJ) -o main $(LDFLAGS) + ./main -h + +bench: examples/bench/bench.cpp $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/bench/bench.cpp $(WHISPER_OBJ) -o bench $(LDFLAGS) + +quantize: examples/quantize/quantize.cpp $(WHISPER_OBJ) $(SRC_COMMON) + $(CXX) $(CXXFLAGS) examples/quantize/quantize.cpp $(SRC_COMMON) $(WHISPER_OBJ) -o quantize $(LDFLAGS) + +server: examples/server/server.cpp $(SRC_COMMON) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/server/server.cpp $(SRC_COMMON) $(WHISPER_OBJ) -o server $(LDFLAGS) + +stream: examples/stream/stream.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/stream/stream.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) -o stream $(CC_SDL) $(LDFLAGS) + +command: examples/command/command.cpp examples/grammar-parser.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/command/command.cpp examples/grammar-parser.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) -o command $(CC_SDL) $(LDFLAGS) + +lsp: examples/lsp/lsp.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/lsp/lsp.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) -o lsp $(CC_SDL) $(LDFLAGS) + +talk: examples/talk/talk.cpp examples/talk/gpt-2.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/talk/talk.cpp examples/talk/gpt-2.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) -o talk $(CC_SDL) $(LDFLAGS) + +talk-llama: examples/talk-llama/talk-llama.cpp examples/talk-llama/llama.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) + $(CXX) $(CXXFLAGS) examples/talk-llama/talk-llama.cpp examples/talk-llama/llama.cpp $(SRC_COMMON) $(SRC_COMMON_SDL) $(WHISPER_OBJ) -o talk-llama $(CC_SDL) $(LDFLAGS) + +# +# Audio samples +# + +# download a few audio samples into folder "./samples": +.PHONY: samples +samples: + @echo "Downloading samples..." + @mkdir -p samples + @wget --quiet --show-progress -O samples/gb0.ogg https://upload.wikimedia.org/wikipedia/commons/2/22/George_W._Bush%27s_weekly_radio_address_%28November_1%2C_2008%29.oga + @wget --quiet --show-progress -O samples/gb1.ogg https://upload.wikimedia.org/wikipedia/commons/1/1f/George_W_Bush_Columbia_FINAL.ogg + @wget --quiet --show-progress -O samples/hp0.ogg https://upload.wikimedia.org/wikipedia/en/d/d4/En.henryfphillips.ogg + @wget --quiet --show-progress -O samples/mm1.wav https://cdn.openai.com/whisper/draft-20220913a/micro-machines.wav + @wget --quiet --show-progress -O samples/a13.mp3 https://upload.wikimedia.org/wikipedia/commons/transcoded/6/6f/Apollo13-wehaveaproblem.ogg/Apollo13-wehaveaproblem.ogg.mp3 + @wget --quiet --show-progress -O samples/diffusion2023-07-03.flac https://archive.org/download/diffusion2023-07-03/diffusion2023-07-03.flac + @echo "Converting to 16-bit WAV ..." + @ffmpeg -loglevel -0 -y -i samples/gb0.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/gb0.wav + @ffmpeg -loglevel -0 -y -i samples/gb1.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/gb1.wav + @ffmpeg -loglevel -0 -y -i samples/hp0.ogg -ar 16000 -ac 1 -c:a pcm_s16le samples/hp0.wav + @rm samples/*.ogg + @ffmpeg -loglevel -0 -y -i samples/mm1.wav -ar 16000 -ac 1 -c:a pcm_s16le samples/mm0.wav + @rm samples/mm1.wav + @ffmpeg -loglevel -0 -y -i samples/a13.mp3 -ar 16000 -ac 1 -c:a pcm_s16le -ss 00:00:00 -to 00:00:30 samples/a13.wav + @rm samples/a13.mp3 + @ffmpeg -loglevel -0 -y -i samples/diffusion2023-07-03.flac -ar 16000 -ac 1 -c:a pcm_s16le samples/diffusion2023-07-03.wav + @rm samples/diffusion2023-07-03.flac + +# +# Models +# + +# if not already downloaded, the following targets download the specified model and +# runs it on all samples in the folder "./samples": + +.PHONY: tiny.en +.PHONY: tiny +.PHONY: base.en +.PHONY: base +.PHONY: small.en +.PHONY: small +.PHONY: medium.en +.PHONY: medium +.PHONY: large-v1 +.PHONY: large-v2 +.PHONY: large-v3 + +tiny.en tiny base.en base small.en small medium.en medium large-v1 large-v2 large-v3: main + bash ./models/download-ggml-model.sh $@ + @echo "" + @echo "===============================================" + @echo "Running $@ on all samples in ./samples ..." + @echo "===============================================" + @echo "" + @for f in samples/*.wav; do \ + echo "----------------------------------------------" ; \ + echo "[+] Running $@ on $$f ... (run 'ffplay $$f' to listen)" ; \ + echo "----------------------------------------------" ; \ + echo "" ; \ + ./main -m models/ggml-$@.bin -f $$f ; \ + echo "" ; \ + done + +# +# Tests +# + +.PHONY: tests +tests: + bash ./tests/run-tests.sh $(word 2, $(MAKECMDGOALS)) diff --git a/whisper.cpp-1.5.2/Package.swift b/whisper.cpp-1.5.2/Package.swift new file mode 100644 index 0000000..bbb7fb0 --- /dev/null +++ b/whisper.cpp-1.5.2/Package.swift @@ -0,0 +1,61 @@ +// swift-tools-version:5.5 + +import PackageDescription + +let package = Package( + name: "whisper", + platforms: [ + .macOS(.v12), + .iOS(.v14), + .watchOS(.v4), + .tvOS(.v14) + ], + products: [ + .library(name: "whisper", targets: ["whisper"]), + ], + targets: [ + .target( + name: "whisper", + path: ".", + exclude: [ + "bindings", + "cmake", + "coreml", + "examples", + "extra", + "models", + "samples", + "tests", + "CMakeLists.txt", + "ggml-cuda.cu", + "ggml-cuda.h", + "Makefile" + ], + sources: [ + "ggml.c", + "whisper.cpp", + "ggml-alloc.c", + "ggml-backend.c", + "ggml-quants.c", + "ggml-metal.m" + ], + resources: [.process("ggml-metal.metal")], + publicHeadersPath: "spm-headers", + cSettings: [ + .unsafeFlags(["-Wno-shorten-64-to-32", "-O3", "-DNDEBUG"]), + .define("GGML_USE_ACCELERATE"), + .unsafeFlags(["-fno-objc-arc"]), + .define("GGML_USE_METAL") + // NOTE: NEW_LAPACK will required iOS version 16.4+ + // We should consider add this in the future when we drop support for iOS 14 + // (ref: ref: https://developer.apple.com/documentation/accelerate/1513264-cblas_sgemm?language=objc) + // .define("ACCELERATE_NEW_LAPACK"), + // .define("ACCELERATE_LAPACK_ILP64") + ], + linkerSettings: [ + .linkedFramework("Accelerate") + ] + ) + ], + cxxLanguageStandard: .cxx11 +) diff --git a/whisper.cpp-1.5.2/README.md b/whisper.cpp-1.5.2/README.md new file mode 100644 index 0000000..3407635 --- /dev/null +++ b/whisper.cpp-1.5.2/README.md @@ -0,0 +1,790 @@ +# whisper.cpp + +![whisper.cpp](https://user-images.githubusercontent.com/1991296/235238348-05d0f6a4-da44-4900-a1de-d0707e75b763.jpeg) + +[![Actions Status](https://github.com/ggerganov/whisper.cpp/workflows/CI/badge.svg)](https://github.com/ggerganov/whisper.cpp/actions) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) +[![npm](https://img.shields.io/npm/v/whisper.cpp.svg)](https://www.npmjs.com/package/whisper.cpp/) + +Stable: [v1.5.2](https://github.com/ggerganov/whisper.cpp/releases/tag/v1.5.2) / [Roadmap | F.A.Q.](https://github.com/ggerganov/whisper.cpp/discussions/126) + +High-performance inference of [OpenAI's Whisper](https://github.com/openai/whisper) automatic speech recognition (ASR) model: + +- Plain C/C++ implementation without dependencies +- Apple Silicon first-class citizen - optimized via ARM NEON, Accelerate framework, Metal and [Core ML](https://github.com/ggerganov/whisper.cpp#core-ml-support) +- AVX intrinsics support for x86 architectures +- VSX intrinsics support for POWER architectures +- Mixed F16 / F32 precision +- [4-bit and 5-bit integer quantization support](https://github.com/ggerganov/whisper.cpp#quantization) +- Zero memory allocations at runtime +- Support for CPU-only inference +- [Efficient GPU support for NVIDIA](https://github.com/ggerganov/whisper.cpp#nvidia-gpu-support-via-cublas) +- [Partial OpenCL GPU support via CLBlast](https://github.com/ggerganov/whisper.cpp#opencl-gpu-support-via-clblast) +- [OpenVINO Support](https://github.com/ggerganov/whisper.cpp#openvino-support) +- [C-style API](https://github.com/ggerganov/whisper.cpp/blob/master/whisper.h) + +Supported platforms: + +- [x] Mac OS (Intel and Arm) +- [x] [iOS](examples/whisper.objc) +- [x] [Android](examples/whisper.android) +- [x] [Java](bindings/java/README.md) +- [x] Linux / [FreeBSD](https://github.com/ggerganov/whisper.cpp/issues/56#issuecomment-1350920264) +- [x] [WebAssembly](examples/whisper.wasm) +- [x] Windows ([MSVC](https://github.com/ggerganov/whisper.cpp/blob/master/.github/workflows/build.yml#L117-L144) and [MinGW](https://github.com/ggerganov/whisper.cpp/issues/168)] +- [x] [Raspberry Pi](https://github.com/ggerganov/whisper.cpp/discussions/166) + +The entire high-level implementation of the model is contained in [whisper.h](whisper.h) and [whisper.cpp](whisper.cpp). +The rest of the code is part of the [ggml](https://github.com/ggerganov/ggml) machine learning library. + +Having such a lightweight implementation of the model allows to easily integrate it in different platforms and applications. +As an example, here is a video of running the model on an iPhone 13 device - fully offline, on-device: [whisper.objc](examples/whisper.objc) + +https://user-images.githubusercontent.com/1991296/197385372-962a6dea-bca1-4d50-bf96-1d8c27b98c81.mp4 + +You can also easily make your own offline voice assistant application: [command](examples/command) + +https://user-images.githubusercontent.com/1991296/204038393-2f846eae-c255-4099-a76d-5735c25c49da.mp4 + +On Apple Silicon, the inference runs fully on the GPU via Metal: + +https://github.com/ggerganov/whisper.cpp/assets/1991296/c82e8f86-60dc-49f2-b048-d2fdbd6b5225 + +Or you can even run it straight in the browser: [talk.wasm](examples/talk.wasm) + +## Implementation details + +- The core tensor operations are implemented in C ([ggml.h](ggml.h) / [ggml.c](ggml.c)) +- The transformer model and the high-level C-style API are implemented in C++ ([whisper.h](whisper.h) / [whisper.cpp](whisper.cpp)) +- Sample usage is demonstrated in [main.cpp](examples/main) +- Sample real-time audio transcription from the microphone is demonstrated in [stream.cpp](examples/stream) +- Various other examples are available in the [examples](examples) folder + +The tensor operators are optimized heavily for Apple silicon CPUs. Depending on the computation size, Arm Neon SIMD +intrinsics or CBLAS Accelerate framework routines are used. The latter are especially effective for bigger sizes since +the Accelerate framework utilizes the special-purpose AMX coprocessor available in modern Apple products. + +## Quick start + +First clone the repository. + +Then, download one of the Whisper models converted in [ggml format](models). For example: + +```bash +bash ./models/download-ggml-model.sh base.en +``` + +If you wish to convert the Whisper models to ggml format yourself, instructions are in [models/README.md](models/README.md). + +Now build the [main](examples/main) example and transcribe an audio file like this: + +```bash +# build the main example +make + +# transcribe an audio file +./main -f samples/jfk.wav +``` + +--- + +For a quick demo, simply run `make base.en`: + +```java +$ make base.en + +cc -I. -O3 -std=c11 -pthread -DGGML_USE_ACCELERATE -c ggml.c -o ggml.o +c++ -I. -I./examples -O3 -std=c++11 -pthread -c whisper.cpp -o whisper.o +c++ -I. -I./examples -O3 -std=c++11 -pthread examples/main/main.cpp whisper.o ggml.o -o main -framework Accelerate +./main -h + +usage: ./main [options] file0.wav file1.wav ... + +options: + -h, --help [default] show this help message and exit + -t N, --threads N [4 ] number of threads to use during computation + -p N, --processors N [1 ] number of processors to use during computation + -ot N, --offset-t N [0 ] time offset in milliseconds + -on N, --offset-n N [0 ] segment index offset + -d N, --duration N [0 ] duration of audio to process in milliseconds + -mc N, --max-context N [-1 ] maximum number of text context tokens to store + -ml N, --max-len N [0 ] maximum segment length in characters + -sow, --split-on-word [false ] split on word rather than on token + -bo N, --best-of N [5 ] number of best candidates to keep + -bs N, --beam-size N [5 ] beam size for beam search + -wt N, --word-thold N [0.01 ] word timestamp probability threshold + -et N, --entropy-thold N [2.40 ] entropy threshold for decoder fail + -lpt N, --logprob-thold N [-1.00 ] log probability threshold for decoder fail + -debug, --debug-mode [false ] enable debug mode (eg. dump log_mel) + -tr, --translate [false ] translate from source language to english + -di, --diarize [false ] stereo audio diarization + -tdrz, --tinydiarize [false ] enable tinydiarize (requires a tdrz model) + -nf, --no-fallback [false ] do not use temperature fallback while decoding + -otxt, --output-txt [false ] output result in a text file + -ovtt, --output-vtt [false ] output result in a vtt file + -osrt, --output-srt [false ] output result in a srt file + -olrc, --output-lrc [false ] output result in a lrc file + -owts, --output-words [false ] output script for generating karaoke video + -fp, --font-path [/System/Library/Fonts/Supplemental/Courier New Bold.ttf] path to a monospace font for karaoke video + -ocsv, --output-csv [false ] output result in a CSV file + -oj, --output-json [false ] output result in a JSON file + -ojf, --output-json-full [false ] include more information in the JSON file + -of FNAME, --output-file FNAME [ ] output file path (without file extension) + -ps, --print-special [false ] print special tokens + -pc, --print-colors [false ] print colors + -pp, --print-progress [false ] print progress + -nt, --no-timestamps [false ] do not print timestamps + -l LANG, --language LANG [en ] spoken language ('auto' for auto-detect) + -dl, --detect-language [false ] exit after automatically detecting language + --prompt PROMPT [ ] initial prompt + -m FNAME, --model FNAME [models/ggml-base.en.bin] model path + -f FNAME, --file FNAME [ ] input WAV file path + -oved D, --ov-e-device DNAME [CPU ] the OpenVINO device used for encode inference + -ls, --log-score [false ] log best decoder scores of tokens + -ng, --no-gpu [false ] disable GPU + + +bash ./models/download-ggml-model.sh base.en +Downloading ggml model base.en ... +ggml-base.en.bin 100%[========================>] 141.11M 6.34MB/s in 24s +Done! Model 'base.en' saved in 'models/ggml-base.en.bin' +You can now use it like this: + + $ ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + +=============================================== +Running base.en on all samples in ./samples ... +=============================================== + +---------------------------------------------- +[+] Running base.en on samples/jfk.wav ... (run 'ffplay samples/jfk.wav' to listen) +---------------------------------------------- + +whisper_init_from_file: loading model from 'models/ggml-base.en.bin' +whisper_model_load: loading model +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 512 +whisper_model_load: n_audio_head = 8 +whisper_model_load: n_audio_layer = 6 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 512 +whisper_model_load: n_text_head = 8 +whisper_model_load: n_text_layer = 6 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 2 +whisper_model_load: mem required = 215.00 MB (+ 6.00 MB per decoder) +whisper_model_load: kv self size = 5.25 MB +whisper_model_load: kv cross size = 17.58 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: model ctx = 140.60 MB +whisper_model_load: model size = 140.54 MB + +system_info: n_threads = 4 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | + +main: processing 'samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + + +[00:00:00.000 --> 00:00:11.000] And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country. + + +whisper_print_timings: fallbacks = 0 p / 0 h +whisper_print_timings: load time = 113.81 ms +whisper_print_timings: mel time = 15.40 ms +whisper_print_timings: sample time = 11.58 ms / 27 runs ( 0.43 ms per run) +whisper_print_timings: encode time = 266.60 ms / 1 runs ( 266.60 ms per run) +whisper_print_timings: decode time = 66.11 ms / 27 runs ( 2.45 ms per run) +whisper_print_timings: total time = 476.31 ms +``` + +The command downloads the `base.en` model converted to custom `ggml` format and runs the inference on all `.wav` samples in the folder `samples`. + +For detailed usage instructions, run: `./main -h` + +Note that the [main](examples/main) example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool. +For example, you can use `ffmpeg` like this: + +```java +ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav +``` + +## More audio samples + +If you want some extra audio samples to play with, simply run: + +``` +make samples +``` + +This will download a few more audio files from Wikipedia and convert them to 16-bit WAV format via `ffmpeg`. + +You can download and run the other models as follows: + +``` +make tiny.en +make tiny +make base.en +make base +make small.en +make small +make medium.en +make medium +make large-v1 +make large-v2 +make large-v3 +``` + +## Memory usage + +| Model | Disk | Mem | +| --- | --- | --- | +| tiny | 75 MiB | ~273 MB | +| base | 142 MiB | ~388 MB | +| small | 466 MiB | ~852 MB | +| medium | 1.5 GiB | ~2.1 GB | +| large | 2.9 GiB | ~3.9 GB | + +## Quantization + +`whisper.cpp` supports integer quantization of the Whisper `ggml` models. +Quantized models require less memory and disk space and depending on the hardware can be processed more efficiently. + +Here are the steps for creating and using a quantized model: + +```bash +# quantize a model with Q5_0 method +make quantize +./quantize models/ggml-base.en.bin models/ggml-base.en-q5_0.bin q5_0 + +# run the examples as usual, specifying the quantized model file +./main -m models/ggml-base.en-q5_0.bin ./samples/gb0.wav +``` + +## Core ML support + +On Apple Silicon devices, the Encoder inference can be executed on the Apple Neural Engine (ANE) via Core ML. This can result in significant +speed-up - more than x3 faster compared with CPU-only execution. Here are the instructions for generating a Core ML model and using it with `whisper.cpp`: + +- Install Python dependencies needed for the creation of the Core ML model: + + ```bash + pip install ane_transformers + pip install openai-whisper + pip install coremltools + ``` + + - To ensure `coremltools` operates correctly, please confirm that [Xcode](https://developer.apple.com/xcode/) is installed and execute `xcode-select --install` to install the command-line tools. + - Python 3.10 is recommended. + - [OPTIONAL] It is recommended to utilize a Python version management system, such as [Miniconda](https://docs.conda.io/en/latest/miniconda.html) for this step: + - To create an environment, use: `conda create -n py310-whisper python=3.10 -y` + - To activate the environment, use: `conda activate py310-whisper` + +- Generate a Core ML model. For example, to generate a `base.en` model, use: + + ```bash + ./models/generate-coreml-model.sh base.en + ``` + + This will generate the folder `models/ggml-base.en-encoder.mlmodelc` + +- Build `whisper.cpp` with Core ML support: + + ```bash + # using Makefile + make clean + WHISPER_COREML=1 make -j + + # using CMake + cmake -B build -DWHISPER_COREML=1 + cmake --build build -j --config Release + ``` + +- Run the examples as usual. For example: + + ```bash + ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + ... + + whisper_init_state: loading Core ML model from 'models/ggml-base.en-encoder.mlmodelc' + whisper_init_state: first run on a device may take a while ... + whisper_init_state: Core ML model loaded + + system_info: n_threads = 4 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | COREML = 1 | + + ... + ``` + + The first run on a device is slow, since the ANE service compiles the Core ML model to some device-specific format. + Next runs are faster. + +For more information about the Core ML implementation please refer to PR [#566](https://github.com/ggerganov/whisper.cpp/pull/566). + +## OpenVINO support + +On platforms that support [OpenVINO](https://github.com/openvinotoolkit/openvino), the Encoder inference can be executed +on OpenVINO-supported devices including x86 CPUs and Intel GPUs (integrated & discrete). + +This can result in significant speedup in encoder performance. Here are the instructions for generating the OpenVINO model and using it with `whisper.cpp`: + +- First, setup python virtual env. and install python dependencies. Python 3.10 is recommended. + + Windows: + ``` + cd models + python -m venv openvino_conv_env + openvino_conv_env\Scripts\activate + python -m pip install --upgrade pip + pip install -r openvino-conversion-requirements.txt + ``` + + Linux and macOS: + ``` + cd models + python3 -m venv openvino_conv_env + source openvino_conv_env/bin/activate + python -m pip install --upgrade pip + pip install -r openvino-conversion-requirements.txt + ``` + +- Generate an OpenVINO encoder model. For example, to generate a `base.en` model, use: + + ``` + python convert-whisper-to-openvino.py --model base.en + ``` + + This will produce ggml-base.en-encoder-openvino.xml/.bin IR model files. It's recommended to relocate these to the same folder as ggml models, as that + is the default location that the OpenVINO extension will search at runtime. + +- Build `whisper.cpp` with OpenVINO support: + + Download OpenVINO package from [release page](https://github.com/openvinotoolkit/openvino/releases). The recommended version to use is [2023.0.0](https://github.com/openvinotoolkit/openvino/releases/tag/2023.0.0). + + After downloading & extracting package onto your development system, set up required environment by sourcing setupvars script. For example: + + Linux: + ```bash + source /path/to/l_openvino_toolkit_ubuntu22_2023.0.0.10926.b4452d56304_x86_64/setupvars.sh + ``` + + Windows (cmd): + ``` + C:\Path\To\w_openvino_toolkit_windows_2023.0.0.10926.b4452d56304_x86_64\setupvars.bat + ``` + + And then build the project using cmake: + ```bash + cmake -B build -DWHISPER_OPENVINO=1 + cmake --build build -j --config Release + ``` + +- Run the examples as usual. For example: + ```bash + ./main -m models/ggml-base.en.bin -f samples/jfk.wav + + ... + + whisper_ctx_init_openvino_encoder: loading OpenVINO model from 'models/ggml-base.en-encoder-openvino.xml' + whisper_ctx_init_openvino_encoder: first run on a device may take a while ... + whisper_openvino_init: path_model = models/ggml-base.en-encoder-openvino.xml, device = GPU, cache_dir = models/ggml-base.en-encoder-openvino-cache + whisper_ctx_init_openvino_encoder: OpenVINO model loaded + + system_info: n_threads = 4 / 8 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | COREML = 0 | OPENVINO = 1 | + + ... + ``` + + The first time run on an OpenVINO device is slow, since the OpenVINO framework will compile the IR (Intermediate Representation) model to a device-specific 'blob'. This device-specific blob will get + cached for the next run. + +For more information about the Core ML implementation please refer to PR [#1037](https://github.com/ggerganov/whisper.cpp/pull/1037). + +## NVIDIA GPU support + +With NVIDIA cards the processing of the models is done efficiently on the GPU via cuBLAS and custom CUDA kernels. +First, make sure you have installed `cuda`: https://developer.nvidia.com/cuda-downloads + +Now build `whisper.cpp` with cuBLAS support: + +``` +make clean +WHISPER_CUBLAS=1 make -j +``` + +## OpenCL GPU support via CLBlast + +For cards and integrated GPUs that support OpenCL, the Encoder processing can be largely offloaded to the GPU through CLBlast. This is especially useful for users with AMD APUs or low end devices for up to ~2x speedup. + +First, make sure you have installed `CLBlast` for your OS or Distribution: https://github.com/CNugteren/CLBlast + +Now build `whisper.cpp` with CLBlast support: + +``` +Makefile: +cd whisper.cpp +make clean +WHISPER_CLBLAST=1 make -j + +CMake: +cd whisper.cpp +cmake -B build -DWHISPER_CLBLAST=ON +cmake --build build -j --config Release +``` + + +Run all the examples as usual. + +## BLAS CPU support via OpenBLAS + +Encoder processing can be accelerated on the CPU via OpenBLAS. +First, make sure you have installed `openblas`: https://www.openblas.net/ + +Now build `whisper.cpp` with OpenBLAS support: + +``` +make clean +WHISPER_OPENBLAS=1 make -j +``` + +## Limitations + +- Inference only + +## Another example + +Here is another example of transcribing a [3:24 min speech](https://upload.wikimedia.org/wikipedia/commons/1/1f/George_W_Bush_Columbia_FINAL.ogg) +in about half a minute on a MacBook M1 Pro, using `medium.en` model: + +
+ Expand to see the result + +```java +$ ./main -m models/ggml-medium.en.bin -f samples/gb1.wav -t 8 + +whisper_init_from_file: loading model from 'models/ggml-medium.en.bin' +whisper_model_load: loading model +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 1024 +whisper_model_load: n_audio_head = 16 +whisper_model_load: n_audio_layer = 24 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 1024 +whisper_model_load: n_text_head = 16 +whisper_model_load: n_text_layer = 24 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 4 +whisper_model_load: mem required = 1720.00 MB (+ 43.00 MB per decoder) +whisper_model_load: kv self size = 42.00 MB +whisper_model_load: kv cross size = 140.62 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: model ctx = 1462.35 MB +whisper_model_load: model size = 1462.12 MB + +system_info: n_threads = 8 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | + +main: processing 'samples/gb1.wav' (3179750 samples, 198.7 sec), 8 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + + +[00:00:00.000 --> 00:00:08.000] My fellow Americans, this day has brought terrible news and great sadness to our country. +[00:00:08.000 --> 00:00:17.000] At nine o'clock this morning, Mission Control in Houston lost contact with our Space Shuttle Columbia. +[00:00:17.000 --> 00:00:23.000] A short time later, debris was seen falling from the skies above Texas. +[00:00:23.000 --> 00:00:29.000] The Columbia's lost. There are no survivors. +[00:00:29.000 --> 00:00:32.000] On board was a crew of seven. +[00:00:32.000 --> 00:00:39.000] Colonel Rick Husband, Lieutenant Colonel Michael Anderson, Commander Laurel Clark, +[00:00:39.000 --> 00:00:48.000] Captain David Brown, Commander William McCool, Dr. Kultna Shavla, and Ilan Ramon, +[00:00:48.000 --> 00:00:52.000] a colonel in the Israeli Air Force. +[00:00:52.000 --> 00:00:58.000] These men and women assumed great risk in the service to all humanity. +[00:00:58.000 --> 00:01:03.000] In an age when space flight has come to seem almost routine, +[00:01:03.000 --> 00:01:07.000] it is easy to overlook the dangers of travel by rocket +[00:01:07.000 --> 00:01:12.000] and the difficulties of navigating the fierce outer atmosphere of the Earth. +[00:01:12.000 --> 00:01:18.000] These astronauts knew the dangers, and they faced them willingly, +[00:01:18.000 --> 00:01:23.000] knowing they had a high and noble purpose in life. +[00:01:23.000 --> 00:01:31.000] Because of their courage and daring and idealism, we will miss them all the more. +[00:01:31.000 --> 00:01:36.000] All Americans today are thinking as well of the families of these men and women +[00:01:36.000 --> 00:01:40.000] who have been given this sudden shock and grief. +[00:01:40.000 --> 00:01:45.000] You're not alone. Our entire nation grieves with you, +[00:01:45.000 --> 00:01:52.000] and those you love will always have the respect and gratitude of this country. +[00:01:52.000 --> 00:01:56.000] The cause in which they died will continue. +[00:01:56.000 --> 00:02:04.000] Mankind is led into the darkness beyond our world by the inspiration of discovery +[00:02:04.000 --> 00:02:11.000] and the longing to understand. Our journey into space will go on. +[00:02:11.000 --> 00:02:16.000] In the skies today, we saw destruction and tragedy. +[00:02:16.000 --> 00:02:22.000] Yet farther than we can see, there is comfort and hope. +[00:02:22.000 --> 00:02:29.000] In the words of the prophet Isaiah, "Lift your eyes and look to the heavens +[00:02:29.000 --> 00:02:35.000] who created all these. He who brings out the starry hosts one by one +[00:02:35.000 --> 00:02:39.000] and calls them each by name." +[00:02:39.000 --> 00:02:46.000] Because of His great power and mighty strength, not one of them is missing. +[00:02:46.000 --> 00:02:55.000] The same Creator who names the stars also knows the names of the seven souls we mourn today. +[00:02:55.000 --> 00:03:01.000] The crew of the shuttle Columbia did not return safely to earth, +[00:03:01.000 --> 00:03:05.000] yet we can pray that all are safely home. +[00:03:05.000 --> 00:03:13.000] May God bless the grieving families, and may God continue to bless America. +[00:03:13.000 --> 00:03:19.000] [Silence] + + +whisper_print_timings: fallbacks = 1 p / 0 h +whisper_print_timings: load time = 569.03 ms +whisper_print_timings: mel time = 146.85 ms +whisper_print_timings: sample time = 238.66 ms / 553 runs ( 0.43 ms per run) +whisper_print_timings: encode time = 18665.10 ms / 9 runs ( 2073.90 ms per run) +whisper_print_timings: decode time = 13090.93 ms / 549 runs ( 23.85 ms per run) +whisper_print_timings: total time = 32733.52 ms +``` +
+ +## Real-time audio input example + +This is a naive example of performing real-time inference on audio from your microphone. +The [stream](examples/stream) tool samples the audio every half a second and runs the transcription continuously. +More info is available in [issue #10](https://github.com/ggerganov/whisper.cpp/issues/10). + +```java +make stream +./stream -m ./models/ggml-base.en.bin -t 8 --step 500 --length 5000 +``` + +https://user-images.githubusercontent.com/1991296/194935793-76afede7-cfa8-48d8-a80f-28ba83be7d09.mp4 + +## Confidence color-coding + +Adding the `--print-colors` argument will print the transcribed text using an experimental color coding strategy +to highlight words with high or low confidence: + +```java +./main -m models/ggml-base.en.bin -f samples/gb0.wav --print-colors +``` + +image + +## Controlling the length of the generated text segments (experimental) + +For example, to limit the line length to a maximum of 16 characters, simply add `-ml 16`: + +```java +./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 16 + +whisper_model_load: loading model from './models/ggml-base.en.bin' +... +system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + +[00:00:00.000 --> 00:00:00.850] And so my +[00:00:00.850 --> 00:00:01.590] fellow +[00:00:01.590 --> 00:00:04.140] Americans, ask +[00:00:04.140 --> 00:00:05.660] not what your +[00:00:05.660 --> 00:00:06.840] country can do +[00:00:06.840 --> 00:00:08.430] for you, ask +[00:00:08.430 --> 00:00:09.440] what you can do +[00:00:09.440 --> 00:00:10.020] for your +[00:00:10.020 --> 00:00:11.000] country. +``` + +## Word-level timestamp (experimental) + +The `--max-len` argument can be used to obtain word-level timestamps. Simply use `-ml 1`: + +```java +./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 1 + +whisper_model_load: loading model from './models/ggml-base.en.bin' +... +system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ... + +[00:00:00.000 --> 00:00:00.320] +[00:00:00.320 --> 00:00:00.370] And +[00:00:00.370 --> 00:00:00.690] so +[00:00:00.690 --> 00:00:00.850] my +[00:00:00.850 --> 00:00:01.590] fellow +[00:00:01.590 --> 00:00:02.850] Americans +[00:00:02.850 --> 00:00:03.300] , +[00:00:03.300 --> 00:00:04.140] ask +[00:00:04.140 --> 00:00:04.990] not +[00:00:04.990 --> 00:00:05.410] what +[00:00:05.410 --> 00:00:05.660] your +[00:00:05.660 --> 00:00:06.260] country +[00:00:06.260 --> 00:00:06.600] can +[00:00:06.600 --> 00:00:06.840] do +[00:00:06.840 --> 00:00:07.010] for +[00:00:07.010 --> 00:00:08.170] you +[00:00:08.170 --> 00:00:08.190] , +[00:00:08.190 --> 00:00:08.430] ask +[00:00:08.430 --> 00:00:08.910] what +[00:00:08.910 --> 00:00:09.040] you +[00:00:09.040 --> 00:00:09.320] can +[00:00:09.320 --> 00:00:09.440] do +[00:00:09.440 --> 00:00:09.760] for +[00:00:09.760 --> 00:00:10.020] your +[00:00:10.020 --> 00:00:10.510] country +[00:00:10.510 --> 00:00:11.000] . +``` + +## Speaker segmentation via tinydiarize (experimental) + +More information about this approach is available here: https://github.com/ggerganov/whisper.cpp/pull/1058 + +Sample usage: + +```py +# download a tinydiarize compatible model +./models/download-ggml-model.sh small.en-tdrz + +# run as usual, adding the "-tdrz" command-line argument +./main -f ./samples/a13.wav -m ./models/ggml-small.en-tdrz.bin -tdrz +... +main: processing './samples/a13.wav' (480000 samples, 30.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, tdrz = 1, timestamps = 1 ... +... +[00:00:00.000 --> 00:00:03.800] Okay Houston, we've had a problem here. [SPEAKER_TURN] +[00:00:03.800 --> 00:00:06.200] This is Houston. Say again please. [SPEAKER_TURN] +[00:00:06.200 --> 00:00:08.260] Uh Houston we've had a problem. +[00:00:08.260 --> 00:00:11.320] We've had a main beam up on a volt. [SPEAKER_TURN] +[00:00:11.320 --> 00:00:13.820] Roger main beam interval. [SPEAKER_TURN] +[00:00:13.820 --> 00:00:15.100] Uh uh [SPEAKER_TURN] +[00:00:15.100 --> 00:00:18.020] So okay stand, by thirteen we're looking at it. [SPEAKER_TURN] +[00:00:18.020 --> 00:00:25.740] Okay uh right now uh Houston the uh voltage is uh is looking good um. +[00:00:27.620 --> 00:00:29.940] And we had a a pretty large bank or so. +``` + +## Karaoke-style movie generation (experimental) + +The [main](examples/main) example provides support for output of karaoke-style movies, where the +currently pronounced word is highlighted. Use the `-wts` argument and run the generated bash script. +This requires to have `ffmpeg` installed. + +Here are a few *"typical"* examples: + +```java +./main -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -owts +source ./samples/jfk.wav.wts +ffplay ./samples/jfk.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337465-dbee4b5e-9aeb-48a3-b1c6-323ac4db5b2c.mp4 + +--- + +```java +./main -m ./models/ggml-base.en.bin -f ./samples/mm0.wav -owts +source ./samples/mm0.wav.wts +ffplay ./samples/mm0.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337504-cc8fd233-0cb7-4920-95f9-4227de3570aa.mp4 + +--- + +```java +./main -m ./models/ggml-base.en.bin -f ./samples/gb0.wav -owts +source ./samples/gb0.wav.wts +ffplay ./samples/gb0.wav.mp4 +``` + +https://user-images.githubusercontent.com/1991296/199337538-b7b0c7a3-2753-4a88-a0cd-f28a317987ba.mp4 + +--- + +## Video comparison of different models + +Use the [extra/bench-wts.sh](https://github.com/ggerganov/whisper.cpp/blob/master/extra/bench-wts.sh) script to generate a video in the following format: + +```java +./extra/bench-wts.sh samples/jfk.wav +ffplay ./samples/jfk.wav.all.mp4 +``` + +https://user-images.githubusercontent.com/1991296/223206245-2d36d903-cf8e-4f09-8c3b-eb9f9c39d6fc.mp4 + +--- + +## Benchmarks + +In order to have an objective comparison of the performance of the inference across different system configurations, +use the [bench](examples/bench) tool. The tool simply runs the Encoder part of the model and prints how much time it +took to execute it. The results are summarized in the following Github issue: + +[Benchmark results](https://github.com/ggerganov/whisper.cpp/issues/89) + +Additionally a script to run whisper.cpp with different models and audio files is provided [bench.py](bench.py). + +You can run it with the following command, by default it will run against any standard model in the models folder. + +```bash +python3 extra/bench.py -f samples/jfk.wav -t 2,4,8 -p 1,2 +``` + +It is written in python with the intention of being easy to modify and extend for your benchmarking use case. + +It outputs a csv file with the results of the benchmarking. + + +## ggml format + +The original models are converted to a custom binary format. This allows to pack everything needed into a single file: + +- model parameters +- mel filters +- vocabulary +- weights + +You can download the converted models using the [models/download-ggml-model.sh](models/download-ggml-model.sh) script +or manually from here: + +- https://huggingface.co/ggerganov/whisper.cpp +- https://ggml.ggerganov.com + +For more details, see the conversion script [models/convert-pt-to-ggml.py](models/convert-pt-to-ggml.py) or the README +in [models](models). + +## [Bindings](https://github.com/ggerganov/whisper.cpp/discussions/categories/bindings) + +- [X] Rust: [tazz4843/whisper-rs](https://github.com/tazz4843/whisper-rs) | [#310](https://github.com/ggerganov/whisper.cpp/discussions/310) +- [X] JavaScript: [bindings/javascript](bindings/javascript) | [#309](https://github.com/ggerganov/whisper.cpp/discussions/309) + - React Native (iOS / Android): [whisper.rn](https://github.com/mybigday/whisper.rn) +- [X] Go: [bindings/go](bindings/go) | [#312](https://github.com/ggerganov/whisper.cpp/discussions/312) +- [X] Java: + - [GiviMAD/whisper-jni](https://github.com/GiviMAD/whisper-jni) +- [X] Ruby: [bindings/ruby](bindings/ruby) | [#507](https://github.com/ggerganov/whisper.cpp/discussions/507) +- [X] Objective-C / Swift: [ggerganov/whisper.spm](https://github.com/ggerganov/whisper.spm) | [#313](https://github.com/ggerganov/whisper.cpp/discussions/313) + - [exPHAT/SwiftWhisper](https://github.com/exPHAT/SwiftWhisper) +- [X] .NET: | [#422](https://github.com/ggerganov/whisper.cpp/discussions/422) + - [sandrohanea/whisper.net](https://github.com/sandrohanea/whisper.net) + - [NickDarvey/whisper](https://github.com/NickDarvey/whisper) +- [X] Python: | [#9](https://github.com/ggerganov/whisper.cpp/issues/9) + - [stlukey/whispercpp.py](https://github.com/stlukey/whispercpp.py) (Cython) + - [aarnphm/whispercpp](https://github.com/aarnphm/whispercpp) (Pybind11) +- [X] R: [bnosac/audio.whisper](https://github.com/bnosac/audio.whisper) +- [X] Unity: [macoron/whisper.unity](https://github.com/Macoron/whisper.unity) + +## Examples + +There are various examples of using the library for different projects in the [examples](examples) folder. +Some of the examples are even ported to run in the browser using WebAssembly. Check them out! + +| Example | Web | Description | +| --- | --- | --- | +| [main](examples/main) | [whisper.wasm](examples/whisper.wasm) | Tool for translating and transcribing audio using Whisper | +| [bench](examples/bench) | [bench.wasm](examples/bench.wasm) | Benchmark the performance of Whisper on your machine | +| [stream](examples/stream) | [stream.wasm](examples/stream.wasm) | Real-time transcription of raw microphone capture | +| [command](examples/command) | [command.wasm](examples/command.wasm) | Basic voice assistant example for receiving voice commands from the mic | +| [wchess](examples/wchess) | [wchess.wasm](examples/wchess) | Voice-controlled chess | +| [talk](examples/talk) | [talk.wasm](examples/talk.wasm) | Talk with a GPT-2 bot | +| [talk-llama](examples/talk-llama) | | Talk with a LLaMA bot | +| [whisper.objc](examples/whisper.objc) | | iOS mobile application using whisper.cpp | +| [whisper.swiftui](examples/whisper.swiftui) | | SwiftUI iOS / macOS application using whisper.cpp | +| [whisper.android](examples/whisper.android) | | Android mobile application using whisper.cpp | +| [whisper.nvim](examples/whisper.nvim) | | Speech-to-text plugin for Neovim | +| [generate-karaoke.sh](examples/generate-karaoke.sh) | | Helper script to easily [generate a karaoke video](https://youtu.be/uj7hVta4blM) of raw audio capture | +| [livestream.sh](examples/livestream.sh) | | [Livestream audio transcription](https://github.com/ggerganov/whisper.cpp/issues/185) | +| [yt-wsp.sh](examples/yt-wsp.sh) | | Download + transcribe and/or translate any VOD [(original)](https://gist.github.com/DaniruKun/96f763ec1a037cc92fe1a059b643b818) | +| [server](examples/server) | | HTTP transcription server with OAI-like API | + +## [Discussions](https://github.com/ggerganov/whisper.cpp/discussions) + +If you have any kind of feedback about this project feel free to use the Discussions section and open a new topic. +You can use the [Show and tell](https://github.com/ggerganov/whisper.cpp/discussions/categories/show-and-tell) category +to share your own projects that use `whisper.cpp`. If you have a question, make sure to check the +[Frequently asked questions (#126)](https://github.com/ggerganov/whisper.cpp/discussions/126) discussion. diff --git a/whisper.cpp-1.5.2/bindings/CMakeLists.txt b/whisper.cpp-1.5.2/bindings/CMakeLists.txt new file mode 100644 index 0000000..af79c51 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/CMakeLists.txt @@ -0,0 +1,19 @@ +if (EMSCRIPTEN) + add_subdirectory(javascript) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/javascript/publish.log + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/whisper.js + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/libwhisper.worker.js + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/package.json + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/javascript + COMMAND npm publish + COMMAND touch publish.log + COMMENT "Publishing npm module v${PROJECT_VERSION}" + VERBATIM + ) + + add_custom_target(publish-npm + DEPENDS javascript/publish.log + ) +endif() diff --git a/whisper.cpp-1.5.2/bindings/go/.gitignore b/whisper.cpp-1.5.2/bindings/go/.gitignore new file mode 100644 index 0000000..036df1d --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/.gitignore @@ -0,0 +1,2 @@ +build +models diff --git a/whisper.cpp-1.5.2/bindings/go/LICENSE b/whisper.cpp-1.5.2/bindings/go/LICENSE new file mode 100644 index 0000000..a8f0d7b --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 David Thorpe + +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/whisper.cpp-1.5.2/bindings/go/Makefile b/whisper.cpp-1.5.2/bindings/go/Makefile new file mode 100644 index 0000000..4f3a416 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/Makefile @@ -0,0 +1,64 @@ +ifndef UNAME_S +UNAME_S := $(shell uname -s) +endif + +ifndef UNAME_P +UNAME_P := $(shell uname -p) +endif + +ifndef UNAME_M +UNAME_M := $(shell uname -m) +endif + +GGML_METAL_PATH_RESOURCES := $(abspath ../..) +BUILD_DIR := build +MODELS_DIR := models +EXAMPLES_DIR := $(wildcard examples/*) +INCLUDE_PATH := $(abspath ../..) +LIBRARY_PATH := $(abspath ../..) + +ifeq ($(UNAME_S),Darwin) + EXT_LDFLAGS := -framework Foundation -framework Metal -framework MetalKit +endif + +all: clean whisper examples + +whisper: mkdir + @echo Build whisper + @${MAKE} -C ../.. libwhisper.a + +test: model-small whisper modtidy +ifeq ($(UNAME_S),Darwin) + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v . + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v ./pkg/whisper/... +else + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v . + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v ./pkg/whisper/... +endif + +examples: $(EXAMPLES_DIR) + +model-small: mkdir examples/go-model-download + @${BUILD_DIR}/go-model-download -out models ggml-small.en.bin + +$(EXAMPLES_DIR): mkdir whisper modtidy + @echo Build example $(notdir $@) +ifeq ($(UNAME_S),Darwin) + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go build ${BUILD_FLAGS} -ldflags "-extldflags '$(EXT_LDFLAGS)'" -o ${BUILD_DIR}/$(notdir $@) ./$@ +else + @C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go build ${BUILD_FLAGS} -o ${BUILD_DIR}/$(notdir $@) ./$@ +endif + +mkdir: + @echo Mkdir ${BUILD_DIR} + @install -d ${BUILD_DIR} + @echo Mkdir ${MODELS_DIR} + @install -d ${MODELS_DIR} + +modtidy: + @go mod tidy + +clean: + @echo Clean + @rm -fr $(BUILD_DIR) + @go clean diff --git a/whisper.cpp-1.5.2/bindings/go/README.md b/whisper.cpp-1.5.2/bindings/go/README.md new file mode 100644 index 0000000..1968cfd --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/README.md @@ -0,0 +1,100 @@ +# Go bindings for Whisper + +This package provides Go bindings for whisper.cpp. They have been tested on: + + * Darwin (OS X) 12.6 on x64_64 + * Debian Linux on arm64 + * Fedora Linux on x86_64 + +The "low level" bindings are in the `bindings/go` directory and there is a more +Go-style package in the `bindings/go/pkg/whisper` directory. The most simple usage +is as follows: + +```go +import ( + "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +func main() { + var modelpath string // Path to the model + var samples []float32 // Samples to process + + // Load the model + model, err := whisper.New(modelpath) + if err != nil { + panic(err) + } + defer model.Close() + + // Process samples + context, err := model.NewContext() + if err != nil { + panic(err) + } + if err := context.Process(samples, nil, nil); err != nil { + return err + } + + // Print out the results + for { + segment, err := context.NextSegment() + if err != nil { + break + } + fmt.Printf("[%6s->%6s] %s\n", segment.Start, segment.End, segment.Text) + } +} +``` + +## Building & Testing + +In order to build, you need to have the Go compiler installed. You can get it from [here](https://golang.org/dl/). Run the tests with: + +```bash +git clone https://github.com/ggerganov/whisper.cpp.git +cd whisper.cpp/bindings/go +make test +``` + +This will compile a static `libwhisper.a` in a `build` folder, download a model file, then run the tests. To build the examples: + +```bash +make examples +``` + +The examples are placed in the `build` directory. Once built, you can download all the models with the following command: + +```bash +./build/go-model-download -out models +``` + +And you can then test a model against samples with the following command: + +```bash +./build/go-whisper -model models/ggml-tiny.en.bin samples/jfk.wav +``` + +## Using the bindings + +To use the bindings in your own software, + + 1. Import `github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper` (or `github.com/ggerganov/whisper.cpp/bindings/go` into your package; + 2. Compile `libwhisper.a` (you can use `make whisper` in the `bindings/go` directory); + 3. Link your go binary against whisper by setting the environment variables `C_INCLUDE_PATH` and `LIBRARY_PATH` + to point to the `whisper.h` file directory and `libwhisper.a` file directory respectively. + +Look at the `Makefile` in the `bindings/go` directory for an example. + +The API Documentation: + + * https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go + * https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper + +Getting help: + + * Follow the discussion for the go bindings [here](https://github.com/ggerganov/whisper.cpp/discussions/312) + +## License + +The license for the Go bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details. + diff --git a/whisper.cpp-1.5.2/bindings/go/doc.go b/whisper.cpp-1.5.2/bindings/go/doc.go new file mode 100644 index 0000000..dcc351f --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/doc.go @@ -0,0 +1,5 @@ +/* +github.com/ggerganov/whisper.cpp/bindings/go +provides a speech-to-text service bindings for the Go programming language. +*/ +package whisper diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/context.go b/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/context.go new file mode 100644 index 0000000..639d8f5 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/context.go @@ -0,0 +1,30 @@ +package main + +import ( + "context" + "os" + "os/signal" +) + +// ContextForSignal returns a context object which is cancelled when a signal +// is received. It returns nil if no signal parameter is provided +func ContextForSignal(signals ...os.Signal) context.Context { + if len(signals) == 0 { + return nil + } + + ch := make(chan os.Signal) + ctx, cancel := context.WithCancel(context.Background()) + + // Send message on channel when signal received + signal.Notify(ch, signals...) + + // When any signal received, call cancel + go func() { + <-ch + cancel() + }() + + // Return success + return ctx +} diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/main.go b/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/main.go new file mode 100644 index 0000000..3522d88 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-model-download/main.go @@ -0,0 +1,208 @@ +package main + +import ( + "context" + "flag" + "fmt" + "io" + "net/http" + "net/url" + "os" + "path/filepath" + "syscall" + "time" +) + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +const ( + srcUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main" // The location of the models + srcExt = ".bin" // Filename extension + bufSize = 1024 * 64 // Size of the buffer used for downloading the model +) + +var ( + // The models which will be downloaded, if no model is specified as an argument + modelNames = []string{"ggml-tiny.en", "ggml-tiny", "ggml-base.en", "ggml-base", "ggml-small.en", "ggml-small", "ggml-medium.en", "ggml-medium", "ggml-large-v1", "ggml-large-v2", "ggml-large-v3"} +) + +var ( + // The output folder. When not set, use current working directory. + flagOut = flag.String("out", "", "Output folder") + + // HTTP timeout parameter - will timeout if takes longer than this to download a model + flagTimeout = flag.Duration("timeout", 30*time.Minute, "HTTP timeout") + + // Quiet parameter - will not print progress if set + flagQuiet = flag.Bool("quiet", false, "Quiet mode") +) + +/////////////////////////////////////////////////////////////////////////////// +// MAIN + +func main() { + flag.Usage = func() { + name := filepath.Base(flag.CommandLine.Name()) + fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] \n\n", name) + flag.PrintDefaults() + } + flag.Parse() + + // Get output path + out, err := GetOut() + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(-1) + } + + // Create context which quits on SIGINT or SIGQUIT + ctx := ContextForSignal(os.Interrupt, syscall.SIGQUIT) + + // Progress filehandle + progress := os.Stdout + if *flagQuiet { + progress, err = os.Open(os.DevNull) + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(-1) + } + defer progress.Close() + } + + // Download models - exit on error or interrupt + for _, model := range GetModels() { + url, err := URLForModel(model) + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + continue + } else if path, err := Download(ctx, progress, url, out); err == nil || err == io.EOF { + continue + } else if err == context.Canceled { + os.Remove(path) + fmt.Fprintln(progress, "\nInterrupted") + break + } else if err == context.DeadlineExceeded { + os.Remove(path) + fmt.Fprintln(progress, "Timeout downloading model") + continue + } else { + os.Remove(path) + fmt.Fprintln(os.Stderr, "Error:", err) + break + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// GetOut returns the path to the output directory +func GetOut() (string, error) { + if *flagOut == "" { + return os.Getwd() + } + if info, err := os.Stat(*flagOut); err != nil { + return "", err + } else if !info.IsDir() { + return "", fmt.Errorf("not a directory: %s", info.Name()) + } else { + return *flagOut, nil + } +} + +// GetModels returns the list of models to download +func GetModels() []string { + if flag.NArg() == 0 { + return modelNames + } else { + return flag.Args() + } +} + +// URLForModel returns the URL for the given model on huggingface.co +func URLForModel(model string) (string, error) { + if filepath.Ext(model) != srcExt { + model += srcExt + } + url, err := url.Parse(srcUrl) + if err != nil { + return "", err + } else { + url.Path = filepath.Join(url.Path, model) + } + return url.String(), nil +} + +// Download downloads the model from the given URL to the given output directory +func Download(ctx context.Context, p io.Writer, model, out string) (string, error) { + // Create HTTP client + client := http.Client{ + Timeout: *flagTimeout, + } + + // Initiate the download + req, err := http.NewRequest("GET", model, nil) + if err != nil { + return "", err + } + resp, err := client.Do(req) + if err != nil { + return "", err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("%s: %s", model, resp.Status) + } + + // If output file exists and is the same size as the model, skip + path := filepath.Join(out, filepath.Base(model)) + if info, err := os.Stat(path); err == nil && info.Size() == resp.ContentLength { + fmt.Fprintln(p, "Skipping", model, "as it already exists") + return "", nil + } + + // Create file + w, err := os.Create(path) + if err != nil { + return "", err + } + defer w.Close() + + // Report + fmt.Fprintln(p, "Downloading", model, "to", out) + + // Progressively download the model + data := make([]byte, bufSize) + count, pct := int64(0), int64(0) + ticker := time.NewTicker(5 * time.Second) + for { + select { + case <-ctx.Done(): + // Cancelled, return error + return path, ctx.Err() + case <-ticker.C: + pct = DownloadReport(p, pct, count, resp.ContentLength) + default: + // Read body + n, err := resp.Body.Read(data) + if err != nil { + DownloadReport(p, pct, count, resp.ContentLength) + return path, err + } else if m, err := w.Write(data[:n]); err != nil { + return path, err + } else { + count += int64(m) + } + } + } +} + +// Report periodically reports the download progress when percentage changes +func DownloadReport(w io.Writer, pct, count, total int64) int64 { + pct_ := count * 100 / total + if pct_ > pct { + fmt.Fprintf(w, " ...%d MB written (%d%%)\n", count/1e6, pct_) + } + return pct_ +} diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/color.go b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/color.go new file mode 100644 index 0000000..fa5ac2f --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/color.go @@ -0,0 +1,22 @@ +package main + +import "fmt" + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +const ( + Reset = "\033[0m" + RGBPrefix = "\033[38;5;" // followed by RGB values in decimal format separated by colons + RGBSuffix = "m" +) + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Colorize text with RGB values, from 0 to 23 +func Colorize(text string, v int) string { + // https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit + // Grayscale colors are in the range 232-255 + return RGBPrefix + fmt.Sprint(v%24+232) + RGBSuffix + text + Reset +} diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/flags.go b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/flags.go new file mode 100644 index 0000000..ea20445 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/flags.go @@ -0,0 +1,156 @@ +package main + +import ( + "flag" + "fmt" + "strings" + "time" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type Flags struct { + *flag.FlagSet +} + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func NewFlags(name string, args []string) (*Flags, error) { + flags := &Flags{ + FlagSet: flag.NewFlagSet(name, flag.ContinueOnError), + } + + // Register the command line arguments + registerFlags(flags) + + // Parse command line + if err := flags.Parse(args); err != nil { + return nil, err + } + + // Return success + return flags, nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +func (flags *Flags) GetModel() string { + return flags.Lookup("model").Value.String() +} + +func (flags *Flags) GetLanguage() string { + return flags.Lookup("language").Value.String() +} + +func (flags *Flags) IsTranslate() bool { + return flags.Lookup("translate").Value.(flag.Getter).Get().(bool) +} + +func (flags *Flags) GetOffset() time.Duration { + return flags.Lookup("offset").Value.(flag.Getter).Get().(time.Duration) +} + +func (flags *Flags) GetDuration() time.Duration { + return flags.Lookup("duration").Value.(flag.Getter).Get().(time.Duration) +} + +func (flags *Flags) GetThreads() uint { + return flags.Lookup("threads").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetOut() string { + return strings.ToLower(flags.Lookup("out").Value.String()) +} + +func (flags *Flags) IsSpeedup() bool { + return flags.Lookup("speedup").Value.String() == "true" +} + +func (flags *Flags) IsTokens() bool { + return flags.Lookup("tokens").Value.String() == "true" +} + +func (flags *Flags) IsColorize() bool { + return flags.Lookup("colorize").Value.String() == "true" +} + +func (flags *Flags) GetMaxLen() uint { + return flags.Lookup("max-len").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetMaxTokens() uint { + return flags.Lookup("max-tokens").Value.(flag.Getter).Get().(uint) +} + +func (flags *Flags) GetWordThreshold() float32 { + return float32(flags.Lookup("word-thold").Value.(flag.Getter).Get().(float64)) +} + +func (flags *Flags) SetParams(context whisper.Context) error { + if lang := flags.GetLanguage(); lang != "" && lang != "auto" { + fmt.Fprintf(flags.Output(), "Setting language to %q\n", lang) + if err := context.SetLanguage(lang); err != nil { + return err + } + } + if flags.IsTranslate() && context.IsMultilingual() { + fmt.Fprintf(flags.Output(), "Setting translate to true\n") + context.SetTranslate(true) + } + if offset := flags.GetOffset(); offset != 0 { + fmt.Fprintf(flags.Output(), "Setting offset to %v\n", offset) + context.SetOffset(offset) + } + if duration := flags.GetDuration(); duration != 0 { + fmt.Fprintf(flags.Output(), "Setting duration to %v\n", duration) + context.SetDuration(duration) + } + if flags.IsSpeedup() { + fmt.Fprintf(flags.Output(), "Setting speedup to true\n") + context.SetSpeedup(true) + } + if threads := flags.GetThreads(); threads != 0 { + fmt.Fprintf(flags.Output(), "Setting threads to %d\n", threads) + context.SetThreads(threads) + } + if max_len := flags.GetMaxLen(); max_len != 0 { + fmt.Fprintf(flags.Output(), "Setting max_segment_length to %d\n", max_len) + context.SetMaxSegmentLength(max_len) + } + if max_tokens := flags.GetMaxTokens(); max_tokens != 0 { + fmt.Fprintf(flags.Output(), "Setting max_tokens to %d\n", max_tokens) + context.SetMaxTokensPerSegment(max_tokens) + } + if word_threshold := flags.GetWordThreshold(); word_threshold != 0 { + fmt.Fprintf(flags.Output(), "Setting word_threshold to %f\n", word_threshold) + context.SetTokenThreshold(word_threshold) + } + + // Return success + return nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func registerFlags(flag *Flags) { + flag.String("model", "", "Path to the model file") + flag.String("language", "", "Spoken language") + flag.Bool("translate", false, "Translate from source language to english") + flag.Duration("offset", 0, "Time offset") + flag.Duration("duration", 0, "Duration of audio to process") + flag.Uint("threads", 0, "Number of threads to use") + flag.Bool("speedup", false, "Enable speedup") + flag.Uint("max-len", 0, "Maximum segment length in characters") + flag.Uint("max-tokens", 0, "Maximum tokens per segment") + flag.Float64("word-thold", 0, "Maximum segment score") + flag.Bool("tokens", false, "Display tokens") + flag.Bool("colorize", false, "Colorize tokens") + flag.String("out", "", "Output format (srt, none or leave as empty string)") +} diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/main.go b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/main.go new file mode 100644 index 0000000..1bff7f5 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "os" + "path/filepath" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" +) + +func main() { + flags, err := NewFlags(filepath.Base(os.Args[0]), os.Args[1:]) + if err == flag.ErrHelp { + os.Exit(0) + } else if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } else if flags.GetModel() == "" { + fmt.Fprintln(os.Stderr, "Use -model flag to specify which model file to use") + os.Exit(1) + } else if flags.NArg() == 0 { + fmt.Fprintln(os.Stderr, "No input files specified") + os.Exit(1) + } + + // Load model + model, err := whisper.New(flags.GetModel()) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer model.Close() + + // Process files + for _, filename := range flags.Args() { + if err := Process(model, filename, flags); err != nil { + fmt.Fprintln(os.Stderr, err) + continue + } + } +} diff --git a/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/process.go b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/process.go new file mode 100644 index 0000000..71e52f0 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/examples/go-whisper/process.go @@ -0,0 +1,132 @@ +package main + +import ( + "fmt" + "io" + "os" + "time" + + // Package imports + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" + wav "github.com/go-audio/wav" +) + +func Process(model whisper.Model, path string, flags *Flags) error { + var data []float32 + + // Create processing context + context, err := model.NewContext() + if err != nil { + return err + } + + // Set the parameters + if err := flags.SetParams(context); err != nil { + return err + } + + fmt.Printf("\n%s\n", context.SystemInfo()) + + // Open the file + fmt.Fprintf(flags.Output(), "Loading %q\n", path) + fh, err := os.Open(path) + if err != nil { + return err + } + defer fh.Close() + + // Decode the WAV file - load the full buffer + dec := wav.NewDecoder(fh) + if buf, err := dec.FullPCMBuffer(); err != nil { + return err + } else if dec.SampleRate != whisper.SampleRate { + return fmt.Errorf("unsupported sample rate: %d", dec.SampleRate) + } else if dec.NumChans != 1 { + return fmt.Errorf("unsupported number of channels: %d", dec.NumChans) + } else { + data = buf.AsFloat32Buffer().Data + } + + // Segment callback when -tokens is specified + var cb whisper.SegmentCallback + if flags.IsTokens() { + cb = func(segment whisper.Segment) { + fmt.Fprintf(flags.Output(), "%02d [%6s->%6s] ", segment.Num, segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond)) + for _, token := range segment.Tokens { + if flags.IsColorize() && context.IsText(token) { + fmt.Fprint(flags.Output(), Colorize(token.Text, int(token.P*24.0)), " ") + } else { + fmt.Fprint(flags.Output(), token.Text, " ") + } + } + fmt.Fprintln(flags.Output(), "") + fmt.Fprintln(flags.Output(), "") + } + } + + // Process the data + fmt.Fprintf(flags.Output(), " ...processing %q\n", path) + context.ResetTimings() + if err := context.Process(data, cb, nil); err != nil { + return err + } + + context.PrintTimings() + + // Print out the results + switch { + case flags.GetOut() == "srt": + return OutputSRT(os.Stdout, context) + case flags.GetOut() == "none": + return nil + default: + return Output(os.Stdout, context, flags.IsColorize()) + } +} + +// Output text as SRT file +func OutputSRT(w io.Writer, context whisper.Context) error { + n := 1 + for { + segment, err := context.NextSegment() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + fmt.Fprintln(w, n) + fmt.Fprintln(w, srtTimestamp(segment.Start), " --> ", srtTimestamp(segment.End)) + fmt.Fprintln(w, segment.Text) + fmt.Fprintln(w, "") + n++ + } +} + +// Output text to terminal +func Output(w io.Writer, context whisper.Context, colorize bool) error { + for { + segment, err := context.NextSegment() + if err == io.EOF { + return nil + } else if err != nil { + return err + } + fmt.Fprintf(w, "[%6s->%6s]", segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond)) + if colorize { + for _, token := range segment.Tokens { + if !context.IsText(token) { + continue + } + fmt.Fprint(w, " ", Colorize(token.Text, int(token.P*24.0))) + } + fmt.Fprint(w, "\n") + } else { + fmt.Fprintln(w, " ", segment.Text) + } + } +} + +// Return srtTimestamp +func srtTimestamp(t time.Duration) string { + return fmt.Sprintf("%02d:%02d:%02d,%03d", t/time.Hour, (t%time.Hour)/time.Minute, (t%time.Minute)/time.Second, (t%time.Second)/time.Millisecond) +} diff --git a/whisper.cpp-1.5.2/bindings/go/go.mod b/whisper.cpp-1.5.2/bindings/go/go.mod new file mode 100644 index 0000000..594f184 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/go.mod @@ -0,0 +1,16 @@ +module github.com/ggerganov/whisper.cpp/bindings/go + +go 1.19 + +require ( + github.com/go-audio/wav v1.1.0 + github.com/stretchr/testify v1.8.1 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/go-audio/audio v1.0.0 // indirect + github.com/go-audio/riff v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/whisper.cpp-1.5.2/bindings/go/go.sum b/whisper.cpp-1.5.2/bindings/go/go.sum new file mode 100644 index 0000000..870ebdc --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/go.sum @@ -0,0 +1,23 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4= +github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs= +github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA= +github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498= +github.com/go-audio/wav v1.1.0 h1:jQgLtbqBzY7G+BM8fXF7AHUk1uHUviWS4X39d5rsL2g= +github.com/go-audio/wav v1.1.0/go.mod h1:mpe9qfwbScEbkd8uybLuIpTgHyrISw/OTuvjUW2iGtE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/whisper.cpp-1.5.2/bindings/go/params.go b/whisper.cpp-1.5.2/bindings/go/params.go new file mode 100644 index 0000000..3c9dd5c --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/params.go @@ -0,0 +1,179 @@ +package whisper + +import ( + "fmt" +) + +/////////////////////////////////////////////////////////////////////////////// +// CGO + +/* +#include +*/ +import "C" + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +func (p *Params) SetTranslate(v bool) { + p.translate = toBool(v) +} + +func (p *Params) SetSplitOnWord(v bool) { + p.split_on_word = toBool(v) +} + +func (p *Params) SetNoContext(v bool) { + p.no_context = toBool(v) +} + +func (p *Params) SetSingleSegment(v bool) { + p.single_segment = toBool(v) +} + +func (p *Params) SetPrintSpecial(v bool) { + p.print_special = toBool(v) +} + +func (p *Params) SetPrintProgress(v bool) { + p.print_progress = toBool(v) +} + +func (p *Params) SetPrintRealtime(v bool) { + p.print_realtime = toBool(v) +} + +func (p *Params) SetPrintTimestamps(v bool) { + p.print_timestamps = toBool(v) +} + +func (p *Params) SetSpeedup(v bool) { + p.speed_up = toBool(v) +} + +// Set language id +func (p *Params) SetLanguage(lang int) error { + if lang == -1 { + p.language = nil + return nil + } + str := C.whisper_lang_str(C.int(lang)) + if str == nil { + return ErrInvalidLanguage + } else { + p.language = str + } + return nil +} + +// Get language id +func (p *Params) Language() int { + if p.language == nil { + return -1 + } + return int(C.whisper_lang_id(p.language)) +} + +// Threads available +func (p *Params) Threads() int { + return int(p.n_threads) +} + +// Set number of threads to use +func (p *Params) SetThreads(threads int) { + p.n_threads = C.int(threads) +} + +// Set start offset in ms +func (p *Params) SetOffset(offset_ms int) { + p.offset_ms = C.int(offset_ms) +} + +// Set audio duration to process in ms +func (p *Params) SetDuration(duration_ms int) { + p.duration_ms = C.int(duration_ms) +} + +// Set timestamp token probability threshold (~0.01) +func (p *Params) SetTokenThreshold(t float32) { + p.thold_pt = C.float(t) +} + +// Set timestamp token sum probability threshold (~0.01) +func (p *Params) SetTokenSumThreshold(t float32) { + p.thold_ptsum = C.float(t) +} + +// Set max segment length in characters +func (p *Params) SetMaxSegmentLength(n int) { + p.max_len = C.int(n) +} + +func (p *Params) SetTokenTimestamps(b bool) { + p.token_timestamps = toBool(b) +} + +// Set max tokens per segment (0 = no limit) +func (p *Params) SetMaxTokensPerSegment(n int) { + p.max_tokens = C.int(n) +} + +// Set audio encoder context +func (p *Params) SetAudioCtx(n int) { + p.audio_ctx = C.int(n) +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func toBool(v bool) C.bool { + if v { + return C.bool(true) + } + return C.bool(false) +} + +/////////////////////////////////////////////////////////////////////////////// +// STRINGIFY + +func (p *Params) String() string { + str := "" +} diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/consts.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/consts.go new file mode 100644 index 0000000..5c22dc1 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/consts.go @@ -0,0 +1,28 @@ +package whisper + +import ( + "errors" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// ERRORS + +var ( + ErrUnableToLoadModel = errors.New("unable to load model") + ErrInternalAppError = errors.New("internal application error") + ErrProcessingFailed = errors.New("processing failed") + ErrUnsupportedLanguage = errors.New("unsupported language") + ErrModelNotMultilingual = errors.New("model is not multilingual") +) + +/////////////////////////////////////////////////////////////////////////////// +// CONSTANTS + +// SampleRate is the sample rate of the audio data. +const SampleRate = whisper.SampleRate + +// SampleBits is the number of bytes per sample. +const SampleBits = whisper.SampleBits diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context.go new file mode 100644 index 0000000..f51d4f8 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context.go @@ -0,0 +1,316 @@ +package whisper + +import ( + "fmt" + "io" + "runtime" + "strings" + "time" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type context struct { + n int + model *model + params whisper.Params +} + +// Make sure context adheres to the interface +var _ Context = (*context)(nil) + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func newContext(model *model, params whisper.Params) (Context, error) { + context := new(context) + context.model = model + context.params = params + + // Return success + return context, nil +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Set the language to use for speech recognition. +func (context *context) SetLanguage(lang string) error { + if context.model.ctx == nil { + return ErrInternalAppError + } + if !context.model.IsMultilingual() { + return ErrModelNotMultilingual + } + + if lang == "auto" { + context.params.SetLanguage(-1) + } else if id := context.model.ctx.Whisper_lang_id(lang); id < 0 { + return ErrUnsupportedLanguage + } else if err := context.params.SetLanguage(id); err != nil { + return err + } + // Return success + return nil +} + +func (context *context) IsMultilingual() bool { + return context.model.IsMultilingual() +} + +// Get language +func (context *context) Language() string { + id := context.params.Language() + if id == -1 { + return "auto" + } + return whisper.Whisper_lang_str(context.params.Language()) +} + +// Set translate flag +func (context *context) SetTranslate(v bool) { + context.params.SetTranslate(v) +} + +// Set speedup flag +func (context *context) SetSpeedup(v bool) { + context.params.SetSpeedup(v) +} + +func (context *context) SetSplitOnWord(v bool) { + context.params.SetSplitOnWord(v) +} + +// Set number of threads to use +func (context *context) SetThreads(v uint) { + context.params.SetThreads(int(v)) +} + +// Set time offset +func (context *context) SetOffset(v time.Duration) { + context.params.SetOffset(int(v.Milliseconds())) +} + +// Set duration of audio to process +func (context *context) SetDuration(v time.Duration) { + context.params.SetDuration(int(v.Milliseconds())) +} + +// Set timestamp token probability threshold (~0.01) +func (context *context) SetTokenThreshold(t float32) { + context.params.SetTokenThreshold(t) +} + +// Set timestamp token sum probability threshold (~0.01) +func (context *context) SetTokenSumThreshold(t float32) { + context.params.SetTokenSumThreshold(t) +} + +// Set max segment length in characters +func (context *context) SetMaxSegmentLength(n uint) { + context.params.SetMaxSegmentLength(int(n)) +} + +// Set token timestamps flag +func (context *context) SetTokenTimestamps(b bool) { + context.params.SetTokenTimestamps(b) +} + +// Set max tokens per segment (0 = no limit) +func (context *context) SetMaxTokensPerSegment(n uint) { + context.params.SetMaxTokensPerSegment(int(n)) +} + +// Set audio encoder context +func (context *context) SetAudioCtx(n uint) { + context.params.SetAudioCtx(int(n)) +} + +// ResetTimings resets the mode timings. Should be called before processing +func (context *context) ResetTimings() { + context.model.ctx.Whisper_reset_timings() +} + +// PrintTimings prints the model timings to stdout. +func (context *context) PrintTimings() { + context.model.ctx.Whisper_print_timings() +} + +// SystemInfo returns the system information +func (context *context) SystemInfo() string { + return fmt.Sprintf("system_info: n_threads = %d / %d | %s\n", + context.params.Threads(), + runtime.NumCPU(), + whisper.Whisper_print_system_info(), + ) +} + +// Use mel data at offset_ms to try and auto-detect the spoken language +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// Returns the probabilities of all languages. +func (context *context) WhisperLangAutoDetect(offset_ms int, n_threads int) ([]float32, error) { + langProbs, err := context.model.ctx.Whisper_lang_auto_detect(offset_ms, n_threads) + if err != nil { + return nil, err + } + return langProbs, nil +} + +// Process new sample data and return any errors +func (context *context) Process( + data []float32, + callNewSegment SegmentCallback, + callProgress ProgressCallback, +) error { + if context.model.ctx == nil { + return ErrInternalAppError + } + // If the callback is defined then we force on single_segment mode + if callNewSegment != nil { + context.params.SetSingleSegment(true) + } + + // We don't do parallel processing at the moment + processors := 0 + if processors > 1 { + if err := context.model.ctx.Whisper_full_parallel(context.params, data, processors, nil, func(new int) { + if callNewSegment != nil { + num_segments := context.model.ctx.Whisper_full_n_segments() + s0 := num_segments - new + for i := s0; i < num_segments; i++ { + callNewSegment(toSegment(context.model.ctx, i)) + } + } + }); err != nil { + return err + } + } else if err := context.model.ctx.Whisper_full(context.params, data, nil, func(new int) { + if callNewSegment != nil { + num_segments := context.model.ctx.Whisper_full_n_segments() + s0 := num_segments - new + for i := s0; i < num_segments; i++ { + callNewSegment(toSegment(context.model.ctx, i)) + } + } + }, func(progress int) { + if callProgress != nil { + callProgress(progress) + } + }); err != nil { + return err + } + + // Return success + return nil +} + +// Return the next segment of tokens +func (context *context) NextSegment() (Segment, error) { + if context.model.ctx == nil { + return Segment{}, ErrInternalAppError + } + if context.n >= context.model.ctx.Whisper_full_n_segments() { + return Segment{}, io.EOF + } + + // Populate result + result := toSegment(context.model.ctx, context.n) + + // Increment the cursor + context.n++ + + // Return success + return result, nil +} + +// Test for text tokens +func (context *context) IsText(t Token) bool { + switch { + case context.IsBEG(t): + return false + case context.IsSOT(t): + return false + case whisper.Token(t.Id) >= context.model.ctx.Whisper_token_eot(): + return false + case context.IsPREV(t): + return false + case context.IsSOLM(t): + return false + case context.IsNOT(t): + return false + default: + return true + } +} + +// Test for "begin" token +func (context *context) IsBEG(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_beg() +} + +// Test for "start of transcription" token +func (context *context) IsSOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_sot() +} + +// Test for "end of transcription" token +func (context *context) IsEOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_eot() +} + +// Test for "start of prev" token +func (context *context) IsPREV(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_prev() +} + +// Test for "start of lm" token +func (context *context) IsSOLM(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_solm() +} + +// Test for "No timestamps" token +func (context *context) IsNOT(t Token) bool { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_not() +} + +// Test for token associated with a specific language +func (context *context) IsLANG(t Token, lang string) bool { + if id := context.model.ctx.Whisper_lang_id(lang); id >= 0 { + return whisper.Token(t.Id) == context.model.ctx.Whisper_token_lang(id) + } else { + return false + } +} + +/////////////////////////////////////////////////////////////////////////////// +// PRIVATE METHODS + +func toSegment(ctx *whisper.Context, n int) Segment { + return Segment{ + Num: n, + Text: strings.TrimSpace(ctx.Whisper_full_get_segment_text(n)), + Start: time.Duration(ctx.Whisper_full_get_segment_t0(n)) * time.Millisecond * 10, + End: time.Duration(ctx.Whisper_full_get_segment_t1(n)) * time.Millisecond * 10, + Tokens: toTokens(ctx, n), + } +} + +func toTokens(ctx *whisper.Context, n int) []Token { + result := make([]Token, ctx.Whisper_full_n_tokens(n)) + for i := 0; i < len(result); i++ { + data := ctx.Whisper_full_get_token_data(n, i) + + result[i] = Token{ + Id: int(ctx.Whisper_full_get_token_id(n, i)), + Text: ctx.Whisper_full_get_token_text(n, i), + P: ctx.Whisper_full_get_token_p(n, i), + Start: time.Duration(data.T0()) * time.Millisecond * 10, + End: time.Duration(data.T1()) * time.Millisecond * 10, + } + } + return result +} diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context_test.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context_test.go new file mode 100644 index 0000000..c8c6016 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/context_test.go @@ -0,0 +1,55 @@ +package whisper_test + +import ( + "os" + "testing" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper" + assert "github.com/stretchr/testify/assert" +) + +const ( + ModelPath = "../../models/ggml-tiny.bin" + SamplePath = "../../samples/jfk.wav" +) + +func Test_Whisper_000(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Load model + model, err := whisper.New(ModelPath) + assert.NoError(err) + assert.NotNil(model) + assert.NoError(model.Close()) + + t.Log("languages=", model.Languages()) +} + +func Test_Whisper_001(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Load model + model, err := whisper.New(ModelPath) + assert.NoError(err) + assert.NotNil(model) + defer model.Close() + + // Get context for decoding + ctx, err := model.NewContext() + assert.NoError(err) + assert.NotNil(ctx) + +} diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/doc.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/doc.go new file mode 100644 index 0000000..fd4f1b9 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/doc.go @@ -0,0 +1,4 @@ +/* +This is the higher-level speech-to-text whisper.cpp API for go +*/ +package whisper diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/interface.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/interface.go new file mode 100644 index 0000000..4744271 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/interface.go @@ -0,0 +1,99 @@ +package whisper + +import ( + "io" + "time" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +// SegmentCallback is the callback function for processing segments in real +// time. It is called during the Process function +type SegmentCallback func(Segment) + +// ProgressCallback is the callback function for reporting progress during +// processing. It is called during the Process function +type ProgressCallback func(int) + +// Model is the interface to a whisper model. Create a new model with the +// function whisper.New(string) +type Model interface { + io.Closer + + // Return a new speech-to-text context. + NewContext() (Context, error) + + // Return true if the model is multilingual. + IsMultilingual() bool + + // Return all languages supported. + Languages() []string +} + +// Context is the speach recognition context. +type Context interface { + SetLanguage(string) error // Set the language to use for speech recognition, use "auto" for auto detect language. + SetTranslate(bool) // Set translate flag + IsMultilingual() bool // Return true if the model is multilingual. + Language() string // Get language + + SetOffset(time.Duration) // Set offset + SetDuration(time.Duration) // Set duration + SetThreads(uint) // Set number of threads to use + SetSpeedup(bool) // Set speedup flag + SetSplitOnWord(bool) // Set split on word flag + SetTokenThreshold(float32) // Set timestamp token probability threshold + SetTokenSumThreshold(float32) // Set timestamp token sum probability threshold + SetMaxSegmentLength(uint) // Set max segment length in characters + SetTokenTimestamps(bool) // Set token timestamps flag + SetMaxTokensPerSegment(uint) // Set max tokens per segment (0 = no limit) + SetAudioCtx(uint) // Set audio encoder context + + // Process mono audio data and return any errors. + // If defined, newly generated segments are passed to the + // callback function during processing. + Process([]float32, SegmentCallback, ProgressCallback) error + + // After process is called, return segments until the end of the stream + // is reached, when io.EOF is returned. + NextSegment() (Segment, error) + + IsBEG(Token) bool // Test for "begin" token + IsSOT(Token) bool // Test for "start of transcription" token + IsEOT(Token) bool // Test for "end of transcription" token + IsPREV(Token) bool // Test for "start of prev" token + IsSOLM(Token) bool // Test for "start of lm" token + IsNOT(Token) bool // Test for "No timestamps" token + IsLANG(Token, string) bool // Test for token associated with a specific language + IsText(Token) bool // Test for text token + + // Timings + PrintTimings() + ResetTimings() + + SystemInfo() string +} + +// Segment is the text result of a speech recognition. +type Segment struct { + // Segment Number + Num int + + // Time beginning and end timestamps for the segment. + Start, End time.Duration + + // The text of the segment. + Text string + + // The tokens of the segment. + Tokens []Token +} + +// Token is a text or special token +type Token struct { + Id int + Text string + P float32 + Start, End time.Duration +} diff --git a/whisper.cpp-1.5.2/bindings/go/pkg/whisper/model.go b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/model.go new file mode 100644 index 0000000..68a1502 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/pkg/whisper/model.go @@ -0,0 +1,101 @@ +package whisper + +import ( + "fmt" + "os" + "runtime" + + // Bindings + whisper "github.com/ggerganov/whisper.cpp/bindings/go" +) + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type model struct { + path string + ctx *whisper.Context +} + +// Make sure model adheres to the interface +var _ Model = (*model)(nil) + +/////////////////////////////////////////////////////////////////////////////// +// LIFECYCLE + +func New(path string) (Model, error) { + model := new(model) + if _, err := os.Stat(path); err != nil { + return nil, err + } else if ctx := whisper.Whisper_init(path); ctx == nil { + return nil, ErrUnableToLoadModel + } else { + model.ctx = ctx + model.path = path + } + + // Return success + return model, nil +} + +func (model *model) Close() error { + if model.ctx != nil { + model.ctx.Whisper_free() + } + + // Release resources + model.ctx = nil + + // Return success + return nil +} + +/////////////////////////////////////////////////////////////////////////////// +// STRINGIFY + +func (model *model) String() string { + str := "" +} + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Return true if model is multilingual (language and translation options are supported) +func (model *model) IsMultilingual() bool { + return model.ctx.Whisper_is_multilingual() != 0 +} + +// Return all recognized languages. Initially it is set to auto-detect +func (model *model) Languages() []string { + result := make([]string, 0, whisper.Whisper_lang_max_id()) + for i := 0; i < whisper.Whisper_lang_max_id(); i++ { + str := whisper.Whisper_lang_str(i) + if model.ctx.Whisper_lang_id(str) >= 0 { + result = append(result, str) + } + } + return result +} + +func (model *model) NewContext() (Context, error) { + if model.ctx == nil { + return nil, ErrInternalAppError + } + + // Create new context + params := model.ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY) + params.SetTranslate(false) + params.SetPrintSpecial(false) + params.SetPrintProgress(false) + params.SetPrintRealtime(false) + params.SetPrintTimestamps(false) + params.SetThreads(runtime.NumCPU()) + params.SetNoContext(true) + + // Return new context + return newContext(model, params) +} diff --git a/whisper.cpp-1.5.2/bindings/go/samples/jfk.wav b/whisper.cpp-1.5.2/bindings/go/samples/jfk.wav new file mode 100644 index 0000000..3184d37 Binary files /dev/null and b/whisper.cpp-1.5.2/bindings/go/samples/jfk.wav differ diff --git a/whisper.cpp-1.5.2/bindings/go/whisper.go b/whisper.cpp-1.5.2/bindings/go/whisper.go new file mode 100644 index 0000000..9660662 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/whisper.go @@ -0,0 +1,468 @@ +package whisper + +import ( + "errors" + "unsafe" +) + +/////////////////////////////////////////////////////////////////////////////// +// CGO + +/* +#cgo LDFLAGS: -lwhisper -lm -lstdc++ +#cgo darwin LDFLAGS: -framework Accelerate +#include +#include + +extern void callNewSegment(void* user_data, int new); +extern void callProgress(void* user_data, int progress); +extern bool callEncoderBegin(void* user_data); + +// Text segment callback +// Called on every newly generated text segment +// Use the whisper_full_...() functions to obtain the text segments +static void whisper_new_segment_cb(struct whisper_context* ctx, struct whisper_state* state, int n_new, void* user_data) { + if(user_data != NULL && ctx != NULL) { + callNewSegment(user_data, n_new); + } +} + +// Progress callback +// Called on every newly generated text segment +// Use the whisper_full_...() functions to obtain the text segments +static void whisper_progress_cb(struct whisper_context* ctx, struct whisper_state* state, int progress, void* user_data) { + if(user_data != NULL && ctx != NULL) { + callProgress(user_data, progress); + } +} + +// Encoder begin callback +// If not NULL, called before the encoder starts +// If it returns false, the computation is aborted +static bool whisper_encoder_begin_cb(struct whisper_context* ctx, struct whisper_state* state, void* user_data) { + if(user_data != NULL && ctx != NULL) { + return callEncoderBegin(user_data); + } + return false; +} + +// Get default parameters and set callbacks +static struct whisper_full_params whisper_full_default_params_cb(struct whisper_context* ctx, enum whisper_sampling_strategy strategy) { + struct whisper_full_params params = whisper_full_default_params(strategy); + params.new_segment_callback = whisper_new_segment_cb; + params.new_segment_callback_user_data = (void*)(ctx); + params.encoder_begin_callback = whisper_encoder_begin_cb; + params.encoder_begin_callback_user_data = (void*)(ctx); + params.progress_callback = whisper_progress_cb; + params.progress_callback_user_data = (void*)(ctx); + return params; +} +*/ +import "C" + +/////////////////////////////////////////////////////////////////////////////// +// TYPES + +type ( + Context C.struct_whisper_context + Token C.whisper_token + TokenData C.struct_whisper_token_data + SamplingStrategy C.enum_whisper_sampling_strategy + Params C.struct_whisper_full_params +) + +/////////////////////////////////////////////////////////////////////////////// +// GLOBALS + +const ( + SAMPLING_GREEDY SamplingStrategy = C.WHISPER_SAMPLING_GREEDY + SAMPLING_BEAM_SEARCH SamplingStrategy = C.WHISPER_SAMPLING_BEAM_SEARCH +) + +const ( + SampleRate = C.WHISPER_SAMPLE_RATE // Expected sample rate, samples per second + SampleBits = uint16(unsafe.Sizeof(C.float(0))) * 8 // Sample size in bits + NumFFT = C.WHISPER_N_FFT + HopLength = C.WHISPER_HOP_LENGTH + ChunkSize = C.WHISPER_CHUNK_SIZE +) + +var ( + ErrTokenizerFailed = errors.New("whisper_tokenize failed") + ErrAutoDetectFailed = errors.New("whisper_lang_auto_detect failed") + ErrConversionFailed = errors.New("whisper_convert failed") + ErrInvalidLanguage = errors.New("invalid language") +) + +/////////////////////////////////////////////////////////////////////////////// +// PUBLIC METHODS + +// Allocates all memory needed for the model and loads the model from the given file. +// Returns NULL on failure. +func Whisper_init(path string) *Context { + cPath := C.CString(path) + defer C.free(unsafe.Pointer(cPath)) + if ctx := C.whisper_init_from_file_with_params(cPath, C.whisper_context_default_params()); ctx != nil { + return (*Context)(ctx) + } else { + return nil + } +} + +// Frees all memory allocated by the model. +func (ctx *Context) Whisper_free() { + C.whisper_free((*C.struct_whisper_context)(ctx)) +} + +// Convert RAW PCM audio to log mel spectrogram. +// The resulting spectrogram is stored inside the provided whisper context. +func (ctx *Context) Whisper_pcm_to_mel(data []float32, threads int) error { + if C.whisper_pcm_to_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// This can be used to set a custom log mel spectrogram inside the provided whisper context. +// Use this instead of whisper_pcm_to_mel() if you want to provide your own log mel spectrogram. +// n_mel must be 80 +func (ctx *Context) Whisper_set_mel(data []float32, n_mel int) error { + if C.whisper_set_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(n_mel)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Run the Whisper encoder on the log mel spectrogram stored inside the provided whisper context. +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// offset can be used to specify the offset of the first frame in the spectrogram. +func (ctx *Context) Whisper_encode(offset, threads int) error { + if C.whisper_encode((*C.struct_whisper_context)(ctx), C.int(offset), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Run the Whisper decoder to obtain the logits and probabilities for the next token. +// Make sure to call whisper_encode() first. +// tokens + n_tokens is the provided context for the decoder. +// n_past is the number of tokens to use from previous decoder calls. +func (ctx *Context) Whisper_decode(tokens []Token, past, threads int) error { + if C.whisper_decode((*C.struct_whisper_context)(ctx), (*C.whisper_token)(&tokens[0]), C.int(len(tokens)), C.int(past), C.int(threads)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Convert the provided text into tokens. The tokens pointer must be large enough to hold the resulting tokens. +// Returns the number of tokens on success +func (ctx *Context) Whisper_tokenize(text string, tokens []Token) (int, error) { + cText := C.CString(text) + defer C.free(unsafe.Pointer(cText)) + if n := C.whisper_tokenize((*C.struct_whisper_context)(ctx), cText, (*C.whisper_token)(&tokens[0]), C.int(len(tokens))); n >= 0 { + return int(n), nil + } else { + return 0, ErrTokenizerFailed + } +} + +// Return the id of the specified language, returns -1 if not found +// Examples: +// +// "de" -> 2 +// "german" -> 2 +func (ctx *Context) Whisper_lang_id(lang string) int { + return int(C.whisper_lang_id(C.CString(lang))) +} + +// Largest language id (i.e. number of available languages - 1) +func Whisper_lang_max_id() int { + return int(C.whisper_lang_max_id()) +} + +// Return the short string of the specified language id (e.g. 2 -> "de"), +// returns empty string if not found +func Whisper_lang_str(id int) string { + return C.GoString(C.whisper_lang_str(C.int(id))) +} + +// Use mel data at offset_ms to try and auto-detect the spoken language +// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. +// Returns the probabilities of all languages. +// ref: https://github.com/openai/whisper/blob/main/whisper/decoding.py#L18-L69 +func (ctx *Context) Whisper_lang_auto_detect(offset_ms, n_threads int) ([]float32, error) { + probs := make([]float32, Whisper_lang_max_id()+1) + if n := int(C.whisper_lang_auto_detect((*C.struct_whisper_context)(ctx), C.int(offset_ms), C.int(n_threads), (*C.float)(&probs[0]))); n < 0 { + return nil, ErrAutoDetectFailed + } else { + return probs, nil + } +} + +func (ctx *Context) Whisper_n_len() int { + return int(C.whisper_n_len((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_vocab() int { + return int(C.whisper_n_vocab((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_text_ctx() int { + return int(C.whisper_n_text_ctx((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_n_audio_ctx() int { + return int(C.whisper_n_audio_ctx((*C.struct_whisper_context)(ctx))) +} + +func (ctx *Context) Whisper_is_multilingual() int { + return int(C.whisper_is_multilingual((*C.struct_whisper_context)(ctx))) +} + +// The probabilities for the next token +//func (ctx *Whisper_context) Whisper_get_probs() []float32 { +// return (*[1 << 30]float32)(unsafe.Pointer(C.whisper_get_probs((*C.struct_whisper_context)(ctx))))[:ctx.Whisper_n_vocab()] +//} + +// Token Id -> String. Uses the vocabulary in the provided context +func (ctx *Context) Whisper_token_to_str(token Token) string { + return C.GoString(C.whisper_token_to_str((*C.struct_whisper_context)(ctx), C.whisper_token(token))) +} + +// Special tokens +func (ctx *Context) Whisper_token_eot() Token { + return Token(C.whisper_token_eot((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_sot() Token { + return Token(C.whisper_token_sot((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_prev() Token { + return Token(C.whisper_token_prev((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_solm() Token { + return Token(C.whisper_token_solm((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_not() Token { + return Token(C.whisper_token_not((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_beg() Token { + return Token(C.whisper_token_beg((*C.struct_whisper_context)(ctx))) +} + +// Special tokens +func (ctx *Context) Whisper_token_lang(lang_id int) Token { + return Token(C.whisper_token_lang((*C.struct_whisper_context)(ctx), C.int(lang_id))) +} + +// Task tokens +func (ctx *Context) Whisper_token_translate() Token { + return Token(C.whisper_token_translate((*C.struct_whisper_context)(ctx))) +} + +// Task tokens +func (ctx *Context) Whisper_token_transcribe() Token { + return Token(C.whisper_token_transcribe((*C.struct_whisper_context)(ctx))) +} + +// Performance information +func (ctx *Context) Whisper_print_timings() { + C.whisper_print_timings((*C.struct_whisper_context)(ctx)) +} + +// Performance information +func (ctx *Context) Whisper_reset_timings() { + C.whisper_reset_timings((*C.struct_whisper_context)(ctx)) +} + +// Print system information +func Whisper_print_system_info() string { + return C.GoString(C.whisper_print_system_info()) +} + +// Return default parameters for a strategy +func (ctx *Context) Whisper_full_default_params(strategy SamplingStrategy) Params { + // Get default parameters + return Params(C.whisper_full_default_params_cb((*C.struct_whisper_context)(ctx), C.enum_whisper_sampling_strategy(strategy))) +} + +// Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text +// Uses the specified decoding strategy to obtain the text. +func (ctx *Context) Whisper_full( + params Params, + samples []float32, + encoderBeginCallback func() bool, + newSegmentCallback func(int), + progressCallback func(int), +) error { + registerEncoderBeginCallback(ctx, encoderBeginCallback) + registerNewSegmentCallback(ctx, newSegmentCallback) + registerProgressCallback(ctx, progressCallback) + defer registerEncoderBeginCallback(ctx, nil) + defer registerNewSegmentCallback(ctx, nil) + defer registerProgressCallback(ctx, nil) + if C.whisper_full((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples))) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Split the input audio in chunks and process each chunk separately using whisper_full() +// It seems this approach can offer some speedup in some cases. +// However, the transcription accuracy can be worse at the beginning and end of each chunk. +func (ctx *Context) Whisper_full_parallel(params Params, samples []float32, processors int, encoderBeginCallback func() bool, newSegmentCallback func(int)) error { + registerEncoderBeginCallback(ctx, encoderBeginCallback) + registerNewSegmentCallback(ctx, newSegmentCallback) + defer registerEncoderBeginCallback(ctx, nil) + defer registerNewSegmentCallback(ctx, nil) + + if C.whisper_full_parallel((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples)), C.int(processors)) == 0 { + return nil + } else { + return ErrConversionFailed + } +} + +// Return the id of the autodetected language, returns -1 if not found +// Added to whisper.cpp in +// https://github.com/ggerganov/whisper.cpp/commit/a1c1583cc7cd8b75222857afc936f0638c5683d6 +// +// Examples: +// +// "de" -> 2 +// "german" -> 2 +func (ctx *Context) Whisper_full_lang_id() int { + return int(C.whisper_full_lang_id((*C.struct_whisper_context)(ctx))) +} + +// Number of generated text segments. +// A segment can be a few words, a sentence, or even a paragraph. +func (ctx *Context) Whisper_full_n_segments() int { + return int(C.whisper_full_n_segments((*C.struct_whisper_context)(ctx))) +} + +// Get the start and end time of the specified segment. +func (ctx *Context) Whisper_full_get_segment_t0(segment int) int64 { + return int64(C.whisper_full_get_segment_t0((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the start and end time of the specified segment. +func (ctx *Context) Whisper_full_get_segment_t1(segment int) int64 { + return int64(C.whisper_full_get_segment_t1((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the text of the specified segment. +func (ctx *Context) Whisper_full_get_segment_text(segment int) string { + return C.GoString(C.whisper_full_get_segment_text((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get number of tokens in the specified segment. +func (ctx *Context) Whisper_full_n_tokens(segment int) int { + return int(C.whisper_full_n_tokens((*C.struct_whisper_context)(ctx), C.int(segment))) +} + +// Get the token text of the specified token index in the specified segment. +func (ctx *Context) Whisper_full_get_token_text(segment int, token int) string { + return C.GoString(C.whisper_full_get_token_text((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get the token of the specified token index in the specified segment. +func (ctx *Context) Whisper_full_get_token_id(segment int, token int) Token { + return Token(C.whisper_full_get_token_id((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get token data for the specified token in the specified segment. +// This contains probabilities, timestamps, etc. +func (ctx *Context) Whisper_full_get_token_data(segment int, token int) TokenData { + return TokenData(C.whisper_full_get_token_data((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +// Get the probability of the specified token in the specified segment. +func (ctx *Context) Whisper_full_get_token_p(segment int, token int) float32 { + return float32(C.whisper_full_get_token_p((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token))) +} + +/////////////////////////////////////////////////////////////////////////////// +// CALLBACKS + +var ( + cbNewSegment = make(map[unsafe.Pointer]func(int)) + cbProgress = make(map[unsafe.Pointer]func(int)) + cbEncoderBegin = make(map[unsafe.Pointer]func() bool) +) + +func registerNewSegmentCallback(ctx *Context, fn func(int)) { + if fn == nil { + delete(cbNewSegment, unsafe.Pointer(ctx)) + } else { + cbNewSegment[unsafe.Pointer(ctx)] = fn + } +} + +func registerProgressCallback(ctx *Context, fn func(int)) { + if fn == nil { + delete(cbProgress, unsafe.Pointer(ctx)) + } else { + cbProgress[unsafe.Pointer(ctx)] = fn + } +} + +func registerEncoderBeginCallback(ctx *Context, fn func() bool) { + if fn == nil { + delete(cbEncoderBegin, unsafe.Pointer(ctx)) + } else { + cbEncoderBegin[unsafe.Pointer(ctx)] = fn + } +} + +//export callNewSegment +func callNewSegment(user_data unsafe.Pointer, new C.int) { + if fn, ok := cbNewSegment[user_data]; ok { + fn(int(new)) + } +} + +//export callProgress +func callProgress(user_data unsafe.Pointer, progress C.int) { + if fn, ok := cbProgress[user_data]; ok { + fn(int(progress)) + } +} + +//export callEncoderBegin +func callEncoderBegin(user_data unsafe.Pointer) C.bool { + if fn, ok := cbEncoderBegin[user_data]; ok { + if fn() { + return C.bool(true) + } else { + return C.bool(false) + } + } + return true +} + +func (t TokenData) T0() int64 { + return int64(t.t0) +} + +func (t TokenData) T1() int64 { + return int64(t.t1) +} + +func (t TokenData) Id() Token { + return Token(t.id) +} diff --git a/whisper.cpp-1.5.2/bindings/go/whisper_test.go b/whisper.cpp-1.5.2/bindings/go/whisper_test.go new file mode 100644 index 0000000..40648ff --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/go/whisper_test.go @@ -0,0 +1,113 @@ +package whisper_test + +import ( + "os" + "runtime" + "testing" + "time" + + // Packages + whisper "github.com/ggerganov/whisper.cpp/bindings/go" + wav "github.com/go-audio/wav" + assert "github.com/stretchr/testify/assert" +) + +const ( + ModelPath = "models/ggml-small.en.bin" + SamplePath = "samples/jfk.wav" +) + +func Test_Whisper_000(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + ctx.Whisper_free() +} + +func Test_Whisper_001(t *testing.T) { + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Open samples + fh, err := os.Open(SamplePath) + assert.NoError(err) + defer fh.Close() + + // Read samples + d := wav.NewDecoder(fh) + buf, err := d.FullPCMBuffer() + assert.NoError(err) + + // Run whisper + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + defer ctx.Whisper_free() + params := ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY) + data := buf.AsFloat32Buffer().Data + err = ctx.Whisper_full(params, data, nil, nil, nil) + assert.NoError(err) + + // Print out tokens + num_segments := ctx.Whisper_full_n_segments() + assert.GreaterOrEqual(num_segments, 1) + for i := 0; i < num_segments; i++ { + str := ctx.Whisper_full_get_segment_text(i) + assert.NotEmpty(str) + t0 := time.Duration(ctx.Whisper_full_get_segment_t0(i)) * time.Millisecond + t1 := time.Duration(ctx.Whisper_full_get_segment_t1(i)) * time.Millisecond + t.Logf("[%6s->%-6s] %q", t0, t1, str) + } +} + +func Test_Whisper_002(t *testing.T) { + assert := assert.New(t) + for i := 0; i < whisper.Whisper_lang_max_id(); i++ { + str := whisper.Whisper_lang_str(i) + assert.NotEmpty(str) + t.Log(str) + } +} + +func Test_Whisper_003(t *testing.T) { + threads := runtime.NumCPU() + assert := assert.New(t) + if _, err := os.Stat(ModelPath); os.IsNotExist(err) { + t.Skip("Skipping test, model not found:", ModelPath) + } + if _, err := os.Stat(SamplePath); os.IsNotExist(err) { + t.Skip("Skipping test, sample not found:", SamplePath) + } + + // Open samples + fh, err := os.Open(SamplePath) + assert.NoError(err) + defer fh.Close() + + // Read samples + d := wav.NewDecoder(fh) + buf, err := d.FullPCMBuffer() + assert.NoError(err) + + // Make the model + ctx := whisper.Whisper_init(ModelPath) + assert.NotNil(ctx) + defer ctx.Whisper_free() + + // Get MEL + assert.NoError(ctx.Whisper_pcm_to_mel(buf.AsFloat32Buffer().Data, threads)) + + // Get Languages + languages, err := ctx.Whisper_lang_auto_detect(0, threads) + assert.NoError(err) + for i, p := range languages { + t.Logf("%s: %f", whisper.Whisper_lang_str(i), p) + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/README.md b/whisper.cpp-1.5.2/bindings/java/README.md new file mode 100644 index 0000000..5255612 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/README.md @@ -0,0 +1,71 @@ +# Java JNI bindings for Whisper + +This package provides Java JNI bindings for whisper.cpp. They have been tested on: + + * Darwin (OS X) 12.6 on x64_64 + * Ubuntu on x86_64 + * Windows on x86_64 + +The "low level" bindings are in `WhisperCppJnaLibrary`. The most simple usage is as follows: + +JNA will attempt to load the `whispercpp` shared library from: + +- jna.library.path +- jna.platform.library +- ~/Library/Frameworks +- /Library/Frameworks +- /System/Library/Frameworks +- classpath + +```java +import io.github.ggerganov.whispercpp.WhisperCpp; + +public class Example { + + public static void main(String[] args) { + WhisperCpp whisper = new WhisperCpp(); + // By default, models are loaded from ~/.cache/whisper/ and are usually named "ggml-${name}.bin" + // or you can provide the absolute path to the model file. + long context = whisper.initContext("base.en"); + try { + var whisperParams = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + // custom configuration if required + whisperParams.temperature_inc = 0f; + + var samples = readAudio(); // divide each value by 32767.0f + whisper.fullTranscribe(whisperParams, samples); + + int segmentCount = whisper.getTextSegmentCount(context); + for (int i = 0; i < segmentCount; i++) { + String text = whisper.getTextSegment(context, i); + System.out.println(segment.getText()); + } + } finally { + whisper.freeContext(context); + } + } +} +``` + +## Building & Testing + +In order to build, you need to have the JDK 8 or higher installed. Run the tests with: + +```bash +git clone https://github.com/ggerganov/whisper.cpp.git +cd whisper.cpp/bindings/java + +./gradlew build +``` + +You need to have the `whisper` library in your [JNA library path](https://java-native-access.github.io/jna/4.2.1/com/sun/jna/NativeLibrary.html). On Windows the dll is included in the jar and you can update it: + +```bash +copy /y ..\..\build\bin\Release\whisper.dll build\generated\resources\main\win32-x86-64\whisper.dll +``` + + +## License + +The license for the Go bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details. + diff --git a/whisper.cpp-1.5.2/bindings/java/build.gradle b/whisper.cpp-1.5.2/bindings/java/build.gradle new file mode 100644 index 0000000..75f3a9c --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/build.gradle @@ -0,0 +1,133 @@ +plugins { + id 'java' + id 'java-library' + id 'maven-publish' + id 'signing' +} + +archivesBaseName = 'whispercpp' +group = 'io.github.ggerganov' +version = '1.4.0' + + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +sourceSets { + main { + resources { + srcDirs = ['src/main/resources', 'build/generated/resources/main'] + } + } + test { + runtimeClasspath += files('build/generated/resources/main') + } +} + +tasks.register('copyLibwhisperDynlib', Copy) { + from '../../build' + include 'libwhisper.dynlib' + into 'build/generated/resources/main/darwin' +} + +tasks.register('copyLibwhisperSo', Copy) { + from '../../build' + include 'libwhisper.so' + into 'build/generated/resources/main/linux-x86-64' +} + +tasks.register('copyWhisperDll', Copy) { + from '../../build/Release' + include 'whisper.dll' + into 'build/generated/resources/main/windows-x86-64' +} + +tasks.register('copyLibs') { + dependsOn copyLibwhisperDynlib, copyLibwhisperSo, copyWhisperDll +} + +test { + systemProperty 'jna.library.path', project.file('build/generated/resources/main').absolutePath +} + +java { + withSourcesJar() + withJavadocJar() +} + +jar { + exclude '**/whisper_java.exp', '**/whisper_java.lib' +} + +javadoc { + options.addStringOption('Xdoclint:none', '-quiet') +} + +tasks.withType(Test) { + useJUnitPlatform() +} + +dependencies { + implementation "net.java.dev.jna:jna:5.13.0" + testImplementation "org.junit.jupiter:junit-jupiter:5.9.2" + testImplementation "org.assertj:assertj-core:3.24.2" +} + +repositories { + mavenCentral() +} + +publishing { + publications { + mavenJava(MavenPublication) { + artifactId = 'whispercpp' + from components.java + pom { + name = 'whispercpp' + description = "Java JNA bindings for OpenAI's Whisper model, implemented in C/C++" + url = 'https://github.com/ggerganov/whisper.cpp' + licenses { + license { + name = 'MIT licence' + url = 'https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/LICENSE' + } + } + developers { + developer { + id = 'ggerganov' + name = 'Georgi Gerganov' + email = 'ggerganov@gmail.com' + } + developer { + id = 'nalbion' + name = 'Nicholas Albion' + email = 'nalbion@yahoo.com' + } + } + scm { + connection = 'scm:git:git://github.com/ggerganov/whisper.cpp.git' + url = 'https://github.com/ggerganov/whisper.cpp' + } + } + } + } + + repositories { + maven { + def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/' + def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/' + url = version.endsWith('-SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + credentials { + username = System.getenv("MAVEN_USERNAME") + password = System.getenv("MAVEN_PASSWORD") + } + } + } +} + +signing { + def signingKey = System.getenv("PGP_SECRET") + def signingPassword = System.getenv("PGP_PASSPHRASE") + useInMemoryPgpKeys(signingKey, signingPassword) + sign publishing.publications.mavenJava +} diff --git a/whisper.cpp-1.5.2/bindings/java/gradle.properties b/whisper.cpp-1.5.2/bindings/java/gradle.properties new file mode 100644 index 0000000..3ea68c2 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/gradle.properties @@ -0,0 +1,6 @@ +org.gradle.jvmargs=-Xms256m -Xmx1024m +system.include.dir=/usr/include +#system.local.include.dir=../../include +system.local.include.dir=./build/generated/sources/headers/java/main +jni.include.dir=/usr/lib/jvm/java-8-openjdk-amd64/include/ +jni.lib.dir=/usr/lib/jvm/java-8-openjdk-amd64/lib/ diff --git a/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.jar b/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..ccebba7 Binary files /dev/null and b/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.jar differ diff --git a/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.properties b/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c85a1f --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/whisper.cpp-1.5.2/bindings/java/gradlew b/whisper.cpp-1.5.2/bindings/java/gradlew new file mode 100644 index 0000000..79a61d4 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original 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 +# +# 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. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/whisper.cpp-1.5.2/bindings/java/gradlew.bat b/whisper.cpp-1.5.2/bindings/java/gradlew.bat new file mode 100644 index 0000000..6689b85 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/whisper.cpp-1.5.2/bindings/java/settings.gradle b/whisper.cpp-1.5.2/bindings/java/settings.gradle new file mode 100644 index 0000000..dbc6f38 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "whispercpp" diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java new file mode 100644 index 0000000..0498eb4 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperContext.java @@ -0,0 +1,41 @@ +package io.github.ggerganov.whispercpp; + +import com.sun.jna.Structure; +import com.sun.jna.ptr.PointerByReference; +import io.github.ggerganov.whispercpp.ggml.GgmlType; +import io.github.ggerganov.whispercpp.WhisperModel; +import io.github.ggerganov.whispercpp.params.WhisperContextParams; + +import java.util.List; + +public class WhisperContext extends Structure { + int t_load_us = 0; + int t_start_us = 0; + + /** weight type (FP32 / FP16 / QX) */ + GgmlType wtype = GgmlType.GGML_TYPE_F16; + /** intermediate type (FP32 or FP16) */ + GgmlType itype = GgmlType.GGML_TYPE_F16; + +// WhisperModel model; + public PointerByReference model; +// whisper_vocab vocab; +// whisper_state * state = nullptr; + public PointerByReference vocab; + public PointerByReference state; + + /** populated by whisper_init_from_file_with_params() */ + String path_model; + WhisperContextParams params; + +// public static class ByReference extends WhisperContext implements Structure.ByReference { +// } +// +// public static class ByValue extends WhisperContext implements Structure.ByValue { +// } +// +// @Override +// protected List getFieldOrder() { +// return List.of("t_load_us", "t_start_us", "wtype", "itype", "model", "vocab", "state", "path_model"); +// } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java new file mode 100644 index 0000000..4c1594d --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCpp.java @@ -0,0 +1,207 @@ +package io.github.ggerganov.whispercpp; + +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.bean.WhisperSegment; +import io.github.ggerganov.whispercpp.params.WhisperContextParams; +import io.github.ggerganov.whispercpp.params.WhisperFullParams; +import io.github.ggerganov.whispercpp.params.WhisperSamplingStrategy; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Before calling most methods, you must call `initContext(modelPath)` to initialise the `ctx` Pointer. + */ +public class WhisperCpp implements AutoCloseable { + private WhisperCppJnaLibrary lib = WhisperCppJnaLibrary.instance; + private Pointer ctx = null; + private Pointer paramsPointer = null; + private Pointer greedyParamsPointer = null; + private Pointer beamParamsPointer = null; + + public File modelDir() { + String modelDirPath = System.getenv("XDG_CACHE_HOME"); + if (modelDirPath == null) { + modelDirPath = System.getProperty("user.home") + "/.cache"; + } + + return new File(modelDirPath, "whisper"); + } + + /** + * @param modelPath - absolute path, or just the name (eg: "base", "base-en" or "base.en") + */ + public void initContext(String modelPath) throws FileNotFoundException { + initContextImpl(modelPath, getContextDefaultParams()); + } + + /** + * @param modelPath - absolute path, or just the name (eg: "base", "base-en" or "base.en") + * @param params - params to use when initialising the context + */ + public void initContext(String modelPath, WhisperContextParams params) throws FileNotFoundException { + initContextImpl(modelPath, params); + } + + private void initContextImpl(String modelPath, WhisperContextParams params) throws FileNotFoundException { + if (ctx != null) { + lib.whisper_free(ctx); + } + + if (!modelPath.contains("/") && !modelPath.contains("\\")) { + if (!modelPath.endsWith(".bin")) { + modelPath = "ggml-" + modelPath.replace("-", ".") + ".bin"; + } + + modelPath = new File(modelDir(), modelPath).getAbsolutePath(); + } + + ctx = lib.whisper_init_from_file_with_params(modelPath, params); + + if (ctx == null) { + throw new FileNotFoundException(modelPath); + } + } + + /** + * Provides default params which can be used with `whisper_init_from_file_with_params()` etc. + * Because this function allocates memory for the params, the caller must call either: + * - call `whisper_free_context_params()` + * - `Native.free(Pointer.nativeValue(pointer));` + */ + public WhisperContextParams getContextDefaultParams() { + paramsPointer = lib.whisper_context_default_params_by_ref(); + WhisperContextParams params = new WhisperContextParams(paramsPointer); + params.read(); + return params; + } + + /** + * Provides default params which can be used with `whisper_full()` etc. + * Because this function allocates memory for the params, the caller must call either: + * - call `whisper_free_params()` + * - `Native.free(Pointer.nativeValue(pointer));` + * + * @param strategy - GREEDY + */ + public WhisperFullParams getFullDefaultParams(WhisperSamplingStrategy strategy) { + Pointer pointer; + + // whisper_full_default_params_by_ref allocates memory which we need to delete, so only create max 1 pointer for each strategy. + if (strategy == WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY) { + if (greedyParamsPointer == null) { + greedyParamsPointer = lib.whisper_full_default_params_by_ref(strategy.ordinal()); + } + pointer = greedyParamsPointer; + } else { + if (beamParamsPointer == null) { + beamParamsPointer = lib.whisper_full_default_params_by_ref(strategy.ordinal()); + } + pointer = beamParamsPointer; + } + + WhisperFullParams params = new WhisperFullParams(pointer); + params.read(); + return params; + } + + @Override + public void close() { + freeContext(); + freeParams(); + System.out.println("Whisper closed"); + } + + private void freeContext() { + if (ctx != null) { + lib.whisper_free(ctx); + } + } + + private void freeParams() { + if (paramsPointer != null) { + Native.free(Pointer.nativeValue(paramsPointer)); + paramsPointer = null; + } + if (greedyParamsPointer != null) { + Native.free(Pointer.nativeValue(greedyParamsPointer)); + greedyParamsPointer = null; + } + if (beamParamsPointer != null) { + Native.free(Pointer.nativeValue(beamParamsPointer)); + beamParamsPointer = null; + } + } + + /** + * Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text. + * Not thread safe for same context + * Uses the specified decoding strategy to obtain the text. + */ + public String fullTranscribe(WhisperFullParams whisperParams, float[] audioData) throws IOException { + if (ctx == null) { + throw new IllegalStateException("Model not initialised"); + } + + if (lib.whisper_full(ctx, whisperParams, audioData, audioData.length) != 0) { + throw new IOException("Failed to process audio"); + } + + int nSegments = lib.whisper_full_n_segments(ctx); + + StringBuilder str = new StringBuilder(); + + for (int i = 0; i < nSegments; i++) { + String text = lib.whisper_full_get_segment_text(ctx, i); + System.out.println("Segment:" + text); + str.append(text); + } + + return str.toString().trim(); + } + public List fullTranscribeWithTime(WhisperFullParams whisperParams, float[] audioData) throws IOException { + if (ctx == null) { + throw new IllegalStateException("Model not initialised"); + } + + if (lib.whisper_full(ctx, whisperParams, audioData, audioData.length) != 0) { + throw new IOException("Failed to process audio"); + } + + int nSegments = lib.whisper_full_n_segments(ctx); + List segments= new ArrayList<>(nSegments); + + + for (int i = 0; i < nSegments; i++) { + long t0 = lib.whisper_full_get_segment_t0(ctx, i); + String text = lib.whisper_full_get_segment_text(ctx, i); + long t1 = lib.whisper_full_get_segment_t1(ctx, i); + segments.add(new WhisperSegment(t0,t1,text)); + } + + return segments; + } + +// public int getTextSegmentCount(Pointer ctx) { +// return lib.whisper_full_n_segments(ctx); +// } +// public String getTextSegment(Pointer ctx, int index) { +// return lib.whisper_full_get_segment_text(ctx, index); +// } + + public String getSystemInfo() { + return lib.whisper_print_system_info(); + } + + public int benchMemcpy(int nthread) { + return lib.whisper_bench_memcpy(nthread); + } + + public int benchGgmlMulMat(int nthread) { + return lib.whisper_bench_ggml_mul_mat(nthread); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java new file mode 100644 index 0000000..56a3738 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/WhisperCppJnaLibrary.java @@ -0,0 +1,396 @@ +package io.github.ggerganov.whispercpp; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.model.WhisperModelLoader; +import io.github.ggerganov.whispercpp.model.WhisperTokenData; +import io.github.ggerganov.whispercpp.params.WhisperContextParams; +import io.github.ggerganov.whispercpp.params.WhisperFullParams; + +public interface WhisperCppJnaLibrary extends Library { + WhisperCppJnaLibrary instance = Native.load("whisper", WhisperCppJnaLibrary.class); + + String whisper_print_system_info(); + + /** + * DEPRECATED. Allocate (almost) all memory needed for the model by loading from a file. + * + * @param path_model Path to the model file + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_from_file(String path_model); + + /** + * Provides default params which can be used with `whisper_init_from_file_with_params()` etc. + * Because this function allocates memory for the params, the caller must call either: + * - call `whisper_free_context_params()` + * - `Native.free(Pointer.nativeValue(pointer));` + */ + Pointer whisper_context_default_params_by_ref(); + + void whisper_free_context_params(Pointer params); + + /** + * Allocate (almost) all memory needed for the model by loading from a file. + * + * @param path_model Path to the model file + * @param params Pointer to whisper_context_params + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_from_file_with_params(String path_model, WhisperContextParams params); + + /** + * Allocate (almost) all memory needed for the model by loading from a buffer. + * + * @param buffer Model buffer + * @param buffer_size Size of the model buffer + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_from_buffer(Pointer buffer, int buffer_size); + + /** + * Allocate (almost) all memory needed for the model using a model loader. + * + * @param loader Model loader + * @return Whisper context on success, null on failure + */ + Pointer whisper_init(WhisperModelLoader loader); + + /** + * Allocate (almost) all memory needed for the model by loading from a file without allocating the state. + * + * @param path_model Path to the model file + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_from_file_no_state(String path_model); + + /** + * Allocate (almost) all memory needed for the model by loading from a buffer without allocating the state. + * + * @param buffer Model buffer + * @param buffer_size Size of the model buffer + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_from_buffer_no_state(Pointer buffer, int buffer_size); + +// Pointer whisper_init_from_buffer_no_state(Pointer buffer, long buffer_size); + + /** + * Allocate (almost) all memory needed for the model using a model loader without allocating the state. + * + * @param loader Model loader + * @return Whisper context on success, null on failure + */ + Pointer whisper_init_no_state(WhisperModelLoader loader); + + /** + * Allocate memory for the Whisper state. + * + * @param ctx Whisper context + * @return Whisper state on success, null on failure + */ + Pointer whisper_init_state(Pointer ctx); + + /** + * Free all allocated memory associated with the Whisper context. + * + * @param ctx Whisper context + */ + void whisper_free(Pointer ctx); + + /** + * Free all allocated memory associated with the Whisper state. + * + * @param state Whisper state + */ + void whisper_free_state(Pointer state); + + + /** + * Convert RAW PCM audio to log mel spectrogram. + * The resulting spectrogram is stored inside the default state of the provided whisper context. + * + * @param ctx - Pointer to a WhisperContext + * @return 0 on success + */ + int whisper_pcm_to_mel(Pointer ctx, final float[] samples, int n_samples, int n_threads); + + /** + * @param ctx Pointer to a WhisperContext + * @param state Pointer to WhisperState + * @param n_samples + * @param n_threads + * @return 0 on success + */ + int whisper_pcm_to_mel_with_state(Pointer ctx, Pointer state, final float[] samples, int n_samples, int n_threads); + + /** + * This can be used to set a custom log mel spectrogram inside the default state of the provided whisper context. + * Use this instead of whisper_pcm_to_mel() if you want to provide your own log mel spectrogram. + * n_mel must be 80 + * @return 0 on success + */ + int whisper_set_mel(Pointer ctx, final float[] data, int n_len, int n_mel); + int whisper_set_mel_with_state(Pointer ctx, Pointer state, final float[] data, int n_len, int n_mel); + + /** + * Run the Whisper encoder on the log mel spectrogram stored inside the default state in the provided whisper context. + * Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first. + * Offset can be used to specify the offset of the first frame in the spectrogram. + * @return 0 on success + */ + int whisper_encode(Pointer ctx, int offset, int n_threads); + + int whisper_encode_with_state(Pointer ctx, Pointer state, int offset, int n_threads); + + /** + * Run the Whisper decoder to obtain the logits and probabilities for the next token. + * Make sure to call whisper_encode() first. + * tokens + n_tokens is the provided context for the decoder. + * n_past is the number of tokens to use from previous decoder calls. + * Returns 0 on success + * TODO: add support for multiple decoders + */ + int whisper_decode(Pointer ctx, Pointer tokens, int n_tokens, int n_past, int n_threads); + + /** + * @param ctx + * @param state + * @param tokens Pointer to int tokens + * @param n_tokens + * @param n_past + * @param n_threads + * @return + */ + int whisper_decode_with_state(Pointer ctx, Pointer state, Pointer tokens, int n_tokens, int n_past, int n_threads); + + /** + * Convert the provided text into tokens. + * The tokens pointer must be large enough to hold the resulting tokens. + * Returns the number of tokens on success, no more than n_max_tokens + * Returns -1 on failure + * TODO: not sure if correct + */ + int whisper_tokenize(Pointer ctx, String text, Pointer tokens, int n_max_tokens); + + /** Largest language id (i.e. number of available languages - 1) */ + int whisper_lang_max_id(); + + /** + * @return the id of the specified language, returns -1 if not found. + * Examples: + * "de" -> 2 + * "german" -> 2 + */ + int whisper_lang_id(String lang); + + /** @return the short string of the specified language id (e.g. 2 -> "de"), returns nullptr if not found */ + String whisper_lang_str(int id); + + /** + * Use mel data at offset_ms to try and auto-detect the spoken language. + * Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first + * Returns the top language id or negative on failure + * If not null, fills the lang_probs array with the probabilities of all languages + * The array must be whisper_lang_max_id() + 1 in size + * + * ref: https://github.com/openai/whisper/blob/main/whisper/decoding.py#L18-L69 + */ + int whisper_lang_auto_detect(Pointer ctx, int offset_ms, int n_threads, float[] lang_probs); + + int whisper_lang_auto_detect_with_state(Pointer ctx, Pointer state, int offset_ms, int n_threads, float[] lang_probs); + + int whisper_n_len (Pointer ctx); // mel length + int whisper_n_len_from_state(Pointer state); // mel length + int whisper_n_vocab (Pointer ctx); + int whisper_n_text_ctx (Pointer ctx); + int whisper_n_audio_ctx (Pointer ctx); + int whisper_is_multilingual (Pointer ctx); + + int whisper_model_n_vocab (Pointer ctx); + int whisper_model_n_audio_ctx (Pointer ctx); + int whisper_model_n_audio_state(Pointer ctx); + int whisper_model_n_audio_head (Pointer ctx); + int whisper_model_n_audio_layer(Pointer ctx); + int whisper_model_n_text_ctx (Pointer ctx); + int whisper_model_n_text_state (Pointer ctx); + int whisper_model_n_text_head (Pointer ctx); + int whisper_model_n_text_layer (Pointer ctx); + int whisper_model_n_mels (Pointer ctx); + int whisper_model_ftype (Pointer ctx); + int whisper_model_type (Pointer ctx); + + /** + * Token logits obtained from the last call to whisper_decode(). + * The logits for the last token are stored in the last row + * Rows: n_tokens + * Cols: n_vocab + */ + float[] whisper_get_logits (Pointer ctx); + float[] whisper_get_logits_from_state(Pointer state); + + // Token Id -> String. Uses the vocabulary in the provided context + String whisper_token_to_str(Pointer ctx, int token); + String whisper_model_type_readable(Pointer ctx); + + // Special tokens + int whisper_token_eot (Pointer ctx); + int whisper_token_sot (Pointer ctx); + int whisper_token_prev(Pointer ctx); + int whisper_token_solm(Pointer ctx); + int whisper_token_not (Pointer ctx); + int whisper_token_beg (Pointer ctx); + int whisper_token_lang(Pointer ctx, int lang_id); + + // Task tokens + int whisper_token_translate (Pointer ctx); + int whisper_token_transcribe(Pointer ctx); + + // Performance information from the default state. + void whisper_print_timings(Pointer ctx); + void whisper_reset_timings(Pointer ctx); + + // Note: Even if `whisper_full_params is stripped back to just 4 ints, JNA throws "Invalid memory access" + // when `whisper_full_default_params()` tries to return a struct. + // WhisperFullParams whisper_full_default_params(int strategy); + + /** + * Provides default params which can be used with `whisper_full()` etc. + * Because this function allocates memory for the params, the caller must call either: + * - call `whisper_free_params()` + * - `Native.free(Pointer.nativeValue(pointer));` + * + * @param strategy - WhisperSamplingStrategy.value + */ + Pointer whisper_full_default_params_by_ref(int strategy); + + void whisper_free_params(Pointer params); + + /** + * Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text + * Not thread safe for same context + * Uses the specified decoding strategy to obtain the text. + */ + int whisper_full(Pointer ctx, WhisperFullParams params, final float[] samples, int n_samples); + + int whisper_full_with_state(Pointer ctx, Pointer state, WhisperFullParams params, final float[] samples, int n_samples); + + // Split the input audio in chunks and process each chunk separately using whisper_full_with_state() + // Result is stored in the default state of the context + // Not thread safe if executed in parallel on the same context. + // It seems this approach can offer some speedup in some cases. + // However, the transcription accuracy can be worse at the beginning and end of each chunk. + int whisper_full_parallel(Pointer ctx, WhisperFullParams params, final float[] samples, int n_samples, int n_processors); + + /** + * Number of generated text segments. + * A segment can be a few words, a sentence, or even a paragraph. + * @param ctx Pointer to WhisperContext + */ + int whisper_full_n_segments (Pointer ctx); + + /** + * @param state Pointer to WhisperState + */ + int whisper_full_n_segments_from_state(Pointer state); + + /** + * Language id associated with the context's default state. + * @param ctx Pointer to WhisperContext + */ + int whisper_full_lang_id(Pointer ctx); + + /** Language id associated with the provided state */ + int whisper_full_lang_id_from_state(Pointer state); + + /** + * Convert RAW PCM audio to log mel spectrogram but applies a Phase Vocoder to speed up the audio x2. + * The resulting spectrogram is stored inside the default state of the provided whisper context. + * @return 0 on success + */ + int whisper_pcm_to_mel_phase_vocoder(Pointer ctx, final float[] samples, int n_samples, int n_threads); + + int whisper_pcm_to_mel_phase_vocoder_with_state(Pointer ctx, Pointer state, final float[] samples, int n_samples, int n_threads); + + /** Get the start time of the specified segment. */ + long whisper_full_get_segment_t0(Pointer ctx, int i_segment); + + /** Get the start time of the specified segment from the state. */ + long whisper_full_get_segment_t0_from_state(Pointer state, int i_segment); + + /** Get the end time of the specified segment. */ + long whisper_full_get_segment_t1(Pointer ctx, int i_segment); + + /** Get the end time of the specified segment from the state. */ + long whisper_full_get_segment_t1_from_state(Pointer state, int i_segment); + + /** Get the text of the specified segment. */ + String whisper_full_get_segment_text(Pointer ctx, int i_segment); + + /** Get the text of the specified segment from the state. */ + String whisper_full_get_segment_text_from_state(Pointer state, int i_segment); + + /** Get the number of tokens in the specified segment. */ + int whisper_full_n_tokens(Pointer ctx, int i_segment); + + /** Get the number of tokens in the specified segment from the state. */ + int whisper_full_n_tokens_from_state(Pointer state, int i_segment); + + /** Get the token text of the specified token in the specified segment. */ + String whisper_full_get_token_text(Pointer ctx, int i_segment, int i_token); + + + /** Get the token text of the specified token in the specified segment from the state. */ + String whisper_full_get_token_text_from_state(Pointer ctx, Pointer state, int i_segment, int i_token); + + /** Get the token ID of the specified token in the specified segment. */ + int whisper_full_get_token_id(Pointer ctx, int i_segment, int i_token); + + /** Get the token ID of the specified token in the specified segment from the state. */ + int whisper_full_get_token_id_from_state(Pointer state, int i_segment, int i_token); + + /** Get token data for the specified token in the specified segment. */ + WhisperTokenData whisper_full_get_token_data(Pointer ctx, int i_segment, int i_token); + + /** Get token data for the specified token in the specified segment from the state. */ + WhisperTokenData whisper_full_get_token_data_from_state(Pointer state, int i_segment, int i_token); + + /** Get the probability of the specified token in the specified segment. */ + float whisper_full_get_token_p(Pointer ctx, int i_segment, int i_token); + + /** Get the probability of the specified token in the specified segment from the state. */ + float whisper_full_get_token_p_from_state(Pointer state, int i_segment, int i_token); + + /** + * Benchmark function for memcpy. + * + * @param nThreads Number of threads to use for the benchmark. + * @return The result of the benchmark. + */ + int whisper_bench_memcpy(int nThreads); + + /** + * Benchmark function for memcpy as a string. + * + * @param nThreads Number of threads to use for the benchmark. + * @return The result of the benchmark as a string. + */ + String whisper_bench_memcpy_str(int nThreads); + + /** + * Benchmark function for ggml_mul_mat. + * + * @param nThreads Number of threads to use for the benchmark. + * @return The result of the benchmark. + */ + int whisper_bench_ggml_mul_mat(int nThreads); + + /** + * Benchmark function for ggml_mul_mat as a string. + * + * @param nThreads Number of threads to use for the benchmark. + * @return The result of the benchmark as a string. + */ + String whisper_bench_ggml_mul_mat_str(int nThreads); +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java new file mode 100644 index 0000000..da970b5 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/bean/WhisperSegment.java @@ -0,0 +1,47 @@ +package io.github.ggerganov.whispercpp.bean; + +/** + * Created by litonglinux@qq.com on 10/21/2023_7:48 AM + */ +public class WhisperSegment { + private long start, end; + private String sentence; + + public WhisperSegment() { + } + + public WhisperSegment(long start, long end, String sentence) { + this.start = start; + this.end = end; + this.sentence = sentence; + } + + public long getStart() { + return start; + } + + public long getEnd() { + return end; + } + + public String getSentence() { + return sentence; + } + + public void setStart(long start) { + this.start = start; + } + + public void setEnd(long end) { + this.end = end; + } + + public void setSentence(String sentence) { + this.sentence = sentence; + } + + @Override + public String toString() { + return "[" + start + " --> " + end + "]:" + sentence; + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java new file mode 100644 index 0000000..3d228cb --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperEncoderBeginCallback.java @@ -0,0 +1,24 @@ +package io.github.ggerganov.whispercpp.callbacks; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.WhisperContext; +import io.github.ggerganov.whispercpp.model.WhisperState; + +/** + * Callback before the encoder starts. + * If not null, called before the encoder starts. + * If it returns false, the computation is aborted. + */ +public interface WhisperEncoderBeginCallback extends Callback { + + /** + * Callback method before the encoder starts. + * + * @param ctx The whisper context. + * @param state The whisper state. + * @param user_data User data. + * @return True if the computation should proceed, false otherwise. + */ + boolean callback(Pointer ctx, Pointer state, Pointer user_data); +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java new file mode 100644 index 0000000..9777c76 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperLogitsFilterCallback.java @@ -0,0 +1,25 @@ +package io.github.ggerganov.whispercpp.callbacks; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.model.WhisperTokenData; + +/** + * Callback to filter logits. + * Can be used to modify the logits before sampling. + * If not null, called after applying temperature to logits. + */ +public interface WhisperLogitsFilterCallback extends Callback { + + /** + * Callback method to filter logits. + * + * @param ctx The whisper context. + * @param state The whisper state. + * @param tokens The array of whisper_token_data. + * @param n_tokens The number of tokens. + * @param logits The array of logits. + * @param user_data User data. + */ + void callback(Pointer ctx, Pointer state, WhisperTokenData[] tokens, int n_tokens, float[] logits, Pointer user_data); +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java new file mode 100644 index 0000000..27b1c61 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperNewSegmentCallback.java @@ -0,0 +1,24 @@ +package io.github.ggerganov.whispercpp.callbacks; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.WhisperContext; +import io.github.ggerganov.whispercpp.model.WhisperState; + +/** + * Callback for the text segment. + * Called on every newly generated text segment. + * Use the whisper_full_...() functions to obtain the text segments. + */ +public interface WhisperNewSegmentCallback extends Callback { + + /** + * Callback method for the text segment. + * + * @param ctx The whisper context. + * @param state The whisper state. + * @param n_new The number of newly generated text segments. + * @param user_data User data. + */ + void callback(Pointer ctx, Pointer state, int n_new, Pointer user_data); +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java new file mode 100644 index 0000000..c64f0ab --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/callbacks/WhisperProgressCallback.java @@ -0,0 +1,22 @@ +package io.github.ggerganov.whispercpp.callbacks; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import io.github.ggerganov.whispercpp.WhisperContext; +import io.github.ggerganov.whispercpp.model.WhisperState; + +/** + * Callback for progress updates. + */ +public interface WhisperProgressCallback extends Callback { + + /** + * Callback method for progress updates. + * + * @param ctx The whisper context. + * @param state The whisper state. + * @param progress The progress value. + * @param user_data User data. + */ + void callback(Pointer ctx, Pointer state, int progress, Pointer user_data); +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java new file mode 100644 index 0000000..2569957 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlTensor.java @@ -0,0 +1,4 @@ +package io.github.ggerganov.whispercpp.ggml; + +public class GgmlTensor { +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java new file mode 100644 index 0000000..363120e --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/ggml/GgmlType.java @@ -0,0 +1,18 @@ +package io.github.ggerganov.whispercpp.ggml; + +public enum GgmlType { + GGML_TYPE_F32, + GGML_TYPE_F16, + GGML_TYPE_Q4_0, + GGML_TYPE_Q4_1, + REMOVED_GGML_TYPE_Q4_2, // support has been removed + REMOVED_GGML_TYPE_Q4_3, // support has been removed + GGML_TYPE_Q5_0, + GGML_TYPE_Q5_1, + GGML_TYPE_Q8_0, + GGML_TYPE_Q8_1, + GGML_TYPE_I8, + GGML_TYPE_I16, + GGML_TYPE_I32, + GGML_TYPE_COUNT, +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java new file mode 100644 index 0000000..b2475b3 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/EModel.java @@ -0,0 +1,10 @@ +package io.github.ggerganov.whispercpp.model; + +public enum EModel { + MODEL_UNKNOWN, + MODEL_TINY, + MODEL_BASE, + MODEL_SMALL, + MODEL_MEDIUM, + MODEL_LARGE, +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java new file mode 100644 index 0000000..497ef42 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModel.java @@ -0,0 +1,49 @@ +package io.github.ggerganov.whispercpp; + +import io.github.ggerganov.whispercpp.ggml.GgmlTensor; +import io.github.ggerganov.whispercpp.model.EModel; + +public class WhisperModel { +// EModel type = EModel.MODEL_UNKNOWN; +// +// WhisperHParams hparams; +// WhisperFilters filters; +// +// // encoder.positional_embedding +// GgmlTensor e_pe; +// +// // encoder.conv1 +// GgmlTensor e_conv_1_w; +// GgmlTensor e_conv_1_b; +// +// // encoder.conv2 +// GgmlTensor e_conv_2_w; +// GgmlTensor e_conv_2_b; +// +// // encoder.ln_post +// GgmlTensor e_ln_w; +// GgmlTensor e_ln_b; +// +// // decoder.positional_embedding +// GgmlTensor d_pe; +// +// // decoder.token_embedding +// GgmlTensor d_te; +// +// // decoder.ln +// GgmlTensor d_ln_w; +// GgmlTensor d_ln_b; +// +// std::vector layers_encoder; +// std::vector layers_decoder; +// +// // context +// struct ggml_context * ctx; +// +// // the model memory buffer is read-only and can be shared between processors +// std::vector * buf; +// +// // tensors +// int n_loaded; +// Map tensors; +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java new file mode 100644 index 0000000..82615d9 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperModelLoader.java @@ -0,0 +1,62 @@ +package io.github.ggerganov.whispercpp.model; + +import com.sun.jna.Callback; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; + + +public class WhisperModelLoader extends Structure { + public Pointer context; + public ReadFunction read; + public EOFFunction eof; + public CloseFunction close; + + public static class ReadFunction implements Callback { + public Pointer invoke(Pointer ctx, Pointer output, int readSize) { + // TODO + return ctx; + } + } + + public static class EOFFunction implements Callback { + public boolean invoke(Pointer ctx) { + // TODO + return false; + } + } + + public static class CloseFunction implements Callback { + public void invoke(Pointer ctx) { + // TODO + } + } + +// public WhisperModelLoader(Pointer p) { +// super(p); +// read = new ReadFunction(); +// eof = new EOFFunction(); +// close = new CloseFunction(); +// read.setCallback(this); +// eof.setCallback(this); +// close.setCallback(this); +// read.write(); +// eof.write(); +// close.write(); +// } + + public WhisperModelLoader() { + super(); + } + + public interface ReadCallback extends Callback { + Pointer invoke(Pointer ctx, Pointer output, int readSize); + } + + public interface EOFCallback extends Callback { + boolean invoke(Pointer ctx); + } + + public interface CloseCallback extends Callback { + void invoke(Pointer ctx); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java new file mode 100644 index 0000000..af93772 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperState.java @@ -0,0 +1,4 @@ +package io.github.ggerganov.whispercpp.model; + +public class WhisperState { +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java new file mode 100644 index 0000000..bfa83f9 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/model/WhisperTokenData.java @@ -0,0 +1,50 @@ +package io.github.ggerganov.whispercpp.model; + +import com.sun.jna.Structure; + +import java.util.Arrays; +import java.util.List; + +/** + * Structure representing token data. + */ +public class WhisperTokenData extends Structure { + + /** Token ID. */ + public int id; + + /** Forced timestamp token ID. */ + public int tid; + + /** Probability of the token. */ + public float p; + + /** Log probability of the token. */ + public float plog; + + /** Probability of the timestamp token. */ + public float pt; + + /** Sum of probabilities of all timestamp tokens. */ + public float ptsum; + + /** + * Start time of the token (token-level timestamp data). + * Do not use if you haven't computed token-level timestamps. + */ + public long t0; + + /** + * End time of the token (token-level timestamp data). + * Do not use if you haven't computed token-level timestamps. + */ + public long t1; + + /** Voice length of the token. */ + public float vlen; + + @Override + protected List getFieldOrder() { + return Arrays.asList("id", "tid", "p", "plog", "pt", "ptsum", "t0", "t1", "vlen"); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java new file mode 100644 index 0000000..fd621dd --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/BeamSearchParams.java @@ -0,0 +1,19 @@ +package io.github.ggerganov.whispercpp.params; + +import com.sun.jna.Structure; + +import java.util.Arrays; +import java.util.List; + +public class BeamSearchParams extends Structure { + /** ref: ... */ + public int beam_size; + + /** ref: ... */ + public float patience; + + @Override + protected List getFieldOrder() { + return Arrays.asList("beam_size", "patience"); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java new file mode 100644 index 0000000..1f6814b --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/CBool.java @@ -0,0 +1,30 @@ +package io.github.ggerganov.whispercpp.params; + +import com.sun.jna.IntegerType; + +import java.util.function.BooleanSupplier; + +public class CBool extends IntegerType implements BooleanSupplier { + public static final int SIZE = 1; + public static final CBool FALSE = new CBool(0); + public static final CBool TRUE = new CBool(1); + + + public CBool() { + this(0); + } + + public CBool(long value) { + super(SIZE, value, true); + } + + @Override + public boolean getAsBoolean() { + return intValue() == 1; + } + + @Override + public String toString() { + return intValue() == 1 ? "true" : "false"; + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java new file mode 100644 index 0000000..e3b0138 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/GreedyParams.java @@ -0,0 +1,16 @@ +package io.github.ggerganov.whispercpp.params; + +import com.sun.jna.Structure; + +import java.util.Collections; +import java.util.List; + +public class GreedyParams extends Structure { + /** ... */ + public int best_of; + + @Override + protected List getFieldOrder() { + return Collections.singletonList("best_of"); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java new file mode 100644 index 0000000..cf98d2c --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperContextParams.java @@ -0,0 +1,31 @@ +package io.github.ggerganov.whispercpp.params; + +import com.sun.jna.*; + +import java.util.Arrays; +import java.util.List; + +/** + * Parameters for the whisper_init_from_file_with_params() function. + * If you change the order or add new parameters, make sure to update the default values in whisper.cpp: + * whisper_context_default_params() + */ +public class WhisperContextParams extends Structure { + + public WhisperContextParams(Pointer p) { + super(p); + } + + /** Use GPU for inference Number (default = true) */ + public CBool use_gpu; + + /** Use GPU for inference Number (default = true) */ + public void useGpu(boolean enable) { + use_gpu = enable ? CBool.TRUE : CBool.FALSE; + } + + @Override + protected List getFieldOrder() { + return Arrays.asList("use_gpu"); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java new file mode 100644 index 0000000..b035243 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFilters.java @@ -0,0 +1,10 @@ +package io.github.ggerganov.whispercpp.params; + +import java.util.List; + +public class WhisperFilters { + int n_mel; + int n_fft; + + List data; +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java new file mode 100644 index 0000000..43c9a0d --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperFullParams.java @@ -0,0 +1,331 @@ +package io.github.ggerganov.whispercpp.params; + +import com.sun.jna.*; +import io.github.ggerganov.whispercpp.callbacks.WhisperEncoderBeginCallback; +import io.github.ggerganov.whispercpp.callbacks.WhisperLogitsFilterCallback; +import io.github.ggerganov.whispercpp.callbacks.WhisperNewSegmentCallback; +import io.github.ggerganov.whispercpp.callbacks.WhisperProgressCallback; + +import java.util.Arrays; +import java.util.List; + +/** + * Parameters for the whisper_full() function. + * If you change the order or add new parameters, make sure to update the default values in whisper.cpp: + * whisper_full_default_params() + */ +public class WhisperFullParams extends Structure { + + public WhisperFullParams(Pointer p) { + super(p); +// super(p, ALIGN_MSVC); +// super(p, ALIGN_GNUC); + } + + /** Sampling strategy for whisper_full() function. */ + public int strategy; + + /** Number of threads. (default = 4) */ + public int n_threads; + + /** Maximum tokens to use from past text as a prompt for the decoder. (default = 16384) */ + public int n_max_text_ctx; + + /** Start offset in milliseconds. (default = 0) */ + public int offset_ms; + + /** Audio duration to process in milliseconds. (default = 0) */ + public int duration_ms; + + /** Translate flag. (default = false) */ + public CBool translate; + + /** The compliment of translateMode() */ + public void transcribeMode() { + translate = CBool.FALSE; + } + + /** The compliment of transcribeMode() */ + public void translateMode() { + translate = CBool.TRUE; + } + + /** Flag to indicate whether to use past transcription (if any) as an initial prompt for the decoder. (default = true) */ + public CBool no_context; + + /** Flag to indicate whether to use past transcription (if any) as an initial prompt for the decoder. (default = true) */ + public void enableContext(boolean enable) { + no_context = enable ? CBool.FALSE : CBool.TRUE; + } + + /** Generate timestamps or not? */ + public CBool no_timestamps; + + /** Flag to force single segment output (useful for streaming). (default = false) */ + public CBool single_segment; + + /** Flag to force single segment output (useful for streaming). (default = false) */ + public void singleSegment(boolean single) { + single_segment = single ? CBool.TRUE : CBool.FALSE; + } + + /** Flag to print special tokens (e.g., <SOT>, <EOT>, <BEG>, etc.). (default = false) */ + public CBool print_special; + + /** Flag to print special tokens (e.g., <SOT>, <EOT>, <BEG>, etc.). (default = false) */ + public void printSpecial(boolean enable) { + print_special = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Flag to print progress information. (default = true) */ + public CBool print_progress; + + /** Flag to print progress information. (default = true) */ + public void printProgress(boolean enable) { + print_progress = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Flag to print results from within whisper.cpp (avoid it, use callback instead). (default = true) */ + public CBool print_realtime; + + /** Flag to print results from within whisper.cpp (avoid it, use callback instead). (default = true) */ + public void printRealtime(boolean enable) { + print_realtime = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Flag to print timestamps for each text segment when printing realtime. (default = true) */ + public CBool print_timestamps; + + /** Flag to print timestamps for each text segment when printing realtime. (default = true) */ + public void printTimestamps(boolean enable) { + print_timestamps = enable ? CBool.TRUE : CBool.FALSE; + } + + /** [EXPERIMENTAL] Flag to enable token-level timestamps. (default = false) */ + public CBool token_timestamps; + + /** [EXPERIMENTAL] Flag to enable token-level timestamps. (default = false) */ + public void tokenTimestamps(boolean enable) { + token_timestamps = enable ? CBool.TRUE : CBool.FALSE; + } + + /** [EXPERIMENTAL] Timestamp token probability threshold (~0.01). (default = 0.01) */ + public float thold_pt; + + /** [EXPERIMENTAL] Timestamp token sum probability threshold (~0.01). */ + public float thold_ptsum; + + /** Maximum segment length in characters. (default = 0) */ + public int max_len; + + /** Flag to split on word rather than on token (when used with max_len). (default = false) */ + public CBool split_on_word; + + /** Flag to split on word rather than on token (when used with max_len). (default = false) */ + public void splitOnWord(boolean enable) { + split_on_word = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Maximum tokens per segment (0, default = no limit) */ + public int max_tokens; + + /** Flag to speed up the audio by 2x using Phase Vocoder. (default = false) */ + public CBool speed_up; + + /** Flag to speed up the audio by 2x using Phase Vocoder. (default = false) */ + public void speedUp(boolean enable) { + speed_up = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Overwrite the audio context size (0 = use default). */ + public int audio_ctx; + + /** Enable tinydiarize (default = false) */ + public CBool tdrz_enable; + + /** Enable tinydiarize (default = false) */ + public void tdrzEnable(boolean enable) { + tdrz_enable = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Tokens to provide to the whisper decoder as an initial prompt. + * These are prepended to any existing text context from a previous call. */ + public String initial_prompt; + + /** Prompt tokens. (int*) */ + public Pointer prompt_tokens; + + public void setPromptTokens(int[] tokens) { + Memory mem = new Memory(tokens.length * 4L); + mem.write(0, tokens, 0, tokens.length); + prompt_tokens = mem; + } + + /** Number of prompt tokens. */ + public int prompt_n_tokens; + + /** Language for auto-detection. + * For auto-detection, set to `null`, `""`, or "auto". */ + public String language; + + /** Flag to indicate whether to detect language automatically. */ + public CBool detect_language; + + /** Flag to indicate whether to detect language automatically. */ + public void detectLanguage(boolean enable) { + detect_language = enable ? CBool.TRUE : CBool.FALSE; + } + + // Common decoding parameters. + + /** Flag to suppress blank tokens. */ + public CBool suppress_blank; + + public void suppressBlanks(boolean enable) { + suppress_blank = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Flag to suppress non-speech tokens. */ + public CBool suppress_non_speech_tokens; + + /** Flag to suppress non-speech tokens. */ + public void suppressNonSpeechTokens(boolean enable) { + suppress_non_speech_tokens = enable ? CBool.TRUE : CBool.FALSE; + } + + /** Initial decoding temperature. */ + public float temperature; + + /** Maximum initial timestamp. */ + public float max_initial_ts; + + /** Length penalty. */ + public float length_penalty; + + // Fallback parameters. + + /** Temperature increment. */ + public float temperature_inc; + + /** Entropy threshold (similar to OpenAI's "compression_ratio_threshold"). */ + public float entropy_thold; + + /** Log probability threshold. */ + public float logprob_thold; + + /** No speech threshold. */ + public float no_speech_thold; + + /** Greedy decoding parameters. */ + public GreedyParams greedy; + + /** + * Beam search decoding parameters. + */ + public BeamSearchParams beam_search; + + public void setBestOf(int bestOf) { + if (greedy == null) { + greedy = new GreedyParams(); + } + greedy.best_of = bestOf; + } + + public void setBeamSize(int beamSize) { + if (beam_search == null) { + beam_search = new BeamSearchParams(); + } + beam_search.beam_size = beamSize; + } + + public void setBeamSizeAndPatience(int beamSize, float patience) { + if (beam_search == null) { + beam_search = new BeamSearchParams(); + } + beam_search.beam_size = beamSize; + beam_search.patience = patience; + } + + /** + * Callback for every newly generated text segment. + * WhisperNewSegmentCallback + */ + public Pointer new_segment_callback; + + /** + * User data for the new_segment_callback. + */ + public Pointer new_segment_callback_user_data; + + /** + * Callback on each progress update. + * WhisperProgressCallback + */ + public Pointer progress_callback; + + /** + * User data for the progress_callback. + */ + public Pointer progress_callback_user_data; + + /** + * Callback each time before the encoder starts. + * WhisperEncoderBeginCallback + */ + public Pointer encoder_begin_callback; + + /** + * User data for the encoder_begin_callback. + */ + public Pointer encoder_begin_callback_user_data; + + /** + * Callback by each decoder to filter obtained logits. + * WhisperLogitsFilterCallback + */ + public Pointer logits_filter_callback; + + /** + * User data for the logits_filter_callback. + */ + public Pointer logits_filter_callback_user_data; + + + public void setNewSegmentCallback(WhisperNewSegmentCallback callback) { + new_segment_callback = CallbackReference.getFunctionPointer(callback); + } + + public void setProgressCallback(WhisperProgressCallback callback) { + progress_callback = CallbackReference.getFunctionPointer(callback); + } + + public void setEncoderBeginCallbackeginCallbackCallback(WhisperEncoderBeginCallback callback) { + encoder_begin_callback = CallbackReference.getFunctionPointer(callback); + } + + public void setLogitsFilterCallback(WhisperLogitsFilterCallback callback) { + logits_filter_callback = CallbackReference.getFunctionPointer(callback); + } + + /** Grammar stuff */ + public Pointer grammar_rules; + public long n_grammar_rules; + public long i_start_rule; + public float grammar_penalty; + + @Override + protected List getFieldOrder() { + return Arrays.asList("strategy", "n_threads", "n_max_text_ctx", "offset_ms", "duration_ms", "translate", + "no_context", "single_segment", "no_timestamps", + "print_special", "print_progress", "print_realtime", "print_timestamps", "token_timestamps", + "thold_pt", "thold_ptsum", "max_len", "split_on_word", "max_tokens", "speed_up", "audio_ctx", + "tdrz_enable", "initial_prompt", "prompt_tokens", "prompt_n_tokens", "language", "detect_language", + "suppress_blank", "suppress_non_speech_tokens", "temperature", "max_initial_ts", "length_penalty", + "temperature_inc", "entropy_thold", "logprob_thold", "no_speech_thold", "greedy", "beam_search", + "new_segment_callback", "new_segment_callback_user_data", + "progress_callback", "progress_callback_user_data", + "encoder_begin_callback", "encoder_begin_callback_user_data", + "logits_filter_callback", "logits_filter_callback_user_data", + "grammar_rules", "n_grammar_rules", "i_start_rule", "grammar_penalty"); + } +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java new file mode 100644 index 0000000..99feae0 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperHParams.java @@ -0,0 +1,15 @@ +package io.github.ggerganov.whispercpp.params; + +public class WhisperHParams { + int n_vocab = 51864; + int n_audio_ctx = 1500; + int n_audio_state = 384; + int n_audio_head = 6; + int n_audio_layer = 4; + int n_text_ctx = 448; + int n_text_state = 384; + int n_text_head = 6; + int n_text_layer = 4; + int n_mels = 80; + int ftype = 1; +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java new file mode 100644 index 0000000..a32c793 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/main/java/io/github/ggerganov/whispercpp/params/WhisperSamplingStrategy.java @@ -0,0 +1,10 @@ +package io.github.ggerganov.whispercpp.params; + +/** Available sampling strategies */ +public enum WhisperSamplingStrategy { + /** similar to OpenAI's GreedyDecoder */ + WHISPER_SAMPLING_GREEDY, + + /** similar to OpenAI's BeamSearchDecoder */ + WHISPER_SAMPLING_BEAM_SEARCH +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java b/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java new file mode 100644 index 0000000..034726a --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperCppTest.java @@ -0,0 +1,144 @@ +package io.github.ggerganov.whispercpp; + +import static org.junit.jupiter.api.Assertions.*; + +import io.github.ggerganov.whispercpp.bean.WhisperSegment; +import io.github.ggerganov.whispercpp.params.CBool; +import io.github.ggerganov.whispercpp.params.WhisperFullParams; +import io.github.ggerganov.whispercpp.params.WhisperSamplingStrategy; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.List; + +class WhisperCppTest { + private static WhisperCpp whisper = new WhisperCpp(); + private static boolean modelInitialised = false; + + @BeforeAll + static void init() throws FileNotFoundException { + // By default, models are loaded from ~/.cache/whisper/ and are usually named "ggml-${name}.bin" + // or you can provide the absolute path to the model file. + //String modelName = "../../models/ggml-tiny.bin"; + String modelName = "../../models/ggml-tiny.en.bin"; + try { + whisper.initContext(modelName); + //whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + //whisper.getJavaDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + modelInitialised = true; + } catch (FileNotFoundException ex) { + System.out.println("Model " + modelName + " not found"); + } + } + + @Test + void testGetDefaultFullParams_BeamSearch() { + // When + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + + // Then + assertEquals(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH.ordinal(), params.strategy); + assertNotEquals(0, params.n_threads); + assertEquals(16384, params.n_max_text_ctx); + assertFalse(params.translate); + assertEquals(0.01f, params.thold_pt); + assertEquals(5, params.beam_search.beam_size); + assertEquals(-1.0f, params.beam_search.patience); + } + + @Test + void testGetDefaultFullParams_Greedy() { + // When + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + + // Then + assertEquals(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY.ordinal(), params.strategy); + assertNotEquals(0, params.n_threads); + assertEquals(16384, params.n_max_text_ctx); + assertEquals(5, params.greedy.best_of); + } + + @Test + void testFullTranscribe() throws Exception { + if (!modelInitialised) { + System.out.println("Model not initialised, skipping test"); + return; + } + + // Given + File file = new File(System.getProperty("user.dir"), "../../samples/jfk.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); + + byte[] b = new byte[audioInputStream.available()]; + float[] floats = new float[b.length / 2]; + + //WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + params.setProgressCallback((ctx, state, progress, user_data) -> System.out.println("progress: " + progress)); + params.print_progress = CBool.FALSE; + //params.initial_prompt = "and so my fellow Americans um, like"; + + + try { + audioInputStream.read(b); + + for (int i = 0, j = 0; i < b.length; i += 2, j++) { + int intSample = (int) (b[i + 1]) << 8 | (int) (b[i]) & 0xFF; + floats[j] = intSample / 32767.0f; + } + + // When + String result = whisper.fullTranscribe(params, floats); + + // Then + System.err.println(result); + assertEquals("And so my fellow Americans ask not what your country can do for you " + + "ask what you can do for your country.", + result.replace(",", "")); + } finally { + audioInputStream.close(); + } + } + + @Test + void testFullTranscribeWithTime() throws Exception { + if (!modelInitialised) { + System.out.println("Model not initialised, skipping test"); + return; + } + + // Given + File file = new File(System.getProperty("user.dir"), "../../samples/jfk.wav"); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file); + + byte[] b = new byte[audioInputStream.available()]; + float[] floats = new float[b.length / 2]; + + //WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY); + WhisperFullParams params = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH); + params.setProgressCallback((ctx, state, progress, user_data) -> System.out.println("progress: " + progress)); + params.print_progress = CBool.FALSE; + //params.initial_prompt = "and so my fellow Americans um, like"; + + try { + audioInputStream.read(b); + + for (int i = 0, j = 0; i < b.length; i += 2, j++) { + int intSample = (int) (b[i + 1]) << 8 | (int) (b[i]) & 0xFF; + floats[j] = intSample / 32767.0f; + } + + List segments = whisper.fullTranscribeWithTime(params, floats); + assertTrue(segments.size() > 0, "The size of segments should be greater than 0"); + for (WhisperSegment segment : segments) { + System.out.println(segment); + } + } finally { + audioInputStream.close(); + } + } + +} diff --git a/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java b/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java new file mode 100644 index 0000000..07a340c --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/java/src/test/java/io/github/ggerganov/whispercpp/WhisperJnaLibraryTest.java @@ -0,0 +1,17 @@ +package io.github.ggerganov.whispercpp; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class WhisperJnaLibraryTest { + + @Test + void testWhisperPrint_system_info() { + String systemInfo = WhisperCppJnaLibrary.instance.whisper_print_system_info(); + // eg: "AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 + // | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | COREML = 0 | " + System.out.println("System info: " + systemInfo); + assertTrue(systemInfo.length() > 10); + } +} diff --git a/whisper.cpp-1.5.2/bindings/javascript/.gitignore b/whisper.cpp-1.5.2/bindings/javascript/.gitignore new file mode 100644 index 0000000..17b4c53 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/.gitignore @@ -0,0 +1 @@ +publish.log diff --git a/whisper.cpp-1.5.2/bindings/javascript/CMakeLists.txt b/whisper.cpp-1.5.2/bindings/javascript/CMakeLists.txt new file mode 100644 index 0000000..6b5af79 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/CMakeLists.txt @@ -0,0 +1,41 @@ +set(TARGET libwhisper) + +add_executable(${TARGET} + emscripten.cpp + ) + +target_link_libraries(${TARGET} PRIVATE + whisper + ) + +unset(EXTRA_FLAGS) + +if (WHISPER_WASM_SINGLE_FILE) + set(EXTRA_FLAGS "-s SINGLE_FILE=1") + message(STATUS "Embedding WASM inside whisper.js") + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libwhisper.js + ${CMAKE_CURRENT_SOURCE_DIR}/whisper.js + ) + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libwhisper.worker.js + ${CMAKE_CURRENT_SOURCE_DIR}/libwhisper.worker.js + ) +endif() + +set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ + --bind \ + -s MODULARIZE=1 \ + -s EXPORT_NAME=\"'whisper_factory'\" \ + -s FORCE_FILESYSTEM=1 \ + -s USE_PTHREADS=1 \ + -s PTHREAD_POOL_SIZE=8 \ + -s ALLOW_MEMORY_GROWTH=1 \ + ${EXTRA_FLAGS} \ + ") diff --git a/whisper.cpp-1.5.2/bindings/javascript/README.md b/whisper.cpp-1.5.2/bindings/javascript/README.md new file mode 100644 index 0000000..3947d25 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/README.md @@ -0,0 +1,78 @@ +# whisper.cpp + +Node.js package for Whisper speech recognition + +Package: https://www.npmjs.com/package/whisper.cpp + +## Details + +The performance is comparable to when running `whisper.cpp` in the browser via WASM. + +The API is currently very rudimentary: [bindings/javascript/emscripten.cpp](/bindings/javascript/emscripten.cpp) + +For sample usage check [tests/test-whisper.js](/tests/test-whisper.js) + +## Package building + test + +```bash +# load emscripten +source /path/to/emsdk/emsdk_env.sh + +# clone repo +git clone https://github.com/ggerganov/whisper.cpp +cd whisper.cpp + +# grab base.en model +./models/download-ggml-model.sh base.en + +# prepare PCM sample for testing +ffmpeg -i samples/jfk.wav -f f32le -acodec pcm_f32le samples/jfk.pcmf32 + +# build +mkdir build-em && cd build-em +emcmake cmake .. && make -j + +# run test +node --experimental-wasm-threads --experimental-wasm-simd ../tests/test-whisper.js + +# publish npm package +make publish-npm +``` + +## Sample run + +```java +$ node --experimental-wasm-threads --experimental-wasm-simd ../tests/test-whisper.js + +whisper_model_load: loading model from 'whisper.bin' +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 512 +whisper_model_load: n_audio_head = 8 +whisper_model_load: n_audio_layer = 6 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 512 +whisper_model_load: n_text_head = 8 +whisper_model_load: n_text_layer = 6 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 2 +whisper_model_load: adding 1607 extra tokens +whisper_model_load: mem_required = 506.00 MB +whisper_model_load: ggml ctx size = 140.60 MB +whisper_model_load: memory size = 22.83 MB +whisper_model_load: model size = 140.54 MB + +system_info: n_threads = 8 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | NEON = 0 | F16C = 0 | FP16_VA = 0 | WASM_SIMD = 1 | BLAS = 0 | + +operator(): processing 176000 samples, 11.0 sec, 8 threads, 1 processors, lang = en, task = transcribe ... + +[00:00:00.000 --> 00:00:11.000] And so my fellow Americans, ask not what your country can do for you, ask what you can do for your country. + +whisper_print_timings: load time = 162.37 ms +whisper_print_timings: mel time = 183.70 ms +whisper_print_timings: sample time = 4.27 ms +whisper_print_timings: encode time = 8582.63 ms / 1430.44 ms per layer +whisper_print_timings: decode time = 436.16 ms / 72.69 ms per layer +whisper_print_timings: total time = 9370.90 ms +``` diff --git a/whisper.cpp-1.5.2/bindings/javascript/emscripten.cpp b/whisper.cpp-1.5.2/bindings/javascript/emscripten.cpp new file mode 100644 index 0000000..b442c1f --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/emscripten.cpp @@ -0,0 +1,93 @@ +// +// This is the Javascript API of whisper.cpp +// +// Very crude at the moment. +// Feel free to contribute and make this better! +// +// See the tests/test-whisper.js for sample usage +// + +#include "whisper.h" + +#include +#include + +#include +#include + +struct whisper_context * g_context; + +EMSCRIPTEN_BINDINGS(whisper) { + emscripten::function("init", emscripten::optional_override([](const std::string & path_model) { + if (g_context == nullptr) { + g_context = whisper_init_from_file_with_params(path_model.c_str(), whisper_context_default_params()); + if (g_context != nullptr) { + return true; + } else { + return false; + } + } + + return false; + })); + + emscripten::function("free", emscripten::optional_override([]() { + if (g_context) { + whisper_free(g_context); + g_context = nullptr; + } + })); + + emscripten::function("full_default", emscripten::optional_override([](const emscripten::val & audio, const std::string & lang, bool translate) { + if (g_context == nullptr) { + return -1; + } + + struct whisper_full_params params = whisper_full_default_params(whisper_sampling_strategy::WHISPER_SAMPLING_GREEDY); + + params.print_realtime = true; + params.print_progress = false; + params.print_timestamps = true; + params.print_special = false; + params.translate = translate; + params.language = whisper_is_multilingual(g_context) ? lang.c_str() : "en"; + params.n_threads = std::min(8, (int) std::thread::hardware_concurrency()); + params.offset_ms = 0; + + std::vector pcmf32; + const int n = audio["length"].as(); + + emscripten::val heap = emscripten::val::module_property("HEAPU8"); + emscripten::val memory = heap["buffer"]; + + pcmf32.resize(n); + + emscripten::val memoryView = audio["constructor"].new_(memory, reinterpret_cast(pcmf32.data()), n); + memoryView.call("set", audio); + + // print system information + { + printf("\n"); + printf("system_info: n_threads = %d / %d | %s\n", + params.n_threads, std::thread::hardware_concurrency(), whisper_print_system_info()); + + printf("\n"); + printf("%s: processing %d samples, %.1f sec, %d threads, %d processors, lang = %s, task = %s ...\n", + __func__, int(pcmf32.size()), float(pcmf32.size())/WHISPER_SAMPLE_RATE, + params.n_threads, 1, + params.language, + params.translate ? "translate" : "transcribe"); + + printf("\n"); + } + + // run whisper + { + whisper_reset_timings(g_context); + whisper_full(g_context, params, pcmf32.data(), pcmf32.size()); + whisper_print_timings(g_context); + } + + return 0; + })); +} diff --git a/whisper.cpp-1.5.2/bindings/javascript/libwhisper.worker.js b/whisper.cpp-1.5.2/bindings/javascript/libwhisper.worker.js new file mode 100644 index 0000000..db2083a --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/libwhisper.worker.js @@ -0,0 +1 @@ +"use strict";var Module={};var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";if(ENVIRONMENT_IS_NODE){var nodeWorkerThreads=require("worker_threads");var parentPort=nodeWorkerThreads.parentPort;parentPort.on("message",data=>onmessage({data:data}));var fs=require("fs");Object.assign(global,{self:global,require:require,Module:Module,location:{href:__filename},Worker:nodeWorkerThreads.Worker,importScripts:f=>(0,eval)(fs.readFileSync(f,"utf8")+"//# sourceURL="+f),postMessage:msg=>parentPort.postMessage(msg),performance:global.performance||{now:Date.now}})}var initializedJS=false;function threadPrintErr(){var text=Array.prototype.slice.call(arguments).join(" ");if(ENVIRONMENT_IS_NODE){fs.writeSync(2,text+"\n");return}console.error(text)}function threadAlert(){var text=Array.prototype.slice.call(arguments).join(" ");postMessage({cmd:"alert",text:text,threadId:Module["_pthread_self"]()})}var err=threadPrintErr;self.alert=threadAlert;Module["instantiateWasm"]=(info,receiveInstance)=>{var module=Module["wasmModule"];Module["wasmModule"]=null;var instance=new WebAssembly.Instance(module,info);return receiveInstance(instance)};self.onunhandledrejection=e=>{throw e.reason||e};function handleMessage(e){try{if(e.data.cmd==="load"){let messageQueue=[];self.onmessage=e=>messageQueue.push(e);self.startWorker=instance=>{Module=instance;postMessage({"cmd":"loaded"});for(let msg of messageQueue){handleMessage(msg)}self.onmessage=handleMessage};Module["wasmModule"]=e.data.wasmModule;for(const handler of e.data.handlers){Module[handler]=(...args)=>{postMessage({cmd:"callHandler",handler:handler,args:args})}}Module["wasmMemory"]=e.data.wasmMemory;Module["buffer"]=Module["wasmMemory"].buffer;Module["ENVIRONMENT_IS_PTHREAD"]=true;if(typeof e.data.urlOrBlob=="string"){importScripts(e.data.urlOrBlob)}else{var objectUrl=URL.createObjectURL(e.data.urlOrBlob);importScripts(objectUrl);URL.revokeObjectURL(objectUrl)}whisper_factory(Module)}else if(e.data.cmd==="run"){Module["__emscripten_thread_init"](e.data.pthread_ptr,0,0,1);Module["__emscripten_thread_mailbox_await"](e.data.pthread_ptr);Module["establishStackSpace"]();Module["PThread"].receiveObjectTransfer(e.data);Module["PThread"].threadInitTLS();if(!initializedJS){Module["__embind_initialize_bindings"]();initializedJS=true}try{Module["invokeEntryPoint"](e.data.start_routine,e.data.arg)}catch(ex){if(ex!="unwind"){throw ex}}}else if(e.data.cmd==="cancel"){if(Module["_pthread_self"]()){Module["__emscripten_thread_exit"](-1)}}else if(e.data.target==="setimmediate"){}else if(e.data.cmd==="checkMailbox"){if(initializedJS){Module["checkMailbox"]()}}else if(e.data.cmd){err(`worker.js received unknown command ${e.data.cmd}`);err(e.data)}}catch(ex){if(Module["__emscripten_thread_crashed"]){Module["__emscripten_thread_crashed"]()}throw ex}}self.onmessage=handleMessage; diff --git a/whisper.cpp-1.5.2/bindings/javascript/package-tmpl.json b/whisper.cpp-1.5.2/bindings/javascript/package-tmpl.json new file mode 100644 index 0000000..d8ba210 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/package-tmpl.json @@ -0,0 +1,26 @@ +{ + "name": "whisper.cpp", + "version": "@PROJECT_VERSION@", + "description": "Whisper speech recognition", + "main": "whisper.js", + "scripts": { + "test": "echo \"todo: add tests\" && exit 0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ggerganov/whisper.cpp" + }, + "keywords": [ + "openai", + "whisper", + "speech-to-text", + "speech-recognition", + "transformer" + ], + "author": "Georgi Gerganov", + "license": "MIT", + "bugs": { + "url": "https://github.com/ggerganov/whisper.cpp/issues" + }, + "homepage": "https://github.com/ggerganov/whisper.cpp#readme" +} diff --git a/whisper.cpp-1.5.2/bindings/javascript/package.json b/whisper.cpp-1.5.2/bindings/javascript/package.json new file mode 100644 index 0000000..2445896 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/package.json @@ -0,0 +1,26 @@ +{ + "name": "whisper.cpp", + "version": "1.5.2", + "description": "Whisper speech recognition", + "main": "whisper.js", + "scripts": { + "test": "echo \"todo: add tests\" && exit 0" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ggerganov/whisper.cpp" + }, + "keywords": [ + "openai", + "whisper", + "speech-to-text", + "speech-recognition", + "transformer" + ], + "author": "Georgi Gerganov", + "license": "MIT", + "bugs": { + "url": "https://github.com/ggerganov/whisper.cpp/issues" + }, + "homepage": "https://github.com/ggerganov/whisper.cpp#readme" +} diff --git a/whisper.cpp-1.5.2/bindings/javascript/whisper.js b/whisper.cpp-1.5.2/bindings/javascript/whisper.js new file mode 100644 index 0000000..77dd855 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/javascript/whisper.js @@ -0,0 +1,19 @@ + +var whisper_factory = (() => { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir = _scriptDir || __filename; + return ( +function(moduleArg = {}) { + +function GROWABLE_HEAP_I8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP8}function GROWABLE_HEAP_U8(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU8}function GROWABLE_HEAP_I16(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP16}function GROWABLE_HEAP_U16(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU16}function GROWABLE_HEAP_I32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAP32}function GROWABLE_HEAP_U32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPU32}function GROWABLE_HEAP_F32(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF32}function GROWABLE_HEAP_F64(){if(wasmMemory.buffer!=HEAP8.buffer){updateMemoryViews()}return HEAPF64}var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var ENVIRONMENT_IS_PTHREAD=Module["ENVIRONMENT_IS_PTHREAD"]||false;var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_NODE){var fs=require("fs");var nodePath=require("path");if(ENVIRONMENT_IS_WORKER){scriptDirectory=nodePath.dirname(scriptDirectory)+"/"}else{scriptDirectory=__dirname+"/"}read_=(filename,binary)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);return fs.readFileSync(filename,binary?undefined:"utf8")};readBinary=filename=>{var ret=read_(filename,true);if(!ret.buffer){ret=new Uint8Array(ret)}return ret};readAsync=(filename,onload,onerror,binary=true)=>{filename=isFileURI(filename)?new URL(filename):nodePath.normalize(filename);fs.readFile(filename,binary?undefined:"utf8",(err,data)=>{if(err)onerror(err);else onload(binary?data.buffer:data)})};if(!Module["thisProgram"]&&process.argv.length>1){thisProgram=process.argv[1].replace(/\\/g,"/")}arguments_=process.argv.slice(2);quit_=(status,toThrow)=>{process.exitCode=status;throw toThrow};Module["inspect"]=()=>"[Emscripten Module object]";let nodeWorkerThreads;try{nodeWorkerThreads=require("worker_threads")}catch(e){console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?');throw e}global.Worker=nodeWorkerThreads.Worker}else if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}if(!ENVIRONMENT_IS_NODE){read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}if(ENVIRONMENT_IS_NODE){if(typeof performance=="undefined"){global.performance=require("perf_hooks").performance}}var defaultPrint=console.log.bind(console);var defaultPrintErr=console.error.bind(console);if(ENVIRONMENT_IS_NODE){defaultPrint=(...args)=>fs.writeSync(1,args.join(" ")+"\n");defaultPrintErr=(...args)=>fs.writeSync(2,args.join(" ")+"\n")}var out=Module["print"]||defaultPrint;var err=Module["printErr"]||defaultPrintErr;Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||true;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var wasmModule;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||16777216;assert(INITIAL_MEMORY>=65536,"INITIAL_MEMORY should be larger than STACK_SIZE, was "+INITIAL_MEMORY+"! (STACK_SIZE="+65536+")");if(ENVIRONMENT_IS_PTHREAD){wasmMemory=Module["wasmMemory"]}else{if(Module["wasmMemory"]){wasmMemory=Module["wasmMemory"]}else{wasmMemory=new WebAssembly.Memory({"initial":INITIAL_MEMORY/65536,"maximum":2147483648/65536,"shared":true});if(!(wasmMemory.buffer instanceof SharedArrayBuffer)){err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag");if(ENVIRONMENT_IS_NODE){err("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and/or recent version)")}throw Error("bad memory")}}}updateMemoryViews();INITIAL_MEMORY=wasmMemory.buffer.byteLength;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(ENVIRONMENT_IS_PTHREAD)return;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function postRun(){if(ENVIRONMENT_IS_PTHREAD)return;if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){if(Module["onAbort"]){Module["onAbort"](what)}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}function isFileURI(filename){return filename.startsWith("file://")}var wasmBinaryFile;wasmBinaryFile="data:application/octet-stream;base64,AGFzbQEAAAAByARKYAF/AX9gAX8AYAJ/fwBgA39/fwF/YAJ/fwF/YAN/f38AYAR/f39/AGAGf39/f39/AX9gBH9/f38Bf2AAAGAFf39/f38Bf2AFf39/f38AYAZ/f39/f38AYAh/f39/f39/fwF/YAABf2AHf39/f39/fwF/YAd/f39/f39/AGABfQF9YAV/fn5+fgBgA39+fwF+YAV/f39/fgF/YAR/f39/AX5gBH9+fn8AYAp/f39/f39/f39/AX9gB39/f39/fn4Bf2AGf39/f35+AX9gBX9/fn9/AGADf39/AXxgBH9/f38BfGAEf39+fgF/YAJ/fgBgAXwBfWACfH8BfGAFf39+fn4Bf2AIf39/f39/f38AYAx/f39/f39/f39/f38Bf2ADf35/AX9gD39/f39/f39/f39/f39/fwBgCn9/f39/f39/f38AYAt/f39/f39/f39/fwF/YAZ/fH9/f38Bf2AJf39/f39/f39/AGAFf39/f3wBf2AAAXxgA39/fgF/YAABfmACf3wAYAN/f30Bf2AEfn5+fgF/YAJ9fQF9YAJ+fwF/YAN/f3wBf2ABfABgCH9/fn5+f39/AX9gBX9/f399AGAGf39+fn9/AX9gAn5+AXxgAnx8AXxgBn9/f39+fgBgBH9/fn4AYAR/f35/AX9gA39/fwF9YAR/f39+AX5gA39/fgBgAn5+AX1gAn9/AX5gA35+fgF/YAF+AX9gAXwBfGABfwF+YAJ9fwF/YAV/f399fQBgBH9/f30AYAl/f39/f39/f38BfwKmAjABYQFiAAkBYQFjAAUBYQFkAAUBYQFlACsBYQFmAAEBYQFnAAsBYQFoABABYQFpAAQBYQFqAAABYQFrAAUBYQFsAAEBYQFtAAEBYQFuAAkBYQFvAAABYQFwAAgBYQFxAAMBYQFyAAIBYQFzAAUBYQF0AAgBYQF1AAABYQF2AAEBYQF3ABsBYQF4AAoBYQF5ABABYQF6AA4BYQFBAA4BYQFCAAoBYQFDAAQBYQFEAAQBYQFFAAABYQFGAAUBYQFHAAgBYQFIABwBYQFJAAEBYQFKAAEBYQFLAAgBYQFMAAMBYQFNAAgBYQFOAAkBYQFPAAEBYQFQAA4BYQFRAAIBYQFSAAYBYQFTAAIBYQFUAAEBYQFVAAYBYQFWAAQBYQFhAgOAAoCAAgOhB58HAQAF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AgQgBSAGGyEGA0ACQAJAAkACQAJAIAQiAigCFCACLQAbIgQgBMBBAEgiBxsiBCAGIAQgBkkiCRsiBQRAIAggAigCECACQRBqIAcbIgcgBRBKIgpFBEAgBCAGSw0CDAMLIApBAE4NAgwBCyAEIAZNDQILIAIhBSACKAIAIgQNBAwFCyAHIAggBRBKIgQNAQsgCQ0BDAQLIARBAE4NAwsgAigCBCIEDQALIAJBBGohBQtBIBAyIgQgAygCACIDKQIANwIQIAQgAygCCDYCGCADQgA3AgAgA0EANgIIIAQgAjYCCCAEQgA3AgAgBEEANgIcIAUgBDYCACAEIQIgASgCACgCACIDBEAgASADNgIAIAUoAgAhAgsgASgCBCACEKQBIAEgASgCCEEBajYCCEEBDAELIAIhBEEACzoABCAAIAQ2AgALBgAgABAvC4cFAgp/AX4jAEFAaiICJAAgAiAALQAIOgA4IAIgACkDADcDMCAAKAIUIQMgACgCECEEIABCADcDECAAKAIYIQUgAEEANgIYIAIgACgCRDYCKCACIAApAjw3AyAgAiAA/QACLP0LAxAgAiAA/QACHP0LAwAgACgCXCEGIAAoAlghByAAQgA3A1ggACgCTCEIIAAoAlAhCSAAKAJUIQogACgCSCELIAD9DAAAAAAAAAAAAAAAAAAAAAD9CwNIIAAgASkDADcDACAAIAEtAAg6AAggACABKAIQNgIQIAAgASgCFDYCFCAAIAEoAhg2AhggACkDYCEMIAFBADYCGCABQgA3AxAgACABKAJENgJEIAAgASkCPDcCPCAAIAH9AAIs/QsCLCAAIAH9AAIc/QsCHCAAQcgAaiABQcgAahCHAiABIAItADg6AAggASACKQMwNwMAIAEoAhAiAARAIAEgADYCFCAAEC8LIAEgBTYCGCABIAM2AhQgASAENgIQIAEgAigCKDYCRCABIAIpAyA3AjwgASAC/QADEP0LAiwgASAC/QADAP0LAhwgASgCSCIEBEAgASgCTCIDIAQiAEcEQANAIANBDGsiACgCACIFBEAgA0EIayAFNgIAIAUQLwsgACIDIARHDQALIAEoAkghAAsgASAENgJMIAAQLwsgASALNgJIIAEgCTYCUCABIAg2AkwgASgCVCIEBEAgASgCWCIDIAQiAEcEQANAIANBDGsiACgCACIFBEAg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//8Ba0GBgH5LDQELIAFQIAJC////////////AIMiC0KAgICAgIDA//8AVCALQoCAgICAgMD//wBRG0UEQCACQoCAgICAgCCEIQoMAgsgA1AgBEL///////////8AgyICQoCAgICAgMD//wBUIAJCgICAgICAwP//AFEbRQRAIARCgICAgICAIIQhCiADIQEMAgsgASALQoCAgICAgMD//wCFhFAEQCACIAOEUARAQoCAgICAgOD//wAhCkIAIQEMAwsgCkKAgICAgIDA//8AhCEKQgAhAQwCCyADIAJCgICAgICAwP//AIWEUARAIAEgC4QhGUIAIQEgGVAEQEKAgICAgIDg//8AIQoMAwsgCkKAgICAgIDA//8AhCEKDAILIAEgC4RQBEBCACEBDAILIAIgA4RQBEBCACEBDAILIAtC////////P1gEQCAFQdAAaiABIA0gASANIA1QIgYbeSAGQQZ0rXynIgZBD2sQZkEQIAZrIQYgBSkDWCINQiCIIQ4gBSkDUCEBCyACQv///////z9WDQAgBUFAayADIAwgAyAMIAxQIggbeSAIQQZ0rXynIghBD2sQZiAGIAhrQRBqIQYgBSkDSCEMIAUpA0AhAwsgA0IPhiILQoCA/v8PgyICIAFCIIgiBH4iECALQiCIIhMgAUL/////D4MiAX58Ig9CIIYiESABIAJ+fCILIBFUrSACIA1C/////w+DIg1+IhUgBCATfnwiESAMQg+GIhIgA0IxiIRC/////w+DIgMgAX58IhQgDyAQVK1CIIYgD0IgiIR8Ig8gAiAOQoCABIQiDH4iFiANIBN+fCIOIBJCIIhCgICAgAiEIgIgAX58IhAgAyAEfnwiEkIghnwiF3whASAHIAlqIAZqQf//AGshBgJAIAIgBH4iGCAMIBN+fCIEIBhUrSAEIAQgAyANfnwiBFatfCACIAx+fCAEIAQgESAVVK0gESAUVq18fCIEVq18IAMgDH4iAyACIA1+fCICIANUrUIghiACQiCIhHwgBCACQiCGfCICIARUrXwgAiACIBAgElatIA4gFlStIA4gEFatfHxCIIYgEkIgiIR8IgJWrXwgAiACIA8gFFStIA8gF1atfHwiAlatfCIEQoCAgICAgMAAg0IAUgRAIAZBAWohBgwBCyALQj+IIRogBEIBhiACQj+IhCEEIAJCAYYgAUI/iIQhAiALQgGGIQsgGiABQgGGhCEBCyAGQf//AU4EQCAKQoCAgICAgMD//wCEIQpCACEBDAELAn4gBkEATARAQQEgBmsiB0H/AE0EQCAFQTBqIAsgASAGQf8AaiIGEGYgBUEgaiACIAQgBhBmIAVBEGogCyABIAcQrwEgBSACIAQgBxCvASAFKQMwIAUpAziEQgBSrSAFKQMgIAUpAxCEhCELIAUpAyggBSkDGIQhASAFKQMAIQIgBSkDCAwCC0IAIQEMAgsgBEL///////8/gyAGrUIwhoQLIAqEIQogC1AgAUIAWSABQoCAgICAgICAgH9RG0UEQCAKIAJCAXwiAVCtfCEKDAELIAsgAUKAgICAgICAgIB/hYRCAFIEQCACIQEMAQsgCiACIAJCAYN8IgEgAlStfCEKCyAAIAE3AwAgACAKNwMIIAVB4ABqJAAL7AEBBn8jAEEgayIBJAAgAUEANgIQIAFB+AE2AgwgASABKQIMNwMAIAFBFGoiAyABKQIANwIEIAMgADYCACMAQRBrIgIkACAA/hACAEF/RwRAAkAgAkEMaiIFIAM2AgAgAkEIaiIEIAU2AgBBkJg1EFYaA0AgACgCAEEBRgRAQaiYNUGQmDUQjgMMAQsLIAAoAgBFBEAgAEEB/hcCAEGQmDUQUhogBBCtA0GQmDUQVhogAEF//hcCAEGQmDUQUhpBqJg1EKYCGgwBC0GQmDUQUhoLCyACQRBqJAAgACgCBCEGIAFBIGokACAGQQFrCwkAQcEdEO4EAAujCgEJfyMAQRBrIgkkACABQQRqQQH+HgIAGiMAQRBrIgMkACADIAE2AgwgCSADKAIMNgIMIANBEGokACACIABBCGoiACgCBCAAKAIAIgNrQQJ1TwRAAkAgAkEBaiIBIAAoAgQiBCADa0ECdSIDSwRAIwBBIGsiCyQAAkAgASADayIGIAAoAgggBGtBAnVNBEAgACAGELEDDAELIABBEGohByALQQxqIQECfyAGIAAoAgQgACgCAGtBAnVqIQUjAEEQayIEJAAgBCAFNgIMIAUgABCYAyIDTQRAIAAoAgggACgCAGtBAnUiBSADQQF2SQRAIAQgBUEBdDYCCCMAQRBrIgMkACAEQQhqIgUoAgAgBEEMaiIIKAIASSEKIANBEGokACAIIAUgChsoAgAhAwsgBEEQaiQAIAMMAQsQNgALIQUgACgCBCAAKAIAa0ECdSEIQQAhAyMAQRBrIgQkACAEQQA2AgwgAUEANgIMIAEgBzYCECAFBH8gBEEEaiABKAIQIAUQlwMgBCgCBCEDIAQoAggFQQALIQUgASADNgIAIAEgAyAIQQJ0aiIHNgIIIAEgBzYCBCABIAMgBUECdGo2AgwgBEEQaiQAIwBBEGsiBCQAIAQgASgCCDYCBCABKAIIIQMgBCABQQhqNgIMIAQgAyAGQQJ0ajYCCCAEKAIEIQMDQCAEKAIIIANHBEAgASgCEBogBCgCBEEANgIAIAQgBCgCBEEEaiIDNgIEDAELCyAEKAIMIAQoAgQ2AgAgBEEQaiQAIwBBEGsiBiQAIAAoAggaIAAoAgAaIAYgACgCBDYCCCAGIAAoAgA2AgQgBiABKAIENgIAIAYoAgghByAGKAIEIQggBigCACEKIwBBEGsiBSQAIwBBIGsiAyQAIwBBEGsiBCQAIAQgBzYCDCAEIAg2AgggAyAEKAIMNgIYIAMgBCgCCDYCHCAEQRBqJAAgAygCGCEHIAMoAhwhCCMAQRBrIgQkACAEIAg2AgggBCAHNgIMIAQgCjYCBANAIAQoAgwiByAEKAIIRwRAIAQoAgRBBGsgB0EEaygCADYCACAEIAQoAgxBBGs2AgwgBCAEKAIEQQRrNgIEDAELCyADIAQoAgw2AhAgAyAEKAIENgIUIARBEGokACADIAMoAhA2AgwgAyADKAIUNgIIIAUgAygCDDYCCCAFIAMoAgg2AgwgA0EgaiQAIAUoAgwhAyAFQRBqJAAgBiADNgIMIAEgBigCDDYCBCAAKAIAIQMgACABKAIENgIAIAEgAzYCBCAAKAIEIQMgACABKAIINgIEIAEgAzYCCCAAKAIIIQMgACABKAIMNgIIIAEgAzYCDCABIAEoAgQ2AgAgACgCBBogACgCABogACgCCBogACgCABogBkEQaiQAIAEoAgQhAwNAIAMgASgCCCIERwRAIAEoAhAaIAEgBEEEazYCCAwBCwsgASgCACIDBEAgASgCECADIAEoAgwgA2tBAnUQlQMLCyALQSBqJAAMAQsgASADSQRAIAAoAgQaIAAoAgAhAyAAIAFBAnQgA2oQlgMgACgCCBogACgCBBogACgCABoLCwsgACgCACACQQJ0aigCACIBBEAgAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALCyAJKAIMIQEgCUEANgIMIAAoAgAgAkECdGogATYCACAJKAIMIQAgCUEANgIMIAAEQCAAQQRqQX/+HgIARQRAIAAgACgCACgCCBEBAAsLIAlBEGokAAv0AgIDfwh+IwBBMGsiAyQAAn8CQAJAIAEpAxAiBiACKQMQIgeBQgBSDQAgASkDGCIIIAIpAxgiCYFCAFINACABKQMgIgogAikDICILgUIAUg0AIAEpAygiDCACKQMoIg2BQgBSDQAgAUEQaiEEAkAgASgCiAENACACKAKIAQ0ADAILAkAgBiAHUg0AIAggCVINACAKIAtSDQBBASEFIAwgDVENAgtBvMMCKAIAEDAaIANBq9cANgIYIANB8Rg2AhQgA0HkJjYCEEG4wwIoAgBBy+QAIANBEGoQMRAAAAtBvMMCKAIAEDAaIANBpdgANgIoIANB6xg2AiQgA0HkJjYCIEG4wwIoAgBBy+QAIANBIGoQMRAAAAsgACABKAIAIAEoAgwgBEEAQQAQSSIEQQI2AkBBACAFRQ0AGiAAIAQoAgAgBCgCDCAEQRBqQQBBABBJCyEAIAQgATYCjAEgBCAANgKIASAEIAI2ApABIANBMGokACAECyUAIAAtAAtBB3YEQCAAIAAoAgAgACgCCEH/////B3EQ4AELIAALNAEBfyMAQRBrIgMkACADIAE2AgwgACADKAIMNgIAIABBBGogAigCADYCACADQRBqJAAgAAumAgEHfyAAKAIIIQUCQAJAIAAoAgAiA0EPcUUEQCAAQQRqIgFBAP5BAgAhAAwBC0E/IQIjAyIEKAIYIAAoAgQiBkH/////A3FHDQECQCADQQNxQQFHDQAgACgCFCIBRQ0AIAAgAUEBazYCFEEADwsgA0GAAXEiAgRAIAQgAEEQajYCVEEAQQH+HgLQ+zQaCyAAQQRqIQEgACgCDCIHIAAoAhAiADYCACAEQcwAaiAARwRAIABBBGsgBzYCAAsgASAGQQF0IANBHXRxQR91Qf////8Hcf5BAgAhACACRQ0AIARBADYCVAJAQQBBf/4eAtD7NEEBRw0AQdT7NCgCAEUNAEHQ+zRB/////wcQtQELC0EAIQIgBUUgAEEATnENACABEI4BCyACC34BBX8jAEEgayICJAAgAkEIaiAAEIMDIgEoAgBBAf4ZAAAjAEEQayIAJAAgAEEMakHjIRCCAyEFIAEoAgQiAS0AACEEIAFBAToAACAFEIEDAkAgBEEEcUUNAEH8mDUQpgJFDQAgAEHjITYCABBGAAsgAEEQaiQAIAJBIGokAAvfAQEGfyMAQSBrIgIkACACQQhqIAAQgwMiACgCAP4SAAAEf0EABQJ/IwBBEGsiAyQAIANBDGpBgiIQggMhBQJAAkAgAC0ADEUNACAAKAIELQAAQQJxRQ0AIAAoAggoAgAgACgCEEYNAQsDQCAAKAIEIgQtAAAiAUECcQRAIAQgAUEEcjoAAEH8mDVB5Jg1EI4DDAELCyABQQFGIgFFBEAgAC0ADARAIAAoAgggACgCEDYCAAsgBEECOgAACyAFEIEDIANBEGokACABDAELEEYAC0EBcwshBiACQSBqJAAgBgs0AQJ/IwBBEGsiBCQAIAQgAzcDCCAEIAI3AwAgACABQQIgBEEAQQAQSSEFIARBEGokACAFC7kCAQd/AkAgAC0AAEEPcQ0AIABBBGpBAEEK/kgCAA0AQQAPCwJ/AkAgACgCACICQQ9xRQRAIABBBGpBAEEK/kgCAEUNASAAKAIAIQILIAAQ9QEiAUEKRw0AIABBCGohBCAAQQRqIQNB5AAhAQNAAkAgAUUNACADKAIARQ0AIAFBAWshASAEKAIARQ0BCwsgABD1ASIBQQpHDQAgAkF/c0GAAXEhBSACQQRxRSEGIAJBA3FBAkchAgNAAkAgAygCACIBQf////8DcSIHIAFBAEcgBnFyRQ0AAkAgAg0AIAcjAygCGEcNAEEQDAQLIARBAf4eAgAaIAMgASABQYCAgIB4ciIB/kgCABogAyABIAUQywIhASAEQQH+JQIAGiABQRtGDQAgAQ0CCyAAEPUBIgFBCkYNAAsLIAELC4wCAgJ/AnwgALwiAUGAgID8A0YEQEMAAAAADwsCQCABQYCAgPwHa0H///+HeE0EQCABQQF0IgJFBEAjAEEQayIBQwAAgL84AgwgASoCDEMAAAAAlQ8LIAFBgICA/AdGDQEgAkGAgIB4SSABQQBOcUUEQCAAIACTIgAgAJUPCyAAQwAAAEuUvEGAgIDcAGshAQtBsKACKwMAIAEgAUGAgMz5A2siAUGAgIB8cWu+uyABQQ92QfABcSICQaieAmorAwCiRAAAAAAAAPC/oCIDIAOiIgSiQbigAisDACADokHAoAIrAwCgoCAEoiABQRd1t0GooAIrAwCiIAJBsJ4CaisDAKAgA6CgtiEACyAAC+4CAgZ/A34jAEFAaiIDJAACQAJAIAEpAxAgAikDEFINACACKQMgIgkgASkDIIFCAFINACACKQMoIgogASkDKIFCAFINACABKAIwIAEoAjRLDQECfwJAIAEoAogBDQAgAigCiAENAEEADAELQQELIQggAyABKQMYNwMgIAIpAxghCyADIAo3AzggAyAJNwMwIAMgCzcDKCAAQQAgASgCDCIEIAIoAgwiByAEIAdKGyADQSBqQQBBABBJIgRBFzYCQCAIBEAgACAEKAIAIAQoAgwgBEEQakEAQQAQSSEFCyAEIAE2AowBIAQgBTYCiAEgBCACNgKQASADQUBrJAAgBA8LQbzDAigCABAwGiADQZTXADYCGCADQecfNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALQbzDAigCABAwGiADQdvXADYCCCADQegfNgIEIANB5CY2AgBBuMMCKAIAQcvkACADEDEQAAALoQICA38BfgJAIAAoAgwiAkEBcQRAQRgQMiECIAAoAiQoAgQhAyACQfysATYCACACIAM2AgQgAkEIaiAAKAIAIgM2AgAgA0EEakEB/h4CABogAiAAKQIEIgU3AgwgAiAFpyIDIAEgAygCACgCFBEEADoAFCAAKAIkIAI2AgQMAQsgAkEIcQRAQRgQMiECIAAoAiQoAgQhAyACQditATYCACACIAM2AgQgAkEIaiAAKAIAIgM2AgAgA0EEakEB/h4CABogACkCBCEFIAIgAToAFCACIAU3AgwgACgCJCACNgIEDAELQQwQMiECIAAoAiQiAygCBCEEIAIgAToACCACQbSuATYCACACIAQ2AgQgAyACNgIECyAAIAAoAiQoAgQ2AiQLdQEBfyMAQRBrIgIkACACIAE6AA8CQCAALQALQQd2BEAgACgCACEBIABBATYCBAwBCyAAIgEgAS0AC0GAAXFBAXI6AAsgASABLQALQf8AcToACwsgASACLQAPOgAAIAJBADoADiABIAItAA46AAEgAkEQaiQAC6sBAgJ+AX8gACkDICEBIAApAxghAiAAKAIAIgNBEGtBcU0EQCADQSRsQZibAWooAgAgACgCMCAAKAIQQQFrbGogACgCNCACp0EBa2xqIAAoAjggAadBAWtsaiAAKAI8IAAoAihBAWtsag8LIAA1AjQgAkIBfX4gACkDECAANQIwfiADQSRsQZSbAWo1AgB/fCAANQI4IAFCAX1+fCAANQI8IAApAyhCAX1+fKcLDQAgACgCABD7AxogAAsNACAAKAIAEP0DGiAACw4AIABB0ABqEDtB0ABqC8EBAQN/IwBBEGsiBSQAAkAgAiAALQALQQd2BH8gACgCCEH/////B3FBAWsFQQoLIgQCfyAALQALQQd2BEAgACgCBAwBCyAALQALQf8AcQsiA2tNBEAgAkUNAQJ/IAAtAAtBB3YEQCAAKAIADAELIAALIgQgA2ogASACEHcgACACIANqIgEQmQEgBUEAOgAPIAEgBGogBS0ADzoAAAwBCyAAIAQgAiAEayADaiADIANBACACIAEQzAELIAVBEGokACAAC3UBAX4gACABIAR+IAIgA358IANCIIgiAiABQiCIIgR+fCADQv////8PgyIDIAFC/////w+DIgF+IgVCIIggAyAEfnwiA0IgiHwgASACfiADQv////8Pg3wiAUIgiHw3AwggACAFQv////8PgyABQiCGhDcDAAsYACAALQAAQSBxRQRAIAEgAiAAEM4CGgsLqwEBBn8jAEEQayICJAAgACgCBCEDIAEgACgCACIEcCIFIQACQAJAA0ACQCADIABBAnRqIgYoAgAiB0UNACABIAdGDQAgAEEBaiIAQQAgACAERxsiACAFRw0BDAILCyAAQX9HDQELQbzDAigCABAwGiACQbUwNgIIIAJBlvEANgIEIAJB5CY2AgBBuMMCKAIAQcvkACACEDEQAAALIAYgATYCACACQRBqJAAgAAtGAQJ/IwBBEGsiBSQAIAUgAjYCDCAFIAQ2AgggBUEEaiAFQQxqEH8hBiAAIAEgAyAFKAIIELABIQAgBhB+IAVBEGokACAAC+0BAQJ/An8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELIQQCQCACIAFrQQVIDQAgBEUNACABIAIQ6gEgAkEEayEEAn8gAC0AC0EHdgRAIAAoAgQMAQsgAC0AC0H/AHELAn8gAC0AC0EHdgRAIAAoAgAMAQsgAAsiAmohBQJAA0ACQCACLAAAIQAgASAETw0AAkAgAEEATA0AIABB/wBODQAgACABKAIARw0DCyABQQRqIQEgAiAFIAJrQQFKaiECDAELCyAAQQBMDQEgAEH/AE4NASACLAAAIAQoAgBBAWtLDQELIANBBDYCAAsLdgEBfyMAQRBrIgIkACAALQALQQd2BEAgACAAKAIAIAAoAghB/////wdxEPEBCyAAIAEoAgg2AgggACABKQIANwIAIAEgAS0AC0GAAXE6AAsgASABLQALQf8AcToACyACQQA6AA8gASACLQAPOgAAIAJBEGokAAtQAQF+AkAgA0HAAHEEQCABIANBQGqthiECQgAhAQwBCyADRQ0AIAIgA60iBIYgAUHAACADa62IhCECIAEgBIYhAQsgACABNwMAIAAgAjcDCAtvAQF/IwBBgAJrIgUkAAJAIAIgA0wNACAEQYDABHENACAFIAFB/wFxIAIgA2siA0GAAiADQYACSSIBGxCgASABRQRAA0AgACAFQYACEGEgA0GAAmsiA0H/AUsNAAsLIAAgBSADEGELIAVBgAJqJAALegEDfwJAAkAgACIBQQNxRQ0AIAEtAABFBEBBAA8LA0AgAUEBaiIBQQNxRQ0BIAEtAAANAAsMAQsDQCABIgJBBGohASACKAIAIgNBf3MgA0GBgoQIa3FBgIGChHhxRQ0ACwNAIAIiAUEBaiECIAEtAAANAAsLIAEgAGsLOAIDfwF+IwBBEGsiACQAIAAQ1wEgACkDACEDIAAoAgghAiAAQRBqJAAgAkHoB22sIANCwIQ9fnwL9gIDA38BfAF9IwBBEGsiASQAAn0gALwiA0H/////B3EiAkHan6T6A00EQEMAAIA/IAJBgICAzANJDQEaIAC7EIQBDAELIAJB0aftgwRNBEAgAkHkl9uABE8EQEQYLURU+yEJQEQYLURU+yEJwCADQQBIGyAAu6AQhAGMDAILIAC7IQQgA0EASARAIAREGC1EVPsh+T+gEIMBDAILRBgtRFT7Ifk/IAShEIMBDAELIAJB1eOIhwRNBEAgAkHg27+FBE8EQEQYLURU+yEZQEQYLURU+yEZwCADQQBIGyAAu6AQhAEMAgsgA0EASARARNIhM3982RLAIAC7oRCDAQwCCyAAu0TSITN/fNkSwKAQgwEMAQsgACAAkyACQYCAgPwHTw0AGgJAAkACQAJAIAAgAUEIahCvBEEDcQ4DAAECAwsgASsDCBCEAQwDCyABKwMImhCDAQwCCyABKwMIEIQBjAwBCyABKwMIEIMBCyEFIAFBEGokACAFC9YBAQJ/IwBBEGsiBCQAAkACQCACQQtJBEAgACIDIAAtAAtBgAFxIAJyOgALIAAgAC0AC0H/AHE6AAsMAQsgAkHv////B0sNASAEQQhqIAAgAkELTwR/IAJBEGpBcHEiAyADQQFrIgMgA0ELRhsFQQoLQQFqEMMBIAQoAgwaIAAgBCgCCCIDNgIAIAAgACgCCEGAgICAeHEgBCgCDEH/////B3FyNgIIIAAgACgCCEGAgICAeHI2AgggACACNgIECyADIAEgAkEBahB3IARBEGokAA8LEE0ACwoAIABBlIo1EHkLBABBAAuJAgEHfyABIAAoAggiAyAAKAIEIgJrQQJ1TQRAIAAgAQR/IAJBACABQQJ0IgD8CwAgACACagUgAgs2AgQPCwJAIAIgACgCACIFa0ECdSIHIAFqIgRBgICAgARJBEBB/////wMgAyAFayIDQQF1IgggBCAEIAhJGyADQfz///8HTxsiAwRAIANBgICAgARPDQIgA0ECdBAyIQYLIAdBAnQgBmoiBEEAIAFBAnQiAfwLACABIARqIQEgAiAFRwRAA0AgBEEEayIEIAJBBGsiAioCADgCACACIAVHDQALCyAAIAYgA0ECdGo2AgggACABNgIEIAAgBDYCACAFBEAgBRAvCw8LEDYACxBHAAstACACRQRAIAAoAgQgASgCBEYPCyAAIAFGBEBBAQ8LIAAoAgQgASgCBBCfAUULUgEBfyABQQFrIgJBEE0EfyACQQJ0QdypA2ooAgAFQcYiCyECIABB6LUDNgIAIABB7LYDNgIAIABBBGogAhCKAyAAIAE2AgggAEGooQM2AgAgAAvHCQIEfwZ+IwBB8ABrIgYkACAEQv///////////wCDIQkCQAJAIAFQIgUgAkL///////////8AgyIKQoCAgICAgMD//wB9QoCAgICAgMCAgH9UIApQG0UEQCADQgBSIAlCgICAgICAwP//AH0iC0KAgICAgIDAgIB/ViALQoCAgICAgMCAgH9RGw0BCyAFIApCgICAgICAwP//AFQgCkKAgICAgIDA//8AURtFBEAgAkKAgICAgIAghCEEIAEhAwwCCyADUCAJQoCAgICAgMD//wBUIAlCgICAgICAwP//AFEbRQRAIARCgICA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Qd/bv4UETQRAIAC7IQQgA0EASARAIARE0iEzf3zZEkCgEIQBIQAMAwsgBETSITN/fNkSwKAQhAGMIQAMAgtEGC1EVPshGUBEGC1EVPshGcAgA0EASBsgALugEIMBIQAMAQsgAkGAgID8B08EQCAAIACTIQAMAQsCQAJAAkACQCAAIAFBCGoQrwRBA3EOAwABAgMLIAErAwgQgwEhAAwDCyABKwMIEIQBIQAMAgsgASsDCJoQgwEhAAwBCyABKwMIEIQBjCEACyABQRBqJAAgAAuPBAEDfyACQYAETwRAIAAgASAC/AoAACAADwsgACACaiEEAkAgACABc0EDcUUEQAJ/IAAgAEEDcUUNABogACACRQ0AGiAAIAEgAEF/cyICIAQgAEEBaiIDIAMgBEkbaiIDIAJBA3EiAiACIANLG0EBaiIC/AoAACABIAJqIQEgACACagshAgJAIARBfHEiA0HAAEkNACACIANBQGoiBUsNAANAIAIgASgCADYCACACIAEoAgQ2AgQgAiABKAIINgIIIAIgASgCDDYCDCACIAEoAhA2AhAgAiABKAIUNgIUIAIgASgCGDYCGCACIAEoAhw2AhwgAiABKAIgNgIgIAIgASgCJDYCJCACIAEoAig2AiggAiABKAIsNgIsIAIgASgCMDYCMCACIAEoAjQ2AjQgAiABKAI4NgI4IAIgASgCPDYCPCABQUBrIQEgAkFAayICIAVNDQALCyACIANPDQEgAiABIAJBf3MgAyACQQRqIgUgAyAFSxtqQXxxQQRqIgP8CgAAIAEgA2ohASACIANqIQIMAQsgBEEESQRAIAAhAgwBCyAAIARBBGsiA0sEQCAAIQIMAQsgACECA0AgAiABLQAAOgAAIAIgAS0AAToAASACIAEtAAI6AAIgAiABLQADOgADIAFBBGohASACQQRqIgIgA00NAAsLIAIgBEkEQCACIAEgBCACa/wKAAALIAALIAAjAEEQayIBJAAgAEIANwIAIABBADYCCCABQRBqJAALugcBCH8jAEHQAGsiBCQAIAQgACkCGDcDSAJAAkACQAJ/IwBBIGsiAiQAIAQoAkwhBiABIAQoAkgiB3AiCCEDAkADQAJAIAYgA0ECdGoiCSgCACIFRQ0AIAEgBUYNACADQQFqIgNBACADIAdHGyIDIAhHDQEMAgsLIANBf0YNAAJAAkAgASAFRgRAQX4hAwwBCyAFDQEgCSABNgIACyACQSBqJAAgAwwCC0G8wwIoAgAQMBogAkG+LzYCGCACQY7xADYCFCACQeQmNgIQQbjDAigCAEHL5AAgAkEQahAxEAAAC0G8wwIoAgAQMBogAkG1MDYCCCACQYfxADYCBCACQeQmNgIAQbjDAigCAEHL5AAgAhAxEAAAC0F+Rg0AIAFBJEEAIAAoAiAiAkEBRhtqKAKMASIDBEAgACADEH0gACgCICECCyABQSBBBCACQQFGG2ooAowBIgMEQCAAIAMQfSAAKAIgIQILIAFBHEEIIAJBAUYbaigCjAEiAwRAIAAgAxB9IAAoAiAhAgsgAUEYQQwgAkEBRhtqKAKMASIDBEAgACADEH0gACgCICECCyABQRRBECACQQFGG2ooAowBIgMEQCAAIAMQfSAAKAIgIQILIAFBEEEUIAJBAUYbaigCjAEiAwRAIAAgAxB9IAAoAiAhAgsgAUEMQRggAkEBRhtqKAKMASIDBEAgACADEH0gACgCICECCyABQQhBHCACQQFGG2ooAowBIgMEQCAAIAMQfSAAKAIgIQILIAFBJEEAIAFBBEEgIAJBAUYbaigCjAEiAwR/IAAgAxB9IAAoAiAFIAILQQFHG2ooAowBIgIEQCAAIAIQfQsCQCABKAJADQAgASgCiAENACAAKAIIIgIgACgCAE4NAiABLQDUAUUEQCAEIAI2AgAgAUHwJSAEEHMaIAAoAgghAgsgACgCFCACQQJ0aiABNgIAIAAgAkEBajYCCAwBCyAAKAIEIgIgACgCAE4NAiABLQDUAUUEQCAEIAI2AiAgAUH4JSAEQSBqEHMaIAAoAgQhAgsgAkECdCIDIAAoAgxqIAE2AgAgACgCECIFBEAgAyAFaiABKAKIATYCAAsgACACQQFqNgIECyAEQdAAaiQADwtBvMMCKAIAEDAaIARBwB42AhggBEGh+QA2AhQgBEHkJjYCEEG4wwIoAgBBy+QAIARBEGoQMRAAAAtBvMMCKAIAEDAaIARB3x42AjggBEGq+QA2AjQgBEHkJjYCMEG4wwIoAgBBy+QAIARBMGoQMRAAAAsSACAAKAIAIgAEQCAAEOEDGgsLEQAgACABKAIAEOEDNgIAIAALRwECfyAAIAE3A3AgACAAKAIsIAAoAgQiA2usNwN4IAAoAgghAgJAIAFQDQAgAiADa6wgAVcNACADIAGnaiECCyAAIAI2AmgLHwAgAEHMAGoiAEEA/kECAEGAgICABHEEQCAAEI4BCwuQAQEEfwJAIwMoAhgiASAAKAJMQf////97cUYNAEEBIQMgAEHMAGoiAkEAIAH+SAIARQ0AIAJBACABQYCAgIAEciIE/kgCACIARQ0AA0AgAEGAgICABHIhAQJAIABBgICAgARxRQRAIAAgAiAAIAH+SAIARw0BCyACIAEQrQQLIAJBACAE/kgCACIADQALCyADC0sBAnwgACAAoiIBIACiIgIgASABoqIgAUSnRjuMh83GPqJEdOfK4vkAKr+goiACIAFEsvtuiRARgT+iRHesy1RVVcW/oKIgAKCgtgtPAQF8IAAgAKIiACAAIACiIgGiIABEaVDu4EKT+T6iRCceD+iHwFa/oKIgAURCOgXhU1WlP6IgAESBXgz9///fv6JEAAAAAAAA8D+goKC2CwQAIAALkgQBB38jAEEgayIDJAAgACgCACIGRQRAIAAoAhQhCCADIAApAgQ3AxggCCADQRhqIAEQYkECdGooAgAhBgsCQCABKALQAQ0AIAEoAsgBBEAgACABQQEQeAwBCwJAAkAgASgCQEECaw48AAABAAAAAAAAAQEBAQEBAQEBAAEBAQEBAAEBAQEBAQEBAQEAAAABAAEBAQEBAQEBAQEBAQEBAQEBAQEAAQsDQCABIAdBAnRqKAKMASICRQ0BAkAgAigCCCAGKAIARw0AIAMgACkCBDcDECADQRBqIAIQYiEFIAIoAtABRQ0AIAAoAgwgBUEDdGoiBCgCAEEBRw0AIAQoAgQNACABKAIAIAIoAgBHDQAgASkDECACKQMQUg0AIAEoAjAgAigCMEcNACABKQMYIAIpAxhSDQAgASgCNCACKAI0Rw0AIAEpAyAgAikDIFINACABKAI4IAIoAjhHDQAgASkDKCACKQMoUg0AIAEoAjwgAigCPEcNACACKALIASIFBEAgAyAAKQIENwMIIANBCGogBRBiIQQgACgCDCAEQQN0aiIEKAIEQQFHDQEgBCgCAA0BIAUoAtABIAIoAtABRw0BIAEgBTYCyAEgBEECNgIEIAAgAUEAEHgMBAsgASACNgLIASAEQQE2AgQgACABQQAQeAwDCyAHQQFqIgdBCkcNAAsLIAYgARDpBAsgA0EgaiQAC4YDAQd/An8jAEFAaiIEJAAgASkDKCABKQMgIAEpAxggASkDEH5+fiACKQMoIAIpAyAgAikDGCACKQMQfn5+UQRAIAJBEGohAwJ/IAEoAogBRQRAQQAgAigCiAFFDQEaC0EBCyEJIAAgAigCACACKAIMIAMgAkEAEEkhCCAEIAJB1AFqIgc2AiAgCEHJywAgBEEgahBzIgMgAigCMDYCMCADIAIoAjQ2AjQgAyACKAI4NgI4IAMgAigCPDYCPCABQdQBaiEFAkAgAi0A1AEEQCAEIAU2AhQgBCAHNgIQIANB0NMAIARBEGoQcxoMAQsgBCAFNgIAIANBv8sAIAQQcxoLIANBHDYCQEEAIQUgCQRAIAAgAygCACADKAIMIANBEGpBAEEAEEkhBQsgAyABNgKMASADIAU2AogBIAMgAjYCkAEgBEFAayQAIAMMAQtBvMMCKAIAEDAaIARB29YANgI4IARByyE2AjQgBEHkJjYCMEG4wwIoAgBBy+QAIARBMGoQMRAAAAsLdgEBfyMAQRBrIgIkACAALQALQQd2BEAgACAAKAIAIAAoAghB/////wdxEOABCyAAIAEoAgg2AgggACABKQIANwIAIAEgAS0AC0GAAXE6AAsgASABLQALQf8AcToACyACQQA2AgwgASACKAIMNgIAIAJBEGokAAuyAgEEfyMAQRBrIgckACAHIAE2AgxBACEBQQYhBQJAAkAgACAHQQxqEEINAEEEIQUgA0HAAAJ/IAAoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgoAgALIgYgAygCACgCDBEDAEUNACADIAZBACADKAIAKAI0EQMAIQEDQAJAIAAQXBogAUEwayEBIAAgB0EMahBCDQAgBEECSA0AIANBwAACfyAAKAIAIgUoAgwiBiAFKAIQRgRAIAUgBSgCACgCJBEAAAwBCyAGKAIACyIFIAMoAgAoAgwRAwBFDQMgBEEBayEEIAMgBUEAIAMoAgAoAjQRAwAgAUEKbGohAQwBCwtBAiEFIAAgB0EMahBCRQ0BCyACIAIoAgAgBXI2AgALIAdBEGokACABC9gCAQR/IwBBEGsiByQAIAcgATYCDEEAIQFBBiEFAkACQCAAIAdBDGoQQw0AQQQhBQJ/IAAoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgtAAALwCIGQQBOBH8gAygCCCAGQf8BcUECdGooAgBBwABxQQBHBUEAC0UNACADIAZBACADKAIAKAIkEQMAIQEDQAJAIAAQXRogAUEwayEBIAAgB0EMahBDDQAgBEECSA0AAn8gACgCACIFKAIMIgYgBSgCEEYEQCAFIAUoAgAoAiQRAAAMAQsgBi0AAAvAIgVBAE4EfyADKAIIIAVB/wFxQQJ0aigCAEHAAHFBAEcFQQALRQ0DIARBAWshBCADIAVBACADKAIAKAIkEQMAIAFBCmxqIQEMAQsLQQIhBSAAIAdBDGoQQ0UNAQsgAiACKAIAIAVyNgIACyAHQRBqJAAgAQuZAQEEfyMAQRBrIgQkACAEIAE2AgwgBCADNgIIIARBBGogBEEMahB/IQcgBCgCCCEDIwBBEGsiASQAIAEgAzYCDCABIAM2AghBfyEFAkBBAEEAIAIgAxCwASIDQQBIDQAgACADQQFqIgMQOyIANgIAIABFDQAgACADIAIgASgCDBCwASEFCyABQRBqJAAgBxB+IARBEGokACAFCy4AAkAgACgCBEHKAHEiAARAIABBwABGBEBBCA8LIABBCEcNAUEQDwtBAA8LQQoL+QECA34CfyMAQRBrIgUkAAJ+IAG9IgNC////////////AIMiAkKAgICAgICACH1C/////////+//AFgEQCACQjyGIQQgAkIEiEKAgICAgICAgDx8DAELIAJCgICAgICAgPj/AFoEQCADQjyGIQQgA0IEiEKAgICAgIDA//8AhAwBCyACUARAQgAMAQsgBSACQgAgA6dnQSBqIAJCIIinZyACQoCAgIAQVBsiBkExahBmIAUpAwAhBCAFKQMIQoCAgICAgMAAhUGM+AAgBmutQjCGhAshAiAAIAQ3AwAgACACIANCgICAgICAgICAf4OENwMIIAVBEGokAAsJACAAQQEQtQELKAEBfyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwsMACAAKAIAIAEQ6QQLbAECfyAAKAIEIgEEQCABKAIIIgIEQCACEC8LIAEoAgwiAgRAIAIQLwsgASgCFCICBEAgAhAvCyABKAIYIgIEQCACEC8LIAEQLwsgACgCACIBBEAgAS0ABARAIAEoAgAQpwELIAEQLwsgABAvC40F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AgsgACAINgIcIAAgCTYCGCAAIAU2AhQgAkUNASACEC8PCyAAKAIcIQMgACgCGCECAkAgAC0AWgRAIAIgA0kNBSACIAAoAhQiBmsiB0EBaiIFQQBIDQQgB0H/////ByADIAZrIgNBAXQiBCAFIAQgBUsbIANB/////wNPGyIEBH8gBBAyBUEACyIFaiIDIAE6AAAgBCAFaiEIIANBAWohCQJAIAIgBkYEQCADIQUMAQsCQAJAIAdBEEkNACAGIAIgBWprIAJqQRBJDQAgA0EQayEKIAJBEGshCyACIAdBcHEiBGshAiADIARrIQNBACEBA0AgCiABayALIAFr/QAAAP0LAAAgAUEQaiIBIARHDQALIAQgB0YNAQsgBkF/cyACaiENIAIgBmtBA3EiBARAQQAhAQNAIANBAWsiAyACQQFrIgItAAA6AAAgAUEBaiIBIARHDQALCyANQQNJDQADQCADQQFrIAJBAWstAAA6AAAgA0ECayACQQJrLQAAOgAAIANBA2sgAkEDay0AADoAACADQQRrIgMgAkEEayICLQAAOgAAIAIgBkcNAAsLIAAoAhQhAgsgACAINgIcIAAgCTYCGCAAIAU2AhQgAg0BDAILIAIgA0cNBCACIAAoAhQiB2siBkEBaiIDQQBIDQMgBkH/////ByAGQQF0IgUgAyADIAVJGyAGQf////8DTxsiBAR/IAQQMgVBAAsiBWoiAyABOgAAIAQgBWohCCADQQFqIQkCQCACIAdGBEAgAyEFDAELAkACQCAGQRBJDQAgByACIAVqayACakEQSQ0AIANBEGshCiACQRBrIQsgAiAGQXBxIgRrIQIgAyAEayEDQQAhAQNAIAogAWsgCyABa/0AAAD9CwAAIAFBEGoiASAERw0ACyAEIAZGDQELIAdBf3MgAmohDiACIAdrQQNxIgQEQEEAIQEDQCADQQFrIgMgAkEBayICLQAAOgAAIAFBAWoiASAERw0ACwsgDkEDSQ0AA0AgA0EBayACQQFrLQAAOgAAIANBAmsgAkECay0AADoAACADQQNrIAJBA2stAAA6AAAgA0EEayIDIAJBBGsiAi0AADoAACACIAdHDQALCyAAKAIUIQILIAAgCDYCHCAAIAk2AhggACAFNgIUIAJFDQELIAIQLwsPCxA2AAsQNgALIAIgAToAACAAIAJBAWo2AhgLlAQBBH8gASAAIAFGIgI6AAwCQCACDQADQCABKAIIIgItAAwNAQJAIAIgAigCCCIDKAIAIgRGBEACQCADKAIEIgRFDQAgBC0ADA0ADAILAkAgASACKAIARgRAIAIhAQwBCyACIAIoAgQiASgCACIANgIEIAEgAAR/IAAgAjYCCCACKAIIBSADCzYCCCACKAIIIgAgACgCACACR0ECdGogATYCACABIAI2AgAgAiABNgIIIAEoAggiAygCACECCyABQQE6AAwgA0EAOgAMIAMgAigCBCIANgIAIAAEQCAAIAM2AggLIAIgAygCCDYCCCADKAIIIgAgACgCACADR0ECdGogAjYCACACIAM2AgQgAyACNgIIDwsCQCAERQ0AIAQtAAwNAAwBCwJAIAEgAigCAEcEQCACIQEMAQsgAiABKAIEIgA2AgAgASAABH8gACACNgIIIAIoAggFIAMLNgIIIAIoAggiACAAKAIAIAJHQQJ0aiABNgIAIAEgAjYCBCACIAE2AgggASgCCCEDCyABQQE6AAwgA0EAOgAMIAMgAygCBCIAKAIAIgE2AgQgAQRAIAEgAzYCCAsgACADKAIINgIIIAMoAggiASABKAIAIANHQQJ0aiAANgIAIAAgAzYCACADIAA2AggMAgsgBEEMaiEFIAJBAToADCADIAAgA0Y6AAwgBUEBOgAAIAMiASAARw0ACwsLnAIBBH8gACgCiAEiAQRAIAAgATYCjAEgARAvCyAAKAJ8IgEEQCAAIAE2AoABIAEQLwsgACgCcCIBBEAgACABNgJ0IAEQLwsgACgCZCIBBEAgACABNgJoIAEQLwsgACgCRCIDBEAgAyECIAMgACgCSCIBRwRAA0AgAUEMayICKAIAIgQEQCABQQhrIAQ2AgAgBBAvCyACIgEgA0cNAAsgACgCRCECCyAAIAM2AkggAhAvCyAAKAI4IgMEQCADIQIgAyAAKAI8IgFHBEADQCABQQxrIgIoAgAiBARAIAFBCGsgBDYCACAEEC8LIAIiASADRw0ACyAAKAI4IQILIAAgAzYCPCACEC8LIAAoAgAiAQRAIAAgATYCBCABEC8LC3ABA38gARBoIgJB8P///wdJBEACQCACQQpNBEAgACACOgALIAAhAwwBCyACQQ9yQQFqIgQQMiEDIAAgBEGAgICAeHI2AgggACADNgIAIAAgAjYCBAsgAyABIAL8CgAAIAIgA2pBADoAACAADwsQTQALHgEBfyAABEAgACgCACIBBEAgACABEQEACyAAEC8LC3sBAn8jAEEQayICJAAgACgCBCEDIAAgARB9AkAgAyAAKAIEIgNODQAgACgCDCADQQJ0akEEaygCACABRg0AQbzDAigCABAwGiACQekTNgIIIAJByPkANgIEIAJB5CY2AgBBuMMCKAIAQcvkACACEDEQAAALIAJBEGokAAsTACABQQF0QdCqA2pBAiAAEIEEC84BAQF/An8jAEEwayIDJAAgASgCiAFFBEAgACABKAIAIAEoAgwgAUEQakEAQQAQSSIARQRAQbzDAigCABAwGiADQdcvNgIYIANBxhQ2AhQgA0HkJjYCEEG4wwIoAgBBy+QAIANBEGoQMRAAAAsgACABNgKMASAAQQA2AogBIABBEzYCQCAAIAI4AkQgA0EwaiQAIAAMAQtBvMMCKAIAEDAaIANBmyE2AiggA0HcHjYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxEAAACwv0AgIDfwh+IwBBMGsiAyQAAn8CQAJAIAEpAxAiBiACKQMQIgeBQgBSDQAgASkDGCIIIAIpAxgiCYFCAFINACABKQMgIgogAikDICILgUIAUg0AIAEpAygiDCACKQMoIg2BQgBSDQAgAUEQaiEEAkAgASgCiAENACACKAKIAQ0ADAILAkAgBiAHUg0AIAggCVINACAKIAtSDQBBASEFIAwgDVENAgtBvMMCKAIAEDAaIANBq9cANgIYIANByBo2AhQgA0HkJjYCEEG4wwIoAgBBy+QAIANBEGoQMRAAAAtBvMMCKAIAEDAaIANBpdgANgIoIANBwho2AiQgA0HkJjYCIEG4wwIoAgBBy+QAIANBIGoQMRAAAAsgACABKAIAIAEoAgwgBEEAQQAQSSIEQQY2AkBBACAFRQ0AGiAAIAQoAgAgBCgCDCAEQRBqQQBBABBJCyEAIAQgATYCjAEgBCAANgKIASAEIAI2ApABIANBMGokACAEC3YBAX8jAEEQayICJAAgAiAANgIMAkAgACABRg0AA0AgAiABQQFrIgE2AgggACABTw0BIAIoAgwiAC0AACEBIAAgAigCCCIALQAAOgAAIAAgAToAACACIAIoAgxBAWoiADYCDCACKAIIIQEMAAsACyACQRBqJAAL2wgBAX9BAEEB/h4CkNY0QQBKBEADQEEAQQH+JQKQ1jQaEAMQ1gFBAEEB/h4CkNY0QQBKDQALCwJAAkAgAEHguwNGDQAgAEGUvANGBEBBASEBDAELIABByLwDRgRAQQIhAQwBCyAAQfy8A0YEQEEDIQEMAQsgAEGwvQNGBEBBBCEBDAELIABB5L0DRgRAQQUhAQwBCyAAQZi+A0YEQEEGIQEMAQsgAEHMvgNGBEBBByEBDAELIABBgL8DRgRAQQghAQwBCyAAQbS/A0YEQEEJIQEMAQsgAEHovwNGBEBBCiEBDAELIABBnMADRgRAQQshAQwBCyAAQdDAA0YEQEEMIQEMAQsgAEGEwQNGBEBBDSEBDAELIABBuMEDRgRAQQ4hAQwBCyAAQezBA0YEQEEPIQEMAQsgAEGgwgNGBEBBECEBDAELIABB1MIDRgRAQREhAQwBCyAAQYjDA0YEQEESIQEMAQsgAEG8wwNGBEBBEyEBDAELIABB8MMDRgRAQRQhAQwBCyAAQaTEA0YEQEEVIQEMAQsgAEHYxANGBEBBFiEBDAELIABBjMUDRgRAQRchAQwBCyAAQcDFA0YEQEEYIQEMAQsgAEH0xQNGBEBBGSEBDAELIABBqMYDRgRAQRohAQwBCyAAQdzGA0YEQEEbIQEMAQsgAEGQxwNGBEBBHCEBDAELIABBxMcDRgRAQR0hAQwBCyAAQfjHA0YEQEEeIQEMAQsgAEGsyANGBEBBHyEBDAELIABB4MgDRgRAQSAhAQwBCyAAQZTJA0YEQEEhIQEMAQsgAEHIyQNGBEBBIiEBDAELIABB/MkDRgRAQSMhAQwBCyAAQbDKA0YEQEEkIQEMAQsgAEHkygNGBEBBJSEBDAELIABBmMsDRgRAQSYhAQwBCyAAQczLA0YEQEEnIQEMAQsgAEGAzANGBEBBKCEBDAELIABBtMwDRgRAQSkhAQwBCyAAQejMA0YEQEEqIQEMAQsgAEGczQNGBEBBKyEBDAELIABB0M0DRgRAQSwhAQwBCyAAQYTOA0YEQEEtIQEMAQsgAEG4zgNGBEBBLiEBDAELIABB7M4DRgRAQS8hAQwBCyAAQaDPA0YEQEEwIQEMAQsgAEHUzwNGBEBBMSEBDAELIABBiNADRgRAQTIhAQwBCyAAQbzQA0YEQEEzIQEMAQsgAEHw0ANGBEBBNCEBDAELIABBpNEDRgRAQTUhAQwBCyAAQdjRA0YEQEE2IQEMAQsgAEGM0gNGBEBBNyEBDAELIABBwNIDRgRAQTghAQwBCyAAQfTSA0YEQEE5IQEMAQsgAEGo0wNGBEBBOiEBDAELIABB3NMDRgRAQTshAQwBCyAAQZDUA0YEQEE8IQEMAQsgAEHE1ANGBEBBPSEBDAELIABB+NQDRgRAQT4hAQwBCyAAQazVA0cNAUE/IQELIAFBNGxB3LsDakEAOgAAIAAtAAhFDQAgACgCBBAvC0EAQQH+JQKQ1jQaC9sBAgF/An5BASEEAkAgAEIAUiABQv///////////wCDIgVCgICAgICAwP//AFYgBUKAgICAgIDA//8AURsNACACQgBSIANC////////////AIMiBkKAgICAgIDA//8AViAGQoCAgICAgMD//wBRGw0AIAAgAoQgBSAGhIRQBEBBAA8LIAEgA4NCAFkEQEF/IQQgACACVCABIANTIAEgA1EbDQEgACAChSABIAOFhEIAUg8LQX8hBCAAIAJWIAEgA1UgASADURsNACAAIAKFIAEgA4WEQgBSIQQLIAQLUAEBfgJAIANBwABxBEAgAiADQUBqrYghAUIAIQIMAQsgA0UNACACQcAAIANrrYYgASADrSIEiIQhASACIASIIQILIAAgATcDACAAIAI3AwgLqQEBA38jAEGgAWsiBCQAIAQgACAEQZ4BaiABGyIFNgKUAUF/IQAgBCABQQFrIgZBACABIAZPGzYCmAEgBEEAQZAB/AsAIARBfzYCTCAEQc8BNgIkIARBfzYCUCAEIARBnwFqNgIsIAQgBEGUAWo2AlQCQCABQQBIBEAjA0EcakE9NgIADAELIAVBADoAACAEIAIgA0HNAUHOARDDAiEACyAEQaABaiQAIAALqAEAAkAgAUGACE4EQCAARAAAAAAAAOB/oiEAIAFB/w9JBEAgAUH/B2shAQwCCyAARAAAAAAAAOB/oiEAQf0XIAEgAUH9F04bQf4PayEBDAELIAFBgXhKDQAgAEQAAAAAAABgA6IhACABQbhwSwRAIAFByQdqIQEMAQsgAEQAAAAAAABgA6IhAEHwaCABIAFB8GhMG0GSD2ohAQsgACABQf8Haq1CNIa/ogswAQF/IAEjAyICKAJIIABBAnRqIgAoAgBHBEAgACAB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NEHA1zQoAgBBAWo2AgBBAQs6AAQgACABNgIAIAVBEGokAAuIAQEDf0GcEBA7IQEgABDoBCEDIAEgACgCHCICIAIoAgQRAAAiAjYCDCABIAM2AgggAUEANgIEIAEgADYCACABQRxqQQBBgBD8CwAgAUEBNgIQIAEgAyACIAMgAnBrIAJwIgJqNgIUIAEgACgCJCACazYCGEEIEDsiABCCBDYCBCAAIAE2AgAgAAuTwwcF1gF/On4gewZ9BHwjAEFAaiIuJAACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCAABEACQCABKAJAIgJFDQACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAJBAWsOSEMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobRERERBwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ2NzU4OTo7PD0+P0BBQkQLIAEoAowBIQUgASgCkAEhAyMAQYADayIEJAACQAJAIAUoAgAiAkEOSw0AAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkBBASACdEHM+wFxRQRAAkACQAJAIAIEQCACQQFHDRggAygCAA4CAgEDCyAFKQMQItkBINkBIAMpAxAi2gF/It0BINoBflINBSAFKQMYItsBIAMpAxgi3gGBQgBSDQUgBSkDICLYASADKQMgIt8BgUIAUg0FIAUpAygi4AEgAykDKCLhAYFCAFINBSDZASABKQMQUg0FINsBIAEpAxhSDQUg2AEgASkDIFINBSDgASABKQMoUg0FAkAgACgCAA4DBQAFAAsgASgCMEEERw0GIAUoAjBBBEcNByABKAI8IQkgASgCOCEKIAEoAjQhCCADKAI8IQsgAygCOCEMIAMoAjQhDSAFKAI8IQ8gBSgCOCEOIAUoAjQhECDgASDYASDbAX4i3AF+pyICIAAoAggiB2pBAWsgB20iByAAKAIEbCIAIAdqIgcgAiACIAdKGyEHIAMoAjAiAkEERwRAIAAgB04N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y+QAIANBgAJqEDEMTgtBvMMCKAIAEDAaIANBycAANgKYAiADQevMADYClAIgA0HkJjYCkAJBuMMCKAIAQcvkACADQZACahAxDE0LQbzDAigCABAwGiADQb3AADYCGCADQbrOADYCFCADQeQmNgIQQbjDAigCAEHL5AAgA0EQahAxDEwLQbzDAigCABAwGiADQcnAADYCKCADQbnOADYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxDEsLQbzDAigCABAwGiADQd3QADYCOCADQbTOADYCNCADQeQmNgIwQbjDAigCAEHL5AAgA0EwahAxDEoLQbzDAigCABAwGiADQdfUADYCSCADQbHOADYCRCADQeQmNgJAQbjDAigCAEHL5AAgA0FAaxAxDEkLQbzDAigCABAwGiADQcg6NgJYIANBrs4ANgJUIANB5CY2AlBBuMMCKAIAQcvkACADQdAAahAxDEgLQbzDAigCABAwGiADQfE8NgJoIANBrc4ANgJkIANB5CY2AmBBuMMCKAIAQcvkACADQeAAahAxDEcLQbzDAigCABAwGiADQdQ6NgJ4IANBrM4ANgJ0IANB5CY2AnBBuMMCKAIAQcvkACADQfAAahAxDEYLQbzDAigCABAwGiADQf08NgKIASADQavOADYChAEgA0HkJjYCgAFBuMMCKAIAQcvkACADQYABahAxDEULINgBINsBfiDiAX4g2gF+pyIAQQBMDQELIAQoAtABQQAgAEECdPwLAAsgA0GgCGokAAwBC0G8wwIoAgAQMBogA0GbITYCCCADQafPADYCBCADQeQmNgIAQbjDAigCAEHL5AAgAxAxDEELDCwLIAEoAowBIQcgASgCkAEhBCABIQIjAEHQAGsiBSQAAkACQCAHKAIARQRAAkAgBygCMEEERw0AIAcoAjQiDK0i2QEgBykDECLYAUIChlINACAHNQI4ItsBINkBIAcpAxgi2gF+Ug0AIAc1Ajwg2wEgBykDICLZAX5SDQACQCABKAIwIgEgAigCAEEkbCIDQZibAWooAgBHDQAgAigCNCIIrSLbASACKQMQItwBIAGtfiADQZSbAWo0AgB/Ug0AIAI1Ajgi3QEg2wEgAikDGCLeAX5SDQAgAjUCPCDdASACKQMgItsBflINAAJAINgBINwBUg0AINoBIN4BUg0AINkBINsBUg0AIAcpAygi2wEgAikDKFINAAJAIAQpAxBCAVINACAEKQMYQgFSDQAgBCkDIEIBUg0AIAQpAyhCAVINAAJAIAAoAgAOAwcABwALINkBINoBfiDbAX6nIgEgACgCCCIDakEBayADbSIGIAAoAgRsIgMgBmoiACABIAAgAUgbIgsgA0wNBiDYAaciBkECdCENIAQoAtABKgIAIrIC/RMhkgIgBkFwcSIBQQBMDQUgASAGQQ9xIg4gBkEDcSIQayIRaiEEIAFBAWsiEkEEdkEBaiIAQf7///8BcSETIABBAXEhFgNAIAMgCGwhACACKALQASIJIAcoAtABIgpHBH8gACAJaiAKIAMgDGxqIA38CgAAIAIoAtABBSAJCyAAaiEKQQAhCUEAIQ8gEkEPRwRAA0AgCiAJQQJ0IhVqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwIAogFUHAAHJqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwIAlBIGohCSAPQQJqIg8gE0cNAAsLIBYEQCAKIAlBAnRqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwCwJAIAEgBk4NAEEAIQkgASEAIA5BBE8EQANAIAogASAJakECdGoiACCSAiAA/QACAP3mAf0LAgAgCUEEaiIJIBFHDQALIAQhACAQRQ0BCwNAIAogAEECdGoiCSCyAiAJKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwGC0G8wwIoAgAQMBogBUHU2AA2AgggBUG2zwA2AgQMOgtBvMMCKAIAEDAaIAVBuc8ANgIYIAVBtc8ANgIUDD4LQbzDAigCABAwGiAFQfTLADYCKCAFQbTPADYCJAw+C0G8wwIoAgAQMBogBUHf2QA2AjggBUGzzwA2AjQgBUHkJjYCMEG4wwIoAgBBy+QAIAVBMGoQMQxCC0G8wwIoAgAQMBogBUGbITYCSCAFQeXPADYCRCAFQeQmNgJAQbjDAigCAEHL5AAgBUFAaxAxDEELIAcoAtABIQQgAigC0AEhCSABIAZIBEAgBkEPcSEAIAQgCUcEQCABIAAgBkEDcSIOayIQaiEEIABBBEkhEQNAIAMgCGwhACAHKALQASIKIAlHBEAgACAJaiAKIAMgDGxqIA38CgAAIAIoAtABIQkLIAAgCWohD0EAIQogASEAAkAgEUUEQANAIA8gASAKakECdGoiACCSAiAA/QACAP3mAf0LAgAgCkEEaiIKIBBHDQALIAQhACAORQ0BCwNAIA8gAEECdGoiCiCyAiAKKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwCCyABIAAgBkEDcSIHayIMaiECIABBBEkhDQNAIAkgAyAIbGohBEEAIQogASEAAkAgDUUEQANAIAQgASAKakECdGoiACCSAiAA/QACAP3mAf0LAgAgCkEEaiIKIAxHDQALIAIhACAHRQ0BCwNAIAQgAEECdGoiCiCyAiAKKgIAlDgCACAAQQFqIgAgBkcNAAsLIANBAWoiAyALRw0ACwwBCyAEIAlGDQAgA0EBaiG2ASALIANrQQFxBEAgAigC0AEiASAHKALQASIERwRAIAEgAyAIbGogBCADIAxsaiAN/AoAAAsgA0EBaiEDCyC2ASALRg0AA0AgAigC0AEiACAHKALQASIBRwRAIAAgAyAIbGogASADIAxsaiAN/AoAAAsgAigC0AEiACAHKALQASIBRwRAIAAgA0EBaiIEIAhsaiABIAQgDGxqIA38CgAACyADQQJqIgMgC0cNAAsLIAVB0ABqJAAMKwsgASgCjAEhAiABKAKQASEDIwBB0ABrIgQkAAJAAkACQAJAAkAgAigCAEUEQCACKQMQItkBIAEpAxBSDQEgAikDGCLYASABKQMYUg0BIAIpAyAi2gEgASkDIFINASACKQMoItsBIAEpAyhSDQEgASgCMCIFIAEoAgAiC0EkbCIHQZibAWooAgBHDQIgASgCNCIMrSLcASDZASAFrX4i3gEgB0GUmwFqKAIAIg2sf1INAiABKAI4Ig+tIt0BINgBINwBflINAiABKAI8Ig6tIt8BINoBIN0BflINAiACKAIwQQRHDQIgAjUCNCLgASDZAUIChlINAiACNQI4IuEBINgBIOABflINAiACNQI8INoBIOEBflINAiABKAJQIQYgASgCTCEJIAEoAkghCiABKAJEIQgCQCABKAJURQRAIAAoAgAiBw0BIAEoAtABIAIoAtABIAtBEGtBcU0EfyAMINgBp0EBa2wgBSDZAadsaiAPINoBp0EBa2xqIA4g2wGnQQFrbGoFINoBQgF9IN0BfiDYAUIBfSDcAX58INsBQgF9IN8Bfnwg3gEgDa1/fKcL/AoAAAsgACgCACEHCwJAAkAgBw4DAQABAAsgCCADKQMYItgBQgF9ItoBQgAg2AEg2gFaG6dsIAZqIAogAykDICLaAUIBfSLZAUIAINkBINoBWBunbGogCSADKQMoItkBQgF9ItsBQgAg2QEg2wFaG6dsaiACKAIAQSRsQZibAWooAgAgAykDECLbAUIBfSLcAUIAINsBINwBWhunbGohBSADKAI8IQ0gAygCOCEPIAMoAjQhDiABKQMoIdwBIAEpAxAh3QEgASkDICHeASABKQMYId8BIAMoAjAhtwEgACgCCCECIAAoAgQhCwJ/IAEoAgAiAEEQa0FxTQRAIABBJGxBmJsBaigCACABKAIwIN0Bp0EBa2xqIAEoAjQg3wGnQQFrbGogASgCOCDeAadBAWtsaiABKAI8INwBp0EBa2xqDAELIAE1AjQg3wFCAX1+IN0BIAE1AjB+IABBJGxBlJsBajUCAH98IAE1Ajgg3gFCAX1+fCABNQI8INwBQgF9fnynCyAFSQ0EILcBQQRHDQUgAiDZASDYASDaAX4i3AF+pyIAakEBayACbSICIAtsIgcgAiAHaiICIAAgACACShsiAE4NACDbAaciBUEATA0AIAMoAtABIQsgBUEDcSEMIAVBfHEhAiAGIAEoAtABIhBqIREgAKwh2QEgB6wh2gEgBUEQSSESA0AgCyANINoBINwBfyLbAaciAGwiE2ogDyDaASDbAcQg3AF+fSLbASDYAX8i3QGnIgNsIhZqIA4g2wEg2AEg3QF+faciB2wiFWohASAHIAhsIhggAyAKbCIaIBAgACAJbCIZampqIAZqIQNBACEHQQAhAAJAAkAgEg0AIBEgGGogGWogGmogCyAVaiATaiAWamtBEEkNAANAIAMgAEECdCITaiABIBNq/QACAP0LAgAgAEEEaiIAIAJHDQALIAIiACAFRg0BCyAAQX9zIAVqIbgBIAwEQANAIAMgAEECdCIWaiABIBZqKgIAOAIAIABBAWohACAHQQFqIgcgDEcNAAsLILgBQQNJDQADQCADIABBAnQiB2ogASAHaioCADgCACADIAdBBGoiE2ogASATaioCADgCACADIAdBCGoiE2ogASATaioCADgCACADIAdBDGoiB2ogASAHaioCADgCACAAQQRqIgAgBUcNAAsLINoBQgF8ItoBINkBUg0ACwsgBEHQAGokAAwFC0G8wwIoAgAQMBogBEGbITYCSCAEQcvQADYCRAw/C0G8wwIoAgAQMBogBEG5zwA2AjggBEHxzwA2AjQMPwtBvMMCKAIAEDAaIARBxNkANgIoIARB8s8ANgIkDD8LQbzDAigCABAwGiAEQYzMADYCCCAEQZrQADYCBAw2C0G8wwIoAgAQMBogBEGJ0QA2AhggBEGc0AA2AhQMPgsMKgsgACABKAKMASABEPUCDCkLIAAgASgCjAEgARD1AgwoCyABKAKMASEEIAEoApABIQIjAEEQayIFJAACQAJAAkACQAJAAkAgBCgCACIDQQZrQQlJDQAgAw4EAgEAAAQLAkAgACgCAA4DAwADAAsgAikDICLbAUIAVw0CIAIpAxgi3AFCAFcNAiACKQMQIt0BQgBXDQIgASgCPCEHIAEoAjghBiABKAI0IQkgAigCOCEKIAIoAjQhCCAEKAI8IQsgBCgCOCEMIAQoAjQhDSADQSRsQaCbAWooAgAhAyACKAIwIQ8gBCgCECEOA0AgByDaAaciAGwhECAAIAtsIREgACAKbCESQgAh2AEDQCAGINgBpyIAbCETIAAgDGwhFiAAIAhsIQBCACHZAQNAIAQoAtABIAIoAtABIA8g2QGnIhVsaiAAaiASaigCACANbGogFmogEWogASgC0AEgCSAVbGogE2ogEGogDiADEQUAINkBQgF8ItkBIN0BUg0ACyDYAUIBfCLYASDcAVINAAsg2gFCAXwi2gEg2wFSDQALDAILAkAgACgCAA4DAgACAAsgAikDICLbAUIAVw0BIAIpAxgi3AFCAFcNASACKQMQIt0BQgBXDQEgBCgCECIAQQBMDQEgASgCPCEGIAEoAjghCSABKAI0IQogAigCOCEIIAIoAjQhCyAEKAI8IQwgBCgCOCENIAQoAjQhDyACKAIwIQ4gASgC0AEhECAEKALQASERIAIoAtABIRIgAEF8cSETIABBA3EhBCAAQQRJIRYD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JAACQCAEKAIARQRAIAAgBCABQwAAAAAQ7QQgAkEQaiQADAELQbzDAigCABAwGiACQZshNgIIIAJBpdQANgIEDCoLDCMLIAEoAowBIQsgASgCkAEhDCABIQMjAEEQayINJAACQCALKAIARQRAAkACQCAAKAIADgMBAAEACyAAKAIIIQEgACgCBCECIAwEfiAMKQMYBUIBCyHaASABIAspAyggCykDICALKQMYfn6nIgRqQQFrIAFtIgEgAmwiBiABIAZqIgEgBCABIARIGyIJTg0AIAsoAhAiB0FwcSIBIAdBD3EiDyAHQQNxIgprIg5qIQQgACgCECAHQRBqIAJsQQJ0aiIFIAdBAnQiGmohGSAHQXxxIQIgB0EBayEQIAFBAWsiEUEEdkEBaiIAQf7///8BcSESIABBAXEhEyADKgJEIrQC/RMhkgIgCawh2QEgBqwh2AEgB0EISSEWA0AgAygCNCG8ASADKALQASEXIAsoAjQhACALKALQASEGIAwEfyAMKALQASAMKAI0INgBINoBgadsagVBAAshCSDYAachFQJAIAdBAEwiGA0AIAYgACAVbGohCEEAIQZBACEAAkAgFg0AIAUgCGtBEEkNAANAIAUgAEECdCIbaiAIIBtq/QACAP0LAgAgAEEEaiIAIAJHDQALIAcgAiIARg0BCyAQIABrIbsBIAoEQANAIAUgAEECdCIcaiAIIBxqKgIAOAIAIABBAWohACAGQQFqIgYgCkcNAAsLILsBQQNJDQADQCAFIABBAnQiBmogBiAIaioCADgCACAFIAZBBGoiG2ogCCAbaioCADgCACAFIAZBCGoiG2ogCCAbaioCADgCACAFIAZBDGoiBmogBiAIaioCADgCACAAQQRqIgAgB0cNAAsLAkAgAUEATCIbDQBBACEIQQAhBiARQQ9HBEADQCAFIAhBAnQiHGoiACCSAiAA/QAAAP3mAf0LAAAgACCSAiAA/QAAEP3mAf0LABAgACCSAiAA/QAAIP3mAf0LACAgACCSAiAA/QAAMP3mAf0LADAgBSAcQcAAcmoiACCSAiAA/QAAAP3mAf0LAAAgACCSAiAA/QAAEP3mAf0LABAgACCSAiAA/QAAIP3mAf0LACAgACCSAiAA/QAAMP3mAf0LADAgCEEgaiEIIAZBAmoiBiASRw0ACwsgE0UNACAFIAhBAnRqIgAgkgIgAP0AAAD95gH9CwAAIAAgkgIgAP0AABD95gH9CwAQIAAgkgIgAP0AACD95gH9CwAgIAAgkgIgAP0AADD95gH9CwAwCyC8ASAVbCG9AQJAIAEgB04iFA0AQQAhCCABIQAgD0EETwRAA0AgBSABIAhqQQJ0aiIAIJICIAD9AAIA/eYB/QsCACAIQQRqIgggDkcNAAsgBCEAIApFDQELA0AgBSAAQQJ0aiIIILQCIAgqAgCUOAIAIABBAWoiACAHRw0ACwsgvQEgF2ohCAJAAkACQCAJRQ0AIBgNAUEAIQZBACEAAkAgFg0AIAkgGUkgCSAaaiAFS3ENAANAIAUgAEECdCIVaiIXIAkgFWr9AAIAIBf9AAIA/eQB/QsCACAAQQRqIgAgAkcNAAsgByACIgBGDQELIABBf3MgB2ohvgEgCgRAA0AgBSAAQQJ0IhdqIhwgCSAXaioCACAcKgIAkjgCACAAQQFqIQAgBkEBaiIGIApHDQALCyC+AUEDSQ0AA0AgBSAAQQJ0IgZqIhUgBiAJaioCACAVKgIAkjgCACAFIAZBBGoiFWoiFyAJIBVqKgIAIBcqAgCSOAIAIAUgBkEIaiIVaiIXIAkgFWoqAgAgFyoCAJI4AgAgBSAGQQxqIgZqIhUgBiAJaioCACAVKgIAkjgCACAAQQRqIgAgB0cNAAsLIBgNAEMAAID/IbICQQAhCUEAIQBBACEVIBBBA08EQANAILICIAUgAEECdCIGaioCACKzAiCyAiCzAl4bIrICIAUgBkEEcmoqAgAiswIgsgIgswJeGyKyAiAFIAZBCHJqKgIAIrMCILICILMCXhsisgIgBSAGQQxyaioCACKzAiCyAiCzAl4bIbICIABBBGohACAVQQRqIhUgAkcNAAsLIAoEQANAILICIAUgAEECdGoqAgAiswIgsgIgswJeGyGyAiAAQQFqIQAgCUEBaiIJIApHDQALC0QAAAAAAAAAACG4AkEAIQADQEMAAAAAIbMCIAUgAEECdCIGaioCACK1AkMAAID/XARAILgCQYD8ASC1AiCyApMiswKLQwAAgHeUQwAAgAiUQYCAgIgHILMCvCIJQQF0IhVBgICAeHEiGCAYQYCAgIgHTRtBAXZBgICAPGq+krwiGEENdkGA+AFxIBhB/x9xaiAVQYCAgHhLGyAJQRB2QYCAAnFyQQF0QZDWLGovAQBBAnRBkNYEaioCACKzArugIbgCCyAGIAhqILMCOAIAIAcgAEEBaiIARw0ACwwBC0QAAAAAAAAAACG4AgtEAAAAAAAA8D8guAKjtiGyAgJAIBsNACCyAv0TIZMCQQAhBkEAIQkgEUEPRwRAA0AgCCAGQQJ0IhVqIgAgkwIgAP0AAAD95gH9CwAAIAAgkwIgAP0AABD95gH9CwAQIAAgkwIgAP0AACD95gH9CwAgIAAgkwIgAP0AADD95gH9CwAwIAggFUHAAHJqIgAgkwIgAP0AAAD95gH9CwAAIAAgkwIgAP0AABD95gH9CwAQIAAgkwIgAP0AACD95gH9CwAgIAAgkwIgAP0AADD95gH9CwAwIAZBIGohBiAJQQJqIgkgEkcNAAsLIBNFDQAgCCAGQQJ0aiIAIJMCIAD9AAAA/eYB/QsAACAAIJMCIAD9AAAQ/eYB/QsAECAAIJMCIAD9AAAg/eYB/QsAICAAIJMCIAD9AAAw/eYB/QsAMAsCQCAUDQAgASEAIA9BBE8EQCCyAv0TIZMCQQAhAANAIAggACABakECdGoiBiAG/QACACCTAv3mAf0LAgAgAEEEaiIAIA5HDQALIAQhACAKRQ0BCwNAIAggAEECdGoiBiAGKgIAILIClDgCACAAQQFqIgAgB0cNAAsLINgBQgF8ItgBINkBUg0ACwsgDUEQaiQADAELQbzDAigCABAwGiANQZshNgIIIA1Bj9UANgIEIA1B5CY2AgBBuMMCKAIAQcvkACANEDEMNwsMIgsgASgCjAEhAiABKAKQASEEIwBB4ABrIgMkAAJAAkACQAJAAkACQCACKAIARQRAIAIoAjBBBEcNASACKAI0IgytItkBIAIpAxAi2AFCAoZSDQEgAjUCOCLbASDZASACKQMYItoBflINASACNQI8INsBIAIpAyAi2QF+Ug0BIAQoAjAiBSAEKAIAQSRsIgdBmJsBaigCAEcNAiAEKAI0Ig2tItsBIAQpAxAi3AEgBa1+IAdBlJsBajQCAH9SDQIgBDUCOCLdASAEKQMYIt4BINsBflINAiAENQI8IN0BIAQpAyAi3wF+Ug0CIAEoAjAiBSABKAIAQSRsIgdBmJsBaigCAEcNAyABKAI0Ig+tItsBIAEpAxAi3QEgBa1+IAdBlJsBajQCAH9SDQMgATUCOCLgASDbASABKQMYIuEBflINAyABNQI8IOABIAEpAyAi2wF+Ug0DINgBIN0BUg0EINoBIOEBUg0EINkBINsBUg0EIAIpAygi2wEgASkDKFINBCDYASDcAVINBSDaASDeAVINBSDZASDfAVINBSAEKQMoINsBUg0FAkACQCAAKAIADgMBAAEACyDZASDaAX4g2wF+pyIFIAAoAggiB2pBAWsgB20iByAAKAIEIgZsIgogByAKaiIAIAUgACAFSBsiFk4NACAGIA1sIAdsIhUg2AGnIgVBAnQiAGohGCAGIA9sIAdsIhIgAGohGiAFQQNxIQggBUF8cSEAIAIoAtABIhkgBiAMbCAHbGohFCASIAEoAtABIg5qIRcgBCgC0AEhECAFQXBxIgRBAEwhGyAEQX9zIAVqQQNJIRwDQCAQIAogDWxqIQYgGSAKIAxsaiEJ/QwAAAAAAAAAAAAAAAAAAAAAIpICIZMC/QwAAAAAAAAAAAAAAAAAAAAAIZQC/QwAAAAAAAAAAAAAAAAAAAAAIZUCQQAhAiAbRQRAA0AgkgIgBiACQQJ0IgdqIgH9AAAwIAcgCWoiB/0AADD95gH95AEhkgIgkwIgAf0AACAgB/0AACD95gH95AEhkwIglAIgAf0AABAgB/0AABD95gH95AEhlAIglQIgAf0AAAAgB/0AAAD95gH95AEhlQIgAkEQaiICIARIDQALIJUCIJMC/eQBIJQCIJIC/eQB/eQBIZICCyCSAv0fAyCSAv0fAiCSAv0fACCSAv0fAZKSkiGyAgJAIAQgBU4NAEEAIQIgBCEBIAgEQANAIAYgAUECdCIHaioCACAHIAlqKgIAlCCyApIhsgIgAUEBaiEBIAJBAWoiAiAIRw0ACwsgHA0AA0AgBiABQQJ0IgJBDGoiB2oqAgAgByAJaioCAJQgBiACQQhqIgdqKgIAIAcgCWoqAgCUIAYgAkEEaiIHaioCACAHIAlqKgIAlCACIAZqKgIAIAIgCWoqAgCUILICkpKSkiGyAiABQQRqIgEgBUcNAAsLAkAgBUEATA0AIAsgD2whESAOIAogD2xqIQdBACEBQQAhAgJAAkAgBUEESSITDQAgESAXaiAUIAsgDGxqa0EQSQ0AA0AgByACQQJ0Ih1qIAkgHWr9AAIA/QsCACACQQRqIgIgAEcNAAsgBSAAIgJGDQELIAJBf3MgBWohvwEgCARAA0AgByACQQJ0Ih9qIAkgH2oqAgA4AgAgAkEBaiECIAFBAWoiASAIRw0ACwsgvwFBA0kNAANAIAcgAkECdCIBaiABIAlqKgIAOAIAIAcgAUEEaiIdaiAJIB1qKgIAOAIAIAcgAUEIaiIdaiAJIB1qKgIAOAIAIAcgAUEMaiIBaiABIAlqKgIAOAIAIAJBBGoiAiAFRw0ACwtBACEBAkAgE0UEQCCyAv0TIZICA0AgByABQQJ0aiICIAL9AAIAIJIC/eUB/QsCACABQQRqIgEgAEcNAAsgBSAAIgFGDQELA0AgByABQQJ0aiICIAIqAgAgsgKTOAIAIAFBAWoiASAFRw0ACwtBACECQQAhAQJAIBMNACAOIBEgEmpqIBAgGCALIA1sIglqakkgECAJIBVqaiAOIBEgGmpqSXENAANAIAcgAUECdCIJaiIRIBH9AAIAIAYgCWr9AAIA/eYB/QsCACABQQRqIgEgAEcNAAsgBSAAIgFGDQELIAFBf3MgBWohwAEgCARAA0AgByABQQJ0IhFqIhMgEyoCACAGIBFqKgIAlDgCACABQQFqIQEgAkEBaiICIAhHDQALCyDAAUEDSQ0AA0AgByABQQJ0IgJqIgkgCSoCACACIAZqKgIAlDgCACAHIAJBBGoiCWoiESARKgIAIAYgCWoqAgCUOAIAIAcgAkEIaiIJaiIRIBEqAgAgBiAJaioCAJQ4AgAgByACQQxqIgJqIgkgCSoCACACIAZqKgIAlDgCACABQQRqIgEgBUcNAAsLIAtBAWohCyAKQQFqIgogFkcNAAsLIANB4ABqJAAMBgtBvMMCKAIAEDAaIANBmyE2AlggA0Hv1QA2AlQgA0HkJjYCUEG4wwIoAgBBy+QAIANB0ABqEDEMOwtBvMMCKAIAEDAaIANB39kANgJIIANBm9UANgJEIANB5CY2AkBBuMMCKAIAQcvkACADQUBrEDEMOgtBvMMCKAIAEDAaIANBu9gANgI4IANBnNUANgI0IANB5CY2AjBBuMMCKAIAQcvkACADQTBqEDEMOQtBvMMCKAIAEDAaIANB9MsANgIoIANBndUANgIkIANB5CY2AiBBuMMCKAIAQcvkACADQSBqEDEMOAtBvMMCKAIAEDAaIANBuc8ANgIYIANBntUANgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEMNwtBvMMCKAIAEDAaIANBns4ANgIIIANBn9UANgIEIANB5CY2AgBBuMMCKAIAQcvkACADEDEMNgsMIQsgASgCjAEhBCABKAKQASEDIwBBEGsiAiQAAkACQAJAAkAgBCgCAA4CAAIBCyAAIAQgAyABQQEQ7AQMAgtBvMMCKAIAEDAaIAJBmyE2AgggAkHR2gA2AgQMKAsgACAEIAMgAUEBEOsECyACQRBqJAAMIAsgASgCjAEhBCABKAKQASEDIwBBEGsiAiQAAkACQAJAAkAgBCgCAA4CAAIBCyAAIAQgAyABQQAQ7AQMAgtBvMMCKAIAEDAaIAJBmyE2AgggAkHo2gA2AgQMJwsgACAEIAMgAUEAEOsECyACQRBqJAAMHwsgASgCjAEhBCMAQdAAayICJAACQAJAAkACQAJAAkAgBCgCACIDQRNLDQAgAwRAIANBAUcEQEEBIAN0Qcz/P3FFDQJBvMMCKAIAEDAaIAJBmyE2AkggAkGM1wA2AkQMLgsCQCAAKAIADgMCAAIACyAEKQMoIAQpAyAi2AEgBCkDGCLaAX5+pyDaAaciA20hBSAEKAIwQQJHDQIgASgCSCIAINgBp0cNAyAEKAI4IQkgBCgCNCEKIAQoAhAhByABKgJMIrICQwAAAL+UQQECfyAAtxCnBJwiuAKZRAAAAAAAAOBBYwRAILgCqgwBC0GAgICAeAt0IgayIrMClRD9ASG0AiCyAowgswKVEP0BIbMCIAdBAEwNASADQQBMDQEgBUEATA0BIAEoAtABIQggBCgC0AEhC0EAIQEDQCAIIAFBAXQiAGohDCAAIAtqIQ0gAbIhtQJBACEEA0AgDCAEIApsIgBqIQ8gACANaiEOQQAhAANAIA8gACAJbCIQaiHBASAOIBBqIRACQCAAIAZOBEAgtAIgACAGa0EBdEEBcrIQtAEhsgIgAEEBaiEADAELILMCIABBAWoiALIQtAEhsgILIMEBILUCILIClCAQLwEAQQJ0QZDWBGoqAgCSOAIAIAAgBUcNAAsgBEEBaiIEIANHDQALIAFBAWoiASAHRw0ACwwBCwJAIAAoAgAOAwEAAQALIAQpAyggBCkDICLYASAEKQMYItkBfn4g2QF/IdwBIAQoAjBBBEcNAyDYASABKAJIIgCsUg0EIAQoAjghAyAEKAI0IQUgBCkDECHdASABKgJMIrICQwAAAL+UQQECfyAAtxCnBJwiuAKZRAAAAAAAAOBBYwRAILgCqgwBC0GAgICAeAt0IgCyIrMClRD9ASG0AiCyAowgswKVEP0BIbMCIN0BQgBXDQAg2QFCAFcNACDcAUIAVw0AIACsId4BIAEoAtABIQAgBCgC0AEhAQNAIAAg2gGnQQJ0IgRqIQcgASAEaiEEINoBtCG1AkIAIdsBA0AgByAFINsBp2wiBmohCSAEIAZqIQZCACHYAQNAIAkgAyDYAadsIgpqIcIBIAYgCmohCgJAINgBIN4BWQRAILQCINgBIN4BfUIBhkIBhLQQtAEhsgIg2AFCAXwh2AEMAQsgswIg2AFCAXwi2AG0ELQBIbICCyDCASC1AiCyApQgCioCAJI4AgAg2AEg3AFSDQALINsBQgF8ItsBINkBUg0ACyDaAUIBfCLaASDdAVINAAsLIAJB0ABqJAAMBAtBvMMCKAIAEDAaIAJBw9IANgIYIAJBzdYANgIUDCcLQbzDAigCABAwGiACQaw7NgIIIAJBz9YANgIEDCcLQbzDAigCABAwGiACQd3QADYCOCACQZLWADYCNAwnC0G8wwIoAgAQMBogAkGsOzYCKCACQZPWADYCJAwjCwweCyABKAKMASEDIwBBMGsiBCQAAkACQAJAAkAgAygCACICQRNLDQAgAgRAQQEgAnRBzv8/cUUNAUG8wwIoAgAQMBogBEGbITYCKCAEQdbXADYCJAw0CwJAIAAoAgAOAwEAAQALIAEoAjBBBEcNAiADKAIwQQRHDQEgACgCBCIFIAMpAyggAykDICADKQMYfn6nIgxODQAgAygCECIHQQBMDQBBACAHayENIAdBAXEhDyAHQXxxIQIgAygCNCIJIAAoAggiCmwhDiABKAI0IgggCmwhECADKALQASIRIAUgCWxqIRIgASgC0AEiEyAFIAhsaiEWIAEqAkQisgL9EyGSAiABKgJIIrMC/RMhkwIgB0EESSEVA0AgESAFIAlsaiEBIBMgBSAIbGohA0EAIQACQAJAIBUNACAWIAYgEGxqIBIgBiAObGprQRBJDQADQCADIABBAnQiC2ogkgIgkwIgASALav0AAgD96gH96wH9CwIAIABBBGoiACACRw0ACyACIgAgB0YNAQsgAEF/cyHDASAPBEAgAyAAQQJ0IhhqIAEgGGoqAgAitAIgswIgswIgtAJeGyK0AiCyAiCyAiC0Al0bOAIAIABBAXIhAAsgwwEgDUYNAANAIAMgAEECdCILaiABIAtqKgIAIrQCILMCILMCILQCXhsitAIgsgIgsgIgtAJdGzgCACADIAtBBGoiC2ogASALaioCACK0AiCzAiCzAiC0Al4bIrQCILICILICILQCXRs4AgAgAEECaiIAIAdHDQALCyAGQQFqIQYgBSAKaiIFIAxIDQALCyAEQTBqJAAMAgtBvMMCKAIAEDAaIARBttEANgIIIARBr9cANgIEDCkLQbzDAigCABAwGiAEQd3QADYCGCAEQa7XADYCFAwxCwwdCyABKAKMASECIAEoApABIQMjAEGQAWsiBCQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAigCAA4CAQALCyADKAIADQIgASgCAA0DIAIoAjBBAkcNBCADKAIwQQRHDQUgAikDICLfASACKQMQItwBfiLiASACKQMYIuMBfqchByADKQMYIeEBIAMpAxAh4AECQAJAIAAoAgAOAwABAwELIAMoAjQhCiACKAI4IQYgAigCNCEJIAAoAhBBACAAKAIM/AsAIAAoAhAhBQJAIN8BQgBXDQAg4wFCAFcNACDcAUIAVw0AIN8BQgFSINwBQghUciEIINwBQgODIeQBINwBQniDIdoBINwBQgGGIeUBIAmtIeYBIAatIecBIAIoAtABIgutIegBIAWtIekBA0Ag2QEg5wF+IOgBfCHqASDZAUIBhiDpAXwh6wEgCyAGINkBp2xqIQxCACHdAQNAIAwgCSDdAadsaiEAIAUg3QEg4gF+p0EBdGohAkIAId4BQgAh2wFCACHYAQJAIAgg6wEg3QEg5QF+fKcg6gEg3QEg5gF+fKdrQRBJckUEQANAIAIg2QEg2wF8p0EBdGogACDbAadBAXRq/QABAP0LAQAg2wFCCHwi2wEg2gFSDQALINoBItgBINwBUQ0BCyDcASDYAUJ/hXwhiwIg5AFCAFIEQANAIAIg2AEg3wF+INkBfKdBAXRqIAAg2AGnQQF0ai8BADsBACDYAUIBfCHYASDeAUIBfCLeASDkAVINAAsLIIsCQgNUDQADQCACINgBIN8BfiDZAXynQQF0aiAAINgBp0EBdGovAQA7AQAgAiDYAUIBfCLbASDfAX4g2QF8p0EBdGogACDbAadB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ASAANQIwfiAHQSRsQZSbAWo1AgB/fCAAKAI4IgetINgBQgF9fnwgADUCPCAAKQMoQgF9fnynCyIAQQBMDQAgASkDGCLdAUIAVw0AIAEpAxAi2wFCAFcNAAJAAkAgA0ECRwRAIAAgBGohCSABKALQASEAINsBIN0BfqchCiAIIAtssiGyAiDbAachBiAIQQBMDQEgC0EATA0CIAutItgBQv7///8PgyHiASDYAUIBgyHjASDYAUIBfSHkASAIrSHlASADQQFrIQsDQEIAId8BA0AgACDfAaciASAGbEECdGohECABIA5sIA9rrCHmAUIAIeABA0AgECDgAaciCEECdGohAQJAAkACQCADDgIBAAILIAFBADYCACAIIA1sIAxrrCHhAUIAIdoBA0ACQCDaASDmAXwi2AFCAFMNACDeASDYAUL/////D4NXDQAgBCACINgBp2xqIQhCACHYAUIAIdwBIOQBQgBSBEADQAJAINgBIOEBfCLnAUIAUw0AINkBIOcBQv////8Pg1cNACABIAgg5wGnQQJ0aioCACABKgIAkjgCAAsCQCDYAUIBhCDhAXwi5wFCAFMNACDZASDnAUL/////D4NXDQAgASAIIOcBp0ECdGoqAgAgASoCAJI4AgALINgBQgJ8IdgBINwBQgJ8ItwBIOIBUg0ACwsg4wFQDQAg2AEg4QF8ItgBQgBTDQAg2QEg2AFC/////w+DVw0AIAEgCCDYAadBAnRqKgIAIAEqAgCSOAIACyDaAUIBfCLaASDlAVINAAsMAQsgAUH///97NgIAIAggDWwgDGusIeEBQgAh2gEDQAJAINoBIOYBfCLYAUIAUw0AIN4BINgBQv////8Pg1cNACAEIAIg2AGnbGohCEIAIdgBQgAh3AEg5AFCAFIEQANAAkAg2AEg4QF8IucBQgBTDQAg2QEg5wFC/////w+DVw0AIAgg5wGnQQJ0aioCACKzAiABKgIAXkUNACABILMCOAIACwJAINgBQgGEIOEBfCLnAUIAUw0AINkBIOcBQv////8Pg1cNACAIIOcBp0ECdGoqAgAiswIgASoCAF5FDQAgASCzAjgCAAsg2AFCAnwh2AEg3AFCAnwi3AEg4gFSDQALCyDjAVANACDYASDhAXwi2AFCAFMNACDZASDYAUL/////D4NXDQAgCCDYAadBAnRqKgIAIrMC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IAVBfnEhCQNAIAcgASgC0AEgASgCNCAAbGogAigC0AEgAigCNCAAbGogAxEFACAHIAEoAtABIABBAXIiCiABKAI0bGogAigC0AEgAigCNCAKbGogAxEFACAAQQJqIQAgBkECaiIGIAlHDQALCyAFQQFxRQ0AIAcgASgC0AEgASgCNCAAbGogAigC0AEgAigCNCAAbGogAxEFAAsgBEEgaiQADAILQbzDAigCABAwGiAEQZshNgIYIARB+eoANgIUDCALQbzDAigCABAwGiAEQbnPADYCCCAEQdrqADYCBAwWCwwLCyABKAKMASECIAEoApABIQMgASgCRCEFIwBBEGsiBCQAAkAgAigCAEUEQAJAAkAgACgCAA4DAQABAAsgAikDKCACKQMgIAIpAxh+fqciB0EATA0AIAIoAhAhBkEAIQADQCAGIAEoAtABIAEoAjQgAGxqIAIoAtABIAIoAjQgAGxqIAMoAtABIAMoAjQgAGxqIAURBgAgAEEBaiIAIAdHDQALCyAEQRBqJAAMAQtBvMMCKAIAEDAaIARBmyE2AgggBEGp6wA2AgQMFQsMCgsCQCAAKAIADgMKAAoACyABIAEoAowBIAEoAkQRAgAMCQsCQCAAKAIADgMJAAkACyABIAEoAowBIAEoApABIAEoAkQRBQAMCAsCQCAAKAIADgMIAAgACyABIAEoAowBIAEoApABIAEoApQBIAEoAkQRBgAMBwsgASgCjAEhAgJAAkAgACgCAA4DAQABAAsgASACIAAoAgQgACgCCCABKAJMIAEoAkQRCwALDAYLIAEoAowBIQIgASgCkAEhBAJAAkAgACgCAA4DAQABAAsgASACIAQgACgCBCAAKAIIIAEoAkwgASgCRBEMAAsMBQsgASgCjAEhAiABKAKQASEEIAEoApQBIQMCQAJAIAAoAgAOAwEAAQALIAEgAiAEIAMgACgCBCAAKAIIIAEoAkwgASgCRBEQAAsMBAsgACEEIAEoAowBIQkgASgCkAEhCiMAQeAAayIFJAACQAJAAn0CQCAJKAIARQRAAkAgCSgCMEEERw0AIAk1AjQi2QEgCSkDECLYAUIChlINACAJNQI4ItsBINkBIAkpAxgi2gF+Ug0AIAk1Ajwg2wEgCSkDICLZAX5SDQACQCAKKAIwIgAgCigCAEEkbCICQZibAWooAgBHDQAgCjUCNCLbASAKKQMQItwBIACtfiACQZSbAWo0AgB/Ug0AIAo1Ajgi3QEg2wEgCikDGCLeAX5SDQAgCjUCPCDdASAKKQMgItsBflINAAJAIAEpAxBCAVINACABKQMYQgFSDQAgASkDIEIBUg0AIAEpAyhCAVINAAJAINgBINwBUg0AINoBIN4BUg0AINkBINsBUg0AIAkpAygi2wEgCikDKFINACAEKAIIIgAg2AGnIgZBAnQiE0EEamwiAyAEKAIMTQRAINkBINoBfiDbAX6nIQIgBCgCECEHIAQoAgQhCAJAAkACQCAEKAIADgMAAgECCyAIDQogB0EAIAP8CwAMCgsgCA0JIAEoAtABIQlDAAAAACAAQQBMDQgaIABBA3EhBEEAIQMgAEEESQRAQQAhAAwICyAAQXxxIQpBACEAQQAhBgNAILgCIAcgAEECdCIBaioCALugIAcgAUEEcmoqAgC7oCAHIAFBCHJqKgIAu6AgByABQQxyaioCALugIbgCIABBBGohACAGQQRqIgYgCkcNAAsMBwsgACACakEBayAAbSIBIAhsIg0gASANaiIBIAIgASACSBsiFk4NCCAGQXBxIgIgBkEPcSIVIAZBA3EiDGsiGGohAyAAQQJ0IhogCEECdCIAQQRqIAZsaiEZIAZBfHEhASAGQX5xIRQgBkEBcSEXIAZBAWshDiAAIAdqIRAgAkEBayIbQQR2QQFqIgBB/v///wFxIRwgAEEBcSEdIAYgCGxBAnQhHwNAIAQoAhAiHiAaaiAfaiEHIAooAjQhIyAKKALQASERAkAgBkEATCIlBEBEAAAAAAAAAAAhuAIMAQsgCSgC0AEgCSgCNCANbGohC0MAAID/IbICQQAhD0EAIQBBACESIA5BA08EQANAILICIAsgAEECdCIIaioCACKzAiCyAiCzAl4bIrICIAsgCEEEcmoqAgAiswIgsgIgswJeGyKyAiALIAhBCHJqKgIAIrMCILICILMCXhsisgIgCyAIQQxyaioCACKzAiCyAiCzAl4bIbICIABBBGohACASQQRqIhIgAUcNAAsLIAwEQANAILICIAsgAEECdGoqAgAiswIgsgIgswJeGyGyAiAAQQFqIQAgD0EBaiIPIAxHDQALC0QAAAAAAAAAACG4AkEAIQBBACEIIA4EQANAQwAAAAAhswICQCALIABBAnQi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QQFqIQAgA0EBaiIDIARHDQALCyC4ArYLIbICIAlDAACAvyACspUgsgKUOAIACyAFQeAAaiQADAALDAMLIAEoAowBIQkgASgCkAEhCiABKAKUASECIAEhAyMAQeAAayIFJAACQCAJKAIARQRAAkAgASgCMCIBIAMoAgBBJGwiBEGYmwFqKAIARw0AIAM1AjQi2QEgAykDECLYASABrX4gBEGUmwFqNAIAf1INACADNQI4ItsBINkBIAMpAxgi2gF+Ug0AIAM1Ajwg2wEgAykDICLZAX5SDQACQCAJKAIwQQRHDQAgCTUCNCLdASAJKQMQItsBQgKGUg0AIAk1Ajgi3gEg3QEgCSkDGCLcAX5SDQAgCTUCPCDeASAJKQMgIt0BflINAAJAIAooAjAiASAKKAIAQSRsIgRBmJsBaigCAEcNACAKNQI0It4BIAopAxAi3wEgAa1+IARBlJsBajQCAH9SDQAgCjUCOCLgASDeASAKKQMYIuEBflINACAKNQI8IOABIAopAyAi3gF+Ug0AAkAgAigCMCIBIAIoAgBBJGwiBEGYmwFqKAIARw0AIAI1AjQi4AEgAikDECABrX4gBEGUmwFqNAIAf1INACACNQI4IuIBIAIpAxgg4AF+Ug0AIAI1AjwgAikDICDiAX5SDQACQCDbASDfAVINACDcASDhAVINACDdASDeAVINACDZASDdAVINACDaASDcAVINACDYASDbAVINACAJKQMoItsBIAopAyhSDQAg2wEgAykDKFINAAJAAkAgACgCAA4DAQABAAsg2QEg2gF+INsBfiLZASAANAIIItoBfEIBfSDaAX8i2wEgADQCBH4i2gEg2gEg2wF8ItsBINkBINkBINsBVRsi3AFZDQAgAigC0AEhGCDYAaciBkFwcSIBIAZBD3EiDSAGQQNxIgxrIg9qIQQg2AFCfoMh3QEg2AFCAYMh3gEgBkF8cSECIAZBAnQhDiABQQFrIhBBBHZBAWoiAEH+////AXEhESAAQQFxIRIg2QG0IbUCIAZBAWtBA0khGgNAIAkoAtABINoBpyITIAkoAjRsaiEAIAMoAjQgE2whFkMAAID/IbICAkAgBkEATCIZDQBBACEIQQAhB0EAIRUgGkUEQANAILICIAAgB0ECdCILaioCACKzAiCyAiCzAl4bIrICIAAgC0EEcmoqAgAiswIg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ayIBIAgoAuACIgUgAmtBBHVNBEACQCABRQ0AIAIhAyABQQdxIgQEQEEAIQUDQCADQQA2AgggA0IANwMAIANBEGohAyAFQQFqIgUgBEcNAAsLIAFBBHQgAmohAiABQQFrQf////8AcUEHSQ0AA0AgA0IANwNwIANCADcDYCADQgA3A1AgA0IANwNAIANCADcDMCADQgA3AyAgA0IANwMQIANBADYCCCADQgA3AwAgA0EANgJ4IANBADYCaCADQQA2AlggA0EANgJIIANBADYCOCADQQA2AiggA0EANgIYIANBgAFqIgMgAkcNAAsLIAggAjYC3AIMAQsCQCACIAgoAtgCIgRrQQR1IgsgAWoiA0GAgICAAUkEQEH/////ACAFIARrIgVBA3UiCSADIAMgCUkbIAVB8P///wdPGyIJBEAgCUGAgICAAU8NAiAJQQR0EDIhBwsgByALQQR0aiIFIQMgAUEHcSILBEADQCADQQA2AgggA0IANwMAIANBEGohAyAKQQFqIgogC0cNAAsLIAFBBHQgBWohCiABQQFrQf////8AcUEHTwRAA0AgA0IANwNwIANCADcDYCADQgA3A1AgA0IANwNAIANCADcDMCADQgA3AyAgA0IANwMQIANBADYCCCADQgA3AwAgA0EANgJ4IANBADYCaCADQQA2AlggA0EANgJIIANBADYCOCADQQA2AiggA0EANgIYIANBgAFqIgMgCkcNAAsLIAIgBEcEQANAIAVBEGsiBSACQRBrIgIpAwA3AwAgBSACKAIINgIIIAIgBEcNAAsLIAggByAJQQR0ajYC4AIgCCAKNgLcAiAIKALYAiEBIAggBTYC2AIgAQRAIAEQLwsMAgsMDAsQRwALIAgoAtgCIQQMAQsgASAMTQ0AIAggBCAMQQR0ajYC3AILAkAgDEEATA0AIAgoAsACIQJBACEBIAxBAUcEQCAMQX5xIQVBACELA0AgAiABQQJ0aioCACEaIAQgAUEEdGoiAyABNgIIIAMgGrs5AwAgAiABQQFyIgNBAnRqKgIAIRogBCADQQR0aiIJIAM2AgggCSAauzkDACABQQJqIQEgC0ECaiILIAVHDQALCyAMQQFxRQ0AIAIgAUECdGoqAgAhGiAEIAFBBHRqIgIgATYCCCACIBq7OQMACyAGAn8gDUUEQEEAIQlBAAwBCyAEIA1B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QQJ0IgIgACgCJGooAgAgACgCICACaigCABEFAAwBCwsgACgCHCIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgACgCIBAvIAAoAiQQLyAAKAIwEC8gACgCPBAvIAALIAAgACAAKAIYRSABciIBNgIQIAAoAhQgAXEEQBBGAAsLRgAjAEEQayIBJAAgASADNgIMIAQgAiADIAJrIgL8CgAAIAEgAiAEajYCCCAAIAEoAgw2AgAgACABKAIINgIEIAFBEGokAAs2AQF/IwBBEGsiAyQAIAMgATYCDCADIAI2AgggACADKAIMNgIAIAAgAygCCDYCBCADQRBqJAALOwEBfyAAQfDKAigCACIBNgIAIAAgAUEMaygCAGpB/MoCKAIANgIAIABBCGoQ8gEaIABB7ABqEMACIAALDAAgAEEIahDAAiAACwgAIAAQugIaC9IDAgJ+An8jAEEgayIEJAACQCABQv///////////wCDIgNCgICAgICAwIA8fSADQoCAgICAgMD/wwB9VARAIAFCBIYgAEI8iIQhAyAAQv//////////D4MiAEKBgICAgICAgAhaBEAgA0KBgICAgICAgMAAfCECDAILIANCgICAgICAgIBAfSECIABCgICAgICAgIAIUg0BIAIgA0IBg3whAgwBCyAAUCADQoCAgICAgMD//wBUIANCgICAgICAwP//AFEbRQRAIAFCBIYgAEI8iIRC/////////wODQoCAgICAgID8/wCEIQIMAQtCgICAgICAgPj/ACECIANC////////v//DAFYNAEIAIQIgA0IwiKciBUGR9wBJDQAgBEEQaiAAIAFC////////P4NCgICAgICAwACEIgIgBUGB9wBrEGYgBCAAIAJBgfgAIAVrEK8BIAQpAwhCBIYgBCkDACIAQjyIhCECIAQpAxAgBCkDGIRCAFKtIABC//////////8Pg4QiAEKBgICAgICAgAhaBEAgAkIBfCECDAELIABCgICAgICAgIAIUg0AIAJCAYMgAnwhAgsgBEEgaiQAIAIgAUKAgICAgICAgIB/g4S/C4gCAAJAIAAEfyABQf8ATQ0BAkAjAygCYCgCAEUEQCABQYB/cUGAvwNGDQMMAQsgAUH/D00EQCAAIAFBP3FBgAFyOgABIAAgAUEGdkHAAXI6AABBAg8LIAFBgEBxQYDA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fyMAQRBrIgEkACAAQQE2AiAgAEEEaiICEFYaIAAoAiwgACgCMEcEQANAIAFBBGogABCfBCACEFIaIAEoAgwgASgCBBEBACACEFYaIAAoAiwgACgCMEcNAAsLIAIQUhogAEEANgIgIAFBEGokAAueDAMGfAN+CH8jAEEQayIOJAACQAJAIAG9IglCNIinIg1B/w9xIg9BvghrIhBB/35LIAC9IghCNIinIgtB/w9rQYJwT3ENACAJQgGGIgpCgICAgICAgBB8QoGAgICAgIAQVARARAAAAAAAAPA/IQIgCEKAgICAgICA+D9RDQIgClANAiAKQoGAgICAgIBwVCAIQgGGIghCgICAgICAgHBYcUUEQCAAIAGgIQIMAwsgCEKAgICAgICA8P8AUQ0CRAAAAAAAAAAAIAEgAaIgCEL/////////7/8AViAJQgBZcxshAgwCCyAIQgGGQoCAgICAgIAQfEKBgICAgICAEFQEQCAAIACiIQIgCEIAUwRAIAKaIAIgCRCkBEEBRhshAgsgCUIAWQ0CIwBBEGsiC0QAAAAAAADwPyACozkDCCALKwMIIQIMAgsgCEIAUwRAIAkQpAQiDEUEQCAAIAChIgAgAKMhAgwDCyALQf8PcSELIAxBAUZBEnQhDCAIQv///////////wCDIQgLIBBB/35NBEBEAAAAAAAA8D8hAiAIQoCAgICAgID4P1ENAiAPQb0HTQRAIAEgAZogCEKAgICAgICA+D9WG0QAAAAAAADwP6AhAgwDCyANQYAQSSAIQoGAgICAgID4P1RHBEAjAEEQayILRAAAAAAAAABwOQMIIAsrAwhEAAAAAAAAAHCiIQIMAwsjAEEQayILRAAAAAAAAAAQOQMIIAsrAwhEAAAAAAAAABCiIQIMAgsgCw0AIABEAAAAAAAAMEOivUL///////////8Ag0KAgICAgICAoAN9IQgLAnwgCUKAgIBAg78iBSEHIA4gCEKAgICA0Kql8z99IglCNIentyIDQdCgAisDAKIgCUItiKdB/wBxQQV0IgtBqKECaisDAKAgCCAJQoCAgICAgIB4g30iCEKAgICACHxCgICAgHCDvyIAIAtBkKECaisDACIEokQAAAAAAADwv6AiAiAIvyAAoSAEoiIEoCIAIANByKACKwMAoiALQaChAmorAwCgIgMgACADoCIDoaCgIAQgAEHYoAIrAwAiBKIiBiACIASiIgSgoqAgAiAEoiICIAMgAyACoCICoaCgIAAgACAGoiIDoiADIAMgAEGIoQIrAwCiQYChAisDAKCiIABB+KACKwMAokHwoAIrAwCgoKIgAEHooAIrAwCiQeCgAisDAKCgoqAiACACIAIgAKAiAqGgOQMIIAcgAr1CgICAQIO/IgOiIQAgASAFoSADoiAOKwMIIAIgA6GgIAGioCEBAkAgAL1CNIinQf8PcSILQckHa0E/SQ0AIAtByQdJBEAgAEQAAAAAAADwP6AiAJogACAMGwwCCyALQYkISSERQQAhCyARDQAgAL1CAFMEQCMAQRBrIgtEAAAAAAAAAJBEAAAAAAAAABAgDBs5AwggCysDCEQAAAAAAAAAEKIMAgsjAEEQayILRAAAAAAAAADwRAAAAAAAAABwIAwbOQMIIAsrAwhEAAAAAAAAAHCiDAELQZjbASsDACAAokGg2wErAwAiAqAiAyACoSICQbDbASsDAKIgAkGo2wErAwCiIACgoCABoCIAIACiIgEgAaIgAEHQ2wErAwCiQcjbASsDAKCiIAEgAEHA2wErAwCiQbjbASsDAKCiIAO9IgmnQQR0QfAPcSINQYjcAWorAwAgAKCgoCEAIA1BkNwBaikDACAJIAytfEIthnwhCCALRQRAAnwgCUKAgICACINQBEAgCEKAgICAgICAiD99vyIBIACiIAGgRAAAAAAAAAB/ogwBCyAIQoCAgICAgIDwP3wiCL8iASAAoiIDIAGgIgCZRAAAAAAAAPA/YwR8IwBBEGsiCyESIAtEAAAAAAAAEAA5AwggEiALKwMIRAAAAAAAABAAojkDCCAIQoCAgICAgICAgH+DvyAARAAAAAAAAPC/RAAAAAAAAPA/IABEAAAAAAAAAABjGyICoCIFIAMgASAAoaAgACACIAWhoKCgIAKhIgAgAEQAAAAAAAAAAGEbBSAAC0QAAAAAAAAQAKILDAELIAi/IgEgAKIgAaALIQILIA5BEGokACACC8EBAQN/AkAgASACKAIQIgMEfyADBSACENICDQEgAigCEAsgAigCFCIFa0sEQCACIAAgASACKAIkEQMADwsCQCACKAJQQQBIBEBBACEDDAELIAEhBANAIAQiA0UEQEEAIQMMAgsgACADQQFrIgRqLQAAQQpHDQALIAIgACADIAIoAiQRAwAiBCADSQ0BIAAgA2ohACABIANrIQEgAigCFCEFCyAFIAAgARB7GiACIAIoAhQgAWo2AhQgASADaiEECyAECzcBAn8gACgCTEEASARAIAAgASACEKkEDwsgABCCASEEIAAgASACEKkEIQIgBARAIAAQgQELIAILfAECfyAAIAAoAkgiAUEBayABcjYCSCAAKAIUIAAoAhxHBEAgAEEAQQAgACgCJBEDABoLIABBADYCHCAAQgA3AxAgACgCACIBQQRxBEAgACABQSByNgIAQX8PCyAAIAAoAiwgACgCMGoiAjYCCCAAIAI2AgQgAUEbdEEfdQuNAQECfyMAQRBrIgAkACAAQQo6AA8CQAJAQcC6AygCACIBBH8gAQVBsLoDENICDQJBwLoDKAIAC0HEugMoAgAiAUYNAEGAuwMoAgBBCkYNAEHEugMgAUEBajYCACABQQo6AAAMAQtBsLoDIABBD2pBAUHUugMoAgARAwBBAUcNACAALQAPGgsgAEEQaiQAC1kBAX8gACAAKAJIIgFBAWsgAXI2AkggACgCACIBQQhxBEAgACABQSByNgIAQX8PCyAAQgA3AgQgACAAKAIsIgE2AhwgACABNgIUIAAgASAAKAIwajYCEEEAC9MBAgF/AnwgAisDICEFAn8CQCABKwMgIgYgACsDIGRFBEBBACAFIAZkRQ0CGiABIAIQPkEBIAErAyAgACsDIGRFDQIaIAAgARA+DAELIAUgBmQEQCAAIAIQPkEBDAILIAAgARA+QQEgAisDICABKwMgZEUNARogASACED4LQQILIQQgAysDICACKwMgZAR/IAIgAxA+IAIrAyAgASsDIGRFBEAgBEEBag8LIAEgAhA+IAErAyAgACsDIGRFBEAgBEECag8LIAAgARA+IARBA2oFIAQLC34BAX8gACABIAIgAxDTAiEFIAQrAyAgAysDIGQEfyADIAQQPiADKwMgIAIrAyBkRQRAIAVBAWoPCyACIAMQPiACKwMgIAErAyBkRQRAIAVBAmoPCyABIAIQPiABKwMgIAArAyBkRQRAIAVBA2oPCyAAIAEQPiAFQQRqBSAFCwtIAQF/IABBwLMBNgIAIAAoAggiAQRAIAEgASgCACgCBBEBAAsgAEHcqQE2AgAgACgCBCIBBEAgASABKAIAKAIEEQEACyAAEC8L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A0AgBEEEayIEIAFBBGsiASgCADYCACABIAZHDQALCyAHIA0gCyANayIB/AoAACAAIAU2AgggACABIAdqNgIEIAAgBDYCACAGBEAgBhAvCwsPCxA2AAsQRwALIAohBSAEIQELA0AgASAFKAIANgIAIAFBBGohASAFQQRqIgUgC0kNAAsLIAAgATYCBCAEIAlBAnRrIA0gCPwKAAAgDSACIAcgAmv8CgAAC+kaAgl/A3wjAEEQayIDJAADQCABQRBrIQcDQCAAIQQDQAJAAkACQAJAAkACQAJAAkAgASAEayIIQQR1IgkOBgcHAAEEAgMLIAFBEGsiACsDACAEKwMAZEUNBiADIAT9AAMA/QsDACAEIAAoAgg2AgggBCAAKQMANwMAIAAgAygCCDYCCCAAIAMpAwA3AwAMBgsgBEEQaiEAIAFBEGsiASsDACEMIAQrAxAiDSAEKwMAZEUEQCAMIA1kRQ0GIAMgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASADKAIINgIIIAEgAykDADcDACAEKwMQIAQrAwBkRQ0GIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDAAwGCyAMIA1kBEAgAyAE/QADAP0LAwAgBCABKAIINgIIIAQgASkDADcDACABIAMoAgg2AgggASADKQMANwMADAYLIAMgBP0AAwD9CwMAIAQgACgCCDYCCCAEIAApAwA3AwAgACADKAIINgIIIAAgAykDADcDACABKwMAIAQrAxBkRQ0FIAMgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASADKAIINgIIIAEgAykDADcDAAwFCyAEIARBEGoiAiAEQSBqIgAgBEEwaiIFENgBGiABQRBrIgErAwAgBCsDMGRFDQQgAyAF/QADAP0LAwAgBSABKAIINgIIIAUgASkDADcDACABIAMoAgg2AgggASADKQMANwMAIAUrAwAgACsDAGRFDQQgAyAA/QADAP0LAwAgACAFKAIINgIIIAAgBSkDADcDACAFIAMoAgg2AgggBSADKQMANwMAIAArAwAgAisDAGRFDQQgAyAC/QADAP0LAwAgAiAAKAIINgIIIAIgACkDADcDACAAIAMoAgg2AgggACADKQMANwMAIAQrAxAgBCsD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EC8LIAAoAvinASIBBEAgAEH8pwFqIAE2AgAgARAvCyAAKALspwEiAQRAIABB8KcBaiABNgIAIAEQLwsgAEHUpwFqKAIAIgEEQCAAQdinAWogATYCACABEC8LIABBwKcBaigCACIBBEAgAEHEpwFqIAE2AgAgARAvCyAAQaynAWooAgAiAQRAIABBsKcBaiABNgIAIAEQLwsgAEGYpwFqKAIAIgEEQCAAQZynAWogATYCACABEC8LIABBuJIBahClASAAQeD9AGoQpQEgAEGI6QBqEKUBIABBsNQAahClASAAQdg/ahClASAAQYArahClASAAQagWahClASAAQdABahClASAAKAKoASIBBEAgACABNgKsASABEC8LIAAoAoABIgMEQCAAKAKEASICIAMiAUcEQANAIAJBDGsgAkEQayICKAIIEJYBIAIgA0cNAAsgACgCgAEhAQsgACADNgKEASABEC8LIAAoAlgiAwRAIAAoAlwiAiADIgFHBEADQCACQQxrIAJBEGsiAigCCBCWASACIANHDQALIAAoAlghAQsgACADNgJcIAEQLwsgAAtDACABBEAgACABKAIAEPMCIAAgASgCBBDzAiABLAArQQBIBEAgASgCIBAvCyABLAAbQQBIBEAgASgCEBAvCyABEC8LCzEAIAEEQCAAIAEoAgAQ9AIgACABKAIEEPQCIAEsAB9BAEgEQCABKAIUEC8LIAEQLwsLmUgEF34XfwR7AX0jAEGQAWsiIyQAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEoAjAiHSABKAIAIhpBJGwiG0GYmwFqKAIARyImDQAgATUCNCIDIAEpAxAgHa1+IBtBlJsBajQCAH9SDQAgATUCOCIFIAEpAxggA35SDQAgATUCPCABKQMgIAV+Ug0AIAIoAjAiGyACKAIAIhxBJGwiIkGYmwFqKAIARw0AIAI1AjQiAyACKQMQIButfiAiQZSbAWo0AgB/Ug0AIAI1AjgiBSACKQMYIAN+Ug0AIBogHEcNACACNQI8IAIpAyAgBX5RDQELAkACQAJAIBoOAgIAAQsgAikDKCIRIAIpAyAiDyACKQMYIhAgAikDECIMfn5+IAEpAygiDSABKQMgIgcgASkDGCIOIAEpAxAiCX5+flEEQAJAIAAoAgAOAw0ADQALIAIoAjwhISACKAI4IR8g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IBogHUcNACAOQgBXDQggDUIAVw0IIBsgHE4NCCAdIAynbCEAIBysIQsgG6whBQNAIB4gBKciGmwhGyAaICRsIRpCACEGA0AgKCAGpyIdbCEcIB0gIGwhHSAFIQMDQCACKALQASAhIAOnIh9saiAdaiAaaiABKALQASAfICJsaiAcaiAbaiAA/AoAACADQgF8IgMgC1INAAsgBkIBfCIGIA1SDQALIA4gBEIBfCIEUg0ACwwICwJAIBogAEEkbCImQZibAWooAgBHDQAgIa0iBSAMIBqtfiAmQZSbAWo0AgAiC39SDQAgIK0iCSAFIBB+Ug0AICStIAkgD35SDQAgHUEERgRAIABFBEAgDkIAVw0KIA1CAFcNCiAbIBxODQogAigC0AEhHSAbIAenQQJ0IgBsISEgHyAcayAAbCEfIBsgImwhJSAcIBtrQQFxISZBACECIBwgG0EBaiInRiEpA0AgHiAIp2whJEIAIQMDQCACICFqIRogKCADp2whICAmBH8gGiAdaiABKALQASAlaiAgaiAkaiAA/AoAACAAIBpqIRogJwUgGwshAiApRQRAA0AgGiAdaiABKALQASACICJsaiAgaiAkaiAA/AoAACAdIAAgGmoiGmogASgC0AEgAkEBaiAibGogIGogJGogAPwKAAAgACAaaiEaIAJBAmoiAiAcRw0ACwsgGiAfaiECIANCAXwiAyANUg0ACyAOIAhCAXwiCFINAAsMCgtBsYAcIAB2QQFxRQRAIAcgC38hAyAOQgBXDQogDUIAVw0KIBsgHE4NCiAAQSRsQaSbAWooAgAhHSACKALQASEkIBogA6dsIhogG2whJSAaIB8gHGtsISYgB6chICAbQQFqIScgGyAibCEpIBwgG2siKkEBcSErQQAhAANAIB4gCKdsISFCACEDA0AgACAlaiECICggA6dsIR8gKwR/IAEoAtABIClqIB9qICFqIAIgJGogICAdEQUAIAIgGmohAiAnBSAbCyEAICpBAUcEQANAIAEoAtABIAAgImxqIB9qICFqIAIgJGogICAdEQUAIAEoAtABIABBAWogImxqIB9qICFqICQgAiAaaiICaiAgIB0RBQAgAiAaaiECIABBAmoiACAcRw0ACwsgAiAmaiEAIANCAXwiAyANUg0ACyAOIAhCAXwiCFINAAsMCgtBvMMCKAIAEDAa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KAIMNgIAIAhBEGokAA8LEE0ACw0AIAAgASABEGgQywELIAAgAEHotQM2AgAgAEHYtgM2AgAgAEEEaiABEIoDIAALPQECfyABEGgiA0ENahAyIgJBADYCCCACIAM2AgQgAiADNgIAIAJBDGoiAiABIANBAWr8CgAAIAAgAjYCAAsSACAAKAIAIAEoAgAQnwFBH3YLgAMCBX8DfiMAQdAAayIDJAACQAJAIAEpAyAiCCACKQMYUQRAIAIpAyhCAVINASACKAIAQRJHDQICfwJAIAEoAogBDQAgAigCiAENAEEADAELQQELIQcgASkDECEJIAIpAxAhCiADIAIpAyA3A0ggAyAINwNAIAMgCjcDOCADIAk3AzAgAEEAQQQgA0EwakEAQQAQSSIEQSI2AkAgBwRAIAAgBCgCACAEKAIMIARBEGpBAEEAEEkhBQsgBCABNgKMASAEIAU2AogBIAQgAjYCkAEgA0HQAGokACAEDwtBvMMCKAIAEDAaIANBkyo2AiggA0GRJTYCJCADQeQmNgIgQbjDAigCAEHL5AAgA0EgahAxEAAAC0G8wwIoAgAQMBogA0HLPjYCGCADQZIlNgIUIANB5CY2AhBBuMMCKAIAQcvkACADQRBqEDEQAAALQbzDAigCABAwGiADQfE7NgIIIANBkyU2AgQgA0HkJjYCAEG4wwIoAgBBy+QAIAMQMRAAAAsMACAAEJQCGiAAEC8LCQAgACABEJQECwcAIAAQUhoLCAAgABCmAhoLFgAgACABIAJCgICAgICAgICAfxDgAwsJACAAEEQ2AgALIwECfyAAIQEDQCABIgJBBGohASACKAIADQALIAIgAGtBAnULBwAgACgCBAswACMAQRBrIgIkAAJAIAAgAUYEQCABQQA6AHgMAQsgAkEPaiABEJsDCyACQRBqJAALJgEBfyAAKAIEIQIDQCABIAJHBEAgAkEEayECDAELCyAAIAE2AgQLSwEBfyMAQRBrIgMkAAJAAkAgAkEeSw0AIAEtAHgNACABQQE6AHgMAQsgA0EPaiACEJ0DIQELIANBEGokACAAIAI2AgQgACABNgIAC18BBX8jAEEQayIAJAAgAEH/////AzYCDCAAQf////8HNgIIIwBBEGsiASQAIABBCGoiAigCACAAQQxqIgMoAgBJIQQgAUEQaiQAIAIgAyAEGygCACEF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AyAAIAJBAWo2AgggAiABQQx2QeABcjoAACAAIAAoAggiAkEBajYCCCACIAFBBnZBP3FBgAFyOgAAIAAgACgCCCICQQFqNgIIIAIgAUE/cUGAAXI6AAALIAAgACgCDEECaiICNgIMDAELC0ECDAILQQEMAQsgBQshCSAEIAAoAgw2AgAgByAAKAIINgIAIABBEGokACAJCz4BA38jAEEQayIBJAAgASAANgIMIAFBCGogAUEMahB/IQNBBEEBIwMoAmAoAgAbIQIgAxB+IAFBEGokACACCzwBAn8jAEEQayIFJAAgBSAENgIMIAVBCGogBUEMahB/IQYgACABIAIgAxDwASEAIAYQfiAFQRBqJAAgAAsSACAEIAI2AgAgByAFNgIAQQMLKAEBfyAAQdzsAjYCAAJAIAAoAggiAUUNACAALQAMRQ0AIAEQLwsgAAsEACABC0ABAn8gACgCACgCACIAKAIAIAAoAggiAkEBdWohASAAKAIEIQAgASACQQFxBH8gASgCACAAaigCAAUgAAsRAQALLgAgASAAQQhqIgAoAgQgACgCACIAa0ECdUkEfyABQQJ0IABqKAIAQQBHBUEACwvLAQEDfyAAQcjsAjYCACAAQQhqIQMDQCACIAAoAgwgACgCCCIBa0ECdUkEQCACQQJ0IAFqKAIAIgEEQCABQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsLIAJBAWohAgwBCwsgAEGYAWoQMxojAEEQayICJAAgAiADNgIMIAIoAgwiASgCBBogASgCCBogASgCABogASgCAARAIAEQsAMgAigCDEEQaiACKAIMIgEoAgAgASgCCCABKAIAa0ECdRCVAwsgAkEQaiQAIAALDAAgACAAKAIAEJYDC3ABAX8jAEEQayICJAAgAiAANgIEIAIgACgCBCIANgIIIAIgACABQQJ0ajYCDCACKAIIIQEgAigCDCEAA0AgACABRgRAIAIoAgQgAigCCDYCBCACQRBqJAAFIAFBADYCACACIAFBBGoiATYCCAwBCwsLIAAgAEGY9QI2AgAgACgCCBBERwRAIAAoAggQ4wMLIAALBABBfwvgAQEIfyMAQRBrIgUkACMAQSBrIgMkACADQRhqIAAgARCaAyADQRBqIANBDGogAygCGCADKAIcIAIQvAIgAygCECEEIwBBEGsiASQAIAEgADYCDCABQQxqIgAhCiAEIQcgACgCACEEIwBBEGsiACQAIAAgBDYCDCAKIAchCSAAKAIMIQYgAEEQaiQAIAkgBmtBAnUQrgIhACABQRBqJAAgAyAANgIMIAMgAiADKAIUIAJrajYCCCAFIAMoAgw2AgggBSADKAIINgIMIANBIGokACAFKAIMIQggBUEQaiQAIAgL8gcBDH8jAEEQayITJAAgAiAANgIAIANBgARxIRUgB0ECdCEWA0AgFEEERgRAAn8gDS0AC0EHdgRAIA0oAgQMAQsgDS0AC0H/AHELQQFLBEAgEyANEHU2AgwgAiATQQxqQQEQrgIgDRCbASACKAIAELQDNgIACyADQbABcSIDQRBHBEAgASADQSBGBH8gAigCAAUgAAs2AgALIBNBEGokAAUCQAJAAkACQAJAAkAgCCAUaiwAAA4FAAEDAgQFCyABIAIoAgA2AgAMBAsgASACKAIANgIAIAZBICAGKAIAKAIsEQQAIQcgAiACKAIAIg9BBGo2AgAgDyAHNgIADAMLAn8gDS0AC0EHdgRAIA0oAgQMAQsgDS0AC0H/AHELRQ0CAn8gDS0AC0EHdgRAIA0oAgAMAQsgDQsoAgAhByACIAIoAgAiD0EEajYCACAPIAc2AgAMAgsCfyAMLQALQQd2BEAgDCgCBAwBCyAMLQALQf8AcQtFIRkgFUUNASAZDQEgAiAMEHUgDBCbASACKAIAELQDNgIADAELIAIoAgAhGiAEIBZqIgQhBwNAAkAgBSAHTQ0AIAZBwAAgBygCACAGKAIAKAIMEQMARQ0AIAdBBGohBwwBCwsgDkEASgRAIAIoAgAhDyAOIRADQAJAIAQgB08NACAQRQ0AIBBBAWshECAHQQRrIgcoAgAhESACIA9BBGoiEjYCACAPIBE2AgAgEiEPDAELCwJAIBBFBEBBACERDAELIAZBMCAGKAIAKAIsEQQAIREgAigCACEPCwNAIA9BBGohEiAQQQBKBEAgDyARNgIAIBBBAWshECASIQ8MAQsLIAIgEjYCACAPIAk2AgALAkAgBCAHRgRAIAZBMCAGKAIAKAIsEQQAIQ8gAiACKAIAIhBBBGoiBzYCACAQIA82AgAMAQsCfyALLQALQQd2BEAgCygCBAwBCyALLQALQf8AcQsEfwJ/IAstAAtBB3YEQCALKAIADAELIAsLLAAABUF/CyERQQAhD0EAIRADQCAEIAdHBEACQCAPIBFHBEAgDyESDAELIAIgAigCACISQQRqNgIAIBIgCjYCAEEAIRICfyALLQALQQd2BEAgCygCBAwBCyALLQALQf8AcQsgEEEBaiIQTQRAIA8hEQwBCwJ/IAstAAtBB3YEQCALKAIADAELIAsLIBBqLQAAQf8ARgRAQX8hEQwBCwJ/IAstAAtBB3YEQCALKAIADAELIAsLIBBqLAAAIRELIAdBBGsiBygCACEPIAIgAigCACIYQQRqNgIAIBggDzYCACASQQFqIQ8MAQsLIAIoAgAhBwsgGiAHEOoBCyAUQQFqIRQMAQsLC+cDAQF/IwBBEGsiCiQAIAkCfyAABEAgAhC7AyEAAkAgAQRAIApBBGoiASAAIAAoAgAoAiwRAgAgAyAKKAIENgAAIAEgACAAKAIAKAIgEQIADAELIApBBGoiASAAIAAoAgAoAigRAgAgAyAKKAIENgAAIAEgACAAKAIAKAIcEQIACyAIIAEQiAEgARBQGiAEIAAgACgCACgCDBEAADYCACAFIAAgACgCACgCEBEAADYCACAKQQRqIgEgACAAKAIAKAIUEQIAIAYgARBlIAEQMxogASAAIAAoAgAoAhgRAgAgByABEIgBIAEQUBogACAAKAIAKAIkEQAADAELIAIQugMhAAJAIAEEQCAKQQRqIgEgACAAKAIAKAIsEQIAIAMgCigCBDYAACABIAAgACgCACgCIBECAAwBCyAKQQRqIgEgACAAKAIAKAIoEQIAIAMgCigCBDYAACABIAAgACgCACgCHBECAAsgCCABEIgBIAEQUBogBCAAIAAoAgAoAgwRAAA2AgAgBSAAIAAoAgAoAhARAAA2AgAgCkEEaiIBIAAgACgCACgCFBECACAGIAEQZSABEDMaIAEgACAAKAIAKAIYEQIAIAcgARCIASABEFAaIAAgACgCACgCJBEAAAs2AgAgCkEQaiQAC90BAQh/IwBBEGsiBSQAIwBBIGsiAyQAIANBGGogACABEJoDIANBEGogA0EMaiADKAIYIAMoAhwgAhC8AiADKAIQIQQjAEEQayIBJAAgASAANgIMIAFBDGoiACEKIAQhByAAKAIAIQQjAEEQayIAJAAgACAENgIMIAogByEJIAAoAgwhBiAAQRBqJAAgCSAGaxCvAiEAIAFBEGokACADIAA2AgwgAyACIAMoAhQgAmtqNgIIIAUgAygCDDYCCCAFIAMoAgg2AgwgA0EgaiQAIAUoAgwhCCAFQRBqJAAgCAveBwEMfyMAQRBrIhMkACACIAA2AgAgA0GABHEhFgNAIBRBBEYEQAJ/IA0tAAtBB3YEQCANKAIEDAELIA0tAAtB/wBxC0EBSwRAIBMgDRB1NgIMIAIgE0EMakEBEK8CIA0QnQEgAigCABC3AzYCAAsgA0GwAXEiA0EQRwRAIAEgA0EgRgR/IAIoAgAFIAALNgIACyATQRBqJAAFAkACQAJAAkACQAJAIAggFGosAAAOBQABAwIEBQsgASACKAIANgIADAQLIAEgAigCADYCACAGQSAgBigCACgCHBEEACEPIAIgAigCACIQQQFqNgIAIBAgDzoAAAwDCwJ/IA0tAAtBB3YEQCANKAIEDAELIA0tAAtB/wBxC0UNAgJ/IA0tAAtBB3YEQCANKAIADAELIA0LLQAAIQ8gAiACKAIAIhBBAWo2AgAgECAPOgAADAILAn8gDC0AC0EHdgRAIAwoAgQMAQsgDC0AC0H/AHELRSEZIBZFDQEgGQ0BIAIgDBB1IAwQnQEgAigCABC3AzYCAAwBCyACKAIAIRogBCAHaiIEIREDQAJAIAUgEU0NACARLAAAIg9BAE4EfyAGKAIIIA9B/wFxQQJ0aigCAEHAAHFBAEcFQQALRQ0AIBFBAWohEQwBCwsgDiIPQQBKBEADQAJAIAQgEU8NACAPRQ0AIA9BAWshDyARQQFrIhEtAAAhECACIAIoAgAiEkEBajYCACASIBA6AAAMAQsLIA8EfyAGQTAgBigCACgCHBEEAAVBAAshEgNAIAIgAigCACIQQQFqNgIAIA9BAEoEQCAQIBI6AAAgD0EBayEPDAELCyAQIAk6AAALAkAgBCARRgRAIAZBMCAGKAIAKAIcEQQAIQ8gAiACKAIAIhBBAWo2AgAgECAPOgAADAELAn8gCy0AC0EHdgRAIAsoAgQMAQsgCy0AC0H/AHELBH8CfyALLQALQQd2BEAgCygCAAwBCyALCywAAAVBfwshEkEAIQ9BACEQA0AgBCARRg0BAkAgDyASRwRAIA8hFQwBCyACIAIoAgAiEkEBajYCACASIAo6AABBACEVAn8gCy0AC0EHdgRAIAsoAgQMAQsgCy0AC0H/AHELIBBBAWoiEE0EQCAPIRIMAQsCfyALLQALQQd2BEAgCygCAAwBCyALCyAQai0AAEH/AEYEQEF/IRIMAQsCfyALLQALQQd2BEAgCygCAAwBCyALCyAQaiwAACESCyARQQFrIhEtAAAhDyACIAIoAgAiGEEBajYCACAYIA86AAAgFUEBaiEPDAALAAsgGiACKAIAEKwBCyAUQQFqIRQMAQsLC+MDAQF/IwBBEGsiCiQAIAkCfyAABEAgAhDAAyEAAkAgAQRAIApBBGoiASAAIAAoAgAoAiwRAgAgAyAKKAIENgAAIAEgACAAKAIAKAIgEQIADAELIApBBGoiASAAIAAoAgAoAigRAgAgAyAKKAIENgAAIAEgACAAKAIAKAIcEQIACyAIIAEQZSABEDMaIAQgACAAKAIAKAIMEQAAOgAAIAUgACAAKAIAKAIQEQAAOgAAIApBBGoiASAAIAAoAgAoAhQRAgAgBiABEGUgARAzGiABIAAgACgCACgCGBECACAHIAEQZSABEDMaIAAgACgCACgCJBEAAAwBCyACEL8DIQACQCABBEAgCkEEaiIBIAAgACgCACgCLBECACADIAooAgQ2AAAgASAAIAAoAgAoAiARAgAMAQsgCkEEaiIBIAAgACgCACgCKBECACADIAooAgQ2AAAgASAAIAAoAgAoAhwRAgALIAggARBlIAEQMxogBCAAIAAoAgAoAgwRAAA6AAAgBSAAIAAoAgAoAhARAAA6AAAgCkEEaiIBIAAgACgCACgCFBECACAGIAEQZSABEDMaIAEgACAAKAIAKAIYEQIAIAcgARBlIAEQMxogACAAKAIAKAIkEQAACzYCACAKQRBqJAALCgAgAEGwiTUQeQsKACAAQbiJNRB5Cx8BAX8gASgCABD7AyECIAAgASgCADYCBCAAIAI2AgALwBgBCX8jAEGQBGsiCyQAIAsgCjYCiAQgCyABNgKMBAJAIAAgC0GMBGoQQgRAIAUgBSgCAEEEcjYCAEEAIQAMAQsgC0H3ATYCSCALIAtB6ABqIAtB8ABqIAtByABqIg8QUSIRKAIAIgE2AmQgCyABQZADajYCYCMAQRBrIgEkACAPQgA3AgAgD0EANgIIIAFBEGokACMAQRBrIgEkACALQTxqIg5CADcCACAOQQA2AgggAUEQaiQAIwBBEGsiASQAIAtBMGoiDUIANwIAIA1BADYCCCABQRBqJAAjAEEQayIBJAAgC0EkaiIMQgA3AgAgDEEANgIIIAFBEGokACMAQRBrIgEkACALQRhqIhBCADcCACAQQQA2AgggAUEQaiQAIwBBEGsiCiQAIAsCfyACBEAgCkEEaiICIAMQuwMiASABKAIAKAIsEQIAIAsgCigCBDYAXCACIAEgASgCACgCIBECACAMIAIQiAEgAhBQGiACIAEgASgCACgCHBECACANIAIQiAEgAhBQGiALIAEgASgCACgCDBEAADYCWCALIAEgASgCACgCEBEAADYCVCACIAEgASgCACgCFBECACAPIAIQZSACEDMaIAIgASABKAIAKAIYEQIAIA4gAhCIASACEFAaIAEgASgCACgCJBEAAAwBCyAKQQRqIgIgAxC6AyIBIAEoAgAoAiwRAgAgCyAKKAIENgBcIAIgASABKAIAKAIgEQIAIAwgAhCIASACEFAaIAIgASABKAIAKAIcEQIAIA0gAhCIASACEFAaIAsgASABKAIAKAIMEQAANgJYIAsgASABKAIAKAIQEQAANgJUIAIgASABKAIAKAIUEQIAIA8gAhBlIAIQMxogAiABIAEoAgAoAhgRAgAgDiACEIgBIAIQUBogASABKAIAKAIkEQAACzYCFCAKQRBqJAAgCSAIKAIANgIAIARBgARxIRJBACEDQQAhAQNAIAEhAgJAAkACQAJAIANBBEYNACAAIAtBjARqEEINAEEAIQoCQAJAAkACQAJAAkAgC0HcAGogA2osAAAOBQEABAMFCQsgA0EDRg0HIAdBAQJ/IAAoAgAiASgCDCIEIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAQoAgALIAcoAgAoAgwRAwAEQCALQQxqIAAQvAMgECALKAIMEKECDAILIAUgBSgCAEEEcjYCAEEAIQAMBgsgA0EDRg0GCwNAIAAgC0GMBGoQQg0GIAdBAQJ/IAAoAgAiASgCDCIEIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAQoAgALIAcoAgAoAgwRAwBFDQYgC0EMaiAAELwDIBAgCygCDBChAgwACwALAkACfyANLQALQQd2BEAgDSgCBAwBCyANLQALQf8AcQtFDQACfyAAKAIAIgEoAgwiBCABKAIQRgRAIAEgASgCACgCJBEAAAwBCyAEKAIACwJ/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CyADKAIACwJ/IAItAAtBB3YEQCACKAIADAELIAILIApBAnRqKAIARg0BCyAFIAUoAgBBBHI2AgBBACEADAMLIAAQXBogCkEBaiEKDAALAAtBASEAIBEoAgAgCygCZEYNAEEAIQAgC0EANgIMIA8gESgCACALKAJkIAtBDGoQZCALKAIMBEAgBSAFKAIAQQRyNgIADAELQQEhAAsgEBBQGiAMEFAaIA0QUBogDhBQGiAPEDMaIBEoAgAhASARQQA2AgAgAQRAIAEgESgCBBEBAAsMAwsgAiEBCyADQQFqIQMMAAsACyALQZAEaiQAIAALOQECfyABKAIAIQMgAUEANgIAIAAoAgAhAiAAIAM2AgAgAgRAIAIgACgCBBEBAAsgACABKAIENgIECwoAIABBoIk1EHkLCgAgAEGoiTUQeQvkAQEGfyMAQRBrIgUkACAAKAIEIQNBAQJ/IAIoAgAgACgCAGsiBEH/////B0kEQCAEQQF0DAELQX8LIgQgBEEBTRshBCABKAIAIQcgACgCACEIIANB9wFGBH9BAAUgACgCAAsgBBDEASIGBEAgA0H3AUcEQCAAKAIAGiAAQQA2AgALIAVB9gE2AgQgACAFQQhqIAYgBUEEahBRIgMQvgMgAygCACEGIANBADYCACAGBEAgBiADKAIEEQEACyABIAAoAgAgByAIa2o2AgAgAiAEIAAoAgBqNgIAIAVBEGokAA8LEEYACyABAX8gASgCABD9A8AhAiAAIAEoAgA2AgQgACACOgAAC6kZAQl/IwBBkARrIgskACALIAo2AogEIAsgATYCjAQCQCAAIAtBjARqEEMEQCAFIAUoAgBBBHI2AgBBACEADAELIAtB9wE2AkwgCyALQegAaiALQfAAaiALQcwAaiIPEFEiESgCACIBNgJkIAsgAUGQA2o2AmAjAEEQayIBJAAgD0IANwIAIA9BADYCCCABQRBqJAAjAEEQayIBJAAgC0FAayIOQgA3AgAgDkEANgIIIAFBEGokACMAQRBrIgEkACALQTRqIg1CADcCACANQQA2AgggAUEQaiQAIwBBEGsiASQAIAtBKGoiDEIANwIAIAxBADYCCCABQRBqJAAjAEEQayIBJAAgC0EcaiIQQgA3AgAgEEEANgIIIAFBEGokACMAQRBrIgokACALAn8gAgRAIApBBGoiAiADEMAD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fHwhFiAOIAhBAEdqIQ4LIAFBAWohBCABLQABIgENAQwICwsgBSEADAELQQEhB0EAIQpBACEADAILIAwhBwwDCyAMIQcLIA4NAQtBfyEOCyAHRQ0AIAoQLyAAEC8LIBEEQCADEIEBCyAGQbACaiQAIANBkAFqJAAgDgtDAAJAIABFDQACQAJAAkACQCABQQJqDgYAAQICBAMECyAAIAI8AAAPCyAAIAI9AQAPCyAAIAI+AgAPCyAAIAI3AwALC7UDAgN/AX4jAEEgayIDJAACQCABQv///////////wCDIgVCgICAgICAwMA/fSAFQoCAgICAgMC/wAB9VARAIAFCGYinIQQgAFAgAUL///8PgyIFQoCAgAhUIAVCgICACFEbRQRAIARBgYCAgARqIQIMAgsgBEGAgICABGohAiAAIAVCgICACIWEQgBSDQEgAiAEQQFxaiECDAELIABQIAVCgICAgICAwP//AFQgBUKAgICAgIDA//8AURtFBEAgAUIZiKdB////AXFBgICA/gdyIQIMAQtBgICA/AchAiAFQv///////7+/wABWDQBBACECIAVCMIinIgRBkf4ASQ0AIANBEGogACABQv///////z+DQoCAgICAgMAAhCIFIARBgf4AaxBmIAMgACAFQYH/ACAEaxCvASADKQMIIgBCGYinIQIgAykDACADKQMQIAMpAxiEQgBSrYQiBVAgAEL///8PgyIAQoCAgAhUIABCgICACFEbRQRAIAJBAWohAgwBCyAFIABCgICACIWEQgBSDQAgAkEBcSACaiECCyADQSBqJAAgAiABQiCIp0GAgICAeHFyvguNBAIFfwF+AkACQAJAAkACQAJ/IAAoAgQiAiAAKAJoRwRAIAAgAkEBajYCBCACLQAADAELIAAQPwsiAkEraw4DAAEAAQsgAkEtRiEFAn8gACgCBCIDIAAoAmhHBEAgACADQQFqNgIEIAMtAAAMAQsgABA/CyIDQTprIQQgAUUNASAEQXVLDQEgACkDcEIAUw0CIAAgACgCBEEBazYCBAwCCyACQTprIQQgAiEDCyAEQXZJDQACQCADQTBrQQpPDQBBACECA0AgAyACQQpsaiEGAn8gACgCBCICIAAoAmhHBEAgACACQQFqNgIEIAItAAAMAQsgABA/CyEDIAZBMGshAiACQcyZs+YASCADQTBr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IwNBHGpBxAA2AgALIARB8AJqIBcgFiAPEO0DIAQpA/gCIRUgBCkD8AILIRYgDiAVNwMoIA4gFjcDICAEQZDGAGokACAOKQMoIRUgDikDICEWDAQLIAEpA3BCAFkEQCABIAEoAgRBAWs2AgQLDAELAkACfyABKAIEIgIgASgCaEcEQCABIAJBAWo2AgQgAi0AAAwBCyABED8LQShGBEBBASEGDAELQoCAgICAgOD//wAhFSABKQNwQgBTDQMgASABKAIEQQFrNgIEDAMLA0ACfyABKAIEIgIgASgCaEcEQCABIAJBAWo2AgQgAi0AAAwBCyABED8LIglBwQBrIQICQAJAIAlBMGtBCkkNACACQRpJDQAgCUHfAEYNACAJQeEAa0EaTw0BCyAGQQFqIQYMAQsLQoCAgICAgOD//wAhFSAJQSlGDQIgASkDcCIYQgBZBEAgASABKAIEQQFrNgIECwJAIAMEQCAGDQEMBAsMAQsDQCAYQgBZBEAgASABKAIEQQFrNgIECyAGQQFrIgYNAAsMAgsjA0EcakEcNgIAIAFCABCAAQtCACEVCyAAIBY3AwAgACAVNwMIIA5BMGokAAvKBgIFfwR+IwBBgAFrIgUkAAJAAkACQCADIARCAEIAEK4BRQ0AAn8gBEL///////8/gyELAn8gBEIwiKdB//8BcSIGQf//AUcEQEEEIAYNARpBAkEDIAMgC4RQGwwCCyADIAuEUAsLIQkgAkIwiKciCEH//wFxIgdB//8BRg0AIAkNAQsgBUEQaiABIAIgAyAEEEsgBSAFKQMQIgIgBSkDGCIBIAIgARDsAyAFKQMIIQIgBSkDACEEDAELIAEgAkL///////////8AgyILIAMgBEL///////////8AgyIKEK4BQQBMBEAgASALIAMgChCuAQRAIAEhBAwCCyAFQfAAaiABIAJCAEIAEEsgBSkDeCECIAUpA3AhBAwBCyAEQjCIp0H//wFxIQYgBwR+IAEFIAVB4ABqIAEgC0IAQoCAgICAgMC7wAAQSyAFKQNoIgtCMIinQfgAayEHIAUpA2ALIQQgBkUEQCAFQdAAaiADIApCAEKAgICAgIDAu8AAEEsgBSkDWCIKQjCIp0H4AGshBiAFKQNQIQMLIApC////////P4NCgICAgICAwACEIQwgC0L///////8/g0KAgICAgIDAAIQhCyAGIAdIBEADQAJ+IAsgDH0gAyAEVq19IgpCAFkEQCAKIAQgA30iBIRQBEAgBUEgaiABIAJCAEIAEEsgBSkDKCECIAUpAyAhBAwFCyAKQgGGIARCP4iEDAELIAtCAYYgBEI/iIQLIQsgBEIBhiEEIAdBAWsiByAGSg0ACyAGIQcLAkAgCyAMfSADIARWrX0iCkIAUwRAIAshCgwBCyAKIAQgA30iBIRCAFINACAFQTBqIAEgAkIAQgAQSyAFKQM4IQIgBSkDMCEEDAELIApC////////P1gEQANAIARCP4ghDSAHQQFrIQcgBEIBhiEEIA0gCkIBhoQiCkKAgICAgIDAAFQNAAsLIAhBgIACcSEGIAdBAEwEQCAFQUBrIAQgCkL///////8/gyAHQfgAaiAGcq1CMIaEQgBCgICAgICAwMM/EEsgBSkDSCECIAUpA0AhBAwBCyAKQv///////z+DIAYgB3KtQjCGhCECCyAAIAQ3AwAgACACNwMIIAVBgAFqJAALqg8CBX8PfiMAQdACayIFJAAgBEL///////8/gyELIAJC////////P4MhCiACIASFQoCAgICAgICAgH+DIQ0gBEIwiKdB//8BcSEIAkACQCACQjCIp0H//wFxIglB//8Ba0GCgH5PBEAgCEH//wFrQYGAfksNAQsgAVAgAkL///////////8AgyIMQoCAgICAgMD//wBUIAxCgICAgICAwP//AFEbRQRAIAJCgICAgICAIIQhDQwCCyADUCAEQv///////////wCDIgJCgICAgICAwP//AFQgAkKAgICAgIDA//8AURtFBEAgBEKAgICAgIAghCENIAMhAQwCCyABIAxCgICAgICAwP//AIWEUARAIAMgAkKAgICAgIDA//8AhYRQBEBCACEBQoCAgICAgOD//wAhDQwDCyANQoCAgICAgMD//wCEIQ1CACEBDAILIAMgAkKAgICAgIDA//8AhYRQBEBCACEBDAILIAEgDIRQBEBCgICAgICA4P//ACANIAIgA4RQGyENQgAhAQwCCyACIAOEUARAIA1CgICAgICAwP//AIQhDUIAIQEMAgsgDEL///////8/WARAIAVBwAJqIAEgCiABIAogClAiBht5IAZBBnStfKciBkEPaxBmQRAgBmshBiAFKQPIAiEKIAUpA8ACIQELIAJC////////P1YNACAFQbACaiADIAsgAyALIAtQIgcbeSAHQQZ0rXynIgdBD2sQZiAGIAdqQRBrIQYgBSkDuAIhCyAFKQOwAiEDCyAFQaACaiALQoCAgICAgMAAhCISQg+GIANCMYiEIgJCAEKAgICAsOa8gvUAIAJ9IgRCABBgIAVBkAJqQgAgBSkDqAJ9QgAgBEIAEGAgBUGAAmogBSkDmAJCAYYgBSkDkAJCP4iEIgRCACACQgAQYCAFQfABaiAEQgBCACAFKQOIAn1CABBgIAVB4AFqIAUpA/gBQgGGIAUpA/ABQj+IhCIEQgAgAkIAEGAgBUHQAWogBEIAQgAgBSkD6AF9QgAQYCAFQcABaiAFKQPYAUIBhiAFKQPQAUI/iIQiBEIAIAJCABBgIAVBsAFqIARCAEIAIAUpA8gBfUIAEGAgBUGgAWogAkIAIAUpA7gBQgGGIAUpA7ABQj+IhEIBfSICQgAQYCAFQZABaiADQg+GQgAgAkIAEGAgBUHwAGogAkIAQgAgBSkDqAEgBSkDoAEiDCAFKQOYAXwiBCAMVK18IARCAVatfH1CABBgIAVBgAFqQgEgBH1CACACQgAQYCAGIAkgCGtqIQYCfyAFKQNwIhNCAYYiDiAFKQOIASIPQgGGIAUpA4ABQj+IhHwiEELn7AB9IhRCIIgiAiAKQoCAgICAgMAAhCIVQgGGIhZCIIgiBH4iESABQgGGIgxCIIgiCyAQIBRWrSAOIBBWrSAFKQN4QgGGIBNCP4iEIA9CP4h8fHxCAX0iE0IgiCIQfnwiDiARVK0gDiAOIBNC/////w+DIhMgAUI/iCIXIApCAYaEQv////8PgyIKfnwiDlatfCAEIBB+fCAEIBN+IhEgCiAQfnwiDyARVK1CIIYgD0IgiIR8IA4gDiAPQiCGfCIOVq18IA4gDiAUQv////8PgyIUIAp+IhEgAiALfnwiDyARVK0gDyAPIBMgDEL+////D4MiEX58Ig9WrXx8Ig5WrXwgDiAEIBR+IhggECARfnwiBCACIAp+fCIKIAsgE358IhBCIIggCiAQVq0gBCAYVK0gBCAKVq18fEIghoR8IgQgDlStfCAEIA8gAiARfiICIAsgFH58IgtCIIggAiALVq1CIIaEfCICIA9UrSACIBBCIIZ8IAJUrXx8IgIgBFStfCIEQv////////8AWARAIBYgF4QhFSAFQdAAaiACIAQgAyASEGAgAUIxhiAFKQNYfSAFKQNQIgFCAFKtfSEKQgAgAX0hCyAGQf7/AGoMAQsgBUHgAGogBEI/hiACQgGIhCICIARCAYgiBCADIBIQYCABQjCGIAUpA2h9IAUpA2AiDEIAUq19IQpCACAMfSELIAEhDCAGQf//AGoLIgZB//8BTgRAIA1CgICAgICAwP//AIQhDUIAIQEMAQsCfiAGQQBKBEAgCkIBhiALQj+IhCEKIARC////////P4MgBq1CMIaEIQwgC0IBhgwBCyAGQY9/TARAQgAhAQwCCyAFQUBrIAIgBEEBIAZrEK8BIAVBMGogDCAVIAZB8ABqEGYgBUEgaiADIBIgBSkDQCICIAUpA0giDBBgIAUpAzggBSkDKEIBhiAFKQMgIgFCP4iEfSAFKQMwIgQgAUIBhiIBVK19IQogBCABfQshBCAFQRBqIAMgEkIDQgAQYCAFIAMgEkIFQgAQYCAMIAIgAiADIAJCAYMiASAEfCIDVCAKIAEgA1atfCIBIBJWIAEgElEbrXwiAlatfCIEIAIgAiAEQoCAgICAgMD//wBUIAMgBSkDEFYgASAFKQMYIgRWIAEgBFEbca18IgJWrXwiBCACIARCgICAgICAwP//AFQgAyAFKQMAViABIAUpAwgiA1YgASADURtxrXwiASACVK18IA2EIQ0LIAAgATcDACAAIA03AwggBUHQAmokAAu/AgEBfyMAQdAAayIEJAACQCADQYCAAU4EQCAEQSBqIAEgAkIAQoCAgICAgID//wAQSyAEKQMoIQIgBCkDICEBIANB//8BSQRAIANB//8AayEDDAILIARBEGogASACQgBCgICAgICAgP//ABBLQf3/AiADIANB/f8CThtB/v8BayEDIAQpAxghAiAEKQMQIQEMAQsgA0GBgH9KDQAgBEFAayABIAJCAEKAgICAgICAORBLIAQpA0ghAiAEKQNAIQEgA0H0gH5LBEAgA0GN/wBqIQMMAQsgBEEwaiABIAJCAEKAgICAgICAORBLQeiBfSADIANB6IF9TBtBmv4BaiEDIAQpAzghAiAEKQMwIQELIAQgASACQgAgA0H//wBqrUIwhhBLIAAgBCkDCDcDCCAAIAQpAwA3AwAgBEHQAGokAAs1ACAAIAE3AwAgACACQv///////z+DIARCMIinQYCAAnEgAkIwiKdB//8BcXKtQjCGhDcDCAvAAQIBfwJ+QX8hAwJAIABCAFIgAUL///////////8AgyIEQoCAgICAgMD//wBWIARCgICAgICAwP//AFEbDQAgAkL///////////8AgyIFQoCAgICAgMD//wBWIAVCgICAgICAwP//AFJxDQAgACAEIAWEhFAEQEEADwsgASACg0IAWQRAIAEgAlIgASACU3ENASAAIAEgAoWEQgBSDwsgAEIAUiABIAJVIAEgAlEbDQAgACABIAKFhEIAUiEDCyADC0sBAn8gACgCACIBBEACfyABKAIMIgIgASgCEEYEQCABIAEoAgAoAiQRAAAMAQsgAigCAAtBf0cEQCAAKAIARQ8LIABBADYCAAtBAQtLAQJ/IAAoAgAiAQRAAn8gASgCDCICIAEoAhBGBEAgASABKAIAKAIkEQAADAELIAItAAALQX9HBEAgACgCAEUPCyAAQQA2AgALQQELpAEBA38gAUEISwRAQQQgASABQQRNGyEBQQEgACAAQQFNGyEAA0ACQCAAIAFqQQFrQQAgAWtxIgIgACAAIAJJGyEDQQAhBCMAQRBrIgIkAAJAIAFBA3ENACADIAFwDQAgAkEMaiABIAMQgwQhA0EAIAIoAgwgAxshBAsgAkEQaiQAIAQiAg0AQayZNf4QAgAiA0UNACADEQkADAELCyACDwsgABAyCwkAIAFBARDyAwsTACABQQhLBEAgABAvDwsgABAvC4YBAQN/IwBBEGsiBCQAIwBBIGsiAyQAIANBGGogACABEL0CIANBEGogA0EMaiADKAIYIAMoAhwgAhC8AiADIAAgAygCECAAa2o2AgwgAyACIAMoAhQgAmtqNgIIIAQgAygCDDYCCCAEIAMoAgg2AgwgA0EgaiQAIAQoAgwhBSAEQRBqJAAgBQsJACAAEL4CEC8LpQEBB38jAEEQayICJAAgACgCQCIBBH8gAkHSATYCBCACQQhqIAEgAkEEahBRIQEgACAAKAIAKAIYEQAAIQQgASgCACEGIAFBADYCACAGEKwEIQUgAEEANgJAIABBAEEAIAAoAgAoAgwRAwAaIAEoAgAhAyABQQA2AgAgAwRAIAMgAUEEaigCABEAABoLQQAgACAEIAVyGwVBAAshByACQRBqJAAgBwsKACAAQaSKNRB5C4YC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KAIANgIADwsgAiACKAIAIgFBBGo2AgAgACABMgEANwMADwsgAiACKAIAIgFBBGo2AgAgACABMwEANwMADwsgAiACKAIAIgFBBGo2AgAgACABMAAANwMADwsgAiACKAIAIgFBBGo2AgAgACABMQAANwMADwsgAiACKAIAQQdqQXhxIgFBCGo2AgAgACABKwMAOQMADwsgACACIAMRAgALDwsgAiACKAIAIgFBBGo2AgAgACABNAIANwMADwsgAiACKAIAIgFBBGo2AgAgACABNQIANwMADwsgAiACKAIAQQdqQXhxIgFBCGo2AgAgACABKQMANwMAC3IBA38gACgCACwAAEEwa0EKTwRAQQAPCwNAIAAoAgAhA0F/IQEgAkHMmbPmAE0EQEF/IAMsAABBMGsiASACQQpsIgJqIAEgAkH/////B3NKGyEBCyAAIANBAWo2AgAgASECIAMsAAFBMGtBCkkNAAsgAguZEwIWfwF+IwBB0ABrIggkACAIIAE2AkwgCEE3aiEYIAhBOGohEgJAAkACQANAQQAhBwNAIAEhDSAHIBFB/////wdzSg0CIAcgEWohEQJAAkACQCABIgctAAAiCQRAA0ACQAJAIAlB/wFxIgFFBEAgByEBDAELIAFBJUcNASAHIQkDQCAJLQABQSVHBEAgCSEBDAILIAdBAWohByAJLQACIRogCUECaiIBIQkgGkElRg0ACwsgByANayIHIBFB/////wdzIhlKDQggAARAIAAgDSAHEGELIAcNBiAIIAE2AkwgAUEBaiEHQX8hDgJAIAEsAAFBMGsiC0EKTw0AIAEtAAJBJEcNACABQQNqIQcgCyEOQQEhEwsgCCAHNgJMQQAhDAJAIAcsAAAiCUEgayIBQR9LBEAgByELDAELIAchC0EBIAF0IgFBidEEcUUNAANAIAggB0EBaiILNgJMIAEgDHIhDCAHLAABIglBIGsiAUEgTw0BIAshB0EBIAF0IgFBidEEcQ0ACwsCQCAJQSpGBEAgC0EBaiEJAn8CQCALLAABQTBrQQpPDQAgCy0AAkEkRw0AIAksAABBMGshASALQQNqIQlBASETAn8gAEUEQCAEIAFBAnRqQQo2AgBBAAwBCyADIAFBA3RqKAIACwwBCyATDQYgAEUEQCAIIAk2AkxBACETQQAhDwwDCyACIAIoAgAiAUEEajYC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BQUAAQIDBAsgAUEQayIBKwMAIAArAwBkRQ0EIAIgAP0AAwD9CwMAIAAgASgCCDYCCCAAIAEpAwA3AwAgASACKAIINgIIIAEgAikDADcDAAwECyAAQRBqIQMgAUEQayIBKwMAIQkgACsDECIKIAArAwBkRQRAIAkgCmRFDQQgAiAD/QADAP0LAwAgAyABKAIINgIIIAMgASkDADcDACABIAIoAgg2AgggASACKQMANwMAIAArAxAgACsDAGRFDQQgAiAA/QADAP0LAwAgACADKAIINgIIIAAgAykDADcDACADIAIoAgg2AgggAyACKQMANwMADAQLIAkgCmQEQCACIAD9AAMA/QsDACAAIAEoAgg2AgggACABKQMANwMAIAEgAigCCDYCCCABIAIpAwA3AwAMBAsgAiAA/QADAP0LAwAgACADKAIINgIIIAAgAykDADcDACADIAIoAgg2AgggAyACKQMANwMAIAErAwAgACsDEGRFDQMgAiAD/QADAP0LAwAgAyABKAIINgIIIAMgASkDADcDACABIAIoAgg2AgggASACKQMANwMADAMLIAAgAEEQaiAAQSBqIAFBEGsQ2AEaDAILIAAgAEEQaiIEIABBIGoiAyAAQTBqIgUQ2AEaIAFBEGsiASsDACAAKwMwZEUNASACIAX9AAMA/QsDACAFIAEoAgg2AgggBSABKQMANwMAIAEgAigCCDYCCCABIAIpAwA3AwAgBSsDACADKwMAZEUNASACIAP9AAMA/QsDACADIAUoAgg2AgggAyAFKQMANwMAIAUgAigCCDYCCCAFIAIpAwA3AwAgAysDACAEKwMAZEUNASACIAT9AAMA/QsDACAEIAMoAgg2AgggBCADKQMANwMAIAMgAigCCDYCCCADIAIpAwA3AwAgACsDECAAKwMAZEUNASACIAD9AAMA/QsDACAAIAQoAgg2AgggACAEKQMANwMAIAQgAigCCDYCCCAEIAIpAwA3AwAMAQsgAEEQaiEEIABBIGohAyAAKwMgIQkCQCAAKwMQIgogACsDACILZEUEQCAJIApkRQ0BIAIgBP0AAwD9CwMAIAQgA0EIaigCADYCCCAEIAMpAwA3AwAgAyACKAIINgIIIAMgAikDADcDACAEKwMAIAtkRQ0BIAIgAP0AAwD9CwMAIAAgBCgCCDYCCCAAIAQpAwA3AwAg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IABBhBlqIABBlBJqKAIANgIAIABB/BhqIAApAowSNwIAIABBADoA/hEgAEHpyAE7AfwRIABBAjoAhxIgAEH4EWoiAkHaGC8AADsBACAAQYAUOwH6ESAAQRA2AuwRIABB0hgpAAAiEzcC8BEgAEGQGWogAEGEEmooAgA2AgAgACAAKQL8ETcDiBkgAEGUGWpBEDYCACAAQaAZaiACKAIANgIAIABBmBlqIBM3AwAgAEEAOgDiESAAQejSATsB4BEgAEECOgDrESAAQdgRakHtGy0AADoAACAAQQU6AN8RIABBETYC0BEgAEEAOgDZESAAQekbKAAANgLUESAAQawZaiAAQegRaigCADYCACAAIAApAuARNwKkGSAAQbAZakERNgIAIABBvBlqIABB3BFqKAIANgIAIABBtBlqIAApAtQRNwIAIABBADoAxhEgAEHm0gE7AcQRIABBAjoAzxEgAEG7EWpBlRwoAAA2AAAgAEEHOgDDESAAQRI2ArQRIABBADoAvxEgAEGSHCgAADYCuBEgAEHIGWogAEHMEWooAgA2AgAgACAAKQLEETcDwBkgAEHMGWpBEjYCACAAQdgZaiAAQcARaigCADYCACAAQdAZaiAAKQK4ETcDACAAQQA6AKoRIABB9tIBOwGoESAAQQI6ALMRIABBpBFqIgJB4CEvAAA7AQAgAEGAFDsBphEgAEETNgKYESAAQdghKQAAIhM3ApwRIABB5BlqIABBsBFqKAIANgIAIAAgACkCqBE3AtwZIABB6BlqQRM2AgAgAEH0GWogAigCADYCACAAQewZaiATNwIAIABBADoAjhEgAEHoygE7AYwRIABBAjoAlxEgAEGEEWpBtwovAAA7AQAgAEEGOgCLESAAQRQ2AvwQIABBADoAhhEgAEGzCigAADYCgBEgAEGAGmogAEGUEWooAgA2AgAgACAAKQKMETcD+BkgAEGEGmpBFDYCACAAQZAaaiAAQYgRaigCADYCACAAQYgaaiAAKQKAETcDACAAQQA6APIQIABB9dYBOwHwECAAQQI6APsQIABB7BBqIgJBjBktAAA6AAAgAEEJOgDvECAAQRU2AuAQIABBADoA7RAgAEGEGSkAACITNwLkECAAQZwaaiAAQfgQaigCADYCACAAIAApAvAQNwKUGiAAQaAaakEVNgIAIABBrBpqIAIoAgA2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IABB4B9qQY4ZKQAAIhM3AwAgAEHYH2ogAEHMC2ooAgA2AgAgAEEJOgDDCyAAQQA6AMELIABB6B9qIAIoAgA2AgAgAEEuNgK0CyAAIBM3ArgLIAAgACkCxAs3A9AfIABBADoAqgsgAEHr3AE7AagLIABBAjoAswsgAEGfC2pBmCkoAAA2AAAgAEEHOgCnCyAAQS82ApgLIABBADoAowsgAEGVKSgAADYCnAsgAEH0H2ogAEGwC2ooAgA2AgAgACAAKQKoCzcC7B8gAEH4H2pBLzYCACAAQYQgaiAAQaQLaigCADYCACAAQfwfaiAAKQKcCzcCACAAQQA6AI4LIABB5egBOwGMCyAAQQI6AJcLIABBiAtqIgJBADoAACAAQQg6AIsLIABBMDYC/AogAELl5tH75q3asO4ANwKACyAAQZAgaiAAQZQLaigCADYCACAAIAApAowLNwOIICAAQZQgakEwNgIAIABBoCBqIAIoAgA2AgAgAEGYIGpC5ebR++at2rDuADcDACAAQQA6APIKIABB7dYBOwHwCiAAQQI6APsKIABB7ApqIgJBgRkvAAA7AQAgAEEKOgDvCiAAQTE2AuAKIABBADoA7gogAEH5GCkAACITNwLkCiAAQawgaiAAQfgKaigCADYCACAAIAApAvAKNwKkICAAQbAgakExNgIAIABBvCBqIAIoAgA2AgAgAEG0IGogEzcCACAAQQA6ANYKIABB4uQBOwHUCiAAQQI6AN8KIABBzApqQbkWLwAAOwEAIABBBjoA0wogAEEyNgLECiAAQQA6AM4KIABBtRYoAAA2AsgKIABByCBqIABB3ApqKAIANgIAIAAgACkC1Ao3A8AgIABBzCBqQTI2AgAgAEHYIGogAEHQCmooAgA2AgAgAEHQIGogACkCyAo3AwAgAEEAOgC6CiAAQeXqATsBuAogAEECOgDDCiAAQbAKakGhHy8AADsBACAAQQY6ALcKIABBMzYCqAogAEEAOgCyCiAAQZ0fKAAANgKsCiAAQeQgaiAAQcAKaigCADYCACAAIAApArgKNwLcICAAQeggakEzNgIAIABB9CBqIABBtApqKAIANgIAIABB7CBqIAApAqwKNwIAIABBADoAngogAEHp5gE7AZwKIABBAjoApwogAEGYCmoiAkHXJi0AADoAACAAQQk6AJsKIABBNDYCjAogAEEAOgCZCiAAQc8mKQAAIhM3ApAKIABBgCFqIABBpApqKAIANgIAIAAgACkCnAo3A/ggIABBhCFqQTQ2AgAgAEGQIWogAigCADYCACAAQYghaiATNwMAIABBADoAggogAEHo8gE7AYAKIABBAjoAiwogAEH8CWoiAkEAOgAAIABBCDoA/wkgAEE1NgLwCSAAQuHktavmrdqw7gA3AvQJIABBnCFqIABBiApqKAIANgIAIAAgACkCgAo3ApQhIABBoCFqQTU2AgAgAEGsIWogAigCADYCACAAQaQhakLh5LWr5q3asO4ANwIAIABBADoA5gkgAEHuygE7AeQJIABBAjoA7wkgAEHcCWpByBsvAAA7AQAgAEEGOgDjCSAAQTY2AtQJIABBADoA3gkgAEHEGygAADYC2AkgAEG4IWogAEHsCWooAgA2AgAgACAAKQLkCTcDsCEgAEG8IWpBNjYCACAAQcghaiAAQeAJaigCADYCACAAQcAhaiAAKQLYCTcDACAAQQA6AMoJIABB7dwBOwHICSAAQQI6ANMJIABBxAlqIgJBqxktAAA6AAAgAEEJOgDHCSAAQTc2ArgJIABBADoAxQkgAEGjGSkAACITNwK8CSAAQdQhaiAAQdAJaigCADYCACAAIAApAsgJNwLMISAAQdghakE3NgIAIABB5CFqIAIoAgA2AgAgAEHcIWogEzcCACAAQQA6AK4JIABB4uYBOwGsCSAAQQI6ALcJIABBowlqQfQYKAAANgAAIABBBzoAqwkgAEE4NgKcCSAAQQA6AKcJIABB8RgoAAA2AqAJIABB8CFqIABBtAlqKAIANgIAIAAgACkCrAk3A+ghIABB9CFqQTg2AgAgAEGAImogAEGoCWooAgA2AgAgAEH4IWogACkCoAk3AwAgAEEAOgCSCSAAQevWATsBkAkgAEECOgCbCSAAQYgJakHyHC8AADsBACAAQQY6AI8JIABBOTYCgAkgAEEAOgCKCSAAQe4cKAAANgKECSAAQYwiaiAAQZgJaigCADYCACAAIAApApAJNwKEIiAAQZAiakE5NgIAIABBnCJqIABBjAlqKAIANgIAIABBlCJqIAApAoQJNwIAIABBADoA9gggAEHz4gE7AfQIIABBAjoA/wggAEHwCGoiAkEAOgAAIABBCDoA8wggAEE6NgLkCCAAQuHYiYvmrdqw7gA3AugIIABBqCJqIABB/AhqKAIANgIAIAAgACkC9Ag3A6AiIABBrCJqQTo2AgAgAEG4ImogAigCADYCACAAQbAiakLh2ImL5q3asO4ANwMAIABBADoA2gggAEHz7gE7AdgIIABBAjoA4wggAEHPCGpBvxsoAAA2AAAgAEEHOgDXCCAAQTs2AsgIIABBADoA0wggAEG8GygAADYCzAggAEHEImogAEHgCGooAgA2AgAgACAAKQLYCDcCvCIgAEHIImpBOzYCACAAQdQiaiAAQdQIaigCADYCACAAQcwiaiAAKQLMCDcCACAAQQA6AL4IIABB59gBOwG8CCAAQQI6AMcIIABBuAhqIgJBADoAACAAQQg6ALsIIABBPDYCrAggAELnwrHLtqzasO4ANwKwCCAAQeAiaiAAQcQIaigCADYCACAAIAApArwINwPYIiAAQeQiakE8NgIAIABB8CJqIAIoAgA2AgAgAEHoImpC58Kxy7as2rDuADcDACAAQQA6AKIIIABB7eQBOwGgCCAAQQI6AKsIIABBlwhqQd0bKAAANgAAIABBBzoAnwggAEE9NgKQCCAAQQA6AJsIIABB2hsoAAA2ApQIIABB/CJqIABBqAhqKAIANgIAIAAgACkCoAg3AvQiIABBgCNqQT02AgAgAEGMI2ogAEGcCGooAgA2AgAgAEGEI2ogACkClAg3AgAgAEEAOgCGCCAAQfDCATsBhAggAEECOgCPCCAAQfIbKAAANgD7ByAAQQc6AIMIIABBPjYC9AcgAEEAOgD/ByAAQe8bKAAANgL4ByAAQZgjaiAAQYwIaigCADYCACAAIAApAoQINwOQIyAAQZwjakE+NgIAIABBqCNqIABBgAhqKAIANgIAIABBoCNqIAApAvgHNwMAIABBADoA6gcgAEHz0gE7AegHIABBAjoA8wcgAEGCKSgAADYA3wcgAEEHOgDnByAAQT82AtgHIABBADoA4wcgAEH/KCgAADYC3AcgAEG0I2ogACgC8Ac2AgAgACAAKQLoBzcCrCMgAEG4I2pBPzYCACAAQcQjaiAAKALkBzYCACAAQbwjaiAAKQLcBzcCACAAQQA6AM4HIABB69oBOwHMByAAQQI6ANcHIABBxxQtAAA6AMQHIABBBToAywcgAEHAADYCvAcgAEEAOgDFByAAQcMUKAAANgLAByAAQdAj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OwGUAiAAQQI6AJ8CIABBADoAkAIgAEEIOgCTAiAAQdoANgKEAiAAQu3CsYv2rNi5+QA3AogCIABBqClqIAAoApwCNgIAIAAgACkClAI3A6ApIABBrClqQdoANgIAIABBuClqIAAoApACNgIAIABBsClqQu3CsYv2rNi5+QA3AwAgAEEAOgD6ASAAQeHmATsB+AEgAEECOgCDAiAAQQA6APQBIABBCDoA9wEgAEHbADYC6AEgAELh5s2L1q3ZueUANwLsASAAQcQpaiAAKAKAAjYCACAAIAApAvgBNwK8KSAAQcgpakHbADYCACAAQdQpaiAAKAL0ATYCACAAQcwpakLh5s2L1q3ZueUANwIAIABBADoA3gEgAEH06AE7AdwBIABBAjoA5wEgAEH4FC0AADoA1AEgAEEFOgDbASAAQdwANgLMASAAQQA6ANUBIABB9BQoAAA2AtABIABB4ClqIAAoAuQBNgIAIAAgACkC3AE3A9gpIABB5ClqQdwANgIAIABB8ClqIAAoAtgBNgIAIABB6ClqIAApAtABNwMAIABBAzoAywEgAEEAOgDDASAAQbwKLQAAOgDCASAAQboKLwAAOwHAASAAQQA6ALwBIABBCDoAvwEgAEHdADYCsAEgAELowt2Llq3asO4ANwK0ASAAQfwpaiAAKALIATYCACAAIAApAsABNwL0KSAAQYAqakHdADYCACAAQYwqaiAAKAK8ATYCACAAQYQqakLowt2Llq3asO4ANwIAIABBADoApgEgAEHs3AE7AaQBIABBAjoArwEgAEGKKSgAADYAmwEgAEEHOgCjASAAQd4ANgKUASAAQQA6AJ8BIABBhykoAAA2ApgBIABBmCpqIAAoAqwBNgIAIAAgACkCpAE3A5AqIABBnCpqQd4ANgIAIABBqCpqIAAoAqABNgIAIABBoCpqIAApApgBNwMAIABBADoAigEgAEHowgE7AYgBIABBAjoAkwEgAEHxKC0AADoAgAEgAEEFOgCHASAAQd8ANgJ4IABBADoAgQEgAEHtKCgAADYCfCAAQbQqaiAAKAKQATYCACAAIAApAogBNwKsKiAAQbgqakHfADYCACAAQcQqaiAAKAKEATYCACAAQbwqaiAAKQJ8NwIAIABBADoAbiAAQeLCATsBbCAAQQI6AHcgAEGyFCgAADYAYyAAQQc6AGsgAEHg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IAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQdjhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGZ4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB1OEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQavhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUHB4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFByeEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEBEDkgACABQbThABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGF4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB6OEAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQefhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUH+4AAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3AgAgAUEANgIIQdDXNCAAKAIgIABBIGogAC0AKyIBwEEASCIEGyAAKAIkIAEgBBsQXxogACwAK0EASARAIAAoAiAQLwsgACwAG0EASARAIAAoAhAQLwsgACwAD0EASARAIAAoAgQQLwsgAEEEaiIBQQAQOSAAIAFB3+EAEDgiASgCCDYCGCAAIAEpAgA3AxAgAUIANwIAIAFBADYCCCAAIABBEGpB8+AAEDciASgCCDYCKCAAIAEpAgA3AyAgAUIANwIAIAFBADYCCEHQ1zQgACgCICAAQSBqIAAtACsiAcBBAEgiBBsgACgCJCABIAQbEF8aIAAsACtBAEgEQCAAKAIgEC8LIAAsABtBAEgEQCAAKAIQEC8LIAAsAA9BAEgEQCAAKAIEEC8LIABBBGoiAUEAEDkgACABQaHhABA4IgEoAgg2AhggACABKQIANwMQIAFCADcCACABQQA2AgggACAAQRBqQfPgABA3IgEoAgg2AiggACABKQIANwMgIAFCADcCACABQQA2AghB0Nc0IAAoAiAgAEEgaiAALQArIgHAQQBIIgQbIAAoAiQgASAEGxBfGiAALAArQQBIBEAgACgCIBAvCyAALAAbQQBIBEAgACgCEBAvCyAALAAPQQBIBEAgACgCBBAvCyAAQQRqIgFBABA5IAAgAUGN4QAQOCIBKAIINgIYIAAgASkCADcDECABQgA3AgAgAUEANgIIIAAgAEEQakHz4AAQNyIBKAIINgIoIAAgASkCADcDICABQgA3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QTBqIQEgAkEwaiICIA1HDQALCyADIAE2AgQMAgsgASACIBH8CgAAIAMgASAMQTBsajYCBAwBCyABBEAgAyABNgIEIAEQLyADQQA2AgggA0IANwIAQQAhBwsgDEHWqtUqTw0CQdWq1SogB0EwbSIBQQF0IgcgDCAHIAxLGyABQarVqhVPGyIBQdaq1SpPDQIgAyABQTBsIgcQMiIBNgIEIAMgATYCACADIAEgB2o2AgggAyACIA1HBH8gASACIBFBMGsiAiACQTBwa0EwaiIC/AoAACABIAJqBSABCzYCBAsgAyAEKAJENgI0IAMgBCkCPDcCLCADIAT9AAIs/QsCHCADIAT9AAIc/QsCDCAIQYgCaiIBIARByABqRwRAIAEgBCgCSCAEKAJMENQEIAhBlAJqIAQoAlQgBCgCWBDTBAsgCCAEKQJgNwKgAiAEKAIAIRQgBSgCnBoiCEEANgJMIAgoAlAiEUUNACAGQQhqIQ1BACEMA0AgCCgCWCAMQQR0aiIEQQhqIgMhAiADKAIAIgchAQJAIAdFDQADQCACIAEgASgCECAUSCIPGyECIAFBBGogASAPGygCACIBDQALIAIgA0YNACACKAIQIBRKDQAgBCgCAEH+////B0sNAAJ/A0AgDSAHIgEoAhAiAkgEQCABKAIAIgcNASABDAILIAIgDU4NAiABKAIEIgcNAAsgAUEEagshAkEUEDIiAyABNgIIIANCADcCACADIA02AhAgAiADNgIAIAQoAgQoAgAiAQRAIAQgATYCBCACKAIAIQMLIAMgAyAEKAIIIhFGIgE6AAwCQCABDQADQCADKAIIIgItAAwNAQJAIAIgAigCCCIBKAIAIgdGBEACQCABKAIEIgdFDQAgBy0ADA0ADAILAkAgAyACKAIARgRAIAIhAwwBCyACIAIoAgQiAygCACIHNgIEIAMgBwR/IAcgAjYCCCACKAIIBSABCzYCCCACKAIIIgEgASgCACACR0ECdGogAzYCACADIAI2AgAgAiADNgIIIAMoAggiASgCACECCyADQQE6AAwgAUEAOgAMIAEgAigCBCIDNgIAIAMEQCADIAE2AggLIAIgASgCCDYCCCABKAIIIgMgAygCACABR0ECdGogAjYCACACIAE2AgQgASACNgIIDAMLAkAgB0UNACAHLQAMDQAMAQsCQCADIAIoAgBH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JAAgBSABNgIcAkAgAigCBEEBcUUEQCAAIAEgAiADIAQgACgCACgCGBEKACECDAELIAVBEGoiASACKAIcIgA2AgAgAEEEakEB/h4CABogARDBASEAIAEoAgAiAkEEakF//h4CAEUEQCACIAIoAgAoAggRAQALAkAgBARAIAEgACAAKAIAKAIYEQIADAELIAVBEGogACAAKAIAKAIcEQIACyAFIAVBEGoQdTYCDANAIAUgBUEQaiIAEJ0BNgIIIAUoAgwiASAFKAIIRwRAIAVBHGogASwAABD8AyAFIAUoAgxBAWo2AgwMAQUgBSgCHCECIAAQMxoLCwsgBUEgaiQAIAILwQUBBn8jAEHAAmsiACQAIAAgAjYCuAIgACABNgK8AiMAQRBrIgIkACAAQcQBaiIBQgA3AgAgAUEANgIIIAJBEGokACAAQRBqIgYgAygCHCICNgIAIAJBBGpBAf4eAgAaIAYQbCICQdDqAkHq6gIgAEHQAWogAigCACgCMBEIABogBigCACICQQRqQX/+HgIARQRAIAIgAigCACgCCBEBAAsgASEDIwBBEGsiASQAIABBuAFqIgJCADcCACACQQA2AgggAUEQaiQAIAIgAi0AC0EHdgR/IAIoAghB/////wdxQQFrBUEKCxA6IAACfyACLQALQQd2BEAgAigCAAwBCyACCyIBNgK0ASAAIAY2AgwgAEEANgIIA0ACQCAAQbwCaiAAQbgCahBCDQAgACgCtAECfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQsgAWpGBEACfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQshBiACAn8gAi0AC0EHdgRAIAIoAgQMAQsgAi0AC0H/AHELQQF0EDogAiACLQALQQd2BH8gAigCCEH/////B3FBAWsFQQoLEDogACAGAn8gAi0AC0EHdgRAIAIoAgAMAQsgAgsiAWo2ArQBCwJ/IABBvAJqIgcoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgoAgALQRAgASAAQbQBaiAAQQhqQQAgAyAAQRBqIABBDGogAEHQAWoQvQENACAHEFwaDAELCyACIAAoArQBIAFrEDoCfyACLQALQQd2BEAgAigCAAwBCyACCyELEEQhCSAAIAU2AgAgCyAJIAAQ1ANBAUcEQCAE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zwFB/wBxC0UNACAAKAIMIgMgAEEQamtBnwFKDQAgACADQQRqNgIMIAMgACgCCDYCAAsgBSACIAAoArQBIAQgBhDYAzcDACAAQcQBaiAAQRBqIAAoAgwgBBBkIABBzAJqIABByAJqEEIEQCAEIAQoAgBBAnI2AgALIAAoAswCIQogARAzGiAAQcQBahAzGiAAQdACaiQAIAoLmgUBBX8jAEHQAmsiACQAIAAgAjYCyAIgACABNgLMAiADEIwBIQYgAyAAQdABahDQASEHIABBxAFqIAMgAEHEAmoQzwEjAEEQayICJAAgAEG4AWoiAUIANwIAIAFBADYCCCACQRBqJAAgASABLQALQQd2BH8gASgCCEH/////B3FBAWsFQQoLEDogAAJ/IAEtAAtBB3YEQCABKAIADAELIAELIgI2ArQBIAAgAEEQajYCDCAAQQA2AggDQAJAIABBzAJqIABByAJqEEINACAAKAK0AQJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyACakYEQAJ/IAEtAAtBB3YEQCABKAIEDAELIAEtAAtB/wBxCyEDIAECfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQtBAXQQOiABIAEtAAtBB3YEfyABKAIIQf////8HcUEBawVBCgsQOiAAIAMCfyABLQALQQd2BEAgASgCAAwBCyABCyICajYCtAELAn8gAEHMAmoiCCgCACIDKAIMIgkgAygCEEYEQCADIAMoAgAoAiQRAAAMAQsgCSgCAAsgBiACIABBtAFqIABBCGogACgCxAIgAEHEAWogAEEQaiAAQQxqIAcQvQENACAIEFwaDAELCwJAAn8gAC0AzwFBB3YEQCAAKALIAQwBCyAALQDPAUH/AHELRQ0AIAAoAgwiAyAAQRBqa0GfAUoNACAAIANBBGo2AgwgAyAAKAIINgIACyAFIAIgACgCtAEgBCAGENsDOwEAIABBxAFqIABBEGogACgCDCAEEGQgAEHMAmogAEHIAmoQQgRAIAQgBCgCAEECcjYCAAsgACgCzAIhCiABEDMaIABBxAFqEDMaIABB0AJqJAAgCguaBQEFfyMAQdACayIAJAAgACACNgLIAiAAIAE2AswCIAMQjAEhBiADIABB0AFqENABIQcgAEHEAWogAyAAQcQCahDPASMAQRBrIgIkACAA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AUEQaiQAIAIgAi0AC0EHdgR/IAIoAghB/////wdxQQFrBUEKCxA6IAACfyACLQALQQd2BEAgAigCAAwBCyACCyIBNgK0ASAAIAY2AgwgAEEANgIIA0ACQCAAQfwBaiAAQfgBahBDDQAgACgCtAECfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQsgAWpGBEACfyACLQALQQd2BEAgAigCBAwBCyACLQALQf8AcQshBiACAn8gAi0AC0EHdgRAIAIoAgQMAQsgAi0AC0H/AHELQQF0EDogAiACLQALQQd2BH8gAigCCEH/////B3FBAWsFQQoLEDogACAGAn8gAi0AC0EHdgRAIAIoAgAMAQsgAgsiAWo2ArQBCwJ/IABB/AFqIgcoAgAiBigCDCIIIAYoAhBGBEAgBiAGKAIAKAIkEQAADAELIAgtAAALwEEQIAEgAEG0AWogAEEIakEAIAMgAEEQaiAAQQxqIABB0AFqEMABDQAgBxBdGgwBCwsgAiAAKAK0ASABaxA6An8gAi0AC0EHdgRAIAIoAgAMAQsgAgshCxBEIQkgACAFNgIAIAsgCSAAENQDQQFHBEAgBEEENgIACyAAQfwBaiAAQfgBahBDBEAgBCAEKAIAQQJyNgIACyAAKAL8ASEKIAIQMxogAxAzGiAAQYACaiQAIAoLHgEBf0HQuwMoAgAiAARAIAAQ4ARB0LsDQQA2AgALC9EFAgN/AX4jAEGQAmsiACQAIAAgAjYCiAIgACABNgKMAiAAQdABaiADIABB4AFqIABB3wFqIABB3gFqELYCIwBBEGsiAiQAIABBxAFqIgFCADcCACABQQA2AgggAkEQaiQAIAEgAS0AC0EHdgR/IAEoAghB/////wdxQQFrBUEKCxA6IAACfyABLQALQQd2BEAgASgCAAwBCyABCyICNgLAASAAIABBIGo2AhwgAEEANgIYIABBAToAFyAAQcUAOgAWA0ACQCAAQYwCaiAAQYgCahBDDQAgACgCwAECfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQsgAmpGBEACfyABLQALQQd2BEAgASgCBAwBCyABLQALQf8AcQshAyABAn8gAS0AC0EHdgRAIAEoAgQMAQsgAS0AC0H/AHELQQF0EDogASABLQALQQd2BH8gASgCCEH/////B3FBAWsFQQoL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QQNxbGogACwADiAxIAV2QQNxbGogACwADyAwIAV2QQNxbGogBiAHai0AAEEPcWwgCmogACwAESAuIAV2QQNxbCAALAAQIC8gBXZBA3FsaiAALAASIC0gBXZBA3FsaiAALAATICwgBXZBA3FsaiAALAAUICsgBXZBA3FsaiAALAAVICogBXZBA3FsaiAALAAWICkgBXZBA3FsaiAALAAXICggBXZBA3FsaiAALAAYICcgBXZBA3FsaiAALAAZICYgBXZBA3FsaiAALAAaICUgBXZBA3FsaiAALAAbICQgBXZBA3FsaiAALAAcICMgBXZBA3FsaiAALAAdICIgBXZBA3FsaiAALAAeICEgBXZBA3FsaiAALAAfICAgBXZBA3FsaiAHIAZBAXJqLQAAQQ9xbGohCiAAQSBqIQAgBUECaiEFIAZBAmohBiAMQQFqIgxBBEcNAAsgBEEgaiEEIAlBCGohCSALIQZBACELIEAhACAGDQALIEEgQiBElCAKspQgQyBClCAOIA8gECARIBIgEyAUIBUgFiAXIBggGSAaIBsgHCAdIB5sampqampqampqampqampqspSTkiFBIAhBAWoiCCANRw0ACwsgASBBOAIAC6YCAQF/IAAgACgCACgCGBEAABogACABEPgDIgE2AkQgAC0AYiECIAAgASABKAIAKAIcEQAAIgE6AGIgASACRwRAIABBADYCECAAQQA2AgwgAEEANgIIIABBADYCHCAAQQA2AhQgAEEANgIYIAAtAGAhASAALQBiBEACQCABRQ0AIAAoAiAiAUUNACABEC8LIAAgAC0AYToAYCAAIAAoAjw2AjQgACgCOCEBIABCADcCOCAAIAE2AiAgAEEAOgBhDwsCQCABDQAgACgCICIBIABBLGpGDQAgAEEAOgBhIAAgATYCOCAAIAAoAjQiATYCPCABEDIhASAAQQE6AGAgACABNgIgDwsgACAAKAI0IgE2AjwgARAyIQEgAEEBOgBhIAAgATYCOAsL8QMCBX8BfiMAQRBrIgMkAAJAIAAoAkBFDQACQCAAKAJEIgQEQCAAKAJcIgJBEHEEQCAAKAIYIAAoAhRHBEBBfyEBIABBfyAAKAIAKAI0EQQAQX9GDQQLIABByABqIQEDQCAAKAJEIgQgASAAKAIgIgIgAiAAKAI0aiADQQxqIAQoAgAoAhQRCgAh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AgAhAAsgAygC1AEgABCkASADIAMoAtgBQQFqNgLYAQsCQCAEQRRqIgAgAUHwA2pGDQAgAS0A+wMiCMAhAiAELAAfQQBOBEAgAkEATgRAIAAgASkD8AM3AgAgACABKAL4AzYCCAwCCyAAIAEoAvADIAEoAvQDEN4BDAELIAAgASgC8AMgAUHwA2ogAkEASCIAGyABKAL0AyAIIAAbEN8BCyAGQQFqIgYgASgCyAQiAEgNAAsLIAMgAygCICICNgLAASACQZiVA0oEQCADIAMoAtwBQQFqNgLcASADIAMoAuABQQFqNgLgASADIAP9AALkASACQZiVA2siBP0R/a4B/QsC5AEgAyADKAL0ASAEajYC9AEgAyADKAL4ASAEajYC+AEgAyADKAL8ASAEajYC/AELAkAgACACTg0AIAFByCU2AuABIAEgAiAAazYC5AFBBEGT4wAgAUHgAWoQNCABKALIBCIGIAMoAiBODQAgA0HUAWohBSADQcQBaiELIAFB8ANqQQRyIQgDQAJAIAMoAvwBIgIgBkgEQCABQZQEaiIAIAYgAmsQOSABIABBsykQOCIAKAIINgKoBCABIAApAgA3A6AEIABCADcCACAAQQA2AgggAUGgBGpBuyoQNyIAKAIAIQIgASAAKAIENgLkAyABIAAoAAc2AOcDIABCADcCACAALQALIQQgAEEANgIIIAEsAPsDQQBIBEAgASgC8AMQLwsgASACNgLwAyAIIAEoAOcDNgADIAggASgC5AM2AgAgASAEOgD7AyABLACrBEEASARAIAEoAqAEEC8LIAEsAJ8EQQBODQEgASgClAQQLwwBCyADKALcASAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQdQpKAAANgADIABB0SkoAAA2AAAMAQsgAygC4AEiACAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQcQpKAAANgADIABBwSkoAAA2AAAMAQsgAygC5AEgBkYEQCABQfADakHhKUENEMsBDAELIAMoAugBIAZGBEAgAUHwA2pB7ylBDhDLAQwBCyADKALsASAGRgRAAn8gASwA+wNBAEgEQCABQQg2AvQDIAEoAvADDAELIAFBCDoA+wMgAUHwA2oLIgBBADoACCAAQtu+zfrEqdOv3QA3AAAMAQsgAygC8AEgBkYEQAJ/IAEsAPsDQQBIBEAgAUEINgL0AyABKALwAwwBCyABQQg6APsDIAFB8ANqCyIAQQA6AAggAELbvsGS1cjVr90ANwAADAELIAMoAvQBIAZGBEACfyABLAD7A0EASARAIAFBCDYC9AMgASgC8AMMAQsgAUEIOgD7AyABQfADagsiAEEAOgAIIABC2765+rSK1K/dADcAAAwBCyADKAL4ASAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQcwpKAAANgADIABBySkoAAA2AAAMAQsgAiAGRgRAAn8gASwA+wNBAEgEQCABQQc2AvQDIAEoAvADDAELIAFBBzoA+wMgAUHwA2oLIgBBADoAByAAQdwpKAAANgADIABB2SkoAAA2AAAMAQsCQCAAIAZODQAgBiAAIAMoAsABIgJqIAJBmJUDSmtBtZQDa0oNACAGIABBf3NqIQxBACEEIwBBEGsiCiQAAkACQEHE1zQoAgAiAkHI1zRHBEADQCACKAIcIAxGDQICQCACKAIEIgAEQANAIAAiAigCACIADQAMAgsACwNAIAIgAigCCCICKAIARw0ACwsgAkHI1zRHDQALCyAKIAw2AgQgCkHBEzYCAEECQaDrACAKEDQMAQsgAigCECACQRBqIAIsABtBAEgbIQQLIApBEGokACABIAFBlARqIAQQpgEiAkG5KRA4IgAoAgg2AqgEIAEgACkCADcDoAQgAEIANwIAIABBADYCCCABQaAEakG7KhA3IgAoAgAhBCABIAAoAgQ2AuQDIAEgACgABzYA5wMgAEIANwIAIAAtAAshCiAAQQA2AgggASwA+wNBAEgEQCABKALwAxAvCyABIAQ2AvADIAggASgA5wM2AAMgCCABKALkAzYCACABIAo6APsDIAEsAKsEQQBIBEAgASgCoAQQLwsgASwAnwRBAE4NASACKAIAEC8MAQsgAUGUBGoiACAGEDkgASAAQaQpEDgiACgCCDYCqAQgASAAKQIANwOgBCAAQgA3AgAgAEEANgIIIAFBoARqQbsqEDciACgCACECIAEgACgCBDYC5AMgASAAKAAHNgDnAyAAQgA3AgAgAC0ACyEEIABBADYCCCABLAD7A0EASARAIAEoAvADEC8LIAEgAjYC8AMgCCABKADnAzYAAyAIIAEoAuQDNgIAIAEgBDoA+wMgASwAqwRBAEgEQCABKAKgBBAvCyABLACfBEEATg0AIAEoApQEEC8LIAEgAUHwA2oiADYClAQgAUGgBGogCyAAIAFBlARqEOIEIAEoAqAEIAY2AhwCQAJAIAUiAiIAKAIAIgRFDQADQCAEIgAoAhAiAiAGSgRAIAAiAigCACIEDQEMAgsgAiAGTg0CIAAoAgQiBA0ACyAAQQRqIQILQSAQMiIEIAY2AhAgBCAANgIIIARCADcCACAEQgA3AhQgBEEANgIcIAIgBDYCACAEIQAgAygC0AEoAgAiCgRAIAMgCjYC0AEgAigCACEACyADKALUASAAEKQBIAMgAygC2AFBAWo2AtgBCwJAIARBFGoiACABQfADakYNACABLQD7AyIKwCECIAQsAB9BAE4EQCACQQBOBEAgACABKQPwAzcCACAAIAEoAvgDNgIIDAILIAAgASgC8AMgASgC9AMQ3gEMAQsgACABKALwAyABQfADaiACQQBIIgAbIAEoAvQDIAogABsQ3wELIAZBAWoiBiADKAIgSA0ACwsgAygCwAEhACABQcglNgLQASABIAAgAEGYlQNKa0G1lANrNgLUAUEEQaztACABQdABahA0IAEoArAEIgAEQCABIAA2ArQEIAAQLwsgASwA+wNBAEgEQCABKALwAxAvCyADKAIQIQggAygCMCEAIAMoAkAhAiABQQE6APgDIAEgASgC+AM2AsgBIAEgAEEPbCACQRhsakEZakG8Amw2AvADQQAhACABQQA2AvQDIAEgASkC8AM3A8ABIAMgAUHAAWoQvgEiAjYCqAEgAkUEQCABQcglNgIAQQJBo+oAIAEQNAwBCyADNAJEISUgAygCQCEKIAMoAjghEiADNAI0IScgAygCKCETIAM0AiQhKCADNAIgISkCQCADKAIwIgwgAygClAEiACADKAKQASIEa0E8bSICSwRAQQAhBiAMIAJrIgQgAygCmAEiCyAAa0E8bU0EQCADIAQEfyAAQQAgBEE8bEE8ayICIAJBPHBrQTxqIgL8CwAgACACagUgAAs2ApQBDAILAkAgACADKAKQASIFa0E8bSIQIARqIgJBxYiRIkkEQEHEiJEiIAsgBWtBPG0iC0EBdCIRIAIgAiARSRsgC0GixIgRTxsiCwRAIAtBxYiRIk8NAiALQTxsEDIhBgsgEEE8bCAGaiICQQAgBEE8bEE8ayIEIARBPHBrQTxqIgT8CwAgAiAEaiEEIAAgBUcEQANAIAJBPGsiAiAAQTxrIgD9AAIA/QsCACACIAAoAjg2AjggAiAAKQIwNwIwIAIgAP0AAiD9CwIgIAIgAP0AAhD9CwIQIAAgBUcNAAsgAygCkAEhAAsgAyAGIAtBPGxqNgKYASADIAQ2ApQBIAMgAjYCkAEgAARAIAAQLwsMAwsQNgALEEcACyACIAxNDQAgAyAEIAxBPGxqNgKUAQsgCEEARyEQAkAgAygCoAEiACADKAKcASIEa0HgAG0iAiAKSQRAQQAhBSAKIAJrIgQgAygCpAEiCyAAa0HgAG1NBEAgAyAEBH8gAEEAIARB4ABsQeAAayICIAJB4ABwa0HgAGoiAvwLACAAIAJqBSAACzYCoAEMAgsCQCAAIAMoApwBIgZrQeAAbSIRIARqIgJBq9WqFUkEQEGq1aoVIAsgBmtB4ABtIgtBAXQiGCACIAIgGEkbIAtB1arVCk8bIgsEQCALQavVqhVPDQIgC0HgAGwQMiEFCyARQeAAbCAFaiICQQAgBEHgAGxB4ABrIgQgBEHgAHBrQeAAaiIE/AsAIAIgBGohBCAAIAZHBEADQCACQeAAayICIABB4ABrIgBB4AD8CgAAIAAgBkcNAAsgAygCnAEhAAsgAyAFIAtB4ABsajYCpAEgAyAENgKgASADIAI2ApwBIAAEQCAAEC8LDAMLEDYACxBHAAsgAiAKTQ0AIAMgBCAKQeAAbGo2AqABCyADIAMoAqgBQQAgE6wiJCAoEFU2AmQgAyADKAKoASAQQgMgJSAkELwBNgJoIAMgAygCqAFBAEIBICQQVTYCbCADIAMoAqgBIBBCAyAkICQQvAE2AnAgAyADKAKoAUEAQgEgJBBVNgJ0IAMgAygCqAFBACAkEEg2AnggAyADKAKoAUEAICQQSDYCfCADKAJkIQIgAUEgEDIiADYC8AMgAUKcgICAgISAgIB/NwL0AyAAQZAeKAAANgAYIABBiB4pAAA3ABAgAEH4Hf0AAAD9CwAAIABBADoAHCABIAFB8ANqIgA2AqAEIAFBsARqIANBtAFqIgUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyADKAJoIQIgAUEgEDIiADYC8AMgAUKUgICAgISAgIB/NwL0AyAAQdEOKAAANgAQIABBwQ79AAAA/QsAACAAQQA6ABQgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCbCECIAFBIBAyIgA2AvADIAFCkoCAgICEgICAfzcC9AMgAEGNEy8AADsAECAAQf0S/QAAAP0LAAAgAEEAOgASIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAnAhAiABQSAQMiIANgLwAyABQpSAgICAhICAgH83AvQDIABBrg4oAAA2ABAgAEGeDv0AAAD9CwAAIABBADoAFCABIAFB8ANqIgA2AqAEIAFBsARqIAUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyADKAJ0IQIgAUEgEDIiADYC8AMgAUKSgICAgISAgIB/NwL0AyAAQe4SLwAAOwAQIABB3hL9AAAA/QsAACAAQQA6ABIgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCeCECIAFBIBAyIgA2AvADIAFCloCAgICEgICAfzcC9AMgAEGDDSkAADcADiAAQfUM/QAAAP0LAAAgAEEAOgAWIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAnwhAiABQSAQMiIANgLwAyABQpSAgICAhICAgH83AvQDIABB8hEoAAA2ABAgAEHiEf0AAAD9CwAAIABBADoAFCABIAFB8ANqIgA2AqAEIAFBsARqIAUgACABQaAEahA8IAEoArAEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyAMQQBKBEAgE0ECdKwhJUEAIQQDQCADKAKQASAEQTxsaiIAIAMoAqgBQQAgJBBINgIkIAAgAygCqAFBACAkEEg2AiggACADKAKoASAIICQgJRBVNgIsIAAgAygCqAFBACAlEEg2AjAgACADKAKoASAIICUgJBBVNgI0IAAgAygCqAFBACAkEEg2AjggACADKAKoAUEAICQQSDYCACAAIAMoAqgBQQAgJBBINgIEIAAgAygCqAEgCCAkICQQVTYCECAAIAMoAqgBQQAgJBBINgIUIAAgAygCqAEgCCAkICQQVTYCGCAAIAMoAqgBIAggJCAkEFU2AhwgACADKAKoAUEAICQQSDYCICAAIAMoAqgBIAggJCAkEFU2AgggACADKAKoAUEAICQQSDYCDCAAKAIkIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQYwNEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIoIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQfcREDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIsIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQdYOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIwIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZATEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAI0IQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbMOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAI4IQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQfESEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIAIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbENEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIEIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZgSEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIQIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQZIMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIUIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQa0REDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIYIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQbwMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIcIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQYsOEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIgIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQc0SEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIIIQYgAUGgBGoiAiAEEDkgASACQc7CABA4IgIoAgg2ArgEIAEgAikCADcDsAQgAkIANwIAIAJBADYCCCABIAFBsARqQeQMEDciAigCCDYC+AMgASACKQIANwPwAyACQgA3AgAgAkEANgIIIAEgAUHwA2oiAjYC5AMgAUGUBGogBSACIAFB5ANqEDwgASgClAQgBjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAAKAIMIQIgAUGgBGoiACAEEDkgASAAQc7CABA4IgAoAgg2ArgEIAEgACkCADcDsAQgAEIANwIAIABBADYCCCABIAFBsARqQdMREDciACgCCDYC+AMgASAAKQIANwPwAyAAQgA3AgAgAEEANgIIIAEgAUHwA2oiADYC5AMgAUGUBGogBSAAIAFB5ANqEDwgASgClAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAEsALsEQQBIBEAgASgCsAQQLwsgASwAqwRBAEgEQCABKAKgBBAvCyAEQQFqIgQgDEcNAAsLIAMgAygCqAFBACASrCIkICcQVTYCgAEgAyADKAKoASAIICQgKRBVNgKEASADIAMoAqgBQQAgJBBINgKIASADIAMoAqgBQQAgJBBINgKMASADKAKAASECIAFBIBAyIgA2AvADIAFCnICAgICEgICAfzcC9AMgAEGtHigAADYAGCAAQaUeKQAANwAQIABBlR79AAAA/QsAACAAQQA6ABwgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygChAEhAiABQSAQMiIANgLwAyABQp6AgICAhICAgH83AvQDIABB6Q0pAAA3ABYgAEHjDSkAADcAECAAQdMN/QAAAP0LAAAgAEEAOgAeIAEgAUHwA2oiADYCoAQgAUGwBGogBSAAIAFBoARqEDwgASgCsAQgAjYCHCABLAD7A0EASARAIAEoAvADEC8LIAMoAogBIQIgAUEgEDIiADYC8AMgAUKRgICAgISAgIB/NwL0AyAAQdENLQAAOgAQIABBwQ39AAAA/QsAACAAQQA6ABEgASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgAygCjAEhAiABQRAQMiIANgLwAyABQo+AgICAgoCAgH83AvQDIABBrRIpAAA3AAcgAEGmEikAADcAACAAQQA6AA8gASABQfADaiIANgKgBCABQbAEaiAFIAAgAUGgBGoQPCABKAKwBCACNgIcIAEsAPsDQQBIBEAgASgC8AMQLwsgCkEASgRAIBJBAnSsISVBACEEA0AgAygCnAEgBEHgAGxqIgAgAygCqAFBACAkEEg2AkggACADKAKoAUEAICQQSDYCTCAAIAMoAqgBIAggJCAlEFU2AlAgACADKAKoAUEAICUQSDYCVCAAIAMoAqgBIAggJSAkEFU2AlggACADKAKoAUEAICQQSDYCXCAAIAMoAqgBQQAgJBBINgIAIAAgAygCqAFBACAkEEg2AgQgACADKAKoASAIICQgJBBVNgIQIAAgAygCqAFBACAkEEg2AhQgACADKAKoASAIICQgJBBVNgIYIAAgAygCqAEgCCAkICQQVTYCHCAAIAMoAqgBQQAgJBBINgIgIAAgAygCqAEgCCAkICQQVTYCCCAAIAMoAqgBQQAgJBBINgIMIAAgAygCqAFBACAkEEg2AiQgACADKAKoAUEAICQQSDYCKCAAIAMoAqgBIAggJCAkEFU2AjQgACADKAKoAUEAICQQSDYCOCAAIAMoAqgBIAggJCAkEFU2AjwgACADKAKoASAIICQgJBBVNgJAIAAgAygCqAFBACAkEEg2AkQgACADKAKoASAIICQgJBBVNgIsIAAgAygCqAFBACAkEEg2AjAgACgCSCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGMDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCTCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakH3ERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCUCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHWDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCVCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGQExA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCWCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGzDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCXCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHxEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCACEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGxDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCBCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGYEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCECEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGSDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCFCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGtERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCGCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakG8DBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCHCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGLDhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCICEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHNEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCCCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHkDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCDCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHTERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCJCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGbDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCKCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGEEhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCNCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakH5CxA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCOCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGWERA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCPCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakGlDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgAEFAaygCACEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHyDRA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCRCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakG2EhA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCLCEGIAFBoARqIgIgBBA5IAEgAkHewgAQOCICKAIINgK4BCABIAIpAgA3A7AEIAJCADcCACACQQA2AgggASABQbAEakHNDBA3IgIoAgg2AvgDIAEgAikCADcD8AMgAkIANwIAIAJBADYCCCABIAFB8ANqIgI2AuQDIAFBlARqIAUgAiABQeQDahA8IAEoApQEIAY2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgACgCMCECIAFBoARqIgAgBBA5IAEgAEHewgAQOCIAKAIINgK4BCABIAApAgA3A7AEIABCADcCACAAQQA2AgggASABQbAEakG+ERA3IgAoAgg2AvgDIAEgACkCADcD8AMgAEIANwIAIABBADYCCCABIAFB8ANqIgA2AuQDIAFBlARqIAUgACABQeQDahA8IAEoApQEIAI2AhwgASwA+wNBAEgEQCABKALwAxAvCyABLAC7BEEASARAIAEoArAEEC8LIAEsAKsEQQBIBEAgASgCoAQQLwsgBEEBaiIEIApHDQALCyADEOUEIgA2AoQCQQAhBCADKAK0ASICIANBuAFqIgZHBEADQCACKAIcEFsgBGohHAJAIAIoAgQiBARAA0AgBCIAKAIAIgQNAAwCCwALA0AgAigCCCIAKAIAIAJHIRsgACECIBsNAAsLIBxBvAJqIQQgBiAAIgJHDQALIAMoAoQCIQALIAMgACAAKAIIEQAAIgAgBCAAKAIAEQQANgKsASADKAKEAiIABH8gACAAKAIAEQAABUGwMAshACABIAS4RAAAAACAhC5BozkDuAEgASAANgK0ASABQcglNgKwAUEEQa3vACABQbABahA0IAMoAqwBEMkBIQwgBiADKAK0ASICRwRAA0AgDCACKAIcEJABAkAgAigCBCIEBEADQCAEIgAoAgAiBA0ADAILAAsDQCACKAIIIgAoAgAgAkchHSAAIQIgHQ0ACwsgBiAAIgJHDQALCyADQQA2ArABIAFBADYCuAQgAUIANwKwBEEAIQoDQAJAIAcoAiQgAUGQBGpBBCAHKAIoEQMAGiAHKAIkIAFBjARqQQQgBygCKBEDABogBygCJCABQYgEakEEIAcoAigRAwAaAkACQAJAIAcoAiQgBygCLBEAAARAIAFByCU2AjAgASAKuEQAAAAAgIQuQaM5AzhBBEGp8QAgAUEwahA0IAMoArABIgANASABQcglNgIQQQNBxOYAIAFBEGoQNEEAIQIMBAtBACEAIAFB0KUB/QAEAP0LBPADQQEhBCABKAKQBEEASg0BDAILQQAhAiAAIAMoArwBIgRGDQIgASAANgIoIAEgBDYCJCABQcglNgIgQQJB1+oAIAFBIGoQNEEBIQIMAgsDQCAHKAIkIAFB8ANqIABBAnRqIgJBBCAHKAIoEQMAGiACKAIAIARsIQQgAEEBaiIAIAEoApAESA0ACwtBACECIAFBADYCqAQgAUIANwOgBCABQQA2ApwEIAFCADcClARBACEAIAEoAowEIggEQCAIQQBIDQQgASAIEDIiADYClAQgASAAIAhqIgI2ApwEIABBACAI/AsAIAEgAjYCmAQLIAcoAiQgACACIABrIgggBygCKBEDABogAUGgBGoiAiAAIAgQywECfyAFIAIQ8AIgBkYEQCABQcglNgJAQQAhBCABIAEoAqAEIAIgASwAqwRBAEgbNgJEQQJB9+cAIAFBQGsQNEEBDAELIAEoAqAEIAFBoARqIAEsAKsEQQBIGyIIEGgiAEHw////B08NBQJAIABBCk0EQCABIAA6AO8DIAFB5ANqIQIMAQsgAEEPckEBaiILEDIhAiABIAtBgICAgHhyNgLsAyABIAI2AuQDIAEgADYC6AMLIAIgCCAA/AoAACAAIAJqQQA6AAAgASABQeQDaiIANgLEBCABQcgEaiAFIAAgAUHEBGoQPCABKALIBCgCHCEAIAEsAO8DQQBIBEAgASgC5AMQLwsgBKwgACkDKCAAKQMgIAApAxggACkDEH5+flIEQCABQcglNgKgAUEAIQQgASABKAKgBCABQaAEaiABLACrBEEASBs2AqQBQQJByecAIAFBoAFqEDQgACkDICEkIAApAxghJSABIAApAxA+ApABIAEgJT4ClAEgASAkPgKYASABQcglNgKAASABIAEoAvADNgKEASABIAEpAvQDNwOIAUECQfzuACABQYABahA0QQEMAQsgACkDGCEkIAEoAvQDIQgCQAJAIAApAxAiJSABKALwAyILrFIEQCABKAL4AyECDAELIAEoAvgDIQIgJCAIrFINACAAKQMgIAKsUQ0BCyABIAApAyA+AnAgASALNgJ0IAEgCDYCeCABIAI2AnwgAUHIJTYCYEEAIQQgASABKAKgBCABQaAEaiABLACrBEEASBs2AmQgASAlPgJoIAEgJD4CbEECQaTuACABQeAAahA0QQEMAQsgBCABKAKIBEEkbEGYmwFqKAIAbCICIAAoAgBBJGxBlJsBaigCAG4gABBbRwRAIAEoAqAEIQggASwAqwQhCyAAEFshACABIAI2AlwgASAANgJYIAFByCU2AlBBACEEIAEgCCABQaAEaiALQQBIGzYCVEECQZviACABQdAAahA0QQEMAQsCQCADKAKEAigCAEE8RgRAIAcoAighAiAHKAIkIAAoAtABIAAQWyACEQMAGgwBCwJAIAAQWyICIAFBsARqIgQoAgQgBCgCACILayIISwRAIAQgAiAIaxDxAgwBCyACIAhJBEAgBCACIAtqNgIECwsgBygCJCABKAKwBCICIAEoArQEIAJrIAcoAigRAwAaIAAgASgCsARBACAAEFsQlwELIAAQWyEeQQEhBCADIAMoArABQQFqNgKwASAeIApqIQpBAAshAiABKAKUBCIABEAgABAvCyABLACrBEEASARAIAEoAqAEEC8LIAQNAQsLIAEoArAEIgAEQCABIAA2ArQEIAAQLwtBACEAIAINACAMEJEBIAMQaSAmfTcDAEEBIQALIAFB0ARqJAAgAAwCCxA2AAsQTQALIR8gBygCJCAHKAIwEQEAIB9FBEAgD0HTHzYCAEECQfPlACAPEDQgAywAkwJBAEgEQCADKAKIAhAvCyAXIAMoAtQBEI8CIBYgAygCyAEQjgIgFSADKAK4ARCNAiADKAKcASIABEAgAyAANgKgASAAEC8LIAMoApABIgAEQCADIAA2ApQBIAAQLwsgAygCWCIABEAgAyAANgJcIAAQLwsgAxAvQQAh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5ZKe4AZsIARqIgA2AgAgA0ECaiIEQQJ0IAJqIABBHnYgAHNB5ZKe4AZsIARqIgA2AgAgA0EDaiIEQfAERwRAIARBAnQgAmogAEEediAAc0Hlkp7gBmwgBGoiADYCACADQQRqIQMMAQsLIAFBADYCwBQgBUHkAmogAUGAAWoiAEHEE/wKAAAgCSgChAIhAiABIAFByBRqNgKIASABQeS1ATYCgAEgASAANgKQASABIAFBzBRqNgKEASAFQZSnAWogAiAAEJACAkACfyAAIAEoApABIgNGBEAgACEDIAEoAoABQRBqDAELIANFDQEgAygCAEEUagshACADIAAoAgARAQALIAEoAsgUIgBBmKcBaigCACECIABBnKcBaigCACEEIAAoApSnASgCACgClBAhACABQcAfNgIwIAEgACAEIAJrarhEAAAAAICELkGjOQM4QQRBgfEAIAFBMGoQNCABKALMFCgChAIhAiABKALIFCEhIAEgAUHIFGo2AogBIAFB1LcBNgKAASABIAFBgAFqIgA2ApABIAEgAUHMFGo2AoQBICFBqKcBaiACIAAQkAICQAJ/IAAgASgCkAEiA0YEQCAAIQMgASgCgAFBEGoMAQsgA0UNASADKAIAQRRqCyEAIAMgACgCABEBAAsgASgCyBQiAEGspwFqKAIAIQIgAEGwpwFqKAIAIQQgACgCqKcBKAIAKAKUECEAIAFBwB82AiAgASAAIAQgAmtquEQAAAAAgIQuQaM5AyhBBEHr7wAgAUEgahA0IAEoAswUKAKEAiECIAEoAsgUISIgASABQcgUajYCiAEgAUGMuQE2AoABIAEgAUGAAWoiADYCkAEgASABQcwUajYChAEgIkG8pwFqIAIgABCQAgJAAn8gACABKAKQASIDRgRAIAAhAyABKAKAAUEQagwBCyADRQ0BIAMoAgBBFGoLIQAgAyAAKAIAEQEACyABKALIFCIAQcCnAWooAgAhAiAAQcSnAWooAgAhBCAAKAK8pwEoAgAoApQQIQAgAUHAHzYCECABIAAgBCACa2q4RAAAAACAhC5BozkDGEEEQdnwACABQRBqEDQgASgCzBQoAoQCIQIgASgCyBQhIyABIAFByBRqNgKIASABQcS6ATYCgAEgASABQYABaiIANgKQASABIAFBzBRqNgKEASAjQdCnAWogAiAAEJACAkACfyAAIAEoApABIgNGBEAgACEDIAEoAoABQRBqDAELIANFDQEgAygCAEEUagshACADIAAoAgARAQALIAEoAsgUIgBB1KcBaigCACECIABB2KcBaigCACEEIAAoAtCnASgCACgClBAhACABQcAfNgIAIAEgACAEIAJrarhEAAAAAICELkGjOQMIQQRBk/AAIAEQNCABKALIFCIDKAKUpwEiAgRAIAEoAswUKAKEAiEAIAIoAgAoApQQIQIgAygClKcBEJEBIANBpKcBaiAAIAAoAggRAAAiACACIAAoAgARBAAiADYCACADIAAQyQE2ApSnASABKALIFCEDCyADKAKopwEiAARAIAEoAswUKAKEAiECIAAoAgAoApQQIQQgABCRASADQbinAWogAiACKAIIEQAAIgAgBCAAKAIAEQQAIgA2AgAgAyAAEMkBNgKopwEgASgCyBQhAwsgAygCvKcBIgAEQCABKALMFCgChAIhAiAAKAIAKAKUECEEIAAQkQEgA0HMpwFqIAIgAigCCBEAACIAIAQgACgCABEEACIANgIAIAMgABDJATYCvKcBIAEoAsgUIQMLIAMoAtCnASIARQ0AIAEoAswUKAKEAiECIAAoAgAoApQQIQQgABCRASADQeCnAWogAiACKAIIEQAAIgAgBCAAKAIAEQQAIgA2AgAgAyAAEMkBNgLQpwEgASgCyBQhAwsgAUHQFGokACADDAELEDYACyIANgKAAiAJIAANARogCRDgBAtBAAsiADYCACAAQQBHCwvqBQIEfwJ8IwBBIGsiBCQAIAQgADYCACAEQQA6ABggBEIANwMQIAQgAjYCDCAEIAE2AgggBCMDNgIEAnwgAwRAIwBBEGsiAyQAIAMgBDYCDCADQQA2AgggA0HIATYCBCADQQRqIQUjAEGAAWsiACQAIwBB4ABrIgEkAAJAQYTzNCgCAEECRgRAIwBBEGtBADYCDAwBCyMAQRBrIgIkAANAAkACQAJAAkACQEGE8zRBAEEB/kgCAA4EAAIBAwULIAJBBGoiBkGE8zQ2AgQgAkHKATYCBCACIwMiBygCRDYCDCAHIAY2AkQQmAQjAyACKAIMNgJEQYTzNEEC/kECAEEDRw0AQYTzNBD6AQsgAkEQaiQADAILQYTzNEEBQQP+SAIAGgtBhPM0QQBBAxChAQwBCwsLIAFBAEHQAPwL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QQAhBgNAIAEgICAEIA/9GwFqIgosAABBIGuylP0TIg39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgFCAH/Q8iDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAcIA/9GwAiAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwIwIAEgDf0M/P////z////8/////P////0MAAAAAAAAAAAAAAAAAAAAACAVIA79Tv0MAAAAAAAAAAAAAAAAAAAAAP0j/YcB/acB/VIgHSAC/a0B/QwDAAAAAwAAAAMAAAADAAAA/U79UP36Af3mAf0LAiAgASAN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBYgDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAeIAL9rQH9DAMAAAADAAAAAwAAAAMAAAD9Tv1Q/foB/eYB/QsCECABIA39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgFyAO/U79DAAAAAAAAAAAAAAAAAAAAAD9I/2HAf2nAf1SIB8gAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwIAIAEgICAKLAABQSBrspT9EyIN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBAgDv1O/QwAAAAAAAAAAAAAAAAAAAAA/SP9hwH9pwH9UiAYIAL9rQH9DAMAAAADAAAAAwAAAAMAAAD9Tv1Q/foB/eYB/QsCcCABIA39DPz////8/////P////z////9DAAAAAAAAAAAAAAAAAAAAAAgESAO/U79DAAAAAAAAAAAAAAAAAAAAAD9I/2HAf2nAf1SIBkgAv2tAf0MAwAAAAMAAAADAAAAAwAAAP1O/VD9+gH95gH9CwJgIAEgDf0M/P////z////8/////P////0MAAAAAAAAAAAAAAAAAAAAACASIA79Tv0MAAAAAAAAAAAAAAAAAAAAAP0j/YcB/acB/VIgGiAC/a0B/QwDAAAAAwAAAAMAAAADAAAA/U79UP36Af3mAf0LAlAgASAN/Qz8/////P////z////8/////QwAAAAAAAAAAAAAAAAAAAAAIBMgDv1O/QwAAAAAAAAAAAAA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JCACIANGIQkgAkEEaiECIAlFDQALDAELIAEgACgCCDYCKAsLjgcCBH8EeyACQR9KBEAgAkEgbSEGA0AgASAFQQd0aiIDQUBrIAAgBUEWbGoiBC8BAEECdEGQ1gRq/QkCACIHIAQoAQIiAkEMdv0RIAJBDXb9HAEgAkEOdv0cAiACQQ92/RwDIgn9DBAAAAAQAAAAEAAAABAAAAD9TiAE/VwABv2JAf2pASIIQQT9rQH9UP0M8P////D////w////8P////2uAf36Af3mAf0LAgAgAyAHIAJBBHT9ESACQQN0/RwBIAJBAnT9HAIgAkEBdP0cA/0MEAAAABAAAAAQAAAAEAAAAP1OIAj9DA8AAAAPAAAADwAAAA8AAAD9Tv1Q/Qzw////8P////D////w/////a4B/foB/eYB/QsCACADIAcgAkEQdv0RIAJBEXb9HAEgAkESdv0cAiACQRN2/RwD/QwQAAAAEAAAABAAAAAQAAAA/U4gBEEKav1cAAD9iQH9qQEiCEEE/a0B/VD9DPD////w////8P////D////9rgH9+gH95gH9CwJQIAMgByACQQR2/REgAkEFdv0cASACQQZ2/RwCIAJBB3b9HAMiCkEE/asB/QwQAAAAEAAAABAAAAAQAAAA/U4gCP0MDwAAAA8AAAAPAAAADwAAAP1O/VD9DPD////w////8P////D////9rgH9+gH95gH9CwIQIAMgByACQRR2/REgAkEVdv0cASACQRZ2/RwCIAJBF3b9HAP9DBAAAAAQAAAAEAAAABAAAAD9TiAEQQ5q/VwAAP2JAf2pASIIQQT9rQH9UP0M8P////D////w////8P////2uAf36Af3mAf0LAmAgAyAHIAr9DBAAAAAQAAAAEAAAABAAAAD9TiAI/QwPAAAADwAAAA8AAAAPAAAA/U79UP0M8P////D////w////8P////2uAf36Af3mAf0LAiAgAyAHIAJBGHb9ESACQRl2/RwBIAJBGnb9HAIgAkEbdv0cA/0MEAAAABAAAAAQAAAAEAAAAP1OIARBEmr9XAAA/YkB/akBIghBBP2tAf1Q/Qzw////8P////D////w/////a4B/foB/eYB/QsCcCADIAcgCUEE/asB/QwQAAAAEAAAABAAAAAQAAAA/U4gCP0MDwAAAA8AAAAPAAAADwAAAP1O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IAAoAgQ2AigPCwsgAUGfeDYCACABQQA2AigPCxD/AQALnQEBBH8CQAJAIAEoAhAgACgCFEEBa0EMbGoiAi0ACEUNASACKAIEIAIoAgAiBWsiAyABKAIMIAEoAggiBGtKDQFBACECIANBAEwNAANAIAIgBWotAAAgAiAEai0AAEcNAiADIAJBAWoiAkcNAAsMAAsgAUGeeDYCACABIAMgBGo2AgggASAAKAIENgIoDwsgAUGfeDYCACABQQA2AigLUgEBfyAAQcyvATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwtQAQF/IABBzK8BNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgAAvPAQEEfwJAAkACQCABKAIQIAAoAhRBDGxqQQxrIgMtAAhFDQIgAygCBCADKAIAayIEIAEoAgwgASgCCCICa0oNAiAEQQBMDQFBACECA0AgACgCDCIFIAMoAgAgAmosAAAgBSgCACgCFBEEACAAKAIMIgUgASgCCCACaiwAACAFKAIAKAIUEQQARw0DIAQgAkEBaiICRw0ACwwACyABKAIIIQILIAFBnng2AgAgASACIARqNgIIIAEgACgCBDYCKA8LIAFBn3g2AgAgAUEANgIoC1IBAX8gAEH0rgE2AgAgACgCCCIBQQRqQX/+HgIARQRAIAEgASgCACgCCBEBAAsgAEHcqQE2AgAgACgCBCIBBEAgASABKAIAKAIEEQEACyAAEC8LUAEBfyAAQfSuATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAALjQQCAnsDfyACQR9KBEAgAkEgbSEHA0AgASAFQQd0aiICQUBrIAAgBUESbGoiBi8BAEECdEGQ1gRq/QkCACIDIAb9XAAC/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAgAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAgAgAiADIAZBBmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAlAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAhAgAiADIAZBCmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAmAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAiAgAiADIAZBDmr9XAAA/YkB/akBIgRBBP2tAf0M+P////j////4////+P////2uAf36Af3mAf0LAnAgAiADIAT9DA8AAAAPAAAADwAAAA8AAAD9Tv0M+P////j////4////+P////2uAf36Af3mAf0LAjAgBUEBaiIFIAdHDQALCwtPAQF/AkAgASgCCCICIAEoAgxGDQAgAi0AACAALQAIRw0AIAFBnXg2AgAgASACQQFqNgIIIAEgACgCBDYCKA8LIAFBn3g2AgAgAUEANgIoC08BAX8CQCABKAIIIgIgASgCDEYNACACLQAAIAAtABRHDQAgAUGdeDYCACABIAJBAWo2AgggASAAKAIENgIoDwsgAUGfeDYCACABQQA2AigLUgEBfyAAQditATYCACAAKAIIIgFBBGpBf/4eAgBFBEAgASABKAIAKAIIEQEACyAAQdypATYCACAAKAIEIgEEQCABIAEoAgAoAgQRAQALIAAQLwtQAQF/IABB2K0BNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgAAtoAQJ/AkAgASgCCCICIAEoAgxGDQAgACgCDCIDIAIsAAAgAygCACgCFBEEAEH/AXEgAC0AFEcNACABQZ14NgIAIAEgASgCCEEBajYCCCABIAAoAgQ2AigPCyABQZ94NgIAIAFBADYCKAtSAQF/IABB/KwBNgIAIAAoAggiAUEEakF//h4CAEUEQCABIAEoAgAoAggRAQALIABB3KkBNgIAIAAoAgQiAQRAIAEgASgCACgCBBEBAAsgABAvC1ABAX8gAEH8rAE2AgAgACgCCCIBQQRqQX/+HgIARQRA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b2FkY2FzdAB1bnNpZ25lZCBzaG9ydABhbGVydAB3aGlzcGVyX2t2X2NhY2hlX2ZpbmRfc2xvdABwcmludAB1bnNpZ25lZCBpbnQAY2lyY3VtZmxleC1hY2NlbnQAZ3JhdmUtYWNjZW50AGZ1bGxfZGVmYXVsdABrdl9jYWNoZV9pbml0AHhkaWdpdAAuY3Jvc3NfYXR0bi5xdWVyeS53ZWlnaHQALmF0dG4ucXVlcnkud2VpZ2h0AC5jcm9zc19hdHRuLmtleS53ZWlnaHQALmF0dG4ua2V5LndlaWdodAAuY3Jvc3NfYXR0bi5vdXQud2VpZ2h0AC5hdHRuLm91dC53ZWlnaHQAZW5jb2Rlci5sbl9wb3N0LndlaWdodAAubWxwX2xuLndlaWdodAAuY3Jvc3NfYXR0bl9sbi53ZWlnaHQALmF0dG5fbG4ud2VpZ2h0AGRlY29kZXIubG4ud2VpZ2h0AGRlY29kZXIudG9rZW5fZW1iZWRkaW5nLndlaWdodAAuY3Jvc3NfYXR0bi52YWx1ZS53ZWlnaHQALmF0dG4udmFsdWUud2VpZ2h0AGVuY29kZXIuY29udjIud2VpZ2h0AC5tbHAuMi53ZWlnaHQAZW5jb2Rlci5jb252MS53ZWlnaHQALm1scC4wLndlaWdodABzZXQAcmlnaHQtY3VybHktYnJhY2tldABsZWZ0LWN1cmx5LWJyYWNrZXQAcmlnaHQtc3F1YXJlLWJyYWNrZXQAbGVmdC1zcXVhcmUtYnJhY2tldABwdW5jdABnZ21sX25ld19vYmplY3QAT2N0AGZsb2F0AFNhdABjb21tZXJjaWFsLWF0AHVpbnQ2NF90AGh5cGhlbi1taW51cwByZXZlcnNlLXNvbGlkdXMAd2hpc3Blcl9leHBfY29tcHV0ZV90b2tlbl9sZXZlbF90aW1lc3RhbXBzAGFmcmlrYWFucwBwYXJhbXMAZ2dtbF9nZXRfbl90YXNrcwByaWdodC1wYXJlbnRoZXNpcwBsZWZ0LXBhcmVudGhlc2lzAHdoaXNwZXJfcHJpbnRfdGltaW5ncwAuY3Jvc3NfYXR0bi5xdWVyeS5iaWFzAC5hdHRuLnF1ZXJ5LmJpYXMALmNyb3NzX2F0dG4ub3V0LmJpYXMALmF0dG4ub3V0LmJpYXMAZW5jb2Rlci5sbl9wb3N0LmJpYXMALm1scF9sbi5iaWFzAC5jcm9zc19hdHRuX2xuLmJpYXMALmF0dG5fbG4uYmlhcwBkZWNvZGVyLmxuLmJpYXMALmNyb3NzX2F0dG4udmFsdWUuYmlhcwAuYXR0bi52YWx1ZS5iaWFzAGVuY29kZXIuY29udjIuYmlhcwAubWxwLjIuYmlhcwBlbmNvZGVyLmNvbnYxLmJpYXMALm1scC4wLmJpYXMAcm93X2lkID49IDAgJiYgcm93X2lkIDwgbl9hcwAlcwBmb3VyAHdoaXNwZXJfbGFuZ19zdHIAQXByAGNvbnN0cnVjdG9yAHZlY3RvcgBjZ3JhcGgtPm5vZGVzW2NncmFwaC0+bl9ub2RlcyAtIDFdID09IHRlbnNvcgB1bmtub3duIGFsbG9jYXRpb24gZXJyb3IAYmFzaGtpcgBsb3dlcgB1cHBlcgBraG1lcgBidWZmZXIAT2N0b2JlcgBOb3ZlbWJlcgBTZXB0ZW1iZXIARGVjZW1iZXIAdGF0YXIAbXlhbm1hcgB1bnNpZ25lZCBjaGFyAGlvc19iYXNlOjpjbGVhcgBNYXIAcQAvVXNlcnMvZ2dlcmdhbm92L2RldmVsb3BtZW50L2dpdGh1Yi93aGlzcGVyLmNwcC93aGlzcGVyLmNwcABmdWxsLXN0b3AAU2VwACVJOiVNOiVTICVwAHR3bwBhdXRvAHBhc2h0bwB6ZXJvAGxhbwB1bmtub3duAFN1bgBKdW4AY2FycmlhZ2UtcmV0dXJuAGJyZXRvbgBzZW1pY29sb24Ac3RkOjpleGNlcHRpb24AX19jeGFfZ3VhcmRfYWNxdWlyZSBkZXRlY3RlZCByZWN1cnNpdmUgaW5pdGlhbGl6YXRpb24ATW9uAGxhdGluAHBlcmNlbnQtc2lnbgBwbHVzLXNpZ24AZXF1YWxzLXNpZ24AbnVtYmVyLXNpZ24AZG9sbGFyLXNpZ24AbGVzcy10aGFuLXNpZ24AZ3JlYXRlci10aGFuLXNpZ24Ac2V2ZW4AdHVya21lbgBoeXBoZW4Ab2NjaXRhbgB0aWJldGFuAG5hbgBnZXJtYW4AY3BsYW4AY2F0YWxhbgBsYXR2aWFuAGJlbGFydXNpYW4AcnVzc2lhbgBwZXJzaWFuAGluZG9uZXNpYW4AaHVuZ2FyaWFuAGJ1bGdhcmlhbgBib3NuaWFuAG1hY2Vkb25pYW4AdWtyYWluaWFuAHNsb3ZlbmlhbgBsaXRodWFuaWFuAG1vbmdvbGlhbgBpdGFsaWFuAG5vcndlZ2lhbgBzZXJiaWFuAGtvcmVhbgBKYW4AYWxudW0AbWVkaXVtAG1hbGF5YWxhbQBKdWwAY250cmwAZ2dtbF9uZXdfdGVuc29yX2ltcGwAYm9vbABzbWFsbABzdGQ6OmJhZF9mdW5jdGlvbl9jYWxsAEFwcmlsAHRhbWlsAGVtc2NyaXB0ZW46OnZhbABueW5vcnNrAGFzdGVyaXNrAHF1ZXN0aW9uLW1hcmsAcXVvdGF0aW9uLW1hcmsAZXhjbGFtYXRpb24tbWFyawBibGFuawB0YWppawBncmVlawB1emJlawBzbG92YWsAagBtYW9yaQBGcmkAYXplcmJhaWphbmkAc3dhaGlsaQBuZXBhbGkAc29tYWxpAGJlbmdhbGkAbWFyYXRoaQBzaW5kaGkAaGluZGkAcHVuamFiaQBiYWRfYXJyYXlfbmV3X2xlbmd0aAB3ZWxzaABmaW5uaXNoAHNwYW5pc2gAZGFuaXNoAHBvbGlzaABlbmdsaXNoAHR1cmtpc2gAbHV4ZW1ib3VyZ2lzaABzd2VkaXNoAHlpZGRpc2gAYmFja3NsYXNoAGdyYXBoAGthemFraABkdXRjaABNYXJjaABmcmVuY2gAY3plY2gAQXVnAHRhZ2Fsb2cAdW5zaWduZWQgbG9uZwB0ZXJtaW5hdGluZwBzdGQ6OndzdHJpbmcAYmFzaWNfc3RyaW5nAHN0ZDo6c3RyaW5nAHN0ZDo6dTE2c3RyaW5nAHN0ZDo6dTMyc3RyaW5nAGVuY29kZXIucG9zaXRpb25hbF9lbWJlZGRpbmcAZGVjb2Rlci5wb3NpdGlvbmFsX2VtYmVkZGluZwBpbmYAJS4wTGYAJUxmAGNncmFwaC0+bl9sZWFmcyA8IGNncmFwaC0+c2l6ZQBjZ3JhcGgtPm5fbm9kZXMgPCBjZ3JhcGgtPnNpemUAd2hpc3Blcl90b2tlbml6ZQBmaXZlAHl1ZQB0cnVlAGJhc3F1ZQBpbnZhbGlkIGFsaWdubWVudCB2YWx1ZQBUdWUAd2hpc3Blcl9pbml0X3N0YXRlAHdoaXNwZXJfaW5pdF93aXRoX3BhcmFtc19ub19zdGF0ZQB3aGlzcGVyX2luaXRfZnJvbV9maWxlX3dpdGhfcGFyYW1zX25vX3N0YXRlAHdoaXNwZXJfbGFuZ19hdXRvX2RldGVjdF93aXRoX3N0YXRlAHdoaXNwZXJfZnVsbF93aXRoX3N0YXRlAHdoaXNwZXJfZW5jb2RlX3dpdGhfc3RhdGUAd2hpc3Blcl9kZWNvZGVfd2l0aF9zdGF0ZQB0cmFuc2xhdGUAZmFsc2UAcG9ydHVndWVzZQBtYWx0ZXNlAGZhcm9lc2UAY2FudG9uZXNlAGNoaW5lc2UAc3VuZGFuZXNlAHZpZXRuYW1lc2UAX19jeGFfZ3VhcmRfcmVsZWFzZQB1bmRlcnNjb3JlAF9fY3hhX2d1YXJkX2FjcXVpcmUAc3JjMC0+dHlwZSA9PSBkc3QtPnR5cGUAZHN0LT50eXBlID09IHNyYzAtPnR5cGUAVW5rbm93biBlcnJvciB0eXBlAEp1bmUAb25lAG5pbmUAbmV3bGluZQBsb3ctbGluZQB2ZXJ0aWNhbC1saW5lAGhhaXRpYW4gY3Jlb2xlAGRvdWJsZQBhcG9zdHJvcGhlAGxhcmdlAHRocmVlAGZyZWUAdGlsZGUAcmlnaHQtYnJhY2UAbGVmdC1icmFjZQBiYWNrc3BhY2UAdHJhbnNjcmliZQBwZXJpb2QAbWFwOjphdDogIGtleSBub3QgZm91bmQAYW1wZXJzYW5kAHZvaWQAd2hpc3Blcl9sYW5nX2lkAHRlcm1pbmF0ZV9oYW5kbGVyIHVuZXhwZWN0ZWRseSByZXR1cm5lZAB0aHJlYWQgY29uc3RydWN0b3IgZmFpbGVkAF9fdGhyZWFkX3NwZWNpZmljX3B0ciBjb25zdHJ1Y3Rpb24gZmFpbGVkAHRocmVhZDo6am9pbiBmYWlsZWQAbXV0ZXggbG9jayBmYWlsZWQAZm9ybS1mZWVkAFdlZAB3aGlzcGVyX21vZGVsX2xvYWQAJTAyZDolMDJkOiUwMmQlcyUwM2QAbGVhZl8lZABub2RlXyVkAGdnbWxfYWxpZ25lZF9tYWxsb2MAZ2dtbF90YWxsb2NyX2FsbG9jAHN0ZDo6YmFkX2FsbG9jAGRzdC0+bmVbMF0gPT0gbmMAYW1oYXJpYwBpY2VsYW5kaWMAYXJhYmljAERlYwAvVXNlcnMvZ2dlcmdhbm92L2RldmVsb3BtZW50L2dpdGh1Yi93aGlzcGVyLmNwcC9nZ21sLmMAL1VzZXJzL2dnZXJnYW5vdi9kZXZlbG9wbWVudC9naXRodWIvd2hpc3Blci5jcHAvZ2dtbC1iYWNrZW5kLmMAL1VzZXJzL2dnZXJnYW5vdi9kZXZlbG9wbWVudC9naXRodWIvd2hpc3Blci5jcHAvZ2dtbC1hbGxvYy5jAHdiAHJiAEZlYgB2ZXJ0aWNhbC10YWIAbl9sb2dpdHMgPT0gY3R4LnZvY2FiLm5fdm9jYWIAdytiAHIrYgBhK2IAcndhAGNwbGFuLT53b3JrX2RhdGEAaGF1c2EAc2hvbmEAY29tbWEAc2luaGFsYQBsaW5nYWxhAGFscGhhAGthbm5hZGEAeW9ydWJhAFtfZXh0cmFfdG9rZW5fAFtfVFRfAFtfTEFOR18AW19TT1RfXQBbX05PVF9dAFtfRU9UX10AW19CRUdfXQBbX1RSQU5TTEFURV9dAFtfVFJBTlNDUklCRV9dAGEtPm5lWzJdID09IGItPm5lWzJdAGEtPm5lWzJdID09IGItPm5lWzFdAGEtPm5lWzFdID09IGItPm5lWzFdAFoAdGVuc29yLT5vcCA9PSBHR01MX09QX1VOQVJZAE1BUF9VTkFSWQBNQVBfQklOQVJZAENQWQAlYSAlYiAlZCAlSDolTTolUyAlWQBQT1NJWABTT0ZUX01BWABBUkdNQVgAVklFVwBESVYAQ1BVAExFQUtZX1JFTFUAU1FSVABBUkdTT1JUAFdJTl9QQVJUAFdJTl9VTlBBUlQAaXNfcG9zaXRpdmVfY2hhciB8fCBwb3MtPnR5cGUgPT0gV0hJU1BFUl9HUkVUWVBFX0NIQVJfTk9UAHd0eXBlICE9IEdHTUxfVFlQRV9DT1VOVABDT05UAFNFVABNVUxfTUFUAFJFUEVBVABDT05DQVQAR0VUX1JPV1MAU1VNX1JPV1MAQ1JPU1NfRU5UUk9QWV9MT1NTAEdFVF9SRUxfUE9TAEFERF9SRUxfUE9TAGF4aXMzID49IDAgJiYgYXhpczMgPCBHR01MX01BWF9ESU1TAGF4aXMyID49IDAgJiYgYXhpczIgPCBHR01MX01BWF9ESU1TAGF4aXMxID49IDAgJiYgYXhpczEgPCBHR01MX01BWF9ESU1TAGF4aXMwID49IDAgJiYgYXhpczAgPCBHR01MX01BWF9ESU1TACVIOiVNOiVTAFNRUgBRAERVUABDTEFNUABESUFHX01BU0tfWkVSTwBGTEFTSF9BVFROAE5BTgBNRUFOAG5lMSA9PSBOAG5lZDEgPT0gTgBTVU0AUk1TX05PUk0AR1JPVVBfTk9STQBQTQBBTQBuZWIxMCA9PSBNAG5lYzAwID09IE0ATlVMAE1VTABJTTJDT0wAdGVuc29yLT5kYXRhID09IE5VTEwAaGFzaF9zZXQua2V5c1tpXSA9PSBOVUxMAHRlbnNvciAhPSBOVUxMAGN0eC0+bWVtX2J1ZmZlciAhPSBOVUxMAHZpZXctPnZpZXdfc3JjICE9IE5VTEwgJiYgdmlldy0+dmlld19zcmMtPmRhdGEgIT0gTlVMTABpICE9IEdHTUxfSEFTSFRBQkxFX0ZVTEwATENfQUxMAHE4X0sAcTZfSwBxNV9LAHE0X0sAcTNfSwBxMl9LAFNPRlRfTUFYX0JBQ0sAU0lMVV9CQUNLAFJFUEVBVF9CQUNLAEdFVF9ST1dTX0JBQ0sAQ1JPU1NfRU5UUk9QWV9MT1NTX0JBQ0sARkxBU0hfQVRUTl9CQUNLAFJNU19OT1JNX0JBQ0sAUk9QRV9CQUNLAEoAQUxJQkkASABMT0cATEFORwBESUFHAERJQUdfTUFTS19JTkYARkxBU0hfRkYAUEVSTVVURQBUUkFOU1BPU0UAUk9QRQBSRVNIQVBFAE5PTkUAVVBTQ0FMRQBPVVRfUFJPRABNVUxfTUFUX0lEAERFUFJFQ0FURUQAQUREAFBBRABQT09MXzJEAENPTlZfVFJBTlNQT1NFXzJEAFBPT0xfMUQAQ09OVl9UUkFOU1BPU0VfMUQAbmV2MSA9PSBEAG5lYzAxID09IEQAbmVrMCA9PSBEAG5lMCA9PSBEAG5lZDAgPT0gRABuZWMxMCA9PSBEAG5lYjAwID09IEQAQUNDAFNVQgBBAGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNob3J0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBzaG9ydD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBpbnQ+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGZsb2F0PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50OF90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQ4X3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxpbnQxNl90PgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1aW50NjRfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8aW50NjRfdD4AZW1zY3JpcHRlbjo6bWVtb3J5X3ZpZXc8dWludDMyX3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGludDMyX3Q+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHVuc2lnbmVkIGNoYXI+AHN0ZDo6YmFzaWNfc3RyaW5nPHVuc2lnbmVkIGNoYXI+AGVtc2NyaXB0ZW46Om1lbW9yeV92aWV3PHNpZ25lZCBjaGFyPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzx1bnNpZ25lZCBsb25nPgBlbXNjcmlwdGVuOjptZW1vcnlfdmlldzxkb3VibGU+AD4+PgA8PDwAMDEyMzQ1Njc4OQBpOABIRUFQVTgAQy5VVEYtOABpMTYAZjE2AGRzdC0+dHlwZSA9PSBHR01MX1RZUEVfRjE2AHNyYzAtPnR5cGUgPT0gR0dNTF9UWVBFX0YxNgAgdjMAYXhpczIgIT0gYXhpczMAYXhpczEgIT0gYXhpczMAYXhpczAgIT0gYXhpczMAbmUwMyA9PSBuZTMAbmIyIDw9IG5iMwBNQVBfQ1VTVE9NMwBuZTMgPT0gbmUxMwBuZTAzID09IG5lMTMAbmUzID09IG5lMDMAYXhpczEgIT0gYXhpczIAYXhpczAgIT0gYXhpczIAZ2dtbF9uZWxlbWVudHMoYSkgPT0gbmUwKm5lMSpuZTIAbl9oZWFkID09IG5lMgBuZTAyID09IG5lMgBuYjEgPD0gbmIyAG5lMiA9PSBuZWEyAE1BUF9DVVNUT00yAGkzMgBmMzIAYi0+dHlwZSA9PSBHR01MX1RZUEVfSTMyAGRzdC0+dHlwZSA9PSBHR01MX1RZUEVfRjMyAHNyYzEtPnR5cGUgPT0gR0dNTF9UWVBFX0YzMgBNQVBfQ1VTVE9NM19GMzIATUFQX0NVU1RPTTJfRjMyAE1BUF9DVVNUT00xX0YzMgBuZTIgPT0gbmUxMgBuZTAyID09IG5lMTIAbmUyID09IG5lMDIAYXhpczAgIT0gYXhpczEAZ2dtbF9uZWxlbWVudHMoYSkgPT0gbmUwKm5lMQBuZTAwID09IG5lMQBuYjAgPD0gbmIxAG5lMSA9PSBuZWExAHE4XzEAcTVfMQBxNF8xAE1BUF9DVVNUT00xAEFERDEAbmUxID09IG5lMTEAbmUxID09IG5lMDEAbmUwID09IG5lMDEAdCA9PSAwIHx8IHQgPT0gMQBtYXNrLT5uZVszXSA9PSAxAGItPm5lWzNdID09IDEAbm9kZS0+c3JjWzFdLT5uZVszXSA9PSAxAG5vZGUtPnNyY1swXS0+bmVbM10gPT0gMQBtYXNrLT5uZVsyXSA9PSAxAG5vZGUtPnNyY1sxXS0+bmVbMl0gPT0gMQBuZWMxMSA9PSAxAG5lYjExID09IDEAbmUwMSA9PSAxAG5lMCA9PSAxAGdnbWxfYmxja19zaXplKHJlc3VsdF90eXBlKSA9PSAxAGswID09IHMwAG5lMDAgPT0gbmUwAG5fZGltcyA8PSBuZTAAbmUwID09IG5lYTAAcThfMABxNV8wAHE0XzAAbmUxID09IG5lMTAAbmUwID09IG5lMDAAY3BsYW4tPm5fdGhyZWFkcyA+IDAAbl9wYXN0ID49IDAAUCA+PSAwAHBhcmFtcy0+aXRoID09IDAAcmMgPT0gMAAoKHVpbnRwdHJfdCkgKG1lbV9idWZmZXIgKyBvYmpfbmV3LT5vZmZzKSklR0dNTF9NRU1fQUxJR04gPT0gMAAoKHVpbnRwdHJfdCkgKGN0eC0+bWVtX2J1ZmZlcikpJUdHTUxfTUVNX0FMSUdOID09IDAAbl9kaW1zICUgMiA9PSAwAHAwID09IDAAVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgeyBhbmQgfS4AZW5jb2Rlci5ibG9ja3MuAGRlY29kZXIuYmxvY2tzLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCBjaGFyYWN0ZXIgcmFuZ2UsIHN1Y2ggYXMgW2ItYV0gaW4gbW9zdCBlbmNvZGluZ3MuAEFuIGVtcHR5IHJlZ2V4IGlzIG5vdCBhbGxvd2VkIGluIHRoZSBQT1NJWCBncmFtbWFyLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCByYW5nZSBpbiBhIHt9IGV4cHJlc3Npb24uAFRoZSBwYXJzZXIgZGlkIG5vdCBjb25zdW1lIHRoZSBlbnRpcmUgcmVndWxhciBleHByZXNzaW9uLgBPbmUgb2YgKj8reyB3YXMgbm90IHByZWNlZGVkIGJ5IGEgdmFsaWQgcmVndWxhciBleHByZXNzaW9uLgBUaGUgY29tcGxleGl0eSBvZiBhbiBhdHRlbXB0ZWQgbWF0Y2ggYWdhaW5zdCBhIHJlZ3VsYXIgZXhwcmVzc2lvbiBleGNlZWRlZCBhIHByZS1zZXQgbGV2ZWwuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGVzY2FwZWQgY2hhcmFjdGVyLCBvciBhIHRyYWlsaW5nIGVzY2FwZS4AVGhlcmUgd2FzIGluc3VmZmljaWVudCBtZW1vcnkgdG8gY29udmVydCB0aGUgZXhwcmVzc2lvbiBpbnRvIGEgZmluaXRlIHN0YXRlIG1hY2hpbmUuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGNvbGxhdGluZyBlbGVtZW50IG5hbWUuAFRoZSBleHByZXNzaW9uIGNvbnRhaW5lZCBhbiBpbnZhbGlkIGNoYXJhY3RlciBjbGFzcyBuYW1lLgBUaGVyZSB3YXMgaW5zdWZmaWNpZW50IG1lbW9yeSB0byBkZXRlcm1pbmUgd2hldGhlciB0aGUgcmVndWxhciBleHByZXNzaW9uIGNvdWxkIG1hdGNoIHRoZSBzcGVjaWZpZWQgY2hhcmFjdGVyIHNlcXVlbmNlLgBUaGUgZXhwcmVzc2lvbiBjb250YWluZWQgYW4gaW52YWxpZCBiYWNrIHJlZmVyZW5jZS4AQW4gaW52YWxpZCByZWdleCBncmFtbWFyIGhhcyBiZWVuIHJlcXVlc3RlZC4AVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgWyBhbmQgXS4AVGhlIGV4cHJlc3Npb24gY29udGFpbmVkIG1pc21hdGNoZWQgKCBhbmQgKS4ALS0tAHcrACdzfCd0fCdyZXwndmV8J218J2xsfCdkfCA/W1s6YWxwaGE6XV0rfCA/W1s6ZGlnaXQ6XV0rfCA/W15cc1s6YWxwaGE6XVs6ZGlnaXQ6XV0rfFxzKyg/IVxTKXxccysAcisAYSsAJXMgKGNvcHkpACVzICh2aWV3KQBnZ21sX2JhY2tlbmRfaXNfY3B1KGJhY2tlbmRfY3B1KQBnZ21sX2lzX2NvbnRpZ3VvdXMoZHN0KQBvZmZzZXQgKyBpbTAqbmIwICsgaW0xKm5iMSArIGltMipuYjIgKyBpbTMqbmIzIDw9IGdnbWxfbmJ5dGVzKGRzdCkAb2Zmc2V0ICsgKG5lMTAgPT0gMCA/IDAgOiBuZTEwLTEpKm5iMCArIChuZTExID09IDAgPyAwIDogbmUxMS0xKSpuYjEgKyAobmUxMiA9PSAwID8gMCA6IG5lMTItMSkqbmIyICsgKG5lMTMgPT0gMCA/IDAgOiBuZTEzLTEpKm5iMyA8IGdnbWxfbmJ5dGVzKGRzdCkAZ2dtbF9pc19zY2FsYXIoZHN0KQBnZ21sX2lzX2NvbnRpZ3VvdXNfZXhjZXB0X2RpbV8xKGRzdCkAZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMxLCBkc3QpAGdnbWxfY2FuX3JlcGVhdChzcmMwLCBkc3QpAGdnbWxfYXJlX3NhbWVfc2hhcGUoc3JjMCwgc3JjMSkgJiYgZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBkc3QpAGdnbWxfY2FuX3JlcGVhdChzcmMxLCBzcmMwKSAmJiBnZ21sX2FyZV9zYW1lX3NoYXBlKHNyYzAsIGRzdCkAJXMgKGNvbnQpAGRzdC0+bmJbMF0gPT0gc2l6ZW9mKGZsb2F0KQBzcmMwLT5uYlswXSA9PSBzaXplb2YoZmxvYXQpAG5idjAgPT0gc2l6ZW9mKGZsb2F0KQBuYnEwID09IHNpemVvZihmbG9hdCkAbmJrMCA9PSBzaXplb2YoZmxvYXQpAG5iMCA9PSBzaXplb2YoZmxvYXQpAG5iYzEwID09IHNpemVvZihmbG9hdCkAbmIxMCA9PSBzaXplb2YoZmxvYXQpAG5iYjEwID09IHNpemVvZihmbG9hdCkAbmIwMCA9PSBzaXplb2YoZmxvYXQpAHNyYzAtPm5iWzBdID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmJ2MCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5icTAgPT0gc2l6ZW9mKGdnbWxfZnAxNl90KQBuYmswID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmIwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmJhMCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5iYzAwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAbmIwMCA9PSBzaXplb2YoZ2dtbF9mcDE2X3QpAG5iYjAwID09IHNpemVvZihnZ21sX2ZwMTZfdCkAJXMgKGNvcHkgb2YgJXMpACFnZ21sX2lzX3ZpZXcodGVuc29yKQAobnVsbCkAZ2dtbF9pc19jb250aWd1b3VzKG1hc2spAG5iMTAgPT0gZ2dtbF90eXBlX3NpemUoc3JjMS0+dHlwZSkAZ2dtbF9pc19xdWFudGl6ZWQoc3JjMC0+dHlwZSkAbmIwMCA9PSBnZ21sX3R5cGVfc2l6ZSh0eXBlKQAlcyAocGVybXV0ZWQpACVzICh0cmFuc3Bvc2VkKQAlcyAocmVzaGFwZWQpAGdnbWxfaXNfY29udGlndW91c19leGNlcHRfZGltXzEoZ3JhZCkAZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBncmFkKQB2aWV3X3NyYyA9PSBOVUxMIHx8IGRhdGFfc2l6ZSArIHZpZXdfb2ZmcyA8PSBnZ21sX25ieXRlcyh2aWV3X3NyYykAcGFyYW1zLT53c2l6ZSA+PSBzaXplb2YoZmxvYXQpICogKG50aCArIG50aCAqIG5jKQBnZ21sX25lbGVtZW50cyhhKSA9PSBnZ21sX25lbGVtZW50cyhiKQBnZ21sX2lzX3NjYWxhcihiKQBnZ21sX2Nhbl9tdWxfbWF0KGEsIGIpAGdnbWxfYXJlX3NhbWVfc2hhcGUoYSwgYikAZ2dtbF9pc19jb250aWd1b3VzKGEpACFnZ21sX2lzX3RyYW5zcG9zZWQoYSkAZ2dtbF9pc19wYWRkZWRfMWQoYSkAZ2dtbF9jYW5fcmVwZWF0X3Jvd3MobWFzaywgYSkAZ2dtbF9jYW5fcmVwZWF0KGIsIGEpAGdnbWxfaXNfY29udGlndW91cyhzcmMxKQBnZ21sX2lzX3NjYWxhcihzcmMxKQBnZ21sX2FyZV9zYW1lX3NoYXBlKHNyYzAsIGRzdCkgJiYgZ2dtbF9hcmVfc2FtZV9zaGFwZShzcmMwLCBzcmMxKQBnZ21sX2lzX2NvbnRpZ3VvdXMob3B0MCkAZ2dtbF9pc19jb250aWd1b3VzKGRzdCkgJiYgZ2dtbF9pc19jb250aWd1b3VzKHNyYzApAGdnbWxfbmVsZW1lbnRzKGRzdCkgPT0gZ2dtbF9uZWxlbWVudHMoc3JjMCkAb2Zmc2V0ICsgKG5lMTAgPT0gMCA/IDAgOiBuZTEwLTEpKm5iMDAgKyAobmUxMSA9PSAwID8gMCA6IG5lMTEtMSkqbmIwMSArIChuZTEyID09IDAgPyAwIDogbmUxMi0xKSpuYjAyICsgKG5lMTMgPT0gMCA/IDAgOiBuZTEzLTEpKm5iMDMgPCBnZ21sX25ieXRlcyhzcmMwKQBnZ21sX2lzX2NvbnRpZ3VvdXNfZXhjZXB0X2RpbV8xKHNyYzApAGdnbWxfY2FuX3JlcGVhdChkc3QsIHNyYzApACkpKQBvcGVyYXRvcigpACgoKABzcmMxLT50eXBlID09IEdHTUxfVFlQRV9GMzIgJiYgIm9ubHkgZjMyIHNyYzEgc3VwcG9ydGVkIGZvciBub3ciAHRlbnNvci0+YnVmZmVyICE9IE5VTEwgJiYgInRlbnNvciBidWZmZXIgbm90IHNldCIAYWxsb2MtPm5fZnJlZV9ibG9ja3MgPCBNQVhfRlJFRV9CTE9DS1MgJiYgIm91dCBvZiBmcmVlIGJsb2NrcyIAb2Zmc2V0ICsgc2l6ZSA8PSBnZ21sX25ieXRlcyh0ZW5zb3IpICYmICJ0ZW5zb3Igd3JpdGUgb3V0IG9mIGJvdW5kcyIAb2Zmc2V0ICsgc2l6ZSA8PSBnZ21sX25ieXRlcyh0ZW5zb3IpICYmICJ0ZW5zb3IgcmVhZCBvdXQgb2YgYm91bmRzIgBkYXRhICE9IE5VTEwgJiYgImZhaWxlZCB0byBhbGxvY2F0ZSBidWZmZXIiACEibm90IGVub3VnaCBzcGFjZSBpbiB0aGUgYnVmZmVyIgB0ZW5zb3ItPmRhdGEgIT0gTlVMTCAmJiAidGVuc29yIG5vdCBhbGxvY2F0ZWQiAGJhc2UgIT0gTlVMTCAmJiAiYmFja2VuZCBidWZmZXIgYmFzZSBjYW5ub3QgYmUgTlVMTCIAUHVyZSB2aXJ0dWFsIGZ1bmN0aW9uIGNhbGxlZCEAV0FSTklORzogQmVoYXZpb3IgbWF5IGJlIHVuZXhwZWN0ZWQgd2hlbiBhbGxvY2F0aW5nIDAgYnl0ZXMgZm9yIGdnbWxfYWxpZ25lZF9tYWxsb2MhACB8IABBVlggPSAAVlNYID0gAEJMQVMgPSAAT1BFTlZJTk8gPSAATkVPTiA9IABDT1JFTUwgPSAATUVUQUwgPSAAV0FTTV9TSU1EID0gAEYxNkMgPSAARlAxNl9WQSA9IABBUk1fRk1BID0gAENVREEgPSAAU1NTRTMgPSAAQVZYMiA9IABBVlg1MTIgPSAAJXM6IG9wIG5vdCBpbXBsZW1lbnRlZDogACVzOiB0ZW5zb3IgJyVzJyBoYXMgd3Jvbmcgc2l6ZSBpbiBtb2RlbCBmaWxlOiBnb3QgJXp1LCBleHBlY3RlZCAlenUKACVzOiB1c2luZyBkaXN0aWxsZWQgbW9kZWwgLSBmb3JjaW5nIG5vX3RpbWVzdGFtcHMKACVzOiBhZGRpbmcgJWQgZXh0cmEgdG9rZW5zCgAlczogICAgICBtZWwgdGltZSA9ICU4LjJmIG1zCgAlczogICAgdG90YWwgdGltZSA9ICU4LjJmIG1zCgAlczogICAgIGxvYWQgdGltZSA9ICU4LjJmIG1zCgBzeXN0ZW1faW5mbzogbl90aHJlYWRzID0gJWQgLyAlZCB8ICVzCgBXSElTUEVSX0FTU0VSVDogJXM6JWQ6ICVzCgBHR01MX0FTU0VSVDogJXM6JWQ6ICVzCgBbJXMgLS0+ICVzXSAgJXMKACVzOiBvZmZzZXQgJWRtcyBpcyBiZWZvcmUgdGhlIHN0YXJ0IG9mIHRoZSBhdWRpbwoAdW5rbm93biB0b2tlbgoAJXM6IGZhaWxlZCB0byBjb21wdXRlIGxvZyBtZWwgc3BlY3Ryb2dyYW0KACVzOiBsb2FkaW5nIG1vZGVsCgAlczogZmFpbGVkIHRvIGxvYWQgbW9kZWwKACVzOiBmYWlsZWQgdG8gZXZhbAoAJXM6ICAgICBmYWxsYmFja3MgPSAlM2QgcCAvICUzZCBoCgAlczogV0FSTiBubyB0ZW5zb3JzIGxvYWRlZCBmcm9tIG1vZGVsIGZpbGUgLSBhc3N1bWluZyBlbXB0eSBtb2RlbCBmb3IgdGVzdGluZwoAJXM6IGVuY29kZXJfYmVnaW5fY2FsbGJhY2sgcmV0dXJuZWQgZmFsc2UgLSBhYm9ydGluZwoAJXM6IHRlbnNvciAnJXMnIGhhcyB3cm9uZyBzaXplIGluIG1vZGVsIGZpbGUKACVzOiB1bmtub3duIHRlbnNvciAnJXMnIGluIG1vZGVsIGZpbGUKACVzOiBubyBzaWduYWwgZGF0YSBhdmFpbGFibGUKACVzOiBmYWlsZWQgdG8gYWxsb2NhdGUgbWVtb3J5IGZvciBrdiBjYWNoZQoAJXM6IGt2X2NhY2hlX2luaXQoKSBmYWlsZWQgZm9yIGNyb3NzLWF0dGVudGlvbiBjYWNoZQoAJXM6IGt2X2NhY2hlX2luaXQoKSBmYWlsZWQgZm9yIHNlbGYtYXR0ZW50aW9uIGNhY2hlCgAlczogZmFpbGVkIHRvIGF1dG8tZGV0ZWN0IGxhbmd1YWdlCgAlczogZmFpbGVkIHRvIGVuY29kZQoAJXM6IGZhaWxlZCB0byBkZWNvZGUKACVzOiBnZ21sX2luaXQoKSBmYWlsZWQKACVzOiBuX3Rva2Vucz0lZCA+IG5fY3R4PSVkCgAlczogRVJST1Igbm90IGFsbCB0ZW5zb3JzIGxvYWRlZCBmcm9tIG1vZGVsIGZpbGUgLSBleHBlY3RlZCAlenUsIGdvdCAlZAoAJXM6IHVua25vd24gbGFuZ3VhZ2UgaWQgJWQKACVzOiB0b28gbWFueSBkZWNvZGVycyByZXF1ZXN0ZWQgKCVkKSwgbWF4ID0gJWQKACVzOiBuX2F1ZGlvX2xheWVyID0gJWQKACVzOiBuX2F1ZGlvX3N0YXRlID0gJWQKACVzOiBuX3RleHRfbGF5ZXIgID0gJWQKACVzOiBuX3RleHRfc3RhdGUgID0gJWQKACVzOiBuX2F1ZGlvX2hlYWQgID0gJWQKACVzOiBuX2F1ZGlvX2N0eCAgID0gJWQKACVzOiBuX3RleHRfaGVhZCAgID0gJWQKACVzOiBuX3RleHRfY3R4ICAg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EBAQEBAAEBAQEBAAEAAQEBAQEBAAABAQEBAQAAAAEBAQEBAQEBAAEBAQEAAQEAAQEBAQEAAQABAQEBAAABAAEBAQEBAQAAAQEBAQABAAABAQEBAQAAAAEBAQEAAAAAAQEBAQEBAQEAAQEBAAEBAQABAQEBAAEBAAEBAQAAAQEAAQEBAQEAAQABAQEAAQABAAEBAQEAAAEAAQEBAAAAAQABAQEBAQEAAAEBAQABAQAAAQEBAQABAAABAQEAAAEAAAEBAQEBAAAAAQEBAAEAAAABAQEBAAAAAAEBAQAAAAAAAQEBAQEBAQEAAQEAAQEBAQABAQEAAQEBAAEBAAABAQEAAQEBAQABAQABAQABAAEBAAEBAQAAAQEAAQEAAAABAQABAQEBAQABAAEBAAEBAAEAAQEBAAEAAQABAQAAAQABAAEBAQEAAAEAAQEAAQAAAQABAQEAAAABAAEBAAAAAAEAAQEBAQEBAAABAQABAQEAAAEBAQABAQAAAQEAAAEBAAABAQEBAAEAAAEBAAEAAQAAAQEBAAABAAABAQAAAAEAAAEBAQEBAAAAAQEAAQEAAAABAQEAAQAAAAEBAAABAAAAAQEBAQAAAAABAQABAAAAAAEBAQAAAAAAAQEAAAAAAAABAQEBAQEBAQABAAEBAQEBAAEBAAEBAQEAAQAAAQEBAQABAQEAAQEBAAEAAQABAQEAAQEAAAEBAQABAAAAAQEBAAEBAQEAAQEAAQABAQABAQABAQABAAEBAAEAAAEAAQEAAQEBAAABAQABAAEAAAEBAAEBAAAAAQEAAQAAAAABAQABAQEBAQABAAEAAQEBAAEAAQEAAQEAAQABAAABAQABAAEBAQABAAEAAQABAAEAAQABAQAAAQABAAEAAAABAAEAAQEBAQAAAQABAAEBAAABAAEBAAEAAAEAAQAAAQAAAQABAQEAAAABAAEAAQAAAAEAAQEAAAAAAQABAAAAAAABAAEBAQEBAQAAAQABAQEBAAABAQABAQEAAAEAAAEBAQAAAQEBAAEBAAABAAEAAQEAAAEBAAABAQAAAQAAAAEBAAABAQEBAAEAAAEAAQEAAQAAAQEAAQABAAABAAABAAEAAAEBAQAAAQAAAQABAAABAAABAQAAAAEAAAEAAAAAAQAAAQEBAQEAAAABAAEBAQAAAAEBAAEBAAAAAQAAAQEAAAABAQEAAQAAAAEAAQABAAAAAQEAAAEAAAABAAAAAQAAAAEBAQEAAAAAAQABAQAAAAABAQABAAAAAAEAAAEAAAAAAQEBAAAAAAABAAEAAAAAAAEBAAAAAAAAAQAAAAAAAAABAQEBAQEBAQAAAQEBAQEBAAEAAQEBAQEAAAABAQEBAQABAQABAQEBAAABAAEBAQEAAQAAAQEBAQAAAAABAQEBAAEBAQABAQEAAAEBAAEBAQABAAEAAQEBAAAAAQABAQEAAQEAAAEBAQAAAQAAAQEBAAEAAAABAQEAAAAAAAEBAQABAQEBAAEBAAABAQEAAQEAAQABAQABAQAAAAEBAAEBAAEBAAEAAQEAAAEAAQABAQABAAABAAEBAAAAAAEAAQEAAQEBAAABAQAAAQEAAAEBAAEAAQAAAQEAAAABAAABAQABAQAAAAEBAAABAAAAAQEAAQAAAAABAQAAAAAAAAEBAAEBAQEBAAEAAAEBAQEAAQABAAEBAQABAAAAAQEBAAEAAQEAAQEAAQAAAQABAQABAAEAAAEBAAEAAAAAAQEAAQABAQEAAQABAAABAQABAAEAAQABAAEAAQAAAAEAAQABAAEBAAABAAEAAAEAAAEAAQABAAAAAQABAAAAAAABAAEAAQEBAQAAAQAAAQEBAAABAAEAAQEAAAEAAAABAQAAAQABAQABAAABAAABAAEAAAEAAQAAAQAAAQAAAAABAAABAAEBAQAAAAEAAAEBAAAAAQABAAEAAAABAAAAAQAAAAEAAQEAAAAAAQAAAQAAAAABAAEAAAAAAAEAAAAAAAAAAQABAQEBAQEAAAABAQEBAQAAAQABAQEBAAAAAAEBAQEAAAEBAAEBAQAAAAEAAQEBAAABAAABAQEAAAAAAAEBAQAAAQEBAAEBAAAAAQEAAQEAAAEAAQABAQAAAAABAAEBAAABAQAAAQEAAAABAAABAQAAAQAAAAEBAAAAAAAAAQEAAAEBAQEAAQAAAAEBAQABAAABAAEBAAEAAAAAAQEAAQAAAQEAAQABAAAAAQABAAEAAAEAAAEAAQAAAAAAAQABAAABAQEAAAEAAAABAQAAAQAAAQABAAABAAAAAAEAAAEAAAEBAAAAAQAAAAEAAAABAAABAAAAAAEAAAAAAAAAAQAAAQEBAQEAAAAAAQEBAQAAAAEAAQEBAAAAAAABAQEAAAABAQABAQAAAAABAAEBAAAAAQAAAQEAAAAAAAABAQAAAAEBAQABAAAAAAEBAAEAAAABAAEAAQAAAAAAAQABAAAAAQEAAAEAAAAAAQAAAQAAAAEAAAABAAAAAAAAAAEAAAABAQEBAAAAAAABAQEAAAAAAQABAQAAAAAAAAEBAAAAAAEBAAEAAAAAAAEAAQAAAAABAAABAAAAAAAAAAEAAAAAAQEBAAAAAAAAAQEAAAAAAAEAAQAAAAAAAAABAAAAAAABAQAAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAQAAAAAAAAEBAAAAAAAAAAABAAAAAAABAAEAAAAAAAABAQAAAAAAAQEBAAAAAAAAAAABAAAAAAEAAAEAAAAAAAEAAQAAAAABAQABAAAAAAAAAQEAAAAAAQABAQAAAAAAAQEBAAAAAAEBAQEAAAAAAAAAAAEAAAABAAAAAQAAAAABAAABAAAAAQEAAAEAAAAAAAEAAQAAAAEAAQABAAAAAAEBAAEAAAABAQEAAQAAAAAAAAEBAAAAAQAAAQEAAAAAAQABAQAAAAEBAAEBAAAAAAABAQEAAAABAAEBAQAAAAABAQEBAAAAAQEBAQEAAAAAAAAAAAEAAAEAAAAAAQAAAAEAAAABAAABAQAAAAEAAAAAAQAAAQAAAQABAAABAAAAAQEAAAEAAAEBAQAAAQAAAAAAAQABAAABAAABAAEAAAABAAEAAQAAAQEAAQABAAAAAAEBAAEAAAEAAQEAAQAAAAEBAQABAAABAQEBAAEAAAAAAAABAQAAAQAAAAEBAAAAAQAAAQEAAAEBAAABAQAAAAABAAEBAAABAAEAAQEAAAABAQABAQAAAQEBAAEBAAAAAAABAQEAAAEAAAEBAQAAAAEAAQEBAAABAQABAQEAAAAAAQEBAQAAAQABAQEBAAAAAQEBAQEAAAEBAQEBAQAAAAAAAAAAAQABAAAAAAABAAABAAAAAAEAAQEAAAAAAQAAAAEAAAABAAEAAQAAAAEAAAEBAAAAAQABAQEAAAABAAAAAAEAAAEAAQAAAQAAAQAAAQABAAABAAEBAAEAAAEAAAABAQAAAQABAAEBAAABAAABAQEAAAEAAQEBAQAAAQAAAAAAAQABAAEAAAABAAEAAAEAAAEAAQABAQAAAQABAAAAAQABAAEAAQABAAEAAQAAAQEAAQABAAEBAQABAAEAAAAAAQEAAQABAAABAQABAAABAAEBAAEAAQEAAQEAAQAAAAEBAQABAAEAAQEBAAEAAAEBAQEAAQABAQEBAQABAAAAAAAAAQEAAQAAAAABAQAAAQAAAAEBAAEBAAAAAQEAAAABAAABAQABAAEAAAEBAAABAQAAAQEAAQEBAAABAQAAAAABAAEBAAEAAAEAAQEAAAEAAQABAQABAQABAAEBAAAAAQEAAQEAAQABAQABAQAAAQEBAAEBAAEBAQEAAQEAAAAAAAEBAQABAAAAAQEBAAABAAABAQEAAQEAAAEBAQAAAAEAAQEBAAEAAQABAQEAAAEBAAEBAQABAQEAAQEBAAAAAAEBAQEAAQAAAQEBAQAAAQABAQEBAAEBAAEBAQEAAAABAQEBAQABAAEBAQEBAAABAQEBAQEAAQEBAQEBAQAAAAAAAAAAAQEAAAAAAAABAAEAAAAAAAEBAQAAAAAAAQAAAQAAAAABAQABAAAAAAEAAQEAAAAAAQEBAQAAAAABAAAAAQAAAAEBAAABAAAAAQABAAEAAAABAQEAAQAAAAEAAAEBAAAAAQEAAQEAAAABAAEBAQAAAAEBAQEBAAAAAQAAAAABAAABAQAAAAEAAAEAAQAAAQAAAQEBAAABAAABAAABAAEAAAEBAAEAAQAAAQABAQABAAABAQEBAAEAAAEAAAABAQAAAQEAAAEBAAABAAEAAQEAAAEBAQABAQAAAQAAAQEBAAABAQABAQEAAAEAAQEBAQAAAQEBAQEBAAABAAAAAAABAAEBAAAAAAEAAQABAAAAAQABAQEAAAABAAEAAAEAAAEAAQEAAQAAAQABAAEBAAABAAEBAQEAAAEAAQAAAAEAAQABAQAAAQABAAEAAQABAAEAAQEBAAEAAQABAAABAQABAAEBAAEBAAEAAQABAQEAAQABAQEBAQABAAEAAAAAAQEAAQEAAAABAQABAAEAAAEBAAEBAQAAAQEAAQAAAQABAQABAQABAAEBAAEAAQEAAQEAAQEBAQABAQABAAAAAQEBAAEBAAABAQEAAQABAAEBAQABAQEAAQEBAAEAAAEBAQEAAQEAAQEBAQABAAEBAQEBAAEBAQEBAQEAAQAAAAAAAAEBAQAAAAAAAQEAAQAAAAABAQEBAAAAAAEBAAABAAAAAQEBAAEAAA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AAAAXwAAAGAAAABhAAAATlN0M19fMjIwX19zaGFyZWRfcHRyX3BvaW50ZXJJUE5TXzEzX19lbXB0eV9zdGF0ZUljRUVOU18xMHNoYXJlZF9wdHJJUzJfRTI3X19zaGFyZWRfcHRyX2RlZmF1bHRfZGVsZXRlSVMyX1MyX0VFTlNfOWFsbG9jYXRvcklTMl9FRUVFAAAAAAjaAABYUwAAiNAAAE5TdDNfXzIxMHNoYXJlZF9wdHJJTlNfMTNfX2VtcHR5X3N0YXRlSWNFRUUyN19fc2hhcmVkX3B0cl9kZWZhdWx0X2RlbGV0ZUlTMl9TMl9FRQAAAAAAAADIVAAAYgAAAGMAAABkAAAAXAAAAE5TdDNfXzIxM19fZW1wdHlfc3RhdGVJY0VFAE5TdDNfXzIxNl9fb3duc19vbmVfc3RhdGVJY0VFAE5TdDNfXzIxNV9faGFzX29uZV9zdGF0ZUljRUUAAAAI2gAAkVQAAChTAAAI2gAAc1QAALBUAAAI2gAAWFQAALxUAAAAAAAAvFQAAGIAAABlAAAAZgAAAFwAAAAAAAAAKFUAAGIAAABnAAAAaAAAAFwAAABOU3QzX18yMjBfX2xfYW5jaG9yX211bHRpbGluZUljRUUAAAAI2gAABFUAALxUAAAAAAAAcFUAAGIAAABpAAAAagAAAFwAAABOU3QzX18yMjBfX3JfYW5jaG9yX211bHRpbGluZUljRUUAAAAI2gAATFUAALxUAAAAAAAAyFUAAGsAAABsAAAAbQAAAFwAAABOU3QzX18yMTVfX3dvcmRfYm91bmRhcnlJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAACNoAAJRVAAC8VAAAAAAAABxWAABuAAAAbwAAAHAAAABcAAAATlN0M19fMjExX19sb29rYWhlYWRJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAACNoAAOxVAAC8VAAAAAAAAGhWAABiAAAAcQAAAHIAAABcAAAATlN0M19fMjIzX19tYXRjaF9hbnlfYnV0X25ld2xpbmVJY0VFAAAAAAjaAABAVgAAvFQAAAAAAADEVgAAcwAAAHQAAAB1AAAAXAAAAE5TdDNfXzIxOF9fbWF0Y2hfY2hhcl9pY2FzZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAAACNoAAIxWAAC8VAAAAAAAACBXAAB2AAAAdwAAAHgAAABcAAAATlN0M19fMjIwX19tYXRjaF9jaGFyX2NvbGxhdGVJY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAI2gAA6FYAALxUAAAAAAAAYFcAAGIAAAB5AAAAegAAAFwAAABOU3QzX18yMTJfX21hdGNoX2NoYXJJY0VFAAAACNoAAERXAAC8VAAAAAAAALhXAAB7AAAAfAAAAH0AAABcAAAATlN0M19fMjE2X19iYWNrX3JlZl9pY2FzZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAjaAACEVwAAvFQAAAAAAAAUWAAAfgAAAH8AAACAAAAAXAAAAE5TdDNfXzIxOF9fYmFja19yZWZfY29sbGF0ZUljTlNfMTJyZWdleF90cmFpdHNJY0VFRUUAAAAACNoAANxXAAC8VAAAAAAAAFBYAABiAAAAgQAAAIIAAABcAAAATlN0M19fMjEwX19iYWNrX3JlZkljRUUACNoAADhYAAC8VAAAAAAAAKxYAACDAAAAhAAAAIUAAABcAAAATlN0M19fMjIwX19icmFja2V0X2V4cHJlc3Npb25JY05TXzEycmVnZXhfdHJhaXRzSWNFRUVFAAAI2gAAdFgAALxUAAAAAAAA/FgAAGIAAACGAAAAhwAAAFwAAABOU3QzX18yMjhfX2JlZ2luX21hcmtlZF9zdWJleHByZXNzaW9uSWNFRQAAAAjaAADQWAAAvFQAAAAAAABIWQAAYgAAAIgAAACJAAAAXAAAAE5TdDNfXzIyNl9fZW5kX21hcmtlZF9zdWJleHByZXNzaW9uSWNFRQAI2gAAIFkAALxUAAAAAAAArFkAAIoAAACLAAAAjAAAAI0AAABOU3QzX18yNl9fbG9vcEljRUUATlN0M19fMjE3X19vd25zX3R3b19zdGF0ZXNJY0VFAAAACNoAAH9ZAAC8VAAACNoAAGxZAACgWQAAAAAAAKBZAACKAAAAjgAAAGYAAABcAAAAAAAAAAhaAABZAAAAjwAAAJAAAABcAAAATlN0M19fMjE3X19yZXBlYXRfb25lX2xvb3BJY0VFAAAI2gAA6FkAALBUAAAAAAAASFoAAIoAAACRAAAAkgAAAJMAAABOU3QzX18yMTFfX2FsdGVybmF0ZUljRUUAAAAACNoAACxaAACgWQAAAAAAAJBaAABZAAAAlAAAAJUAAABcAAAATlN0M19fMjIxX19lbXB0eV9ub25fb3duX3N0YXRlSWNFRQAACNoAAGxaAACwVAAAAAAAANBaAABiAAAAlgAAAJcAAABcAAAATlN0M19fMjExX19tYXRjaF9hbnlJY0VFAAAAAAjaAAC0WgAAvFQAAAAAAACcWwAAmAAAAJkAAACaAAAAmwAAAJwAAACdAAAAngAAAJ8AAACgAAAATlN0M19fMjEwX19mdW5jdGlvbjZfX2Z1bmNJWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzBOU185YWxsb2NhdG9ySVMyX0VFRlAxMWdnbWxfY2dyYXBodkVFRQBOU3QzX18yMTBfX2Z1bmN0aW9uNl9fYmFzZUlGUDExZ2dtbF9jZ3JhcGh2RUVFAADg2QAAZFsAAAjaAAAIWwAAlFsAAFoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8wAADg2QAAqFsAAAAAAABUXAAAmAAAAKEAAACiAAAAowAAAKQAAAClAAAApgAAAKcAAACoAAAATlN0M19fMjEwX19mdW5jdGlvbjZfX2Z1bmNJWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzFOU185YWxsb2NhdG9ySVMyX0VFRlAxMWdnbWxfY2dyYXBodkVFRQAI2gAA+FsAAJRbAABaMTh3aGlzcGVyX2luaXRfc3RhdGVFMyRfMQAA4NkAAGBcAAAAAAAADF0AAJgAAACpAAAAqgAAAKsAAACsAAAArQAAAK4AAACvAAAAsAAAAE5TdDNfXzIxMF9fZnVuY3Rpb242X19mdW5jSVoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8yTlNfOWFsbG9jYXRvcklTMl9FRUZQMTFnZ21sX2NncmFwaHZFRUUACNoAALBcAACUWwAAWjE4d2hpc3Blcl9pbml0X3N0YXRlRTMkXzIAAODZAAAYXQAAAAAAAMRdAACYAAAAsQAAALIAAACzAAAAtAAAALUAAAC2AAAAtwAAALgAAABOU3QzX18yMTBfX2Z1bmN0aW9uNl9fZnVuY0laMTh3aGlzcGVyX2luaXRfc3RhdGVFMyRfM05TXzlhbGxvY2F0b3JJUzJfRUVGUDExZ2dtbF9jZ3JhcGh2RUVFAAjaAABoXQAAlFsAAFoxOHdoaXNwZXJfaW5pdF9zdGF0ZUUzJF8zAADg2QAA0F0AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0loTlNfMTFjaGFyX3RyYWl0c0loRUVOU185YWxsb2NhdG9ySWhFRUVFAADg2QAA9F0AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0l3TlNfMTFjaGFyX3RyYWl0c0l3RUVOU185YWxsb2NhdG9ySXdFRUVFAADg2QAAPF4AAE5TdDNfXzIxMmJhc2ljX3N0cmluZ0lEc05TXzExY2hhcl90cmFpdHNJRHNFRU5TXzlhbGxvY2F0b3JJRHNFRUVFAAAA4NkAAIReAABOU3QzX18yMTJiYXNpY19zdHJpbmdJRGlOU18xMWNoYXJfdHJhaXRzSURpRUVOU185YWxsb2NhdG9ySURpRUVFRQAAAODZAADQXgAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJY0VFAADg2QAAHF8AAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWFFRQAA4NkAAERfAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0loRUUAAODZAABsXwAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJc0VFAADg2QAAlF8AAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXRFRQAA4NkAALxfAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lpRUUAAODZAADkXwAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJakVFAADg2QAADGAAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SWxFRQAA4NkAADRgAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0ltRUUAAODZAABcYAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJeEVFAADg2QAAhGAAAE4xMGVtc2NyaXB0ZW4xMW1lbW9yeV92aWV3SXlFRQAA4NkAAKxgAABOMTBlbXNjcmlwdGVuMTFtZW1vcnlfdmlld0lmRUUAAODZAADUYAAATjEwZW1zY3JpcHRlbjExbWVtb3J5X3ZpZXdJZEVFAADg2QAA/GAAAAAAAAAAAAAAAAAAAAMAAAAEAAAABAAAAAYAAACD+aIARE5uAPwpFQDRVycA3TT1AGLbwAA8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SWNFRUVFAAAAAODZAADEpAAATlN0M19fMjEzYmFzaWNfaXN0cmVhbUljTlNfMTFjaGFyX3RyYWl0c0ljRUVFRQAAZNoAAAClAAAAAAAAAQAAALikAAAD9P//bAAAAAAAAADYpQAA7wAAAPAAAACU////lP///9ilAADxAAAA8gAAAFSlAACMpQAAoKUAAGilAABsAAAAAAAAADClAADhAAAA4gAAAJT///+U////MKUAAOMAAADkAAAATlN0M19fMjE0YmFzaWNfaWZzdHJlYW1JY05TXzExY2hhcl90cmFpdHNJY0VFRUUACNoAAKilAAAwpQAATlN0M19fMjEzYmFzaWNfZmlsZWJ1ZkljTlNfMTFjaGFyX3RyYWl0c0ljRUVFRQAACNoAAOSlAAD4pAAAAAAAAESmAADzAAAA9AAAAE5TdDNfXzI4aW9zX2Jhc2VFAAAA4NkAADCmAAAAAAAA0XSeAFedvSqAcFIP//8+JwoAAABkAAAA6AMAABAnAACghgEAQEIPAICWmAAA4fUFGAAAADUAAABxAAAAa////877//+Sv///AAAAAAAAAAD/////////////////////////////////////////////////////////////////AAECAwQFBgcICf////////8KCwwNDg8QERITFBUWFxgZGhscHR4fICEiI////////woLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wABAgQHAwYFAAAAAAAAAAIAAMADAADABAAAwAUAAMAGAADABwAAwAgAAMAJAADACgAAwAsAAMAMAADADQAAwA4AAMAPAADAEAAAwBEAAMASAADAEwAAwBQAAMAVAADAFgAAwBcAAMAYAADAGQAAwBoAAMAbAADAHAAAwB0AAMAeAADAHwAAwAAAALMBAADDAgAAwwMAAMMEAADDBQAAwwYAAMMHAADDCAAAwwkAAMMKAADDCwAAwwwAAMMNAADTDgAAww8AAMMAAAy7AQAMwwIA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ODY4Nzg4ODk5MDkxOTI5Mzk0OTU5Njk3OTg5OQAAAAAAAAAAAv8ABGQAIAAABP//BgABAAEAAQD//wH/Af//////Af8B/wH/Af8B/wH/Af8B//////8K/yAA//8D/wH/BP8eAAABBf//////YwAACGMA6AMCAAAA//////8AAAAB/wH//////////////wAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAB/wH//////wABIAAEAIAAAAj//wH/Af////////8B/wb/B/8I/wn//////7wCvAIBAP//AQABAP//AAD//////////wAAAAAAAAAAAAAAAAAAAAAUAXj//wEACv///////////wH/Af8AAAAAAAAB/wH/Af8AAAAAAAAAAAAAAAAAAAAAAAAB/wAAAAAAAAH/Af8BAAAAAQAAAAH//////wAAAAAB////AAAAAP////////////8oAAr//////wEACv////8A//////////8BvggB/wH///8BAP//////////////////Cv//////DP8N/04xMF9fY3h4YWJpdjExNl9fc2hpbV90eXBlX2luZm9FAAAI2gAAFtgAACzcAABOMTBfX2N4eGFiaXYxMTdfX2NsYXNzX3R5cGVfaW5mb0UAAAAI2gAARNgAADjYAABOMTBfX2N4eGFiaXYxMTdfX3BiYXNlX3R5cGVfaW5mb0UAAAAI2gAAdNgAADjYAABOMTBfX2N4eGFiaXYxMTlfX3BvaW50ZXJfdHlwZV9pbmZvRQAI2gAApNgAAJjYAAAAAAAAGNkAAP8BAAAAAgAAAQIAAAICAAADAgAATjEwX19jeHhhYml2MTIzX19mdW5kYW1lbnRhbF90eXBlX2luZm9FAAjaAADw2AAAONgAAHYAAADc2AAAJNkAAGIAAADc2AAAMNkAAGMAAADc2AAAPNkAAGgAAADc2AAASNkAAGEAAADc2AAAVNkAAHMAAADc2AAAYNkAAHQAAADc2AAAbNkAAGkAAADc2AAAeNkAAGoAAADc2AAAhNkAAGwAAADc2AAAkNkAAG0AAADc2AAAnNkAAHgAAADc2AAAqNkAAHkAAADc2AAAtNkAAGYAAADc2AAAwNkAAGQAAADc2AAAzNkAAAAAAABo2AAA/wEAAAQCAAABAgAAAgIAAAUCAAAGAgAABwIAAAgCAAAAAAAAUNoAAP8BAAAJAgAAAQIAAAICAAAFAgAACgIAAAsCAAAMAgAATjEwX19jeHhhYml2MTIwX19zaV9jbGFzc190eXBlX2luZm9FAAAAAAjaAAAo2gAAaNgAAAAAAACs2gAA/wEAAA0CAAABAgAAAgIAAAUCAAAOAgAADwIAABACAABOMTBfX2N4eGFiaXYxMjFfX3ZtaV9jbGFzc190eXBlX2luZm9FAAAACNoAAITaAABo2AAAAAAAABzbAAAIAAAAEQIAABICAAAAAAAARNsAAAgAAAATAgAAFAIAAAAAAAAE2wAACAAAABUCAAAWAgAAU3Q5ZXhjZXB0aW9uAAAAAODZAAD02gAAU3Q5YmFkX2FsbG9jAAAAAAjaAAAM2wAABNsAAFN0MjBiYWRfYXJyYXlfbmV3X2xlbmd0aAAAAAAI2gAAKNsAABzbAAAAAAAAiNsAAAcAAAAXAgAAGAIAAAAAAAAQ3AAAGQIAABoCAAD8AQAAU3QxMWxvZ2ljX2Vycm9yAAjaAAB42wAABNsAAAAAAAC82wAABwAAABsCAAAYAgAAU3QxMmxlbmd0aF9lcnJvcgAAAAAI2gAAqNsAAIjbAAAAAAAA8NsAAAcAAAAcAgAAGAIAAFN0MTJvdXRfb2ZfcmFuZ2UAAAAACNoAANzbAACI2wAAU3QxM3J1bnRpbWVfZXJyb3IAAAAI2gAA/NsAAATbAABTdDl0eXBlX2luZm8AAAAA4NkAABzcAAABFT0AAAA+AAAAAAAAAD8AAAAAAAAAWAFoUNwAAFDcAAAAAAEAAAIAAAAAAAAFAAAAAAAAAAAAAAC9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7AAAAugAAAOA9DQAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAA//////////8BWZjcAAAAAAAABQAAAAAAAAAAAAAAywAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAuwAAAMwAAADoPQ0AAAQAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAP////8KAQww3QAAwEwOAP4BAAA=";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}var binary=tryParseAsDataURI(file);if(binary){return binary}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}function getBinaryPromise(binaryFile){return Promise.resolve().then(()=>getBinarySync(binaryFile))}function instantiateArrayBuffer(binaryFile,imports,receiver){return getBinaryPromise(binaryFile).then(binary=>WebAssembly.instantiate(binary,imports)).then(instance=>instance).then(receiver,reason=>{err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)})}function instantiateAsync(binary,binaryFile,imports,callback){return instantiateArrayBuffer(binaryFile,imports,callback)}function createWasm(){var info={"a":wasmImports};function receiveInstance(instance,module){var exports=instance.exports;wasmExports=exports;registerTLSInit(wasmExports["_"]);wasmTable=wasmExports["X"];addOnInit(wasmExports["W"]);wasmModule=module;removeRunDependency("wasm-instantiate");return exports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"],result["module"])}if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}instantiateAsync(wasmBinary,wasmBinaryFile,info,receiveInstantiationResult).catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function ExitStatus(status){this.name="ExitStatus";this.message=`Program terminated with exit(${status})`;this.status=status}var terminateWorker=worker=>{worker.terminate();worker.onmessage=e=>{}};var killThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];delete PThread.pthreads[pthread_ptr];terminateWorker(worker);__emscripten_thread_free_data(pthread_ptr);PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker),1);worker.pthread_ptr=0};var cancelThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];worker.postMessage({"cmd":"cancel"})};var cleanupThread=pthread_ptr=>{var worker=PThread.pthreads[pthread_ptr];assert(worker);PThread.returnWorkerToPool(worker)};var spawnThread=threadParams=>{var worker=PThread.getNewWorker();if(!worker){return 6}PThread.runningWorkers.push(worker);PThread.pthreads[threadParams.pthread_ptr]=worker;worker.pthread_ptr=threadParams.pthread_ptr;var msg={"cmd":"run","start_routine":threadParams.startRoutine,"arg":threadParams.arg,"pthread_ptr":threadParams.pthread_ptr};if(ENVIRONMENT_IS_NODE){worker.unref()}worker.postMessage(msg,threadParams.transferList);return 0};var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments);return PATH.normalize(paths.join("/"))},join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>(view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))),view)}else if(ENVIRONMENT_IS_NODE){try{var crypto_module=require("crypto");var randomFillSync=crypto_module["randomFillSync"];if(randomFillSync){return view=>crypto_module["randomFillSync"](view)}var randomBytes=crypto_module["randomBytes"];return view=>(view.set(randomBytes(view.byteLength)),view)}catch(e){}}abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.buffer instanceof SharedArrayBuffer?heapOrArray.slice(idx,endPtr):heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(ENVIRONMENT_IS_NODE){var BUFSIZE=256;var buf=Buffer.alloc(BUFSIZE);var bytesRead=0;var fd=process.stdin.fd;try{bytesRead=fs.readSync(fd,buf)}catch(e){if(e.toString().includes("EOF"))bytesRead=0;else throw e}if(bytesRead>0){result=buf.slice(0,bytesRead).toString("utf-8")}else{result=null}}else if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw FS.genericErrors[44]},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length{var dep=!noRunDep?getUniqueRunDependency(`al ${url}`):"";readAsync(url,arrayBuffer=>{assert(arrayBuffer,`Loading data file "${url}" failed (no arrayBuffer).`);onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},event=>{if(onerror){onerror()}else{throw`Loading data file "${url}" failed.`}});if(dep)addRunDependency(dep)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={"r":0,"r+":2,"w":512|64|1,"w+":512|64|2,"a":1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath(path,opts={}){path=PATH_FS.resolve(path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=path.split("/").filter(p=>!!p);var current=FS.root;var current_path="/";for(var i=0;i40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath(node){var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?`${mount}/${path}`:mount+path}path=path?`${node.name}/${path}`:node.name;node=node.parent}},hashName(parentid,name){var hash=0;for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get(){return this.node},set(val){this.node=val}},isRead:{get(){return(this.flags&2097155)!==1}},isWrite:{get(){return(this.flags&2097155)!==0}},isAppend:{get(){return this.flags&1024}},flags:{get(){return this.shared.flags},set(val){this.shared.flags=val}},position:{get(){return this.shared.position},set(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create(path,mode){mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode){mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;i0,ioctl(stream,cmd,arg){if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile(path,opts={}){opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error(`Invalid encoding type "${opts.encoding}"`)}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile(path,data,opts={}){opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams(){if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError(){if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.name="ErrnoError";this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack=""})},staticInit(){FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS}},init(input,output,error){FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit(){FS.init.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,GROWABLE_HEAP_I8(),ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>ptr?UTF8ArrayToString(GROWABLE_HEAP_U8(),ptr,maxBytesToRead):"";var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}GROWABLE_HEAP_I32()[buf>>2]=stat.dev;GROWABLE_HEAP_I32()[buf+4>>2]=stat.mode;GROWABLE_HEAP_U32()[buf+8>>2]=stat.nlink;GROWABLE_HEAP_I32()[buf+12>>2]=stat.uid;GROWABLE_HEAP_I32()[buf+16>>2]=stat.gid;GROWABLE_HEAP_I32()[buf+20>>2]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+24>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+28>>2]=tempI64[1];GROWABLE_HEAP_I32()[buf+32>>2]=4096;GROWABLE_HEAP_I32()[buf+36>>2]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+40>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+44>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+48>>2]=atime%1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+56>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+60>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+64>>2]=mtime%1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+72>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+76>>2]=tempI64[1];GROWABLE_HEAP_U32()[buf+80>>2]=ctime%1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[buf+88>>2]=tempI64[0],GROWABLE_HEAP_I32()[buf+92>>2]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=GROWABLE_HEAP_U8().slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get(){var ret=GROWABLE_HEAP_I32()[SYSCALLS.varargs>>2];SYSCALLS.varargs+=4;return ret},getp(){return SYSCALLS.get()},getStr(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream}};function _proc_exit(code){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(0,1,code);EXITSTATUS=code;if(!keepRuntimeAlive()){PThread.terminateAllThreads();if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}var exitJS=(status,implicit)=>{EXITSTATUS=status;if(ENVIRONMENT_IS_PTHREAD){exitOnMainThread(status);throw"unwind"}_proc_exit(status)};var _exit=exitJS;var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var PThread={unusedWorkers:[],runningWorkers:[],tlsInitFunctions:[],pthreads:{},init(){if(ENVIRONMENT_IS_PTHREAD){PThread.initWorker()}else{PThread.initMainThread()}},initMainThread(){var pthreadPoolSize=8;while(pthreadPoolSize--){PThread.allocateUnusedWorker()}addOnPreRun(()=>{addRunDependency("loading-workers");PThread.loadWasmModuleToAllWorkers(()=>removeRunDependency("loading-workers"))})},initWorker(){noExitRuntime=false},setExitStatus:status=>{EXITSTATUS=status},terminateAllThreads__deps:["$terminateWorker"],terminateAllThreads:()=>{for(var worker of PThread.runningWorkers){terminateWorker(worker)}for(var worker of PThread.unusedWorkers){terminateWorker(worker)}PThread.unusedWorkers=[];PThread.runningWorkers=[];PThread.pthreads=[]},returnWorkerToPool:worker=>{var pthread_ptr=worker.pthread_ptr;delete PThread.pthreads[pthread_ptr];PThread.unusedWorkers.push(worker);PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker),1);worker.pthread_ptr=0;__emscripten_thread_free_data(pthread_ptr)},receiveObjectTransfer(data){},threadInitTLS(){PThread.tlsInitFunctions.forEach(f=>f())},loadWasmModuleToWorker:worker=>new Promise(onFinishedLoading=>{worker.onmessage=e=>{var d=e["data"];var cmd=d["cmd"];if(d["targetThread"]&&d["targetThread"]!=_pthread_self()){var targetWorker=PThread.pthreads[d["targetThread"]];if(targetWorker){targetWorker.postMessage(d,d["transferList"])}else{err(`Internal error! Worker sent a message "${cmd}" to target pthread ${d["targetThread"]}, but that thread no longer exists!`)}return}if(cmd==="checkMailbox"){checkMailbox()}else if(cmd==="spawnThread"){spawnThread(d)}else if(cmd==="cleanupThread"){cleanupThread(d["thread"])}else if(cmd==="killThread"){killThread(d["thread"])}else if(cmd==="cancelThread"){cancelThread(d["thread"])}else if(cmd==="loaded"){worker.loaded=true;if(ENVIRONMENT_IS_NODE&&!worker.pthread_ptr){worker.unref()}onFinishedLoading(worker)}else if(cmd==="alert"){alert(`Thread ${d["threadId"]}: ${d["text"]}`)}else if(d.target==="setimmediate"){worker.postMessage(d)}else if(cmd==="callHandler"){Module[d["handler"]](...d["args"])}else if(cmd){err(`worker sent an unknown command ${cmd}`)}};worker.onerror=e=>{var message="worker sent an error!";err(`${message} ${e.filename}:${e.lineno}: ${e.message}`);throw e};if(ENVIRONMENT_IS_NODE){worker.on("message",data=>worker.onmessage({data:data}));worker.on("error",e=>worker.onerror(e))}var handlers=[];var knownHandlers=["onExit","onAbort","print","printErr"];for(var handler of knownHandlers){if(Module.hasOwnProperty(handler)){handlers.push(handler)}}worker.postMessage({"cmd":"load","handlers":handlers,"urlOrBlob":Module["mainScriptUrlOrBlob"]||_scriptDir,"wasmMemory":wasmMemory,"wasmModule":wasmModule})}),loadWasmModuleToAllWorkers(onMaybeReady){if(ENVIRONMENT_IS_PTHREAD){return onMaybeReady()}let pthreadPoolReady=Promise.all(PThread.unusedWorkers.map(PThread.loadWasmModuleToWorker));pthreadPoolReady.then(onMaybeReady)},allocateUnusedWorker(){var worker;var pthreadMainJs=locateFile("libwhisper.worker.js");worker=new Worker(pthreadMainJs);PThread.unusedWorkers.push(worker)},getNewWorker(){if(PThread.unusedWorkers.length==0){PThread.allocateUnusedWorker();PThread.loadWasmModuleToWorker(PThread.unusedWorkers[0])}return PThread.unusedWorkers.pop()}};Module["PThread"]=PThread;var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var establishStackSpace=()=>{var pthread_ptr=_pthread_self();var stackHigh=GROWABLE_HEAP_I32()[pthread_ptr+52>>2];var stackSize=GROWABLE_HEAP_I32()[pthread_ptr+56>>2];var stackLow=stackHigh-stackSize;_emscripten_stack_set_limits(stackHigh,stackLow);stackRestore(stackHigh)};Module["establishStackSpace"]=establishStackSpace;function exitOnMainThread(returnCode){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(1,0,returnCode);_exit(returnCode)}var wasmTableMirror=[];var getWasmTableEntry=funcPtr=>{var func=wasmTableMirror[funcPtr];if(!func){if(funcPtr>=wasmTableMirror.length)wasmTableMirror.length=funcPtr+1;wasmTableMirror[funcPtr]=func=wasmTable.get(funcPtr)}return func};var invokeEntryPoint=(ptr,arg)=>{var result=getWasmTableEntry(ptr)(arg);function finish(result){if(keepRuntimeAlive()){PThread.setExitStatus(result)}else{__emscripten_thread_exit(result)}}finish(result)};Module["invokeEntryPoint"]=invokeEntryPoint;var registerTLSInit=tlsInitFunc=>{PThread.tlsInitFunctions.push(tlsInitFunc)};function ExceptionInfo(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24;this.set_type=function(type){GROWABLE_HEAP_U32()[this.ptr+4>>2]=type};this.get_type=function(){return GROWABLE_HEAP_U32()[this.ptr+4>>2]};this.set_destructor=function(destructor){GROWABLE_HEAP_U32()[this.ptr+8>>2]=destructor};this.get_destructor=function(){return GROWABLE_HEAP_U32()[this.ptr+8>>2]};this.set_caught=function(caught){caught=caught?1:0;GROWABLE_HEAP_I8()[this.ptr+12>>0]=caught};this.get_caught=function(){return GROWABLE_HEAP_I8()[this.ptr+12>>0]!=0};this.set_rethrown=function(rethrown){rethrown=rethrown?1:0;GROWABLE_HEAP_I8()[this.ptr+13>>0]=rethrown};this.get_rethrown=function(){return GROWABLE_HEAP_I8()[this.ptr+13>>0]!=0};this.init=function(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)};this.set_adjusted_ptr=function(adjustedPtr){GROWABLE_HEAP_U32()[this.ptr+16>>2]=adjustedPtr};this.get_adjusted_ptr=function(){return GROWABLE_HEAP_U32()[this.ptr+16>>2]};this.get_exception_ptr=function(){var isPointer=___cxa_is_pointer_type(this.get_type());if(isPointer){return GROWABLE_HEAP_U32()[this.excPtr>>2]}var adjusted=this.get_adjusted_ptr();if(adjusted!==0)return adjusted;return this.excPtr}}var exceptionLast=0;var uncaughtExceptionCount=0;var ___cxa_throw=(ptr,type,destructor)=>{var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast};var ___emscripten_init_main_thread_js=tb=>{__emscripten_thread_init(tb,!ENVIRONMENT_IS_WORKER,1,!ENVIRONMENT_IS_WEB,65536,false);PThread.threadInitTLS()};var ___emscripten_thread_cleanup=thread=>{if(!ENVIRONMENT_IS_PTHREAD)cleanupThread(thread);else postMessage({"cmd":"cleanupThread","thread":thread})};function pthreadCreateProxied(pthread_ptr,attr,startRoutine,arg){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(2,1,pthread_ptr,attr,startRoutine,arg);return ___pthread_create_js(pthread_ptr,attr,startRoutine,arg)}var ___pthread_create_js=(pthread_ptr,attr,startRoutine,arg)=>{if(typeof SharedArrayBuffer=="undefined"){err("Current environment does not support SharedArrayBuffer, pthreads are not available!");return 6}var transferList=[];var error=0;if(ENVIRONMENT_IS_PTHREAD&&(transferList.length===0||error)){return pthreadCreateProxied(pthread_ptr,attr,startRoutine,arg)}if(error)return error;var threadParams={startRoutine:startRoutine,pthread_ptr:pthread_ptr,arg:arg,transferList:transferList};if(ENVIRONMENT_IS_PTHREAD){threadParams.cmd="spawnThread";postMessage(threadParams,transferList);return 0}return spawnThread(threadParams)};var setErrNo=value=>{GROWABLE_HEAP_I32()[___errno_location()>>2]=value;return value};function ___syscall_fcntl64(fd,cmd,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(3,1,fd,cmd,varargs);SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.getp();var offset=0;GROWABLE_HEAP_I16()[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(4,1,fd,op,varargs);SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=SYSCALLS.getp();GROWABLE_HEAP_I32()[argp>>2]=termios.c_iflag||0;GROWABLE_HEAP_I32()[argp+4>>2]=termios.c_oflag||0;GROWABLE_HEAP_I32()[argp+8>>2]=termios.c_cflag||0;GROWABLE_HEAP_I32()[argp+12>>2]=termios.c_lflag||0;for(var i=0;i<32;i++){GROWABLE_HEAP_I8()[argp+i+17>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=SYSCALLS.getp();var c_iflag=GROWABLE_HEAP_I32()[argp>>2];var c_oflag=GROWABLE_HEAP_I32()[argp+4>>2];var c_cflag=GROWABLE_HEAP_I32()[argp+8>>2];var c_lflag=GROWABLE_HEAP_I32()[argp+12>>2];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(GROWABLE_HEAP_I8()[argp+i+17>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag:c_iflag,c_oflag:c_oflag,c_cflag:c_cflag,c_lflag:c_lflag,c_cc:c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.getp();GROWABLE_HEAP_I32()[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.getp();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=SYSCALLS.getp();GROWABLE_HEAP_I16()[argp>>1]=winsize[0];GROWABLE_HEAP_I16()[argp+2>>1]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(5,1,dirfd,path,flags,varargs);SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __embind_register_bigint=(primitiveType,name,size,minRange,maxRange)=>{};var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes=undefined;var readLatin1String=ptr=>{var ret="";var c=ptr;while(GROWABLE_HEAP_U8()[c]){ret+=embind_charCodes[GROWABLE_HEAP_U8()[c++]]}return ret};var awaitingDependencies={};var registeredTypes={};var typeDependencies={};var BindingError=undefined;var throwBindingError=message=>{throw new BindingError(message)};var InternalError=undefined;var throwInternalError=message=>{throw new InternalError(message)};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(function(type){typeDependencies[type]=dependentTypes});function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){if(!("argPackAdvance"in registeredInstance)){throw new TypeError("registerType registeredInstance requires argPackAdvance")}return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;var __embind_register_bool=(rawType,name,trueValue,falseValue)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":function(wt){return!!wt},"toWireType":function(destructors,o){return o?trueValue:falseValue},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":function(pointer){return this["fromWireType"](GROWABLE_HEAP_U8()[pointer])},destructorFunction:null})};function handleAllocatorInit(){Object.assign(HandleAllocator.prototype,{get(id){return this.allocated[id]},has(id){return this.allocated[id]!==undefined},allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id},free(id){this.allocated[id]=undefined;this.freelist.push(id)}})}function HandleAllocator(){this.allocated=[undefined];this.freelist=[]}var emval_handles=new HandleAllocator;var __emval_decref=handle=>{if(handle>=emval_handles.reserved&&0===--emval_handles.get(handle).refcount){emval_handles.free(handle)}};var count_emval_handles=()=>{var count=0;for(var i=emval_handles.reserved;i{emval_handles.allocated.push({value:undefined},{value:null},{value:true},{value:false});emval_handles.reserved=emval_handles.allocated.length;Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles.get(handle).value},toHandle:value=>{switch(value){case undefined:return 1;case null:return 2;case true:return 3;case false:return 4;default:{return emval_handles.allocate({refcount:1,value:value})}}}};function simpleReadValueFromPointer(pointer){return this["fromWireType"](GROWABLE_HEAP_I32()[pointer>>2])}var __embind_register_emval=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},"toWireType":(destructors,value)=>Emval.toHandle(value),"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:null})};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](GROWABLE_HEAP_F32()[pointer>>2])};case 8:return function(pointer){return this["fromWireType"](GROWABLE_HEAP_F64()[pointer>>3])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=(rawType,name,size)=>{name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":value=>value,"toWireType":(destructors,value)=>value,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":floatReadValueFromPointer(name,size),destructorFunction:null})};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{if(undefined===name){return"_unknown"}name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function createNamedFunction(name,body){name=makeLegalFunctionName(name);return{[name]:function(){return body.apply(this,arguments)}}[name]}function newFunc(constructor,argumentList){if(!(constructor instanceof Function)){throw new TypeError(`new_ called with constructor type ${typeof constructor} which is not a function`)}var dummy=createNamedFunction(constructor.name||"unknownFunctionName",function(){});dummy.prototype=constructor.prototype;var obj=new dummy;var r=constructor.apply(obj,argumentList);return r instanceof Object?r:obj}function craftInvokerFunction(humanName,argTypes,classType,cppInvokerFunc,cppTargetFunc,isAsync){var argCount=argTypes.length;if(argCount<2){throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!")}var isClassMethodFunc=argTypes[1]!==null&&classType!==null;var needsDestructorStack=false;for(var i=1;i0?", ":"")+argsListWired}invokerFnBody+=(returns||isAsync?"var rv = ":"")+"invoker(fn"+(argsListWired.length>0?", ":"")+argsListWired+");\n";if(needsDestructorStack){invokerFnBody+="runDestructors(destructors);\n"}else{for(var i=isClassMethodFunc?1:2;i{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(){if(!proto[methodName].overloadTable.hasOwnProperty(arguments.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${arguments.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[arguments.length].apply(this,arguments)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;if(undefined!==numArguments){Module[name].numArguments=numArguments}}};var heap32VectorToArray=(count,firstElement)=>{var array=[];for(var i=0;i>2])}return array};var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistant public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{var f=Module["dynCall_"+sig];return args&&args.length?f.apply(null,[ptr].concat(args)):f.call(null,ptr)};var dynCall=(sig,ptr,args)=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr).apply(null,args);return rtn};var getDynCaller=(sig,ptr)=>{var argCache=[];return function(){argCache.length=0;Object.assign(argCache,arguments);return dynCall(sig,ptr,argCache)}};var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var UnboundTypeError=undefined;var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};var __embind_register_function=(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync)=>{var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,function(argTypes){var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})};var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>GROWABLE_HEAP_I8()[pointer>>0]:pointer=>GROWABLE_HEAP_U8()[pointer>>0];case 2:return signed?pointer=>GROWABLE_HEAP_I16()[pointer>>1]:pointer=>GROWABLE_HEAP_U16()[pointer>>1];case 4:return signed?pointer=>GROWABLE_HEAP_I32()[pointer>>2]:pointer=>GROWABLE_HEAP_U32()[pointer>>2];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};var __embind_register_integer=(primitiveType,name,size,minRange,maxRange)=>{name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name:name,"fromWireType":fromWireType,"toWireType":toWireType,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})};var __embind_register_memory_view=(rawType,dataTypeIndex,name)=>{var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=GROWABLE_HEAP_U32()[handle>>2];var data=GROWABLE_HEAP_U32()[handle+4>>2];return new TA(GROWABLE_HEAP_I8().buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name:name,"fromWireType":decodeMemoryView,"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":decodeMemoryView},{ignoreDuplicateRegistrations:true})};function readPointer(pointer){return this["fromWireType"](GROWABLE_HEAP_U32()[pointer>>2])}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,GROWABLE_HEAP_U8(),outPtr,maxBytesToWrite);var __embind_register_std_string=(rawType,name)=>{name=readLatin1String(name);var stdStringIsUTF8=name==="std::string";registerType(rawType,{name:name,"fromWireType":value=>{var length=GROWABLE_HEAP_U32()[value>>2];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||GROWABLE_HEAP_U8()[currentBytePtr]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i{if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var length;var valueIsOfTypeString=typeof value=="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){length=lengthBytesUTF8(value)}else{length=value.length}var base=_malloc(4+length+1);var ptr=base+4;GROWABLE_HEAP_U32()[base>>2]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}GROWABLE_HEAP_U8()[ptr+i]=charCode}}else{for(var i=0;i_free(ptr)})};var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&GROWABLE_HEAP_U16()[idx])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(GROWABLE_HEAP_U8().slice(ptr,endPtr));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=GROWABLE_HEAP_I16()[ptr+i*2>>1];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>1]=codeUnit;outPtr+=2}GROWABLE_HEAP_I16()[outPtr>>1]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=GROWABLE_HEAP_I32()[ptr+i*4>>2];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{if(maxBytesToWrite===undefined){maxBytesToWrite=2147483647}if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}GROWABLE_HEAP_I32()[outPtr>>2]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}GROWABLE_HEAP_I32()[outPtr>>2]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=(rawType,charSize,name)=>{name=readLatin1String(name);var decodeString,encodeString,getHeap,lengthBytesUTF,shift;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;getHeap=()=>GROWABLE_HEAP_U16();shift=1}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;getHeap=()=>GROWABLE_HEAP_U32();shift=2}registerType(rawType,{name:name,"fromWireType":value=>{var length=GROWABLE_HEAP_U32()[value>>2];var HEAP=getHeap();var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||HEAP[currentBytePtr>>shift]==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},"toWireType":(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);GROWABLE_HEAP_U32()[ptr>>2]=length>>shift;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},"argPackAdvance":GenericWireTypeSize,"readValueFromPointer":simpleReadValueFromPointer,destructorFunction:ptr=>_free(ptr)})};var __embind_register_void=(rawType,name)=>{name=readLatin1String(name);registerType(rawType,{isVoid:true,name:name,"argPackAdvance":0,"fromWireType":()=>undefined,"toWireType":(destructors,o)=>undefined})};var nowIsMonotonic=true;var __emscripten_get_now_is_monotonic=()=>nowIsMonotonic;var maybeExit=()=>{if(!keepRuntimeAlive()){try{if(ENVIRONMENT_IS_PTHREAD)__emscripten_thread_exit(EXITSTATUS);else _exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var __emscripten_thread_mailbox_await=pthread_ptr=>{if(typeof Atomics.waitAsync==="function"){var wait=Atomics.waitAsync(GROWABLE_HEAP_I32(),pthread_ptr>>2,pthread_ptr);wait.value.then(checkMailbox);var waitingAsync=pthread_ptr+128;Atomics.store(GROWABLE_HEAP_I32(),waitingAsync>>2,1)}};Module["__emscripten_thread_mailbox_await"]=__emscripten_thread_mailbox_await;var checkMailbox=()=>{var pthread_ptr=_pthread_self();if(pthread_ptr){__emscripten_thread_mailbox_await(pthread_ptr);callUserCallback(()=>__emscripten_check_mailbox())}};Module["checkMailbox"]=checkMailbox;var __emscripten_notify_mailbox_postmessage=(targetThreadId,currThreadId,mainThreadId)=>{if(targetThreadId==currThreadId){setTimeout(()=>checkMailbox())}else if(ENVIRONMENT_IS_PTHREAD){postMessage({"targetThread":targetThreadId,"cmd":"checkMailbox"})}else{var worker=PThread.pthreads[targetThreadId];if(!worker){return}worker.postMessage({"cmd":"checkMailbox"})}};var withStackSave=f=>{var stack=stackSave();var ret=f();stackRestore(stack);return ret};var proxyToMainThread=function(index,sync){var numCallArgs=arguments.length-2;var outerArgs=arguments;return withStackSave(()=>{var serializedNumCallArgs=numCallArgs;var args=stackAlloc(serializedNumCallArgs*8);var b=args>>3;for(var i=0;i{proxiedJSCallArgs.length=numCallArgs;var b=args>>3;for(var i=0;i{if(ENVIRONMENT_IS_NODE){PThread.pthreads[thread].ref()}};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(humanName+" has unknown type "+getTypeName(rawType))}return impl};var __emval_as=(handle,returnType,destructorsRef)=>{handle=Emval.toValue(handle);returnType=requireRegisteredType(returnType,"emval::as");var destructors=[];var rd=Emval.toHandle(destructors);GROWABLE_HEAP_U32()[destructorsRef>>2]=rd;return returnType["toWireType"](destructors,handle)};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var emval_methodCallers=[];var __emval_call_void_method=(caller,handle,methodName,args)=>{caller=emval_methodCallers[caller];handle=Emval.toValue(handle);methodName=getStringOrSymbol(methodName);caller(handle,methodName,null,args)};var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>2],"parameter "+i)}return a};var emval_registeredMethods=[];var __emval_get_method_caller=(argCount,argTypes)=>{var types=emval_lookupTypes(argCount,argTypes);var retType=types[0];var signatureName=retType.name+"_$"+types.slice(1).map(function(t){return t.name}).join("_")+"$";var returnId=emval_registeredMethods[signatureName];if(returnId!==undefined){return returnId}var params=["retType"];var args=[retType];var argsList="";for(var i=0;i{name=getStringOrSymbol(name);return Emval.toHandle(Module[name])};var __emval_get_property=(handle,key)=>{handle=Emval.toValue(handle);key=Emval.toValue(key);return Emval.toHandle(handle[key])};var __emval_incref=handle=>{if(handle>4){emval_handles.get(handle).refcount+=1}};var craftEmvalAllocator=argCount=>{var argsList="";for(var i=0;iGROWABLE_HEAP_U32();var functionBody="return function emval_allocator_"+argCount+"(constructor, argTypes, args) {\n"+" var HEAPU32 = getMemory();\n";for(var i=0;i>2)], 'parameter "+i+"');\n"+"var arg"+i+" = argType"+i+".readValueFromPointer(args);\n"+"args += argType"+i+"['argPackAdvance'];\n"+"argTypes += 4;\n"}functionBody+="var obj = new constructor("+argsList+");\n"+"return valueToHandle(obj);\n"+"}\n";return new Function("requireRegisteredType","Module","valueToHandle","getMemory",functionBody)(requireRegisteredType,Module,Emval.toHandle,getMemory)};var emval_newers={};var __emval_new=(handle,argCount,argTypes,args)=>{handle=Emval.toValue(handle);var newer=emval_newers[argCount];if(!newer){newer=craftEmvalAllocator(argCount);emval_newers[argCount]=newer}return newer(handle,argTypes,args)};var __emval_new_cstring=v=>Emval.toHandle(getStringOrSymbol(v));var __emval_run_destructors=handle=>{var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)};var _abort=()=>{abort("")};var warnOnce=text=>{if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;if(ENVIRONMENT_IS_NODE)text="warning: "+text;err(text)}};var _emscripten_check_blocking_allowed=()=>{};var runtimeKeepalivePush=()=>{runtimeKeepaliveCounter+=1};var _emscripten_exit_with_live_runtime=()=>{runtimeKeepalivePush();throw"unwind"};var getHeapMax=()=>2147483648;var _emscripten_get_heap_max=()=>getHeapMax();var _emscripten_get_now;_emscripten_get_now=()=>performance.timeOrigin+performance.now();var _emscripten_num_logical_cores=()=>{if(ENVIRONMENT_IS_NODE)return require("os").cpus().length;return navigator["hardwareConcurrency"]};var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};var _emscripten_resize_heap=requestedSize=>{var oldSize=GROWABLE_HEAP_U8().length;requestedSize>>>=0;if(requestedSize<=oldSize){return false}var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}var alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false};var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>0]=str.charCodeAt(i)}GROWABLE_HEAP_I8()[buffer>>0]=0};var _environ_get=function(__environ,environ_buf){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(6,1,__environ,environ_buf);var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;GROWABLE_HEAP_U32()[__environ+i*4>>2]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(7,1,penviron_count,penviron_buf_size);var strings=getEnvStrings();GROWABLE_HEAP_U32()[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);GROWABLE_HEAP_U32()[penviron_buf_size>>2]=bufSize;return 0};function _fd_close(fd){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(8,1,fd);try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=GROWABLE_HEAP_U32()[iov+4>>2];iov+=8;var curr=FS.read(stream,GROWABLE_HEAP_I8(),ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function _fd_seek(fd,offset_low,offset_high,whence,newOffset){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(10,1,fd,offset_low,offset_high,whence,newOffset);var offset=convertI32PairToI53Checked(offset_low,offset_high);try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],GROWABLE_HEAP_I32()[newOffset>>2]=tempI64[0],GROWABLE_HEAP_I32()[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>2];var len=GROWABLE_HEAP_U32()[iov+4>>2];iov+=8;var curr=FS.write(stream,GROWABLE_HEAP_I8(),ptr,len,offset);if(curr<0)return-1;ret+=curr;if(typeof offset!=="undefined"){offset+=curr}}return ret};function _fd_write(fd,iov,iovcnt,pnum){if(ENVIRONMENT_IS_PTHREAD)return proxyToMainThread(11,1,fd,iov,iovcnt,pnum);try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);GROWABLE_HEAP_U32()[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var arraySum=(array,index)=>{var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum};var MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];var addDays=(date,days)=>{var newDate=new Date(date.getTime());while(days>0){var leap=isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate};var writeArrayToMemory=(array,buffer)=>{GROWABLE_HEAP_I8().set(array,buffer)};var _strftime=(s,maxsize,format,tm)=>{var tm_zone=GROWABLE_HEAP_U32()[tm+40>>2];var date={tm_sec:GROWABLE_HEAP_I32()[tm>>2],tm_min:GROWABLE_HEAP_I32()[tm+4>>2],tm_hour:GROWABLE_HEAP_I32()[tm+8>>2],tm_mday:GROWABLE_HEAP_I32()[tm+12>>2],tm_mon:GROWABLE_HEAP_I32()[tm+16>>2],tm_year:GROWABLE_HEAP_I32()[tm+20>>2],tm_wday:GROWABLE_HEAP_I32()[tm+24>>2],tm_yday:GROWABLE_HEAP_I32()[tm+28>>2],tm_isdst:GROWABLE_HEAP_I32()[tm+32>>2],tm_gmtoff:GROWABLE_HEAP_I32()[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}return thisDate.getFullYear()}return thisDate.getFullYear()-1}var EXPANSION_RULES_2={"%a":date=>WEEKDAYS[date.tm_wday].substring(0,3),"%A":date=>WEEKDAYS[date.tm_wday],"%b":date=>MONTHS[date.tm_mon].substring(0,3),"%B":date=>MONTHS[date.tm_mon],"%C":date=>{var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":date=>leadingNulls(date.tm_mday,2),"%e":date=>leadingSomething(date.tm_mday,2," "),"%g":date=>getWeekBasedYear(date).toString().substring(2),"%G":date=>getWeekBasedYear(date),"%H":date=>leadingNulls(date.tm_hour,2),"%I":date=>{var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":date=>leadingNulls(date.tm_mday+arraySum(isLeapYear(date.tm_year+1900)?MONTH_DAYS_LEAP:MONTH_DAYS_REGULAR,date.tm_mon-1),3),"%m":date=>leadingNulls(date.tm_mon+1,2),"%M":date=>leadingNulls(date.tm_min,2),"%n":()=>"\n","%p":date=>{if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}return"PM"},"%S":date=>leadingNulls(date.tm_sec,2),"%t":()=>"\t","%u":date=>date.tm_wday||7,"%U":date=>{var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":date=>{var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":date=>date.tm_wday,"%W":date=>{var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":date=>(date.tm_year+1900).toString().substring(2),"%Y":date=>date.tm_year+1900,"%z":date=>{var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":date=>date.tm_zone,"%%":()=>"%"};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1};var _strftime_l=(s,maxsize,format,tm,loc)=>_strftime(s,maxsize,format,tm);PThread.init();var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();Module["FS_createPath"]=FS.createPath;Module["FS_createDataFile"]=FS.createDataFile;Module["FS_createPreloadedFile"]=FS.createPreloadedFile;Module["FS_unlink"]=FS.unlink;Module["FS_createLazyFile"]=FS.createLazyFile;Module["FS_createDevice"]=FS.createDevice;embind_init_charCodes();BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};handleAllocatorInit();init_emval();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");var proxiedFunctionTable=[_proc_exit,exitOnMainThread,pthreadCreateProxied,___syscall_fcntl64,___syscall_ioctl,___syscall_openat,_environ_get,_environ_sizes_get,_fd_close,_fd_read,_fd_seek,_fd_write];var wasmImports={d:___cxa_throw,J:___emscripten_init_main_thread_js,m:___emscripten_thread_cleanup,G:___pthread_create_js,q:___syscall_fcntl64,L:___syscall_ioctl,M:___syscall_openat,y:__embind_register_bigint,R:__embind_register_bool,Q:__embind_register_emval,s:__embind_register_float,h:__embind_register_function,g:__embind_register_integer,c:__embind_register_memory_view,r:__embind_register_std_string,k:__embind_register_std_wstring,S:__embind_register_void,P:__emscripten_get_now_is_monotonic,F:__emscripten_notify_mailbox_postmessage,H:__emscripten_receive_on_main_thread_js,I:__emscripten_thread_mailbox_await,O:__emscripten_thread_set_strongref,w:__emval_as,U:__emval_call_void_method,f:__emval_decref,V:__emval_get_method_caller,u:__emval_get_module_property,i:__emval_get_property,l:__emval_incref,t:__emval_new,j:__emval_new_cstring,v:__emval_run_destructors,b:_abort,n:_emscripten_check_blocking_allowed,N:_emscripten_exit_with_live_runtime,z:_emscripten_get_heap_max,e:_emscripten_get_now,A:_emscripten_num_logical_cores,E:_emscripten_resize_heap,C:_environ_get,D:_environ_sizes_get,T:_exit,o:_fd_close,K:_fd_read,x:_fd_seek,p:_fd_write,a:wasmMemory||Module["wasmMemory"],B:_strftime_l};var wasmExports=createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["W"])();var _free=a0=>(_free=wasmExports["Y"])(a0);var _malloc=a0=>(_malloc=wasmExports["Z"])(a0);var __emscripten_tls_init=Module["__emscripten_tls_init"]=()=>(__emscripten_tls_init=Module["__emscripten_tls_init"]=wasmExports["_"])();var _pthread_self=Module["_pthread_self"]=()=>(_pthread_self=Module["_pthread_self"]=wasmExports["$"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["aa"])(a0);var __embind_initialize_bindings=Module["__embind_initialize_bindings"]=()=>(__embind_initialize_bindings=Module["__embind_initialize_bindings"]=wasmExports["ba"])();var ___errno_location=()=>(___errno_location=wasmExports["ca"])();var __emscripten_thread_init=Module["__emscripten_thread_init"]=(a0,a1,a2,a3,a4,a5)=>(__emscripten_thread_init=Module["__emscripten_thread_init"]=wasmExports["da"])(a0,a1,a2,a3,a4,a5);var __emscripten_thread_crashed=Module["__emscripten_thread_crashed"]=()=>(__emscripten_thread_crashed=Module["__emscripten_thread_crashed"]=wasmExports["ea"])();var _emscripten_main_thread_process_queued_calls=()=>(_emscripten_main_thread_process_queued_calls=wasmExports["emscripten_main_thread_process_queued_calls"])();var _emscripten_main_runtime_thread_id=()=>(_emscripten_main_runtime_thread_id=wasmExports["emscripten_main_runtime_thread_id"])();var __emscripten_run_on_main_thread_js=(a0,a1,a2,a3)=>(__emscripten_run_on_main_thread_js=wasmExports["fa"])(a0,a1,a2,a3);var __emscripten_thread_free_data=a0=>(__emscripten_thread_free_data=wasmExports["ga"])(a0);var __emscripten_thread_exit=Module["__emscripten_thread_exit"]=a0=>(__emscripten_thread_exit=Module["__emscripten_thread_exit"]=wasmExports["ha"])(a0);var __emscripten_check_mailbox=Module["__emscripten_check_mailbox"]=()=>(__emscripten_check_mailbox=Module["__emscripten_check_mailbox"]=wasmExports["ia"])();var _emscripten_stack_set_limits=(a0,a1)=>(_emscripten_stack_set_limits=wasmExports["ja"])(a0,a1);var stackSave=()=>(stackSave=wasmExports["ka"])();var stackRestore=a0=>(stackRestore=wasmExports["la"])(a0);var stackAlloc=a0=>(stackAlloc=wasmExports["ma"])(a0);var ___cxa_is_pointer_type=a0=>(___cxa_is_pointer_type=wasmExports["na"])(a0);var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["oa"])(a0,a1,a2,a3,a4);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["pa"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["qa"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["ra"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["sa"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function intArrayFromBase64(s){if(typeof ENVIRONMENT_IS_NODE!="undefined"&&ENVIRONMENT_IS_NODE){var buf=Buffer.from(s,"base64");return new Uint8Array(buf.buffer,buf.byteOffset,buf.length)}try{var decoded=atob(s);var bytes=new Uint8Array(decoded.length);for(var i=0;i0){return}if(ENVIRONMENT_IS_PTHREAD){readyPromiseResolve(Module);initRuntime();startWorker(Module);return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}run(); + + + return moduleArg.ready +} + +); +})(); +if (typeof exports === 'object' && typeof module === 'object') + module.exports = whisper_factory; +else if (typeof define === 'function' && define['amd']) + define([], () => whisper_factory); diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/.gitignore b/whisper.cpp-1.5.2/bindings/ruby/ext/.gitignore new file mode 100644 index 0000000..9f9b7ab --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/.gitignore @@ -0,0 +1,9 @@ +Makefile +ggml.c +ggml.h +ggml-alloc.c +ggml-alloc.h +whisper.bundle +whisper.cpp +whisper.h +dr_wav.h diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/extconf.rb b/whisper.cpp-1.5.2/bindings/ruby/ext/extconf.rb new file mode 100644 index 0000000..c736d30 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/extconf.rb @@ -0,0 +1,29 @@ +require 'mkmf' +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','whisper.cpp')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','whisper.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-impl.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-alloc.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-alloc.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend-impl.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-backend.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-quants.h')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','ggml-quants.c')} .") +system("cp #{File.join(File.dirname(__FILE__),'..','..','..','examples','dr_wav.h')} .") + + +# need to use c++ compiler flags +$CXXFLAGS << ' -std=c++11' +# Set to true when building binary gems +if enable_config('static-stdlib', false) + $LDFLAGS << ' -static-libgcc -static-libstdc++' +end + +if enable_config('march-tune-native', false) + $CFLAGS << ' -march=native -mtune=native' + $CXXFLAGS << ' -march=native -mtune=native' +end + +create_makefile('whisper') diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend-impl.h b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend-impl.h new file mode 100644 index 0000000..211e3d4 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend-impl.h @@ -0,0 +1,87 @@ +#pragma once + +// ggml-backend internal header + +#include "ggml-backend.h" + +#ifdef __cplusplus +extern "C" { +#endif + + // + // Backend buffer + // + + typedef void * ggml_backend_buffer_context_t; + + struct ggml_backend_buffer_i { + void (*free_buffer) (ggml_backend_buffer_t buffer); + void * (*get_base) (ggml_backend_buffer_t buffer); // get base pointer + size_t (*get_alloc_size)(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); // pre-allocation callback + void (*init_tensor) (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); // post-allocation callback + void (*free_tensor) (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); // pre-free callback + }; + + struct ggml_backend_buffer { + struct ggml_backend_buffer_i iface; + + ggml_backend_t backend; + ggml_backend_buffer_context_t context; + + size_t size; + }; + + GGML_API ggml_backend_buffer_t ggml_backend_buffer_init( + struct ggml_backend * backend, + struct ggml_backend_buffer_i iface, + ggml_backend_buffer_context_t context, + size_t size); + + // + // Backend + // + + typedef void * ggml_backend_context_t; + + struct ggml_backend_i { + const char * (*get_name)(ggml_backend_t backend); + + void (*free)(ggml_backend_t backend); + + // buffer allocation + ggml_backend_buffer_t (*alloc_buffer)(ggml_backend_t backend, size_t size); + + // get buffer alignment + size_t (*get_alignment)(ggml_backend_t backend); + + // tensor data access + // these functions can be asynchronous, helper functions are provided for synchronous access that automatically call synchronize + void (*set_tensor_async)(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + void (*get_tensor_async)(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + void (*synchronize) (ggml_backend_t backend); + + // (optional) copy tensor between different backends, allow for single-copy tranfers + void (*cpy_tensor_from)(ggml_backend_t backend, struct ggml_tensor * src, struct ggml_tensor * dst); + void (*cpy_tensor_to) (ggml_backend_t backend, struct ggml_tensor * src, struct ggml_tensor * dst); + + // compute graph with a plan + ggml_backend_graph_plan_t (*graph_plan_create) (ggml_backend_t backend, struct ggml_cgraph * cgraph); + void (*graph_plan_free) (ggml_backend_t backend, ggml_backend_graph_plan_t plan); + void (*graph_plan_compute)(ggml_backend_t backend, ggml_backend_graph_plan_t plan); + + // compute graph without a plan + void (*graph_compute)(ggml_backend_t backend, struct ggml_cgraph * cgraph); + + // check if the backend supports an operation + bool (*supports_op)(ggml_backend_t backend, const struct ggml_tensor * op); + }; + + struct ggml_backend { + struct ggml_backend_i iface; + + ggml_backend_context_t context; + }; + +#ifdef __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.c b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.c new file mode 100644 index 0000000..f6e5fce --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.c @@ -0,0 +1,950 @@ +#include "ggml-backend-impl.h" +#include "ggml-alloc.h" +#include "ggml-impl.h" + +#include +#include +#include +#include +#include +#include + +#define UNUSED GGML_UNUSED + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +// backend buffer + +ggml_backend_buffer_t ggml_backend_buffer_init( + struct ggml_backend * backend, + struct ggml_backend_buffer_i iface, + ggml_backend_buffer_context_t context, + size_t size) { + ggml_backend_buffer_t buffer = malloc(sizeof(struct ggml_backend_buffer)); + + GGML_ASSERT(iface.get_base != NULL); + + (*buffer) = (struct ggml_backend_buffer) { + /* .interface = */ iface, + /* .backend = */ backend, + /* .context = */ context, + /* .size = */ size, + }; + + return buffer; +} + +void ggml_backend_buffer_free(ggml_backend_buffer_t buffer) { + if (buffer == NULL) { + return; + } + + if (buffer->iface.free_buffer != NULL) { + buffer->iface.free_buffer(buffer); + } + free(buffer); +} + +size_t ggml_backend_buffer_get_alignment(ggml_backend_buffer_t buffer) { + return ggml_backend_get_alignment(buffer->backend); +} + +size_t ggml_backend_buffer_get_size(ggml_backend_buffer_t buffer) { + return buffer->size; +} + +void * ggml_backend_buffer_get_base(ggml_backend_buffer_t buffer) { + void * base = buffer->iface.get_base(buffer); + + GGML_ASSERT(base != NULL && "backend buffer base cannot be NULL"); + + return base; +} + +size_t ggml_backend_buffer_get_alloc_size(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + // get_alloc_size is optional, defaults to ggml_nbytes + if (buffer->iface.get_alloc_size) { + return buffer->iface.get_alloc_size(buffer, tensor); + } + return ggml_nbytes(tensor); +} + +void ggml_backend_buffer_init_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + // init_tensor is optional + if (buffer->iface.init_tensor) { + buffer->iface.init_tensor(buffer, tensor); + } +} + +void ggml_backend_buffer_free_tensor(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor) { + // free_tensor is optional + if (buffer->iface.free_tensor) { + buffer->iface.free_tensor(buffer, tensor); + } +} + +// backend + +ggml_backend_t ggml_get_backend(const struct ggml_tensor * tensor) { + return tensor->buffer ? tensor->buffer->backend : NULL; +} + +const char * ggml_backend_name(ggml_backend_t backend) { + if (backend == NULL) { + return "NULL"; + } + return backend->iface.get_name(backend); +} + +void ggml_backend_free(ggml_backend_t backend) { + if (backend == NULL) { + return; + } + + backend->iface.free(backend); +} + +ggml_backend_buffer_t ggml_backend_alloc_buffer(ggml_backend_t backend, size_t size) { + return backend->iface.alloc_buffer(backend, size); +} + +size_t ggml_backend_get_alignment(ggml_backend_t backend) { + return backend->iface.get_alignment(backend); +} + +void ggml_backend_tensor_set_async(struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + ggml_get_backend(tensor)->iface.set_tensor_async(ggml_get_backend(tensor), tensor, data, offset, size); +} + +void ggml_backend_tensor_get_async(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + ggml_get_backend(tensor)->iface.get_tensor_async(ggml_get_backend(tensor), tensor, data, offset, size); +} + +void ggml_backend_tensor_set(struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + ggml_backend_t backend = ggml_get_backend(tensor); + + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(backend != NULL && "tensor backend not set"); + + backend->iface.set_tensor_async(backend, tensor, data, offset, size); + backend->iface.synchronize(backend); +} + +void ggml_backend_tensor_get(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + ggml_backend_t backend = ggml_get_backend(tensor); + + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + GGML_ASSERT(backend != NULL && "tensor backend not set"); + + backend->iface.get_tensor_async(backend, tensor, data, offset, size); + backend->iface.synchronize(backend); +} + +void ggml_backend_synchronize(ggml_backend_t backend) { + backend->iface.synchronize(backend); +} + +ggml_backend_graph_plan_t ggml_backend_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + return backend->iface.graph_plan_create(backend, cgraph); +} + +void ggml_backend_graph_plan_free(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + backend->iface.graph_plan_free(backend, plan); +} + +void ggml_backend_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + backend->iface.graph_plan_compute(backend, plan); +} + +void ggml_backend_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + backend->iface.graph_compute(backend, cgraph); +} + +bool ggml_backend_supports_op(ggml_backend_t backend, const struct ggml_tensor * op) { + return backend->iface.supports_op(backend, op); +} + +// backend copy + +static bool ggml_are_same_layout(const struct ggml_tensor * a, const struct ggml_tensor * b) { + if (a->type != b->type) { + return false; + } + for (int i = 0; i < GGML_MAX_DIMS; i++) { + if (a->ne[i] != b->ne[i]) { + return false; + } + if (a->nb[i] != b->nb[i]) { + return false; + } + } + return true; +} + +void ggml_backend_tensor_copy(struct ggml_tensor * src, struct ggml_tensor * dst) { + //printf("src: %s ne: [%d %d %d %d] nb: [%d %d %d %d]\n", src->name, (int)src->ne[0], (int)src->ne[1], (int)src->ne[2], (int)src->ne[3], (int)src->nb[0], (int)src->nb[1], (int)src->nb[2], (int)src->nb[3]); + //printf("dst: %s ne: [%d %d %d %d] nb: [%d %d %d %d]\n", dst->name, (int)dst->ne[0], (int)dst->ne[1], (int)dst->ne[2], (int)dst->ne[3], (int)dst->nb[0], (int)dst->nb[1], (int)dst->nb[2], (int)dst->nb[3]); + GGML_ASSERT(ggml_are_same_layout(src, dst) && "cannot copy tensors with different layouts"); + + // fprintf(stderr, "cpy tensor %s from %s to %s (%lu bytes)\n", src->name, ggml_backend_name(src->backend), ggml_backend_name(dst->backend), ggml_nbytes(src)); + + if (src == dst) { + return; + } + + // TODO: allow backends to support copy to/from same backend + + if (ggml_get_backend(dst)->iface.cpy_tensor_from != NULL) { + ggml_get_backend(dst)->iface.cpy_tensor_from(ggml_get_backend(dst)->context, src, dst); + } else if (ggml_get_backend(src)->iface.cpy_tensor_to != NULL) { + ggml_get_backend(src)->iface.cpy_tensor_to(ggml_get_backend(src)->context, src, dst); + } else { + // shouldn't be hit when copying from/to CPU + #ifndef NDEBUG + fprintf(stderr, "ggml_backend_tensor_copy: neither cpy_tensor_from nor cpy_tensor_to are implemented for backends %s and %s, falling back to get/set\n", ggml_backend_name(src->buffer->backend), ggml_backend_name(dst->buffer->backend)); + #endif + size_t nbytes = ggml_nbytes(src); + void * data = malloc(nbytes); + ggml_backend_tensor_get(src, data, 0, nbytes); + ggml_backend_tensor_set(dst, data, 0, nbytes); + free(data); + } +} + +// backend CPU + +struct ggml_backend_cpu_context { + int n_threads; + void * work_data; + size_t work_size; +}; + +static const char * ggml_backend_cpu_name(ggml_backend_t backend) { + return "CPU"; + + UNUSED(backend); +} + +static void ggml_backend_cpu_free(ggml_backend_t backend) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + free(cpu_ctx->work_data); + free(cpu_ctx); + free(backend); +} + +static void * ggml_backend_cpu_buffer_get_base(ggml_backend_buffer_t buffer) { + return (void *)buffer->context; +} + +static void ggml_backend_cpu_buffer_free_buffer(ggml_backend_buffer_t buffer) { + free(buffer->context); + UNUSED(buffer); +} + +static struct ggml_backend_buffer_i cpu_backend_buffer_i = { + /* .free_buffer = */ ggml_backend_cpu_buffer_free_buffer, + /* .get_base = */ ggml_backend_cpu_buffer_get_base, + /* .get_alloc_size = */ NULL, // defaults to ggml_nbytes + /* .init_tensor = */ NULL, // no initialization required + /* .free_tensor = */ NULL, // no cleanup required +}; + +// for buffers from ptr, free is not called +static struct ggml_backend_buffer_i cpu_backend_buffer_i_from_ptr = { + /* .free_buffer = */ NULL, // ptr is not owned by the buffer, so it does not need to be freed + /* .get_base = */ ggml_backend_cpu_buffer_get_base, + /* .get_alloc_size = */ NULL, // defaults to ggml_nbytes + /* .init_tensor = */ NULL, + /* .free_tensor = */ NULL, +}; + +static const size_t TENSOR_ALIGNMENT = 64; // should be enough for AVX 512 + +static ggml_backend_buffer_t ggml_backend_cpu_alloc_buffer(ggml_backend_t backend, size_t size) { + size += TENSOR_ALIGNMENT; // malloc may return an address that is not aligned + void * data = malloc(size); // TODO: maybe use GGML_ALIGNED_MALLOC? + + GGML_ASSERT(data != NULL && "failed to allocate buffer"); + + return ggml_backend_buffer_init(backend, cpu_backend_buffer_i, data, size); +} + +static size_t ggml_backend_cpu_get_alignment(ggml_backend_t backend) { + return TENSOR_ALIGNMENT; + UNUSED(backend); +} + +static void ggml_backend_cpu_set_tensor_async(ggml_backend_t backend, struct ggml_tensor * tensor, const void * data, size_t offset, size_t size) { + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor write out of bounds"); + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + + memcpy((char *)tensor->data + offset, data, size); + + UNUSED(backend); +} + +static void ggml_backend_cpu_get_tensor_async(ggml_backend_t backend, const struct ggml_tensor * tensor, void * data, size_t offset, size_t size) { + GGML_ASSERT(offset + size <= ggml_nbytes(tensor) && "tensor read out of bounds"); + GGML_ASSERT(tensor->data != NULL && "tensor not allocated"); + + memcpy(data, (const char *)tensor->data + offset, size); + + UNUSED(backend); +} + +static void ggml_backend_cpu_synchronize(ggml_backend_t backend) { + UNUSED(backend); +} + +static void ggml_backend_cpu_cpy_tensor_from(ggml_backend_t backend, struct ggml_tensor * src, struct ggml_tensor * dst) { + ggml_backend_tensor_get(src, dst->data, 0, ggml_nbytes(src)); + + UNUSED(backend); +} + +static void ggml_backend_cpu_cpy_tensor_to(ggml_backend_t backend, struct ggml_tensor * src, struct ggml_tensor * dst) { + ggml_backend_tensor_set(dst, src->data, 0, ggml_nbytes(src)); + + UNUSED(backend); +} + +struct ggml_backend_plan_cpu { + struct ggml_cplan cplan; + struct ggml_cgraph cgraph; +}; + +static ggml_backend_graph_plan_t ggml_backend_cpu_graph_plan_create(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + + struct ggml_backend_plan_cpu * cpu_plan = malloc(sizeof(struct ggml_backend_plan_cpu)); + + cpu_plan->cplan = ggml_graph_plan(cgraph, cpu_ctx->n_threads); + cpu_plan->cgraph = *cgraph; + + if (cpu_plan->cplan.work_size > 0) { + cpu_plan->cplan.work_data = malloc(cpu_plan->cplan.work_size); + } + + return cpu_plan; +} + +static void ggml_backend_cpu_graph_plan_free(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + struct ggml_backend_plan_cpu * cpu_plan = (struct ggml_backend_plan_cpu *)plan; + + free(cpu_plan->cplan.work_data); + free(cpu_plan); + + UNUSED(backend); +} + +static void ggml_backend_cpu_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan) { + struct ggml_backend_plan_cpu * cpu_plan = (struct ggml_backend_plan_cpu *)plan; + + ggml_graph_compute(&cpu_plan->cgraph, &cpu_plan->cplan); + + UNUSED(backend); +} + +static void ggml_backend_cpu_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) { + struct ggml_backend_cpu_context * cpu_ctx = (struct ggml_backend_cpu_context *)backend->context; + + struct ggml_cplan cplan = ggml_graph_plan(cgraph, cpu_ctx->n_threads); + + if (cpu_ctx->work_size < cplan.work_size) { + // TODO: may be faster to free and use malloc to avoid the copy + cpu_ctx->work_data = realloc(cpu_ctx->work_data, cplan.work_size); + cpu_ctx->work_size = cplan.work_size; + } + + cplan.work_data = cpu_ctx->work_data; + + ggml_graph_compute(cgraph, &cplan); +} + +static bool ggml_backend_cpu_supports_op(ggml_backend_t backend, const struct ggml_tensor * op) { + return true; + UNUSED(backend); + UNUSED(op); +} + +static struct ggml_backend_i cpu_backend_i = { + /* .get_name = */ ggml_backend_cpu_name, + /* .free = */ ggml_backend_cpu_free, + /* .alloc_buffer = */ ggml_backend_cpu_alloc_buffer, + /* .get_alignment = */ ggml_backend_cpu_get_alignment, + /* .set_tensor_async = */ ggml_backend_cpu_set_tensor_async, + /* .get_tensor_async = */ ggml_backend_cpu_get_tensor_async, + /* .synchronize = */ ggml_backend_cpu_synchronize, + /* .cpy_tensor_from = */ ggml_backend_cpu_cpy_tensor_from, + /* .cpy_tensor_to = */ ggml_backend_cpu_cpy_tensor_to, + /* .graph_plan_create = */ ggml_backend_cpu_graph_plan_create, + /* .graph_plan_free = */ ggml_backend_cpu_graph_plan_free, + /* .graph_plan_compute = */ ggml_backend_cpu_graph_plan_compute, + /* .graph_compute = */ ggml_backend_cpu_graph_compute, + /* .supports_op = */ ggml_backend_cpu_supports_op, +}; + +ggml_backend_t ggml_backend_cpu_init(void) { + struct ggml_backend_cpu_context * ctx = malloc(sizeof(struct ggml_backend_cpu_context)); + + ctx->n_threads = GGML_DEFAULT_N_THREADS; + ctx->work_data = NULL; + ctx->work_size = 0; + + ggml_backend_t cpu_backend = malloc(sizeof(struct ggml_backend)); + + *cpu_backend = (struct ggml_backend) { + /* .interface = */ cpu_backend_i, + /* .context = */ ctx + }; + return cpu_backend; +} + +bool ggml_backend_is_cpu(ggml_backend_t backend) { + return backend->iface.get_name == ggml_backend_cpu_name; +} + +void ggml_backend_cpu_set_n_threads(ggml_backend_t backend_cpu, int n_threads) { + GGML_ASSERT(ggml_backend_is_cpu(backend_cpu)); + + struct ggml_backend_cpu_context * ctx = (struct ggml_backend_cpu_context *)backend_cpu->context; + ctx->n_threads = n_threads; +} + +ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(ggml_backend_t backend_cpu, void * ptr, size_t size) { + return ggml_backend_buffer_init(backend_cpu, cpu_backend_buffer_i_from_ptr, ptr, size); +} + +// scheduler + +#define GGML_MAX_BACKENDS 4 +#define GGML_MAX_SPLITS 256 +#define GGML_MAX_SPLIT_INPUTS 16 + +struct ggml_backend_sched_split { + ggml_tallocr_t tallocr; + int i_start; + int i_end; + struct ggml_tensor * inputs[GGML_MAX_SPLIT_INPUTS]; + int n_inputs; + struct ggml_cgraph * graph; +}; + +struct ggml_backend_sched { + int n_backends; + ggml_backend_t backends[GGML_MAX_BACKENDS]; + ggml_tallocr_t tallocs[GGML_MAX_BACKENDS]; + + ggml_gallocr_t galloc; + + struct ggml_hash_set hash_set; + ggml_tallocr_t * node_talloc; // [hash_set.size] + struct ggml_tensor * (* node_copies)[GGML_MAX_BACKENDS]; // [hash_set.size][GGML_MAX_BACKENDS] + + struct ggml_cgraph * graph; + struct ggml_backend_sched_split splits[GGML_MAX_SPLITS]; + int n_splits; + + struct ggml_context * ctx; + + // align context_buffer to GGML_MEM_ALIGN + #ifdef _MSC_VER + __declspec(align(GGML_MEM_ALIGN)) + #else + __attribute__((aligned(GGML_MEM_ALIGN))) + #endif + char context_buffer[GGML_MAX_SPLITS*GGML_MAX_SPLIT_INPUTS*sizeof(struct ggml_tensor) + GGML_MAX_SPLITS*sizeof(struct ggml_cgraph)]; +}; + +#define hash_id(node) ggml_hash_find_or_insert(sched->hash_set, node) +#define node_allocr(node) sched->node_talloc[hash_id(node)] + +static bool ggml_is_view_op(enum ggml_op op) { + return op == GGML_OP_VIEW || op == GGML_OP_RESHAPE || op == GGML_OP_PERMUTE || op == GGML_OP_TRANSPOSE; +} + +// returns the priority of the backend, lower is better +static int sched_backend_prio(ggml_backend_sched_t sched, ggml_backend_t backend) { + for (int i = 0; i < sched->n_backends; i++) { + if (sched->backends[i] == backend) { + return i; + } + } + return INT_MAX; +} + +static int sched_allocr_prio(ggml_backend_sched_t sched, ggml_tallocr_t allocr) { + for (int i = 0; i < sched->n_backends; i++) { + if (sched->tallocs[i] == allocr) { + return i; + } + } + return INT_MAX; +} + +// returns the backend that should be used for the node based on the current locations +char causes[GGML_DEFAULT_GRAPH_SIZE*4 + GGML_MAX_SPLITS*GGML_MAX_SPLIT_INPUTS][128]; // debug, remove +static ggml_backend_t sched_backend_from_cur(ggml_backend_sched_t sched, struct ggml_tensor * node) { + // if the dst tensor is already allocated in a buffer, we must assume that it is critical to keep it there + // ie. kv cache updates + // note that this doesn't allow fallback to CPU. need to add output tensors to the splits to copy the data back to the original backend. + // dst + ggml_backend_t cur_backend = ggml_get_backend(node); + if (cur_backend != NULL) { + sprintf(causes[hash_id(node)], "1.dst"); + return cur_backend; + } + + // view_src + if (node->view_src != NULL && ggml_get_backend(node->view_src) != NULL) { + sprintf(causes[hash_id(node)], "1.vsrc"); + return ggml_get_backend(node->view_src); + } + + // src + int cur_prio = INT_MAX; + size_t cur_size = 0; + + for (int i = 0; i < GGML_MAX_SRC; i++) { + const struct ggml_tensor * src = node->src[i]; + if (src == NULL) { + break; + } + ggml_backend_t src_backend = ggml_get_backend(src); + if (src_backend != NULL) { + int src_prio = sched_backend_prio(sched, src_backend); + size_t src_size = ggml_nbytes(src); + if (src_prio < cur_prio && src_size >= cur_size) { + cur_prio = src_prio; + cur_size = src_size; + cur_backend = src_backend; + sprintf(causes[hash_id(node)], "1.src%d", i); + } + } + } + return cur_backend; +} + +static char * fmt_size(size_t size) { + static char buffer[128]; + if (size >= 1024*1024) { + sprintf(buffer, "%zuM", size/1024/1024); + } else { + sprintf(buffer, "%zuK", size/1024); + } + return buffer; +} + +static void sched_print_assignments(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + int cur_split = 0; + for (int i = 0; i < graph->n_nodes; i++) { + if (cur_split < sched->n_splits && i == sched->splits[cur_split].i_start) { + ggml_backend_t split_backend = ggml_tallocr_get_buffer(sched->splits[cur_split].tallocr)->backend; + fprintf(stderr, "\n## SPLIT #%d: %s # %d inputs: ", cur_split, ggml_backend_name(split_backend), sched->splits[cur_split].n_inputs); + for (int j = 0; j < sched->splits[cur_split].n_inputs; j++) { + fprintf(stderr, "[%s (%5.5s)] ", sched->splits[cur_split].inputs[j]->name, fmt_size(ggml_nbytes(sched->splits[cur_split].inputs[j]))); + } + fprintf(stderr, "\n"); + cur_split++; + } + struct ggml_tensor * node = graph->nodes[i]; + if (ggml_is_view_op(node->op)) { + continue; + } + ggml_tallocr_t node_allocr = node_allocr(node); + ggml_backend_t node_backend = node_allocr ? ggml_tallocr_get_buffer(node_allocr)->backend : NULL; + fprintf(stderr, "node #%3d (%10.10s): %20.20s (%4.4s) [%4.4s %8.8s]:", i, ggml_op_name(node->op), node->name, fmt_size(ggml_nbytes(node)), node_allocr ? ggml_backend_name(node_backend) : "NULL", causes[hash_id(node)]); + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + break; + } + ggml_tallocr_t src_allocr = node_allocr(src); + ggml_backend_t src_backend = src_allocr ? ggml_tallocr_get_buffer(src_allocr)->backend : NULL; + fprintf(stderr, " %20.20s (%4.4s) [%4.4s %8.8s]", src->name, fmt_size(ggml_nbytes(src)), src_backend ? ggml_backend_name(src_backend) : "NULL", causes[hash_id(src)]); + } + fprintf(stderr, "\n"); + } +} + +// creates a copy of the tensor with the same memory layout +static struct ggml_tensor * ggml_dup_tensor_layout(struct ggml_context * ctx, const struct ggml_tensor * tensor) { + struct ggml_tensor * dup = ggml_dup_tensor(ctx, tensor); + for (int i = 0; i < GGML_MAX_DIMS; i++) { + dup->nb[i] = tensor->nb[i]; + } + return dup; +} + +// assigns backends to ops and splits the graph into subgraphs that can be computed on the same backend +// TODO: merge passes +static void sched_split_graph(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + // reset state + size_t hash_size = sched->hash_set.size; + memset(sched->hash_set.keys, 0, sizeof(sched->hash_set.keys[0]) * hash_size); + memset(sched->node_talloc, 0, sizeof(sched->node_talloc[0]) * hash_size); + memset(sched->node_copies, 0, sizeof(sched->node_copies[0]) * hash_size); + sched->n_splits = 0; + + struct ggml_init_params params = { + /*.mem_size = */ sizeof(sched->context_buffer), + /*.mem_buffer = */ sched->context_buffer, + /*.no_alloc = */ true + }; + + if (sched->ctx != NULL) { + ggml_free(sched->ctx); + } + + sched->ctx = ggml_init(params); + + // pass 1: assign backends to ops with allocated inputs + for (int i = 0; i < graph->n_leafs; i++) { + struct ggml_tensor * leaf = graph->leafs[i]; + if (node_allocr(leaf) != NULL) { + // do not overwrite user assignments + continue; + } + ggml_backend_t leaf_backend = ggml_get_backend(leaf); + if (leaf_backend == NULL && leaf->view_src != NULL) { + leaf_backend = ggml_get_backend(leaf->view_src); + } + if (leaf_backend != NULL) { + node_allocr(leaf) = ggml_backend_sched_get_tallocr(sched, leaf_backend); + } + } + + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + if (node_allocr(node) != NULL) { + // do not overwrite user assignments + continue; + } + ggml_backend_t node_backend = sched_backend_from_cur(sched, node); + if (node_backend != NULL) { + node_allocr(node) = ggml_backend_sched_get_tallocr(sched, node_backend); + } + } + //printf("PASS 1 ASSIGNMENTS\n"); sched_print_assignments(sched, graph); + + // pass 2: assign backends to ops from current assignments + // TODO: + // - reuse sched_backend_from_cur + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + ggml_tallocr_t node_allocr = node_allocr(node); + if (node_allocr == NULL) { + int cur_prio = INT_MAX; + size_t cur_size = 0; + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + break; + } + ggml_tallocr_t src_allocr = node_allocr(src); + if (src_allocr != NULL) { + int src_prio = sched_allocr_prio(sched, src_allocr); + size_t src_size = ggml_nbytes(src); + if (src_prio < cur_prio && src_size >= cur_size) { + cur_prio = src_prio; + cur_size = src_size; + node_allocr = src_allocr; + sprintf(causes[hash_id(node)], "2.src%d", j); + } + } + } + if (node_allocr != NULL) { + node_allocr(node) = node_allocr; + } + } + } + //printf("PASS 2 ASSIGNMENTS\n"); sched_print_assignments(sched, graph); + + // pass 3: assign backends to remaining src from dst (should only be leafs) + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + ggml_tallocr_t node_allocr = node_allocr(node); + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + break; + } + ggml_tallocr_t src_allocr = node_allocr(src); + if (src_allocr == NULL) { + node_allocr(src) = node_allocr; + } + } + } + //printf("PASS 3 ASSIGNMENTS\n"); sched_print_assignments(sched, graph); + + // pass 4: split graph, find tensors that need to be copied + // TODO: + // - when switching from a less preferred backend to a more preferred backend, check if it is possible to move the switch to an earlier point for the same cost + // find first backend + int cur_split = 0; + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + if (node->view_src == NULL) { + sched->splits[0].tallocr = node_allocr(node); + break; + } + } + sched->splits[0].i_start = 0; + sched->splits[0].n_inputs = 0; + memset(sched->splits[0].inputs, 0, sizeof(sched->splits[0].inputs)); //HACK + ggml_tallocr_t cur_allocr = sched->splits[0].tallocr; + size_t cur_backend_id = sched_allocr_prio(sched, cur_allocr); + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + + if (ggml_is_view_op(node->op)) { + continue; + } + + ggml_tallocr_t node_allocr = node_allocr(node); + + if (node_allocr != cur_allocr) { + sched->splits[cur_split].i_end = i; + cur_split++; + GGML_ASSERT(cur_split < GGML_MAX_SPLITS); + sched->splits[cur_split].tallocr = node_allocr; + sched->splits[cur_split].i_start = i; + sched->splits[cur_split].n_inputs = 0; + memset(sched->splits[cur_split].inputs, 0, sizeof(sched->splits[cur_split].inputs)); //HACK + cur_allocr = node_allocr; + cur_backend_id = sched_allocr_prio(sched, cur_allocr); + } + + // find inputs that are not on the same backend + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + break; + } + ggml_tallocr_t src_allocr = node_allocr(src); + if (src_allocr != node_allocr) { + int n_inputs = sched->splits[cur_split].n_inputs++; + GGML_ASSERT(n_inputs < GGML_MAX_SPLIT_INPUTS); + sched->splits[cur_split].inputs[n_inputs] = (struct ggml_tensor *)src; + + // create copies + size_t id = hash_id(src); + if (sched->node_copies[id][cur_backend_id] == NULL) { + struct ggml_tensor * tensor_copy = ggml_dup_tensor_layout(sched->ctx, src); + sched->node_copies[id][cur_backend_id] = tensor_copy; + node_allocr(tensor_copy) = cur_allocr; + ggml_backend_t backend = ggml_tallocr_get_buffer(cur_allocr)->backend; + ggml_format_name(tensor_copy, "%s#%s", ggml_backend_name(backend), src->name); + } + node->src[j] = sched->node_copies[id][cur_backend_id]; + } + } + } + sched->splits[cur_split].i_end = graph->n_nodes; + sched->n_splits = cur_split + 1; + + //fprintf(stderr, "PASS 4 ASSIGNMENTS\n"); sched_print_assignments(sched, graph); fflush(stdout); + +#if 1 + // sanity check: all sources should have the same backend as the node + for (int i = 0; i < graph->n_nodes; i++) { + struct ggml_tensor * node = graph->nodes[i]; + ggml_tallocr_t node_allocr = node_allocr(node); + if (node_allocr == NULL) { + fprintf(stderr, "!!!!!!! %s has no backend\n", node->name); + } + for (int j = 0; j < GGML_MAX_SRC; j++) { + struct ggml_tensor * src = node->src[j]; + if (src == NULL) { + break; + } + ggml_tallocr_t src_allocr = node_allocr(src); + if (src_allocr != node_allocr /* && src_backend != NULL */) { // ignore nulls for now + fprintf(stderr, "!!!! %s has backend %s, src %d (%s) has backend %s\n", + node->name, node_allocr ? ggml_backend_name(ggml_tallocr_get_buffer(node_allocr)->backend) : "NULL", + j, src->name, src_allocr ? ggml_backend_name(ggml_tallocr_get_buffer(src_allocr)->backend) : "NULL"); + } + } + } +#endif + + // create copies of the graph for each split + // FIXME: avoid this copy, pass split inputs to ggml_gallocr_alloc_graph_n in some other way + struct ggml_cgraph * graph_copy = ggml_new_graph_custom(sched->ctx, graph->n_nodes + sched->n_splits*GGML_MAX_SPLIT_INPUTS, false); + for (int i = 0; i < sched->n_splits; i++) { + struct ggml_backend_sched_split * split = &sched->splits[i]; + split->graph = ggml_graph_view(sched->ctx, graph, split->i_start, split->i_end); + + // add inputs to the graph copy so that they are allocated by ggml-alloc at the start of the split + for (int j = 0; j < split->n_inputs; j++) { + struct ggml_tensor * input = split->inputs[j]; + struct ggml_tensor * input_cpy = sched->node_copies[hash_id(input)][sched_allocr_prio(sched, split->tallocr)]; + input_cpy->src[0] = input; + graph_copy->nodes[graph_copy->n_nodes++] = input_cpy; + } + + for (int j = split->i_start; j < split->i_end; j++) { + graph_copy->nodes[graph_copy->n_nodes++] = graph->nodes[j]; + } + } + sched->graph = graph_copy; +} + +static void sched_alloc_splits(ggml_backend_sched_t sched) { + ggml_gallocr_alloc_graph_n( + sched->galloc, + sched->graph, + sched->hash_set, + sched->node_talloc); +} + +static void sched_compute_splits(ggml_backend_sched_t sched) { + uint64_t copy_us[GGML_MAX_BACKENDS] = {0}; + uint64_t compute_us[GGML_MAX_BACKENDS] = {0}; + + struct ggml_backend_sched_split * splits = sched->splits; + + for (int i = 0; i < sched->n_splits; i++) { + struct ggml_backend_sched_split * split = &splits[i]; + ggml_backend_t split_backend = ggml_tallocr_get_buffer(split->tallocr)->backend; + int split_backend_id = sched_backend_prio(sched, split_backend); + + // copy the input tensors to the split backend + uint64_t copy_start_us = ggml_time_us(); + for (int j = 0; j < split->n_inputs; j++) { + struct ggml_tensor * input_cpy = sched->node_copies[hash_id(split->inputs[j])][sched_backend_prio(sched, split_backend)]; + if (split->inputs[j]->buffer == NULL) { + if (split->inputs[j]->view_src == NULL) { + fprintf(stderr, "input %s has no buffer and no view_src\n", split->inputs[j]->name); + exit(1); + } + struct ggml_tensor * view = split->inputs[j]; + view->backend = view->view_src->backend; + view->buffer = view->view_src->buffer; + view->data = (char *)view->view_src->data + view->view_offs; + ggml_backend_buffer_init_tensor(ggml_backend_sched_get_buffer(sched, view->buffer->backend), view); + } + if (input_cpy->buffer == NULL) { + fprintf(stderr, "input_cpy %s has no buffer\n", input_cpy->name); + exit(1); + } + GGML_ASSERT(split->inputs[j]->buffer->backend != input_cpy->buffer->backend); + GGML_ASSERT(input_cpy->buffer->backend == split_backend); + ggml_backend_tensor_copy(split->inputs[j], input_cpy); + } + // ggml_backend_synchronize(split_backend); + int64_t copy_end_us = ggml_time_us(); + copy_us[split_backend_id] += copy_end_us - copy_start_us; + +#if 0 + char split_filename[GGML_MAX_NAME]; + snprintf(split_filename, GGML_MAX_NAME, "split_%i_%s.dot", i, ggml_backend_name(split_backend)); + ggml_graph_dump_dot(split->graph, NULL, split_filename); +#endif + + uint64_t compute_start_us = ggml_time_us(); + ggml_backend_graph_compute(split_backend, split->graph); + // ggml_backend_synchronize(split_backend); + uint64_t compute_end_us = ggml_time_us(); + compute_us[split_backend_id] += compute_end_us - compute_start_us; + } + +#if 0 + // per-backend timings + fprintf(stderr, "sched_compute_splits times (%d splits):\n", sched->n_splits); + for (int i = 0; i < sched->n_backends; i++) { + if (copy_us[i] > 0 || compute_us[i] > 0) { + fprintf(stderr, "\t%5.5s: %lu us copy, %lu us compute\n", ggml_backend_name(sched->backends[i]), copy_us[i], compute_us[i]); + } + } +#endif +} + +static void sched_reset(ggml_backend_sched_t sched) { + for (int i = 0; i < sched->n_backends; i++) { + ggml_tallocr_reset(sched->tallocs[i]); + } +} + +ggml_backend_sched_t ggml_backend_sched_new(ggml_backend_t * backends, int n_backends) { + GGML_ASSERT(n_backends <= GGML_MAX_BACKENDS); + + struct ggml_backend_sched * sched = malloc(sizeof(struct ggml_backend_sched)); + memset(sched, 0, sizeof(struct ggml_backend_sched)); + + fprintf(stderr, "ggml_backend_sched size: %lu KB\n", sizeof(struct ggml_backend_sched)/1024); + + sched->n_backends = n_backends; + for (int i = 0; i < n_backends; i++) { + sched->backends[i] = backends[i]; + } + + sched->galloc = ggml_gallocr_new(); + + // init measure allocs for each backend + for (int i = 0; i < n_backends; i++) { + sched->tallocs[i] = ggml_tallocr_new_measure_from_backend(backends[i]); + } + + return sched; +} + +void ggml_backend_sched_free(ggml_backend_sched_t sched) { + if (sched == NULL) { + return; + } + for (int i = 0; i < sched->n_backends; i++) { + ggml_tallocr_free(sched->tallocs[i]); + } + ggml_gallocr_free(sched->galloc); + free(sched->hash_set.keys); + free(sched->node_talloc); + free(sched->node_copies); + free(sched); +} + +void ggml_backend_sched_init_measure(ggml_backend_sched_t sched, struct ggml_cgraph * measure_graph) { + // initialize hash tables + size_t hash_size = measure_graph->visited_hash_table.size + GGML_MAX_SPLITS*GGML_MAX_SPLIT_INPUTS; + sched->hash_set.size = hash_size; + sched->hash_set.keys = malloc(sizeof(sched->hash_set.keys[0]) * hash_size); + sched->node_talloc = malloc(sizeof(sched->node_talloc[0]) * hash_size); + sched->node_copies = malloc(sizeof(sched->node_copies[0]) * hash_size); + + sched_split_graph(sched, measure_graph); + sched_alloc_splits(sched); + + // allocate buffers and reset allocators + for (int i = 0; i < sched->n_backends; i++) { + size_t size = ggml_tallocr_max_size(sched->tallocs[i]); + ggml_tallocr_free(sched->tallocs[i]); + sched->tallocs[i] = ggml_tallocr_new_from_backend(sched->backends[i], size); + } + + sched_reset(sched); +} + +void ggml_backend_sched_graph_compute(ggml_backend_sched_t sched, struct ggml_cgraph * graph) { + GGML_ASSERT(sched->hash_set.size >= graph->visited_hash_table.size + GGML_MAX_SPLITS*GGML_MAX_SPLIT_INPUTS); + + sched_split_graph(sched, graph); + sched_alloc_splits(sched); + sched_compute_splits(sched); + sched_reset(sched); +} + +ggml_tallocr_t ggml_backend_sched_get_tallocr(ggml_backend_sched_t sched, ggml_backend_t backend) { + int backend_index = sched_backend_prio(sched, backend); + return sched->tallocs[backend_index]; +} + +ggml_backend_buffer_t ggml_backend_sched_get_buffer(ggml_backend_sched_t sched, ggml_backend_t backend) { + int backend_index = sched_backend_prio(sched, backend); + return ggml_tallocr_get_buffer(sched->tallocs[backend_index]); +} + +void ggml_backend_sched_set_node_backend(ggml_backend_sched_t sched, struct ggml_tensor * node, ggml_backend_t backend) { + int backend_index = sched_backend_prio(sched, backend); + GGML_ASSERT(backend_index >= 0 && backend_index < sched->n_backends); + node_allocr(node) = sched->tallocs[backend_index]; +} diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.h b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.h new file mode 100644 index 0000000..9666873 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-backend.h @@ -0,0 +1,136 @@ +#pragma once + +#include "ggml.h" +#include "ggml-alloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + + // + // Backend buffer + // + + struct ggml_backend_buffer; + typedef struct ggml_backend_buffer * ggml_backend_buffer_t; + + // backend buffer functions + GGML_API void ggml_backend_buffer_free (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_alignment (ggml_backend_buffer_t buffer); + GGML_API void * ggml_backend_buffer_get_base (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_size (ggml_backend_buffer_t buffer); + GGML_API size_t ggml_backend_buffer_get_alloc_size(ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + GGML_API void ggml_backend_buffer_init_tensor (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + GGML_API void ggml_backend_buffer_free_tensor (ggml_backend_buffer_t buffer, struct ggml_tensor * tensor); + + // + // Backend + // + + struct ggml_backend; + typedef struct ggml_backend * ggml_backend_t; + typedef void * ggml_backend_graph_plan_t; + + GGML_API ggml_backend_t ggml_get_backend(const struct ggml_tensor * tensor); + + GGML_API const char * ggml_backend_name(ggml_backend_t backend); + GGML_API void ggml_backend_free(ggml_backend_t backend); + + GGML_API ggml_backend_buffer_t ggml_backend_alloc_buffer(ggml_backend_t backend, size_t size); + + GGML_API size_t ggml_backend_get_alignment(ggml_backend_t backend); + + GGML_API void ggml_backend_tensor_set_async( struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + GGML_API void ggml_backend_tensor_get_async(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + + GGML_API void ggml_backend_tensor_set( struct ggml_tensor * tensor, const void * data, size_t offset, size_t size); + GGML_API void ggml_backend_tensor_get(const struct ggml_tensor * tensor, void * data, size_t offset, size_t size); + + GGML_API void ggml_backend_synchronize(ggml_backend_t backend); + + GGML_API ggml_backend_graph_plan_t ggml_backend_graph_plan_create (ggml_backend_t backend, struct ggml_cgraph * cgraph); + + GGML_API void ggml_backend_graph_plan_free (ggml_backend_t backend, ggml_backend_graph_plan_t plan); + GGML_API void ggml_backend_graph_plan_compute(ggml_backend_t backend, ggml_backend_graph_plan_t plan); + GGML_API void ggml_backend_graph_compute (ggml_backend_t backend, struct ggml_cgraph * cgraph); + GGML_API bool ggml_backend_supports_op (ggml_backend_t backend, const struct ggml_tensor * op); + + // tensor copy between different backends + GGML_API void ggml_backend_tensor_copy(struct ggml_tensor * src, struct ggml_tensor * dst); + + // + // CPU backend + // + + GGML_API ggml_backend_t ggml_backend_cpu_init(void); + + GGML_API bool ggml_backend_is_cpu(ggml_backend_t backend); + GGML_API void ggml_backend_cpu_set_n_threads(ggml_backend_t backend_cpu, int n_threads); + + // Create a backend buffer from an existing pointer + GGML_API ggml_backend_buffer_t ggml_backend_cpu_buffer_from_ptr(ggml_backend_t backend_cpu, void * ptr, size_t size); + + + // + // Backend scheduler + // + + // The backend scheduler allows for multiple backends to be used together + // Handles compute buffer allocation, assignment of tensors to backends, and copying of tensors between backends + // The backends are selected based on: + // - the backend that supports the operation + // - the location of the pre-allocated tensors (e.g. the weights) + /* + Example usage: + + sched = ggml_backend_sched_new({backend_gpu, backend_gpu2, backend_cpu}, num_backends); + // sched is initialized with measure allocators and cannot be used until allocated with a measure graph + + // initialize buffers from a measure graph + measure_graph = build_graph(sched); // use the allocr to allocate inputs as needed + + // in build_graph: + build_graph(...) { + // allocating tensors in a specific backend (optional, recommended: pre-allocate inputs in a different buffer) + alloc_cpu = ggml_backend_sched_get_allocr(sched, backend_cpu); + ggml_allocr_alloc(alloc_cpu, tensor); + + // manually assigning nodes to a backend (optional, shouldn't be needed in most cases) + struct ggml_tensor * node = ggml_mul_mat(ctx, ...); + ggml_backend_sched_set_node_backend(sched, node, backend_gpu); + } + + // allocate backend buffers from measure graph + ggml_backend_sched_init_measure(sched, measure_graph); + + // the scheduler is now ready to compute graphs + + // compute + graph = build_graph(sched); + ggml_backend_sched_graph_compute(sched, graph); + */ + + struct ggml_backend_sched; + typedef struct ggml_backend_sched * ggml_backend_sched_t; + + // Initialize a backend scheduler + GGML_API ggml_backend_sched_t ggml_backend_sched_new(ggml_backend_t * backends, int n_backends); + + GGML_API void ggml_backend_sched_free(ggml_backend_sched_t sched); + + // Initialize backend buffers from a measure graph + GGML_API void ggml_backend_sched_init_measure(ggml_backend_sched_t sched, struct ggml_cgraph * measure_graph); + + GGML_API ggml_tallocr_t ggml_backend_sched_get_tallocr(ggml_backend_sched_t sched, ggml_backend_t backend); + GGML_API ggml_backend_buffer_t ggml_backend_sched_get_buffer (ggml_backend_sched_t sched, ggml_backend_t backend); + + GGML_API void ggml_backend_sched_set_node_backend(ggml_backend_sched_t sched, struct ggml_tensor * node, ggml_backend_t backend); + + // Allocate a graph on the backend scheduler + GGML_API void ggml_backend_sched_graph_compute( + ggml_backend_sched_t sched, + struct ggml_cgraph * graph); + +#ifdef __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-impl.h b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-impl.h new file mode 100644 index 0000000..d88f261 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-impl.h @@ -0,0 +1,249 @@ +#pragma once + +#include "ggml.h" + +// GGML internal header + +#include +#include +#include +#include // memcpy +#include // fabsf + +#ifdef __cplusplus +extern "C" { +#endif + +// static_assert should be a #define, but if it's not, +// fall back to the _Static_assert C11 keyword. +// if C99 - static_assert is noop +// ref: https://stackoverflow.com/a/53923785/4039976 +#ifndef static_assert +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201100L) +#define static_assert(cond, msg) _Static_assert(cond, msg) +#else +#define static_assert(cond, msg) struct global_scope_noop_trick +#endif +#endif + +// __FMA__ and __F16C__ are not defined in MSVC, however they are implied with AVX2/AVX512 +#if defined(_MSC_VER) && (defined(__AVX2__) || defined(__AVX512F__)) +#ifndef __FMA__ +#define __FMA__ +#endif +#ifndef __F16C__ +#define __F16C__ +#endif +#ifndef __SSE3__ +#define __SSE3__ +#endif +#endif + +#undef MIN +#undef MAX + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +// 16-bit float +// on Arm, we use __fp16 +// on x86, we use uint16_t +#if defined(__ARM_NEON) && !defined(_MSC_VER) + +// if YCM cannot find , make a symbolic link to it, for example: +// +// $ ln -sfn /Library/Developer/CommandLineTools/usr/lib/clang/13.1.6/include/arm_neon.h ./src/ +// +#include + +#define GGML_COMPUTE_FP16_TO_FP32(x) ((float) (x)) +#define GGML_COMPUTE_FP32_TO_FP16(x) (x) + +#define GGML_FP16_TO_FP32(x) ((float) (x)) +#define GGML_FP32_TO_FP16(x) (x) + +#else + +#ifdef __wasm_simd128__ +#include +#else +#ifdef __POWER9_VECTOR__ +#include +#undef bool +#define bool _Bool +#else +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#else +#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) || defined(__SSE3__) +#if !defined(__riscv) +#include +#endif +#endif +#endif +#endif +#endif + +#ifdef __riscv_v_intrinsic +#include +#endif + +#ifdef __F16C__ + +#ifdef _MSC_VER +#define GGML_COMPUTE_FP16_TO_FP32(x) _mm_cvtss_f32(_mm_cvtph_ps(_mm_cvtsi32_si128(x))) +#define GGML_COMPUTE_FP32_TO_FP16(x) _mm_extract_epi16(_mm_cvtps_ph(_mm_set_ss(x), 0), 0) +#else +#define GGML_COMPUTE_FP16_TO_FP32(x) _cvtsh_ss(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) _cvtss_sh(x, 0) +#endif + +#elif defined(__POWER9_VECTOR__) + +#define GGML_COMPUTE_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) ggml_compute_fp32_to_fp16(x) +/* the inline asm below is about 12% faster than the lookup method */ +#define GGML_FP16_TO_FP32(x) GGML_COMPUTE_FP16_TO_FP32(x) +#define GGML_FP32_TO_FP16(x) GGML_COMPUTE_FP32_TO_FP16(x) + +static inline float ggml_compute_fp16_to_fp32(ggml_fp16_t h) { + register float f; + register double d; + __asm__( + "mtfprd %0,%2\n" + "xscvhpdp %0,%0\n" + "frsp %1,%0\n" : + /* temp */ "=d"(d), + /* out */ "=f"(f): + /* in */ "r"(h)); + return f; +} + +static inline ggml_fp16_t ggml_compute_fp32_to_fp16(float f) { + register double d; + register ggml_fp16_t r; + __asm__( /* xscvdphp can work on double or single precision */ + "xscvdphp %0,%2\n" + "mffprd %1,%0\n" : + /* temp */ "=d"(d), + /* out */ "=r"(r): + /* in */ "f"(f)); + return r; +} + +#else + +// FP16 <-> FP32 +// ref: https://github.com/Maratyszcza/FP16 + +static inline float fp32_from_bits(uint32_t w) { + union { + uint32_t as_bits; + float as_value; + } fp32; + fp32.as_bits = w; + return fp32.as_value; +} + +static inline uint32_t fp32_to_bits(float f) { + union { + float as_value; + uint32_t as_bits; + } fp32; + fp32.as_value = f; + return fp32.as_bits; +} + +static inline float ggml_compute_fp16_to_fp32(ggml_fp16_t h) { + const uint32_t w = (uint32_t) h << 16; + const uint32_t sign = w & UINT32_C(0x80000000); + const uint32_t two_w = w + w; + + const uint32_t exp_offset = UINT32_C(0xE0) << 23; +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__) + const float exp_scale = 0x1.0p-112f; +#else + const float exp_scale = fp32_from_bits(UINT32_C(0x7800000)); +#endif + const float normalized_value = fp32_from_bits((two_w >> 4) + exp_offset) * exp_scale; + + const uint32_t magic_mask = UINT32_C(126) << 23; + const float magic_bias = 0.5f; + const float denormalized_value = fp32_from_bits((two_w >> 17) | magic_mask) - magic_bias; + + const uint32_t denormalized_cutoff = UINT32_C(1) << 27; + const uint32_t result = sign | + (two_w < denormalized_cutoff ? fp32_to_bits(denormalized_value) : fp32_to_bits(normalized_value)); + return fp32_from_bits(result); +} + +static inline ggml_fp16_t ggml_compute_fp32_to_fp16(float f) { +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) && !defined(__STRICT_ANSI__) + const float scale_to_inf = 0x1.0p+112f; + const float scale_to_zero = 0x1.0p-110f; +#else + const float scale_to_inf = fp32_from_bits(UINT32_C(0x77800000)); + const float scale_to_zero = fp32_from_bits(UINT32_C(0x08800000)); +#endif + float base = (fabsf(f) * scale_to_inf) * scale_to_zero; + + const uint32_t w = fp32_to_bits(f); + const uint32_t shl1_w = w + w; + const uint32_t sign = w & UINT32_C(0x80000000); + uint32_t bias = shl1_w & UINT32_C(0xFF000000); + if (bias < UINT32_C(0x71000000)) { + bias = UINT32_C(0x71000000); + } + + base = fp32_from_bits((bias >> 1) + UINT32_C(0x07800000)) + base; + const uint32_t bits = fp32_to_bits(base); + const uint32_t exp_bits = (bits >> 13) & UINT32_C(0x00007C00); + const uint32_t mantissa_bits = bits & UINT32_C(0x00000FFF); + const uint32_t nonsign = exp_bits + mantissa_bits; + return (sign >> 16) | (shl1_w > UINT32_C(0xFF000000) ? UINT16_C(0x7E00) : nonsign); +} + +#define GGML_COMPUTE_FP16_TO_FP32(x) ggml_compute_fp16_to_fp32(x) +#define GGML_COMPUTE_FP32_TO_FP16(x) ggml_compute_fp32_to_fp16(x) + +#endif // __F16C__ + +#endif // __ARM_NEON + +// precomputed f32 table for f16 (256 KB) +// defined in ggml.c, initialized in ggml_init() +extern float ggml_table_f32_f16[1 << 16]; + +// On ARM NEON, it's quicker to directly convert x -> x instead of calling into ggml_lookup_fp16_to_fp32, +// so we define GGML_FP16_TO_FP32 and GGML_FP32_TO_FP16 elsewhere for NEON. +// This is also true for POWER9. +#if !defined(GGML_FP16_TO_FP32) || !defined(GGML_FP32_TO_FP16) + +inline static float ggml_lookup_fp16_to_fp32(ggml_fp16_t f) { + uint16_t s; + memcpy(&s, &f, sizeof(uint16_t)); + return ggml_table_f32_f16[s]; +} + +#define GGML_FP16_TO_FP32(x) ggml_lookup_fp16_to_fp32(x) +#define GGML_FP32_TO_FP16(x) GGML_COMPUTE_FP32_TO_FP16(x) + +#endif + +#define GGML_HASHTABLE_FULL ((size_t)-1) +#define GGML_HASHTABLE_ALREADY_EXISTS ((size_t)-2) + +bool ggml_hash_contains (const struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// returns GGML_HASHTABLE_FULL if table is full, otherwise the current index of the key or where it should be inserted +size_t ggml_hash_find (const struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// returns GGML_HAHSHTABLE_ALREADY_EXISTS if key already exists, index otherwise, asserts if table is full +size_t ggml_hash_insert ( struct ggml_hash_set hash_set, struct ggml_tensor * key); + +// return index, asserts if table is full +size_t ggml_hash_find_or_insert( struct ggml_hash_set hash_set, struct ggml_tensor * key); + +#ifdef __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.c b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.c new file mode 100644 index 0000000..740be6d --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.c @@ -0,0 +1,7282 @@ +#include "ggml-quants.h" +#include "ggml-impl.h" + +#include +#include +#include +#include + +#ifdef __ARM_NEON + +// if YCM cannot find , make a symbolic link to it, for example: +// +// $ ln -sfn /Library/Developer/CommandLineTools/usr/lib/clang/13.1.6/include/arm_neon.h ./src/ +// +#include + +#if !defined(__aarch64__) +inline static int32_t vaddvq_s16(int16x8_t v) { + return + (int32_t)vgetq_lane_s16(v, 0) + (int32_t)vgetq_lane_s16(v, 1) + + (int32_t)vgetq_lane_s16(v, 2) + (int32_t)vgetq_lane_s16(v, 3) + + (int32_t)vgetq_lane_s16(v, 4) + (int32_t)vgetq_lane_s16(v, 5) + + (int32_t)vgetq_lane_s16(v, 6) + (int32_t)vgetq_lane_s16(v, 7); +} + +inline static int16x8_t vpaddq_s16(int16x8_t a, int16x8_t b) { + int16x4_t a0 = vpadd_s16(vget_low_s16(a), vget_high_s16(a)); + int16x4_t b0 = vpadd_s16(vget_low_s16(b), vget_high_s16(b)); + return vcombine_s16(a0, b0); +} + +inline static int32_t vaddvq_s32(int32x4_t v) { + return vgetq_lane_s32(v, 0) + vgetq_lane_s32(v, 1) + vgetq_lane_s32(v, 2) + vgetq_lane_s32(v, 3); +} +#endif + +#else + +#ifdef __wasm_simd128__ +#include +#else +#ifdef __POWER9_VECTOR__ +#include +#undef bool +#define bool _Bool +#else +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#else +#if !defined(__riscv) && !defined(__s390__) +#include +#endif +#endif +#endif +#endif +#endif + +#ifdef __riscv_v_intrinsic +#include +#endif + +#undef MIN +#undef MAX +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define MM256_SET_M128I(a, b) _mm256_insertf128_si256(_mm256_castsi128_si256(b), (a), 1) + +#if defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) +// multiply int8_t, add results pairwise twice +static inline __m128i mul_sum_i8_pairs(const __m128i x, const __m128i y) { + // Get absolute values of x vectors + const __m128i ax = _mm_sign_epi8(x, x); + // Sign the values of the y vectors + const __m128i sy = _mm_sign_epi8(y, x); + // Perform multiplication and create 16-bit values + const __m128i dot = _mm_maddubs_epi16(ax, sy); + const __m128i ones = _mm_set1_epi16(1); + return _mm_madd_epi16(ones, dot); +} + +#if __AVX__ || __AVX2__ || __AVX512F__ +// horizontally add 8 floats +static inline float hsum_float_8(const __m256 x) { + __m128 res = _mm256_extractf128_ps(x, 1); + res = _mm_add_ps(res, _mm256_castps256_ps128(x)); + res = _mm_add_ps(res, _mm_movehl_ps(res, res)); + res = _mm_add_ss(res, _mm_movehdup_ps(res)); + return _mm_cvtss_f32(res); +} + +// horizontally add 8 int32_t +static inline int hsum_i32_8(const __m256i a) { + const __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(a), _mm256_extractf128_si256(a, 1)); + const __m128i hi64 = _mm_unpackhi_epi64(sum128, sum128); + const __m128i sum64 = _mm_add_epi32(hi64, sum128); + const __m128i hi32 = _mm_shuffle_epi32(sum64, _MM_SHUFFLE(2, 3, 0, 1)); + return _mm_cvtsi128_si32(_mm_add_epi32(sum64, hi32)); +} + +// horizontally add 4 int32_t +static inline int hsum_i32_4(const __m128i a) { + const __m128i hi64 = _mm_unpackhi_epi64(a, a); + const __m128i sum64 = _mm_add_epi32(hi64, a); + const __m128i hi32 = _mm_shuffle_epi32(sum64, _MM_SHUFFLE(2, 3, 0, 1)); + return _mm_cvtsi128_si32(_mm_add_epi32(sum64, hi32)); +} + +#if defined(__AVX2__) || defined(__AVX512F__) +// spread 32 bits to 32 bytes { 0x00, 0xFF } +static inline __m256i bytes_from_bits_32(const uint8_t * x) { + uint32_t x32; + memcpy(&x32, x, sizeof(uint32_t)); + const __m256i shuf_mask = _mm256_set_epi64x( + 0x0303030303030303, 0x0202020202020202, + 0x0101010101010101, 0x0000000000000000); + __m256i bytes = _mm256_shuffle_epi8(_mm256_set1_epi32(x32), shuf_mask); + const __m256i bit_mask = _mm256_set1_epi64x(0x7fbfdfeff7fbfdfe); + bytes = _mm256_or_si256(bytes, bit_mask); + return _mm256_cmpeq_epi8(bytes, _mm256_set1_epi64x(-1)); +} + +// Unpack 32 4-bit fields into 32 bytes +// The output vector contains 32 bytes, each one in [ 0 .. 15 ] interval +static inline __m256i bytes_from_nibbles_32(const uint8_t * rsi) +{ + const __m128i tmp = _mm_loadu_si128((const __m128i *)rsi); + const __m256i bytes = MM256_SET_M128I(_mm_srli_epi16(tmp, 4), tmp); + const __m256i lowMask = _mm256_set1_epi8( 0xF ); + return _mm256_and_si256(lowMask, bytes); +} + +// add int16_t pairwise and return as float vector +static inline __m256 sum_i16_pairs_float(const __m256i x) { + const __m256i ones = _mm256_set1_epi16(1); + const __m256i summed_pairs = _mm256_madd_epi16(ones, x); + return _mm256_cvtepi32_ps(summed_pairs); +} + +static inline __m256 mul_sum_us8_pairs_float(const __m256i ax, const __m256i sy) { +#if __AVXVNNI__ + const __m256i zero = _mm256_setzero_si256(); + const __m256i summed_pairs = _mm256_dpbusd_epi32(zero, ax, sy); + return _mm256_cvtepi32_ps(summed_pairs); +#else + // Perform multiplication and create 16-bit values + const __m256i dot = _mm256_maddubs_epi16(ax, sy); + return sum_i16_pairs_float(dot); +#endif +} + +// multiply int8_t, add results pairwise twice and return as float vector +static inline __m256 mul_sum_i8_pairs_float(const __m256i x, const __m256i y) { +#if __AVXVNNIINT8__ + const __m256i zero = _mm256_setzero_si256(); + const __m256i summed_pairs = _mm256_dpbssd_epi32(zero, x, y); + return _mm256_cvtepi32_ps(summed_pairs); +#else + // Get absolute values of x vectors + const __m256i ax = _mm256_sign_epi8(x, x); + // Sign the values of the y vectors + const __m256i sy = _mm256_sign_epi8(y, x); + return mul_sum_us8_pairs_float(ax, sy); +#endif +} + +static inline __m128i packNibbles( __m256i bytes ) +{ + // Move bits within 16-bit lanes from 0000_abcd_0000_efgh into 0000_0000_abcd_efgh +#if __AVX512F__ + const __m256i bytes_srli_4 = _mm256_srli_epi16(bytes, 4); // 0000_0000_abcd_0000 + bytes = _mm256_or_si256(bytes, bytes_srli_4); // 0000_abcd_abcd_efgh + return _mm256_cvtepi16_epi8(bytes); // abcd_efgh +#else + const __m256i lowByte = _mm256_set1_epi16( 0xFF ); + __m256i high = _mm256_andnot_si256( lowByte, bytes ); + __m256i low = _mm256_and_si256( lowByte, bytes ); + high = _mm256_srli_epi16( high, 4 ); + bytes = _mm256_or_si256( low, high ); + + // Compress uint16_t lanes into bytes + __m128i r0 = _mm256_castsi256_si128( bytes ); + __m128i r1 = _mm256_extracti128_si256( bytes, 1 ); + return _mm_packus_epi16( r0, r1 ); +#endif +} +#elif defined(__AVX__) +// spread 32 bits to 32 bytes { 0x00, 0xFF } +static inline __m256i bytes_from_bits_32(const uint8_t * x) { + uint32_t x32; + memcpy(&x32, x, sizeof(uint32_t)); + const __m128i shuf_maskl = _mm_set_epi64x(0x0101010101010101, 0x0000000000000000); + const __m128i shuf_maskh = _mm_set_epi64x(0x0303030303030303, 0x0202020202020202); + __m128i bytesl = _mm_shuffle_epi8(_mm_set1_epi32(x32), shuf_maskl); + __m128i bytesh = _mm_shuffle_epi8(_mm_set1_epi32(x32), shuf_maskh); + const __m128i bit_mask = _mm_set1_epi64x(0x7fbfdfeff7fbfdfe); + bytesl = _mm_or_si128(bytesl, bit_mask); + bytesh = _mm_or_si128(bytesh, bit_mask); + bytesl = _mm_cmpeq_epi8(bytesl, _mm_set1_epi64x(-1)); + bytesh = _mm_cmpeq_epi8(bytesh, _mm_set1_epi64x(-1)); + return MM256_SET_M128I(bytesh, bytesl); +} + +// Unpack 32 4-bit fields into 32 bytes +// The output vector contains 32 bytes, each one in [ 0 .. 15 ] interval +static inline __m256i bytes_from_nibbles_32(const uint8_t * rsi) +{ + // Load 16 bytes from memory + __m128i tmpl = _mm_loadu_si128((const __m128i *)rsi); + __m128i tmph = _mm_srli_epi16(tmpl, 4); + const __m128i lowMask = _mm_set1_epi8(0xF); + tmpl = _mm_and_si128(lowMask, tmpl); + tmph = _mm_and_si128(lowMask, tmph); + return MM256_SET_M128I(tmph, tmpl); +} + +// add int16_t pairwise and return as float vector +static inline __m256 sum_i16_pairs_float(const __m128i xh, const __m128i xl) { + const __m128i ones = _mm_set1_epi16(1); + const __m128i summed_pairsl = _mm_madd_epi16(ones, xl); + const __m128i summed_pairsh = _mm_madd_epi16(ones, xh); + const __m256i summed_pairs = MM256_SET_M128I(summed_pairsh, summed_pairsl); + return _mm256_cvtepi32_ps(summed_pairs); +} + +static inline __m256 mul_sum_us8_pairs_float(const __m256i ax, const __m256i sy) { + const __m128i axl = _mm256_castsi256_si128(ax); + const __m128i axh = _mm256_extractf128_si256(ax, 1); + const __m128i syl = _mm256_castsi256_si128(sy); + const __m128i syh = _mm256_extractf128_si256(sy, 1); + // Perform multiplication and create 16-bit values + const __m128i dotl = _mm_maddubs_epi16(axl, syl); + const __m128i doth = _mm_maddubs_epi16(axh, syh); + return sum_i16_pairs_float(doth, dotl); +} + +// multiply int8_t, add results pairwise twice and return as float vector +static inline __m256 mul_sum_i8_pairs_float(const __m256i x, const __m256i y) { + const __m128i xl = _mm256_castsi256_si128(x); + const __m128i xh = _mm256_extractf128_si256(x, 1); + const __m128i yl = _mm256_castsi256_si128(y); + const __m128i yh = _mm256_extractf128_si256(y, 1); + // Get absolute values of x vectors + const __m128i axl = _mm_sign_epi8(xl, xl); + const __m128i axh = _mm_sign_epi8(xh, xh); + // Sign the values of the y vectors + const __m128i syl = _mm_sign_epi8(yl, xl); + const __m128i syh = _mm_sign_epi8(yh, xh); + // Perform multiplication and create 16-bit values + const __m128i dotl = _mm_maddubs_epi16(axl, syl); + const __m128i doth = _mm_maddubs_epi16(axh, syh); + return sum_i16_pairs_float(doth, dotl); +} + +static inline __m128i packNibbles( __m128i bytes1, __m128i bytes2 ) +{ + // Move bits within 16-bit lanes from 0000_abcd_0000_efgh into 0000_0000_abcd_efgh + const __m128i lowByte = _mm_set1_epi16( 0xFF ); + __m128i high = _mm_andnot_si128( lowByte, bytes1 ); + __m128i low = _mm_and_si128( lowByte, bytes1 ); + high = _mm_srli_epi16( high, 4 ); + bytes1 = _mm_or_si128( low, high ); + high = _mm_andnot_si128( lowByte, bytes2 ); + low = _mm_and_si128( lowByte, bytes2 ); + high = _mm_srli_epi16( high, 4 ); + bytes2 = _mm_or_si128( low, high ); + + return _mm_packus_epi16( bytes1, bytes2); +} +#endif +#elif defined(__SSSE3__) +// horizontally add 4x4 floats +static inline float hsum_float_4x4(const __m128 a, const __m128 b, const __m128 c, const __m128 d) { + __m128 res_0 =_mm_hadd_ps(a, b); + __m128 res_1 =_mm_hadd_ps(c, d); + __m128 res =_mm_hadd_ps(res_0, res_1); + res =_mm_hadd_ps(res, res); + res =_mm_hadd_ps(res, res); + + return _mm_cvtss_f32(res); +} +#endif // __AVX__ || __AVX2__ || __AVX512F__ +#endif // defined(__AVX__) || defined(__AVX2__) || defined(__AVX512F__) || defined(__SSSE3__) + +#if defined(__ARM_NEON) + +#if !defined(__aarch64__) + +inline static int32_t vaddvq_s32(int32x4_t v) { + return vgetq_lane_s32(v, 0) + vgetq_lane_s32(v, 1) + vgetq_lane_s32(v, 2) + vgetq_lane_s32(v, 3); +} + +inline static float vaddvq_f32(float32x4_t v) { + return vgetq_lane_f32(v, 0) + vgetq_lane_f32(v, 1) + vgetq_lane_f32(v, 2) + vgetq_lane_f32(v, 3); +} + +inline static float vmaxvq_f32(float32x4_t v) { + return + MAX(MAX(vgetq_lane_f32(v, 0), vgetq_lane_f32(v, 1)), + MAX(vgetq_lane_f32(v, 2), vgetq_lane_f32(v, 3))); +} + +inline static int32x4_t vcvtnq_s32_f32(float32x4_t v) { + int32x4_t res; + + res[0] = roundf(vgetq_lane_f32(v, 0)); + res[1] = roundf(vgetq_lane_f32(v, 1)); + res[2] = roundf(vgetq_lane_f32(v, 2)); + res[3] = roundf(vgetq_lane_f32(v, 3)); + + return res; +} + +#endif +#endif + +#if defined(__ARM_NEON) || defined(__wasm_simd128__) +#define B1(c,s,n) 0x ## n ## c , 0x ## n ## s +#define B2(c,s,n) B1(c,s,n ## c), B1(c,s,n ## s) +#define B3(c,s,n) B2(c,s,n ## c), B2(c,s,n ## s) +#define B4(c,s,n) B3(c,s,n ## c), B3(c,s,n ## s) +#define B5(c,s,n) B4(c,s,n ## c), B4(c,s,n ## s) +#define B6(c,s,n) B5(c,s,n ## c), B5(c,s,n ## s) +#define B7(c,s,n) B6(c,s,n ## c), B6(c,s,n ## s) +#define B8(c,s ) B7(c,s, c), B7(c,s, s) + +// precomputed tables for expanding 8bits to 8 bytes: +static const uint64_t table_b2b_0[1 << 8] = { B8(00, 10) }; // ( b) << 4 +static const uint64_t table_b2b_1[1 << 8] = { B8(10, 00) }; // (!b) << 4 +#endif + +// reference implementation for deterministic creation of model files +void quantize_row_q4_0_reference(const float * restrict x, block_q4_0 * restrict y, int k) { + static const int qk = QK4_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + float max = 0.0f; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + if (amax < fabsf(v)) { + amax = fabsf(v); + max = v; + } + } + + const float d = max / -8; + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < qk/2; ++j) { + const float x0 = x[i*qk + 0 + j]*id; + const float x1 = x[i*qk + qk/2 + j]*id; + + const uint8_t xi0 = MIN(15, (int8_t)(x0 + 8.5f)); + const uint8_t xi1 = MIN(15, (int8_t)(x1 + 8.5f)); + + y[i].qs[j] = xi0; + y[i].qs[j] |= xi1 << 4; + } + } +} + +void quantize_row_q4_0(const float * restrict x, void * restrict y, int k) { + quantize_row_q4_0_reference(x, y, k); +} + +void quantize_row_q4_1_reference(const float * restrict x, block_q4_1 * restrict y, int k) { + const int qk = QK4_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float min = FLT_MAX; + float max = -FLT_MAX; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + + if (v < min) min = v; + if (v > max) max = v; + } + + const float d = (max - min) / ((1 << 4) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + y[i].m = GGML_FP32_TO_FP16(min); + + for (int j = 0; j < qk/2; ++j) { + const float x0 = (x[i*qk + 0 + j] - min)*id; + const float x1 = (x[i*qk + qk/2 + j] - min)*id; + + const uint8_t xi0 = MIN(15, (int8_t)(x0 + 0.5f)); + const uint8_t xi1 = MIN(15, (int8_t)(x1 + 0.5f)); + + y[i].qs[j] = xi0; + y[i].qs[j] |= xi1 << 4; + } + } +} + +void quantize_row_q4_1(const float * restrict x, void * restrict y, int k) { + quantize_row_q4_1_reference(x, y, k); +} + +void quantize_row_q5_0_reference(const float * restrict x, block_q5_0 * restrict y, int k) { + static const int qk = QK5_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + float max = 0.0f; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + if (amax < fabsf(v)) { + amax = fabsf(v); + max = v; + } + } + + const float d = max / -16; + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + uint32_t qh = 0; + + for (int j = 0; j < qk/2; ++j) { + const float x0 = x[i*qk + 0 + j]*id; + const float x1 = x[i*qk + qk/2 + j]*id; + + const uint8_t xi0 = MIN(31, (int8_t)(x0 + 16.5f)); + const uint8_t xi1 = MIN(31, (int8_t)(x1 + 16.5f)); + + y[i].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + qk/2); + } + + memcpy(&y[i].qh, &qh, sizeof(qh)); + } +} + +void quantize_row_q5_0(const float * restrict x, void * restrict y, int k) { + quantize_row_q5_0_reference(x, y, k); +} + +void quantize_row_q5_1_reference(const float * restrict x, block_q5_1 * restrict y, int k) { + const int qk = QK5_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + float min = FLT_MAX; + float max = -FLT_MAX; + + for (int j = 0; j < qk; j++) { + const float v = x[i*qk + j]; + + if (v < min) min = v; + if (v > max) max = v; + } + + const float d = (max - min) / ((1 << 5) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + y[i].m = GGML_FP32_TO_FP16(min); + + uint32_t qh = 0; + + for (int j = 0; j < qk/2; ++j) { + const float x0 = (x[i*qk + 0 + j] - min)*id; + const float x1 = (x[i*qk + qk/2 + j] - min)*id; + + const uint8_t xi0 = (uint8_t)(x0 + 0.5f); + const uint8_t xi1 = (uint8_t)(x1 + 0.5f); + + y[i].qs[j] = (xi0 & 0x0F) | ((xi1 & 0x0F) << 4); + + // get the 5-th bit and store it in qh at the right position + qh |= ((xi0 & 0x10u) >> 4) << (j + 0); + qh |= ((xi1 & 0x10u) >> 4) << (j + qk/2); + } + + memcpy(&y[i].qh, &qh, sizeof(y[i].qh)); + } +} + +void quantize_row_q5_1(const float * restrict x, void * restrict y, int k) { + quantize_row_q5_1_reference(x, y, k); +} + +// reference implementation for deterministic creation of model files +void quantize_row_q8_0_reference(const float * restrict x, block_q8_0 * restrict y, int k) { + assert(k % QK8_0 == 0); + const int nb = k / QK8_0; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + + for (int j = 0; j < QK8_0; j++) { + const float v = x[i*QK8_0 + j]; + amax = MAX(amax, fabsf(v)); + } + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < QK8_0; ++j) { + const float x0 = x[i*QK8_0 + j]*id; + + y[i].qs[j] = roundf(x0); + } + } +} + +void quantize_row_q8_0(const float * restrict x, void * restrict vy, int k) { + assert(QK8_0 == 32); + assert(k % QK8_0 == 0); + const int nb = k / QK8_0; + + block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + for (int i = 0; i < nb; i++) { + float32x4_t srcv [8]; + float32x4_t asrcv[8]; + float32x4_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = vld1q_f32(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = vabsq_f32(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = vmaxq_f32(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = vmaxq_f32(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = vmaxq_f32(amaxv[8*j], amaxv[8*j+4]); + + const float amax = vmaxvq_f32(amaxv[0]); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < 8; j++) { + const float32x4_t v = vmulq_n_f32(srcv[j], id); + const int32x4_t vi = vcvtnq_s32_f32(v); + + y[i].qs[4*j + 0] = vgetq_lane_s32(vi, 0); + y[i].qs[4*j + 1] = vgetq_lane_s32(vi, 1); + y[i].qs[4*j + 2] = vgetq_lane_s32(vi, 2); + y[i].qs[4*j + 3] = vgetq_lane_s32(vi, 3); + } + } +#elif defined(__wasm_simd128__) + for (int i = 0; i < nb; i++) { + v128_t srcv [8]; + v128_t asrcv[8]; + v128_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = wasm_v128_load(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = wasm_f32x4_abs(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = wasm_f32x4_max(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = wasm_f32x4_max(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = wasm_f32x4_max(amaxv[8*j], amaxv[8*j+4]); + + const float amax = MAX(MAX(wasm_f32x4_extract_lane(amaxv[0], 0), + wasm_f32x4_extract_lane(amaxv[0], 1)), + MAX(wasm_f32x4_extract_lane(amaxv[0], 2), + wasm_f32x4_extract_lane(amaxv[0], 3))); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + for (int j = 0; j < 8; j++) { + const v128_t v = wasm_f32x4_mul(srcv[j], wasm_f32x4_splat(id)); + const v128_t vi = wasm_i32x4_trunc_sat_f32x4(v); + + y[i].qs[4*j + 0] = wasm_i32x4_extract_lane(vi, 0); + y[i].qs[4*j + 1] = wasm_i32x4_extract_lane(vi, 1); + y[i].qs[4*j + 2] = wasm_i32x4_extract_lane(vi, 2); + y[i].qs[4*j + 3] = wasm_i32x4_extract_lane(vi, 3); + } + } +#elif defined(__AVX2__) || defined(__AVX__) + for (int i = 0; i < nb; i++) { + // Load elements into 4 AVX vectors + __m256 v0 = _mm256_loadu_ps( x ); + __m256 v1 = _mm256_loadu_ps( x + 8 ); + __m256 v2 = _mm256_loadu_ps( x + 16 ); + __m256 v3 = _mm256_loadu_ps( x + 24 ); + x += 32; + + // Compute max(abs(e)) for the block + const __m256 signBit = _mm256_set1_ps( -0.0f ); + __m256 maxAbs = _mm256_andnot_ps( signBit, v0 ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v1 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v2 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v3 ) ); + + __m128 max4 = _mm_max_ps( _mm256_extractf128_ps( maxAbs, 1 ), _mm256_castps256_ps128( maxAbs ) ); + max4 = _mm_max_ps( max4, _mm_movehl_ps( max4, max4 ) ); + max4 = _mm_max_ss( max4, _mm_movehdup_ps( max4 ) ); + const float maxScalar = _mm_cvtss_f32( max4 ); + + // Quantize these floats + const float d = maxScalar / 127.f; + y[i].d = GGML_FP32_TO_FP16(d); + const float id = ( maxScalar != 0.0f ) ? 127.f / maxScalar : 0.0f; + const __m256 mul = _mm256_set1_ps( id ); + + // Apply the multiplier + v0 = _mm256_mul_ps( v0, mul ); + v1 = _mm256_mul_ps( v1, mul ); + v2 = _mm256_mul_ps( v2, mul ); + v3 = _mm256_mul_ps( v3, mul ); + + // Round to nearest integer + v0 = _mm256_round_ps( v0, _MM_ROUND_NEAREST ); + v1 = _mm256_round_ps( v1, _MM_ROUND_NEAREST ); + v2 = _mm256_round_ps( v2, _MM_ROUND_NEAREST ); + v3 = _mm256_round_ps( v3, _MM_ROUND_NEAREST ); + + // Convert floats to integers + __m256i i0 = _mm256_cvtps_epi32( v0 ); + __m256i i1 = _mm256_cvtps_epi32( v1 ); + __m256i i2 = _mm256_cvtps_epi32( v2 ); + __m256i i3 = _mm256_cvtps_epi32( v3 ); + +#if defined(__AVX2__) + // Convert int32 to int16 + i0 = _mm256_packs_epi32( i0, i1 ); // 0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15 + i2 = _mm256_packs_epi32( i2, i3 ); // 16, 17, 18, 19, 24, 25, 26, 27, 20, 21, 22, 23, 28, 29, 30, 31 + // Convert int16 to int8 + i0 = _mm256_packs_epi16( i0, i2 ); // 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 + + // We got our precious signed bytes, but the order is now wrong + // These AVX2 pack instructions process 16-byte pieces independently + // The following instruction is fixing the order + const __m256i perm = _mm256_setr_epi32( 0, 4, 1, 5, 2, 6, 3, 7 ); + i0 = _mm256_permutevar8x32_epi32( i0, perm ); + + _mm256_storeu_si256((__m256i *)y[i].qs, i0); +#else + // Since we don't have in AVX some necessary functions, + // we split the registers in half and call AVX2 analogs from SSE + __m128i ni0 = _mm256_castsi256_si128( i0 ); + __m128i ni1 = _mm256_extractf128_si256( i0, 1); + __m128i ni2 = _mm256_castsi256_si128( i1 ); + __m128i ni3 = _mm256_extractf128_si256( i1, 1); + __m128i ni4 = _mm256_castsi256_si128( i2 ); + __m128i ni5 = _mm256_extractf128_si256( i2, 1); + __m128i ni6 = _mm256_castsi256_si128( i3 ); + __m128i ni7 = _mm256_extractf128_si256( i3, 1); + + // Convert int32 to int16 + ni0 = _mm_packs_epi32( ni0, ni1 ); + ni2 = _mm_packs_epi32( ni2, ni3 ); + ni4 = _mm_packs_epi32( ni4, ni5 ); + ni6 = _mm_packs_epi32( ni6, ni7 ); + // Convert int16 to int8 + ni0 = _mm_packs_epi16( ni0, ni2 ); + ni4 = _mm_packs_epi16( ni4, ni6 ); + + _mm_storeu_si128((__m128i *)(y[i].qs + 0), ni0); + _mm_storeu_si128((__m128i *)(y[i].qs + 16), ni4); +#endif + } +#elif defined(__riscv_v_intrinsic) + + size_t vl = __riscv_vsetvl_e32m4(QK8_0); + + for (int i = 0; i < nb; i++) { + // load elements + vfloat32m4_t v_x = __riscv_vle32_v_f32m4(x+i*QK8_0, vl); + + vfloat32m4_t vfabs = __riscv_vfabs_v_f32m4(v_x, vl); + vfloat32m1_t tmp = __riscv_vfmv_v_f_f32m1(0.0f, vl); + vfloat32m1_t vmax = __riscv_vfredmax_vs_f32m4_f32m1(vfabs, tmp, vl); + float amax = __riscv_vfmv_f_s_f32m1_f32(vmax); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = GGML_FP32_TO_FP16(d); + + vfloat32m4_t x0 = __riscv_vfmul_vf_f32m4(v_x, id, vl); + + // convert to integer + vint16m2_t vi = __riscv_vfncvt_x_f_w_i16m2(x0, vl); + vint8m1_t vs = __riscv_vncvt_x_x_w_i8m1(vi, vl); + + // store result + __riscv_vse8_v_i8m1(y[i].qs , vs, vl); + } +#else + GGML_UNUSED(nb); + // scalar + quantize_row_q8_0_reference(x, y, k); +#endif +} + +// reference implementation for deterministic creation of model files +void quantize_row_q8_1_reference(const float * restrict x, block_q8_1 * restrict y, int k) { + assert(QK8_1 == 32); + assert(k % QK8_1 == 0); + const int nb = k / QK8_1; + + for (int i = 0; i < nb; i++) { + float amax = 0.0f; // absolute max + + for (int j = 0; j < QK8_1; j++) { + const float v = x[i*QK8_1 + j]; + amax = MAX(amax, fabsf(v)); + } + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = d; + + int sum = 0; + + for (int j = 0; j < QK8_1/2; ++j) { + const float v0 = x[i*QK8_1 + j]*id; + const float v1 = x[i*QK8_1 + QK8_1/2 + j]*id; + + y[i].qs[ j] = roundf(v0); + y[i].qs[QK8_1/2 + j] = roundf(v1); + + sum += y[i].qs[ j]; + sum += y[i].qs[QK8_1/2 + j]; + } + + y[i].s = sum*d; + } +} + +void quantize_row_q8_1(const float * restrict x, void * restrict vy, int k) { + assert(k % QK8_1 == 0); + const int nb = k / QK8_1; + + block_q8_1 * restrict y = vy; + +#if defined(__ARM_NEON) + for (int i = 0; i < nb; i++) { + float32x4_t srcv [8]; + float32x4_t asrcv[8]; + float32x4_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = vld1q_f32(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = vabsq_f32(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = vmaxq_f32(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = vmaxq_f32(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = vmaxq_f32(amaxv[8*j], amaxv[8*j+4]); + + const float amax = vmaxvq_f32(amaxv[0]); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = d; + + int32x4_t accv = vdupq_n_s32(0); + + for (int j = 0; j < 8; j++) { + const float32x4_t v = vmulq_n_f32(srcv[j], id); + const int32x4_t vi = vcvtnq_s32_f32(v); + + y[i].qs[4*j + 0] = vgetq_lane_s32(vi, 0); + y[i].qs[4*j + 1] = vgetq_lane_s32(vi, 1); + y[i].qs[4*j + 2] = vgetq_lane_s32(vi, 2); + y[i].qs[4*j + 3] = vgetq_lane_s32(vi, 3); + + accv = vaddq_s32(accv, vi); + } + + y[i].s = d * vaddvq_s32(accv); + } +#elif defined(__wasm_simd128__) + for (int i = 0; i < nb; i++) { + v128_t srcv [8]; + v128_t asrcv[8]; + v128_t amaxv[8]; + + for (int j = 0; j < 8; j++) srcv[j] = wasm_v128_load(x + i*32 + 4*j); + for (int j = 0; j < 8; j++) asrcv[j] = wasm_f32x4_abs(srcv[j]); + + for (int j = 0; j < 4; j++) amaxv[2*j] = wasm_f32x4_max(asrcv[2*j], asrcv[2*j+1]); + for (int j = 0; j < 2; j++) amaxv[4*j] = wasm_f32x4_max(amaxv[4*j], amaxv[4*j+2]); + for (int j = 0; j < 1; j++) amaxv[8*j] = wasm_f32x4_max(amaxv[8*j], amaxv[8*j+4]); + + const float amax = MAX(MAX(wasm_f32x4_extract_lane(amaxv[0], 0), + wasm_f32x4_extract_lane(amaxv[0], 1)), + MAX(wasm_f32x4_extract_lane(amaxv[0], 2), + wasm_f32x4_extract_lane(amaxv[0], 3))); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = d; + + v128_t accv = wasm_i32x4_splat(0); + + for (int j = 0; j < 8; j++) { + const v128_t v = wasm_f32x4_mul(srcv[j], wasm_f32x4_splat(id)); + const v128_t vi = wasm_i32x4_trunc_sat_f32x4(v); + + y[i].qs[4*j + 0] = wasm_i32x4_extract_lane(vi, 0); + y[i].qs[4*j + 1] = wasm_i32x4_extract_lane(vi, 1); + y[i].qs[4*j + 2] = wasm_i32x4_extract_lane(vi, 2); + y[i].qs[4*j + 3] = wasm_i32x4_extract_lane(vi, 3); + + accv = wasm_i32x4_add(accv, vi); + } + + y[i].s = d * (wasm_i32x4_extract_lane(accv, 0) + + wasm_i32x4_extract_lane(accv, 1) + + wasm_i32x4_extract_lane(accv, 2) + + wasm_i32x4_extract_lane(accv, 3)); + } +#elif defined(__AVX2__) || defined(__AVX__) + for (int i = 0; i < nb; i++) { + // Load elements into 4 AVX vectors + __m256 v0 = _mm256_loadu_ps( x ); + __m256 v1 = _mm256_loadu_ps( x + 8 ); + __m256 v2 = _mm256_loadu_ps( x + 16 ); + __m256 v3 = _mm256_loadu_ps( x + 24 ); + x += 32; + + // Compute max(abs(e)) for the block + const __m256 signBit = _mm256_set1_ps( -0.0f ); + __m256 maxAbs = _mm256_andnot_ps( signBit, v0 ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v1 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v2 ) ); + maxAbs = _mm256_max_ps( maxAbs, _mm256_andnot_ps( signBit, v3 ) ); + + __m128 max4 = _mm_max_ps( _mm256_extractf128_ps( maxAbs, 1 ), _mm256_castps256_ps128( maxAbs ) ); + max4 = _mm_max_ps( max4, _mm_movehl_ps( max4, max4 ) ); + max4 = _mm_max_ss( max4, _mm_movehdup_ps( max4 ) ); + const float maxScalar = _mm_cvtss_f32( max4 ); + + // Quantize these floats + const float d = maxScalar / 127.f; + y[i].d = d; + const float id = ( maxScalar != 0.0f ) ? 127.f / maxScalar : 0.0f; + const __m256 mul = _mm256_set1_ps( id ); + + // Apply the multiplier + v0 = _mm256_mul_ps( v0, mul ); + v1 = _mm256_mul_ps( v1, mul ); + v2 = _mm256_mul_ps( v2, mul ); + v3 = _mm256_mul_ps( v3, mul ); + + // Round to nearest integer + v0 = _mm256_round_ps( v0, _MM_ROUND_NEAREST ); + v1 = _mm256_round_ps( v1, _MM_ROUND_NEAREST ); + v2 = _mm256_round_ps( v2, _MM_ROUND_NEAREST ); + v3 = _mm256_round_ps( v3, _MM_ROUND_NEAREST ); + + // Convert floats to integers + __m256i i0 = _mm256_cvtps_epi32( v0 ); + __m256i i1 = _mm256_cvtps_epi32( v1 ); + __m256i i2 = _mm256_cvtps_epi32( v2 ); + __m256i i3 = _mm256_cvtps_epi32( v3 ); + +#if defined(__AVX2__) + // Compute the sum of the quants and set y[i].s + y[i].s = d * hsum_i32_8(_mm256_add_epi32(_mm256_add_epi32(i0, i1), _mm256_add_epi32(i2, i3))); + + // Convert int32 to int16 + i0 = _mm256_packs_epi32( i0, i1 ); // 0, 1, 2, 3, 8, 9, 10, 11, 4, 5, 6, 7, 12, 13, 14, 15 + i2 = _mm256_packs_epi32( i2, i3 ); // 16, 17, 18, 19, 24, 25, 26, 27, 20, 21, 22, 23, 28, 29, 30, 31 + // Convert int16 to int8 + i0 = _mm256_packs_epi16( i0, i2 ); // 0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19, 24, 25, 26, 27, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31 + + // We got our precious signed bytes, but the order is now wrong + // These AVX2 pack instructions process 16-byte pieces independently + // The following instruction is fixing the order + const __m256i perm = _mm256_setr_epi32( 0, 4, 1, 5, 2, 6, 3, 7 ); + i0 = _mm256_permutevar8x32_epi32( i0, perm ); + + _mm256_storeu_si256((__m256i *)y[i].qs, i0); +#else + // Since we don't have in AVX some necessary functions, + // we split the registers in half and call AVX2 analogs from SSE + __m128i ni0 = _mm256_castsi256_si128( i0 ); + __m128i ni1 = _mm256_extractf128_si256( i0, 1); + __m128i ni2 = _mm256_castsi256_si128( i1 ); + __m128i ni3 = _mm256_extractf128_si256( i1, 1); + __m128i ni4 = _mm256_castsi256_si128( i2 ); + __m128i ni5 = _mm256_extractf128_si256( i2, 1); + __m128i ni6 = _mm256_castsi256_si128( i3 ); + __m128i ni7 = _mm256_extractf128_si256( i3, 1); + + // Compute the sum of the quants and set y[i].s + const __m128i s0 = _mm_add_epi32(_mm_add_epi32(ni0, ni1), _mm_add_epi32(ni2, ni3)); + const __m128i s1 = _mm_add_epi32(_mm_add_epi32(ni4, ni5), _mm_add_epi32(ni6, ni7)); + y[i].s = d * hsum_i32_4(_mm_add_epi32(s0, s1)); + + // Convert int32 to int16 + ni0 = _mm_packs_epi32( ni0, ni1 ); + ni2 = _mm_packs_epi32( ni2, ni3 ); + ni4 = _mm_packs_epi32( ni4, ni5 ); + ni6 = _mm_packs_epi32( ni6, ni7 ); + // Convert int16 to int8 + ni0 = _mm_packs_epi16( ni0, ni2 ); + ni4 = _mm_packs_epi16( ni4, ni6 ); + + _mm_storeu_si128((__m128i *)(y[i].qs + 0), ni0); + _mm_storeu_si128((__m128i *)(y[i].qs + 16), ni4); +#endif + } +#elif defined(__riscv_v_intrinsic) + + size_t vl = __riscv_vsetvl_e32m4(QK8_1); + + for (int i = 0; i < nb; i++) { + // load elements + vfloat32m4_t v_x = __riscv_vle32_v_f32m4(x+i*QK8_1, vl); + + vfloat32m4_t vfabs = __riscv_vfabs_v_f32m4(v_x, vl); + vfloat32m1_t tmp = __riscv_vfmv_v_f_f32m1(0.0, vl); + vfloat32m1_t vmax = __riscv_vfredmax_vs_f32m4_f32m1(vfabs, tmp, vl); + float amax = __riscv_vfmv_f_s_f32m1_f32(vmax); + + const float d = amax / ((1 << 7) - 1); + const float id = d ? 1.0f/d : 0.0f; + + y[i].d = d; + + vfloat32m4_t x0 = __riscv_vfmul_vf_f32m4(v_x, id, vl); + + // convert to integer + vint16m2_t vi = __riscv_vfncvt_x_f_w_i16m2(x0, vl); + vint8m1_t vs = __riscv_vncvt_x_x_w_i8m1(vi, vl); + + // store result + __riscv_vse8_v_i8m1(y[i].qs , vs, vl); + + // compute sum for y[i].s + vint16m1_t tmp2 = __riscv_vmv_v_x_i16m1(0, vl); + vint16m1_t vwrs = __riscv_vwredsum_vs_i8m1_i16m1(vs, tmp2, vl); + + // set y[i].s + int sum = __riscv_vmv_x_s_i16m1_i16(vwrs); + y[i].s = sum*d; + } +#else + GGML_UNUSED(nb); + // scalar + quantize_row_q8_1_reference(x, y, k); +#endif +} + +void dequantize_row_q4_0(const block_q4_0 * restrict x, float * restrict y, int k) { + static const int qk = QK4_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int j = 0; j < qk/2; ++j) { + const int x0 = (x[i].qs[j] & 0x0F) - 8; + const int x1 = (x[i].qs[j] >> 4) - 8; + + y[i*qk + j + 0 ] = x0*d; + y[i*qk + j + qk/2] = x1*d; + } + } +} + +void dequantize_row_q4_1(const block_q4_1 * restrict x, float * restrict y, int k) { + static const int qk = QK4_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + const float m = GGML_FP16_TO_FP32(x[i].m); + + for (int j = 0; j < qk/2; ++j) { + const int x0 = (x[i].qs[j] & 0x0F); + const int x1 = (x[i].qs[j] >> 4); + + y[i*qk + j + 0 ] = x0*d + m; + y[i*qk + j + qk/2] = x1*d + m; + } + } +} + +void dequantize_row_q5_0(const block_q5_0 * restrict x, float * restrict y, int k) { + static const int qk = QK5_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int32_t x0 = ((x[i].qs[j] & 0x0F) | xh_0) - 16; + const int32_t x1 = ((x[i].qs[j] >> 4) | xh_1) - 16; + + y[i*qk + j + 0 ] = x0*d; + y[i*qk + j + qk/2] = x1*d; + } + } +} + +void dequantize_row_q5_1(const block_q5_1 * restrict x, float * restrict y, int k) { + static const int qk = QK5_1; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + const float m = GGML_FP16_TO_FP32(x[i].m); + + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int x0 = (x[i].qs[j] & 0x0F) | xh_0; + const int x1 = (x[i].qs[j] >> 4) | xh_1; + + y[i*qk + j + 0 ] = x0*d + m; + y[i*qk + j + qk/2] = x1*d + m; + } + } +} + +void dequantize_row_q8_0(const block_q8_0 * restrict x, float * restrict y, int k) { + static const int qk = QK8_0; + + assert(k % qk == 0); + + const int nb = k / qk; + + for (int i = 0; i < nb; i++) { + const float d = GGML_FP16_TO_FP32(x[i].d); + + for (int j = 0; j < qk; ++j) { + y[i*qk + j] = x[i].qs[j]*d; + } + } +} + +// +// 2-6 bit quantization in super-blocks +// + +// +// ===================== Helper functions +// +static inline int nearest_int(float fval) { + assert(fval <= 4194303.f); + float val = fval + 12582912.f; + int i; memcpy(&i, &val, sizeof(int)); + return (i & 0x007fffff) - 0x00400000; +} + +static float make_qx_quants(int n, int nmax, const float * restrict x, int8_t * restrict L, int rmse_type) { + float max = 0; + float amax = 0; + for (int i = 0; i < n; ++i) { + float ax = fabsf(x[i]); + if (ax > amax) { amax = ax; max = x[i]; } + } + if (amax < 1e-30f) { // all zero + for (int i = 0; i < n; ++i) { + L[i] = 0; + } + return 0.f; + } + float iscale = -nmax / max; + if (rmse_type == 0) { + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + L[i] = nmax + MAX(-nmax, MIN(nmax-1, l)); + } + return 1/iscale; + } + bool return_early = false; + if (rmse_type < 0) { + rmse_type = -rmse_type; + return_early = true; + } + int weight_type = rmse_type%2; + float sumlx = 0; + float suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l + nmax; + float w = weight_type == 1 ? x[i] * x[i] : 1; + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + float scale = sumlx/suml2; + if (return_early) return suml2 > 0 ? 0.5f*(scale + 1/iscale) : 1/iscale; + float best = scale * sumlx; + for (int is = -9; is <= 9; ++is) { + if (is == 0) { + continue; + } + iscale = -(nmax + 0.1f*is) / max; + sumlx = suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + float w = weight_type == 1 ? x[i] * x[i] : 1; + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + if (suml2 > 0 && sumlx*sumlx > best*suml2) { + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + L[i] = nmax + MAX(-nmax, MIN(nmax-1, l)); + } + scale = sumlx/suml2; best = scale*sumlx; + } + } + return scale; +} + +static float make_q3_quants(int n, int nmax, const float * restrict x, int8_t * restrict L, bool do_rmse) { + float max = 0; + float amax = 0; + for (int i = 0; i < n; ++i) { + float ax = fabsf(x[i]); + if (ax > amax) { amax = ax; max = x[i]; } + } + if (!amax) { // all zero + for (int i = 0; i < n; ++i) { L[i] = 0; } + return 0.f; + } + float iscale = -nmax / max; + if (do_rmse) { + float sumlx = 0; + float suml2 = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l; + float w = x[i]*x[i]; + sumlx += w*x[i]*l; + suml2 += w*l*l; + } + for (int itry = 0; itry < 5; ++itry) { + int n_changed = 0; + for (int i = 0; i < n; ++i) { + float w = x[i]*x[i]; + float slx = sumlx - w*x[i]*L[i]; + if (slx > 0) { + float sl2 = suml2 - w*L[i]*L[i]; + int new_l = nearest_int(x[i] * sl2 / slx); + new_l = MAX(-nmax, MIN(nmax-1, new_l)); + if (new_l != L[i]) { + slx += w*x[i]*new_l; + sl2 += w*new_l*new_l; + if (sl2 > 0 && slx*slx*suml2 > sumlx*sumlx*sl2) { + L[i] = new_l; sumlx = slx; suml2 = sl2; + ++n_changed; + } + } + } + } + if (!n_changed) { + break; + } + } + for (int i = 0; i < n; ++i) { + L[i] += nmax; + } + return sumlx / suml2; + } + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale * x[i]); + l = MAX(-nmax, MIN(nmax-1, l)); + L[i] = l + nmax; + } + return 1/iscale; +} + +static float make_qkx1_quants(int n, int nmax, const float * restrict x, uint8_t * restrict L, float * restrict the_min, + int ntry, float alpha) { + float min = x[0]; + float max = x[0]; + for (int i = 1; i < n; ++i) { + if (x[i] < min) min = x[i]; + if (x[i] > max) max = x[i]; + } + if (max == min) { + for (int i = 0; i < n; ++i) L[i] = 0; + *the_min = 0; + return 0.f; + } + if (min > 0) min = 0; + float iscale = nmax/(max - min); + float scale = 1/iscale; + for (int itry = 0; itry < ntry; ++itry) { + float sumlx = 0; int suml2 = 0; + bool did_change = false; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + l = MAX(0, MIN(nmax, l)); + if (l != L[i]) { + L[i] = l; + did_change = true; + } + sumlx += (x[i] - min)*l; + suml2 += l*l; + } + scale = sumlx/suml2; + float sum = 0; + for (int i = 0; i < n; ++i) { + sum += x[i] - scale*L[i]; + } + min = alpha*min + (1 - alpha)*sum/n; + if (min > 0) min = 0; + iscale = 1/scale; + if (!did_change) break; + } + *the_min = -min; + return scale; +} + +static float make_qkx2_quants(int n, int nmax, const float * restrict x, const float * restrict weights, + uint8_t * restrict L, float * restrict the_min, uint8_t * restrict Laux, + float rmin, float rdelta, int nstep, bool use_mad) { + float min = x[0]; + float max = x[0]; + float sum_w = weights[0]; + float sum_x = sum_w * x[0]; + for (int i = 1; i < n; ++i) { + if (x[i] < min) min = x[i]; + if (x[i] > max) max = x[i]; + float w = weights[i]; + sum_w += w; + sum_x += w * x[i]; + } + if (min > 0) min = 0; + if (max == min) { + for (int i = 0; i < n; ++i) L[i] = 0; + *the_min = -min; + return 0.f; + } + float iscale = nmax/(max - min); + float scale = 1/iscale; + float best_mad = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + L[i] = MAX(0, MIN(nmax, l)); + float diff = scale * L[i] + min - x[i]; + diff = use_mad ? fabsf(diff) : diff * diff; + float w = weights[i]; + best_mad += w * diff; + } + if (nstep < 1) { + *the_min = -min; + return scale; + } + for (int is = 0; is <= nstep; ++is) { + iscale = (rmin + rdelta*is + nmax)/(max - min); + float sum_l = 0, sum_l2 = 0, sum_xl = 0; + for (int i = 0; i < n; ++i) { + int l = nearest_int(iscale*(x[i] - min)); + l = MAX(0, MIN(nmax, l)); + Laux[i] = l; + float w = weights[i]; + sum_l += w*l; + sum_l2 += w*l*l; + sum_xl += w*l*x[i]; + } + float D = sum_w * sum_l2 - sum_l * sum_l; + if (D > 0) { + float this_scale = (sum_w * sum_xl - sum_x * sum_l)/D; + float this_min = (sum_l2 * sum_x - sum_l * sum_xl)/D; + if (this_min > 0) { + this_min = 0; + this_scale = sum_xl / sum_l2; + } + float mad = 0; + for (int i = 0; i < n; ++i) { + float diff = this_scale * Laux[i] + this_min - x[i]; + diff = use_mad ? fabsf(diff) : diff * diff; + float w = weights[i]; + mad += w * diff; + } + if (mad < best_mad) { + for (int i = 0; i < n; ++i) { + L[i] = Laux[i]; + } + best_mad = mad; + scale = this_scale; + min = this_min; + } + } + } + *the_min = -min; + return scale; +} + +#if QK_K == 256 +static inline void get_scale_min_k4(int j, const uint8_t * restrict q, uint8_t * restrict d, uint8_t * restrict m) { + if (j < 4) { + *d = q[j] & 63; *m = q[j + 4] & 63; + } else { + *d = (q[j+4] & 0xF) | ((q[j-4] >> 6) << 4); + *m = (q[j+4] >> 4) | ((q[j-0] >> 6) << 4); + } +} +#endif + +//========================- 2-bit (de)-quantization + +void quantize_row_q2_K_reference(const float * restrict x, block_q2_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[16]; + float weights[16]; + float mins[QK_K/16]; + float scales[QK_K/16]; + + const float q4scale = 15.f; + + for (int i = 0; i < nb; i++) { + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 16; ++l) weights[l] = fabsf(x[16*j + l]); + scales[j] = make_qkx2_quants(16, 3, x + 16*j, weights, L + 16*j, &mins[j], Laux, -0.5f, 0.1f, 15, true); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + + if (max_scale > 0) { + float iscale = q4scale/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*scales[j]); + y[i].scales[j] = l; + } + y[i].d = GGML_FP32_TO_FP16(max_scale/q4scale); + } else { + for (int j = 0; j < QK_K/16; ++j) y[i].scales[j] = 0; + y[i].d = GGML_FP32_TO_FP16(0.f); + } + if (max_min > 0) { + float iscale = q4scale/max_min; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*mins[j]); + y[i].scales[j] |= (l << 4); + } + y[i].dmin = GGML_FP32_TO_FP16(max_min/q4scale); + } else { + y[i].dmin = GGML_FP32_TO_FP16(0.f); + } + for (int j = 0; j < QK_K/16; ++j) { + const float d = GGML_FP16_TO_FP32(y[i].d) * (y[i].scales[j] & 0xF); + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * (y[i].scales[j] >> 4); + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int((x[16*j + ii] + dm)/d); + l = MAX(0, MIN(3, l)); + L[16*j + ii] = l; + } + } + +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } +#else + for (int l = 0; l < 16; ++l) { + y[i].qs[l] = L[l] | (L[l + 16] << 2) | (L[l + 32] << 4) | (L[l + 48] << 6); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q2_K(const block_q2_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * q = x[i].qs; + +#if QK_K == 256 + int is = 0; + float dl, ml; + for (int n = 0; n < QK_K; n += 128) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + + uint8_t sc = x[i].scales[is++]; + dl = d * (sc & 0xF); ml = min * (sc >> 4); + for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l] >> shift) & 3)) - ml; + + sc = x[i].scales[is++]; + dl = d * (sc & 0xF); ml = min * (sc >> 4); + for (int l = 0; l < 16; ++l) *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3)) - ml; + + shift += 2; + } + q += 32; + } +#else + float dl1 = d * (x[i].scales[0] & 0xF), ml1 = min * (x[i].scales[0] >> 4); + float dl2 = d * (x[i].scales[1] & 0xF), ml2 = min * (x[i].scales[1] >> 4); + float dl3 = d * (x[i].scales[2] & 0xF), ml3 = min * (x[i].scales[2] >> 4); + float dl4 = d * (x[i].scales[3] & 0xF), ml4 = min * (x[i].scales[3] >> 4); + for (int l = 0; l < 16; ++l) { + y[l+ 0] = dl1 * ((int8_t)((q[l] >> 0) & 3)) - ml1; + y[l+16] = dl2 * ((int8_t)((q[l] >> 2) & 3)) - ml2; + y[l+32] = dl3 * ((int8_t)((q[l] >> 4) & 3)) - ml3; + y[l+48] = dl4 * ((int8_t)((q[l] >> 6) & 3)) - ml4; + } + y += QK_K; +#endif + } +} + +void quantize_row_q2_K(const float * restrict x, void * restrict vy, int k) { + quantize_row_q2_K_reference(x, vy, k); +} + +size_t ggml_quantize_q2_K(const float * restrict src, void * restrict dst, int n, int k, int64_t * restrict hist) { + (void)hist; // TODO: collect histograms + + for (int j = 0; j < n; j += k) { + block_q2_K * restrict y = (block_q2_K *)dst + j/QK_K; + quantize_row_q2_K_reference(src + j, y, k); + } + return (n/QK_K*sizeof(block_q2_K)); +} + +//========================= 3-bit (de)-quantization + +void quantize_row_q3_K_reference(const float * restrict x, block_q3_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + int8_t L[QK_K]; + float scales[QK_K / 16]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; + float amax = 0; + for (int j = 0; j < QK_K/16; ++j) { + scales[j] = make_q3_quants(16, 4, x + 16*j, L + 16*j, true); + float scale = fabsf(scales[j]); + if (scale > amax) { + amax = scale; max_scale = scales[j]; + } + } + +#if QK_K == 256 + memset(y[i].scales, 0, 12); + if (max_scale) { + float iscale = -32.f/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int8_t l = nearest_int(iscale*scales[j]); + l = MAX(-32, MIN(31, l)) + 32; + if (j < 8) { + y[i].scales[j] = l & 0xF; + } else { + y[i].scales[j-8] |= ((l & 0xF) << 4); + } + l >>= 4; + y[i].scales[j%4 + 8] |= (l << (2*(j/4))); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + } else { + y[i].d = GGML_FP32_TO_FP16(0.f); + } + + int8_t sc; + for (int j = 0; j < QK_K/16; ++j) { + sc = j < 8 ? y[i].scales[j] & 0xF : y[i].scales[j-8] >> 4; + sc = (sc | (((y[i].scales[8 + j%4] >> (2*(j/4))) & 3) << 4)) - 32; + float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-4, MIN(3, l)); + L[16*j + ii] = l + 4; + } + } +#else + if (max_scale) { + float iscale = -8.f/max_scale; + for (int j = 0; j < QK_K/16; j+=2) { + int l1 = nearest_int(iscale*scales[j]); + l1 = 8 + MAX(-8, MIN(7, l1)); + int l2 = nearest_int(iscale*scales[j+1]); + l2 = 8 + MAX(-8, MIN(7, l2)); + y[i].scales[j/2] = l1 | (l2 << 4); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + } else { + for (int j = 0; j < QK_K/16; j+=2) { + y[i].scales[j/2] = 0; + } + y[i].d = GGML_FP32_TO_FP16(0.f); + } + for (int j = 0; j < QK_K/16; ++j) { + int s = j%2 == 0 ? y[i].scales[j/2] & 0xF : y[i].scales[j/2] >> 4; + float d = GGML_FP16_TO_FP32(y[i].d) * (s - 8); + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-4, MIN(3, l)); + L[16*j + ii] = l + 4; + } + } +#endif + + memset(y[i].hmask, 0, QK_K/8); + // We put the high-bit for the 1st 8 quants into bit 0, the next 8 into bit 1, etc. + int m = 0; + uint8_t hm = 1; + for (int j = 0; j < QK_K; ++j) { + if (L[j] > 3) { + y[i].hmask[m] |= hm; + L[j] -= 4; + } + if (++m == QK_K/8) { + m = 0; hm <<= 1; + } + } +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + y[i].qs[j/4 + l] = L[j + l] | (L[j + l + 32] << 2) | (L[j + l + 64] << 4) | (L[j + l + 96] << 6); + } + } +#else + for (int l = 0; l < 16; ++l) { + y[i].qs[l] = L[l] | (L[l + 16] << 2) | (L[l + 32] << 4) | (L[l + 48] << 6); + } +#endif + + x += QK_K; + } +} + +#if QK_K == 256 +void dequantize_row_q3_K(const block_q3_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + const uint32_t kmask1 = 0x03030303; + const uint32_t kmask2 = 0x0f0f0f0f; + + uint32_t aux[4]; + const int8_t * scales = (const int8_t*)aux; + + for (int i = 0; i < nb; i++) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + uint8_t m = 1; + + memcpy(aux, x[i].scales, 12); + uint32_t tmp = aux[2]; + aux[2] = ((aux[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4); + aux[3] = ((aux[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4); + aux[0] = (aux[0] & kmask2) | (((tmp >> 0) & kmask1) << 4); + aux[1] = (aux[1] & kmask2) | (((tmp >> 2) & kmask1) << 4); + + int is = 0; + float dl; + for (int n = 0; n < QK_K; n += 128) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + + dl = d_all * (scales[is++] - 32); + for (int l = 0; l < 16; ++l) { + *y++ = dl * ((int8_t)((q[l+ 0] >> shift) & 3) - ((hm[l+ 0] & m) ? 0 : 4)); + } + + dl = d_all * (scales[is++] - 32); + for (int l = 0; l < 16; ++l) { + *y++ = dl * ((int8_t)((q[l+16] >> shift) & 3) - ((hm[l+16] & m) ? 0 : 4)); + } + + shift += 2; + m <<= 1; + } + q += 32; + } + + } +} +#else +void dequantize_row_q3_K(const block_q3_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + assert(QK_K == 64); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + + const float d1 = d_all * ((x[i].scales[0] & 0xF) - 8); + const float d2 = d_all * ((x[i].scales[0] >> 4) - 8); + const float d3 = d_all * ((x[i].scales[1] & 0xF) - 8); + const float d4 = d_all * ((x[i].scales[1] >> 4) - 8); + + for (int l=0; l<8; ++l) { + uint8_t h = hm[l]; + y[l+ 0] = d1 * ((int8_t)((q[l+0] >> 0) & 3) - ((h & 0x01) ? 0 : 4)); + y[l+ 8] = d1 * ((int8_t)((q[l+8] >> 0) & 3) - ((h & 0x02) ? 0 : 4)); + y[l+16] = d2 * ((int8_t)((q[l+0] >> 2) & 3) - ((h & 0x04) ? 0 : 4)); + y[l+24] = d2 * ((int8_t)((q[l+8] >> 2) & 3) - ((h & 0x08) ? 0 : 4)); + y[l+32] = d3 * ((int8_t)((q[l+0] >> 4) & 3) - ((h & 0x10) ? 0 : 4)); + y[l+40] = d3 * ((int8_t)((q[l+8] >> 4) & 3) - ((h & 0x20) ? 0 : 4)); + y[l+48] = d4 * ((int8_t)((q[l+0] >> 6) & 3) - ((h & 0x40) ? 0 : 4)); + y[l+56] = d4 * ((int8_t)((q[l+8] >> 6) & 3) - ((h & 0x80) ? 0 : 4)); + } + y += QK_K; + } +} +#endif + +void quantize_row_q3_K(const float * restrict x, void * restrict vy, int k) { + quantize_row_q3_K_reference(x, vy, k); +} + +size_t ggml_quantize_q3_K(const float * restrict src, void * restrict dst, int n, int k, int64_t * restrict hist) { + (void)hist; // TODO: collect histograms + + for (int j = 0; j < n; j += k) { + block_q3_K * restrict y = (block_q3_K *)dst + j/QK_K; + quantize_row_q3_K_reference(src + j, y, k); + } + return (n/QK_K*sizeof(block_q3_K)); +} + +// ====================== 4-bit (de)-quantization + +void quantize_row_q4_K_reference(const float * restrict x, block_q4_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + uint8_t L[QK_K]; + uint8_t Laux[32]; + float weights[32]; + float mins[QK_K/32]; + float scales[QK_K/32]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/32; ++j) { + //scales[j] = make_qkx1_quants(32, 15, x + 32*j, L + 32*j, &mins[j], 9, 0.5f); + float sum_x2 = 0; + for (int l = 0; l < 32; ++l) sum_x2 += x[32*j + l] * x[32*j + l]; + float av_x = sqrtf(sum_x2/32); + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + scales[j] = make_qkx2_quants(32, 15, x + 32*j, weights, L + 32*j, &mins[j], Laux, -1.f, 0.1f, 20, false); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + +#if QK_K == 256 + float inv_scale = max_scale > 0 ? 63.f/max_scale : 0.f; + float inv_min = max_min > 0 ? 63.f/max_min : 0.f; + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = nearest_int(inv_scale*scales[j]); + uint8_t lm = nearest_int(inv_min*mins[j]); + ls = MIN(63, ls); + lm = MIN(63, lm); + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(max_scale/63.f); + y[i].dmin = GGML_FP32_TO_FP16(max_min/63.f); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(15, l)); + L[32*j + ii] = l; + } + } +#else + const float s_factor = 15.f; + float inv_scale = max_scale > 0 ? s_factor/max_scale : 0.f; + float inv_min = max_min > 0 ? s_factor/max_min : 0.f; + int d1 = nearest_int(inv_scale*scales[0]); + int m1 = nearest_int(inv_min*mins[0]); + int d2 = nearest_int(inv_scale*scales[1]); + int m2 = nearest_int(inv_min*mins[1]); + y[i].scales[0] = d1 | (m1 << 4); + y[i].scales[1] = d2 | (m2 << 4); + y[i].d[0] = GGML_FP32_TO_FP16(max_scale/s_factor); + y[i].d[1] = GGML_FP32_TO_FP16(max_min/s_factor); + + float sumlx = 0; + int suml2 = 0; + for (int j = 0; j < QK_K/32; ++j) { + const uint8_t sd = y[i].scales[j] & 0xF; + const uint8_t sm = y[i].scales[j] >> 4; + const float d = GGML_FP16_TO_FP32(y[i].d[0]) * sd; + if (!d) continue; + const float m = GGML_FP16_TO_FP32(y[i].d[1]) * sm; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + m)/d); + l = MAX(0, MIN(15, l)); + L[32*j + ii] = l; + sumlx += (x[32*j + ii] + m)*l*sd; + suml2 += l*l*sd*sd; + } + } + if (suml2) { + y[i].d[0] = GGML_FP32_TO_FP16(sumlx/suml2); + } +#endif + uint8_t * q = y[i].qs; + for (int j = 0; j < QK_K; j += 64) { + for (int l = 0; l < 32; ++l) q[l] = L[j + l] | (L[j + l + 32] << 4); + q += 32; + } + + x += QK_K; + + } +} + +void dequantize_row_q4_K(const block_q4_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const uint8_t * q = x[i].qs; + +#if QK_K == 256 + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + int is = 0; + uint8_t sc, m; + for (int j = 0; j < QK_K; j += 64) { + get_scale_min_k4(is + 0, x[i].scales, &sc, &m); + const float d1 = d * sc; const float m1 = min * m; + get_scale_min_k4(is + 1, x[i].scales, &sc, &m); + const float d2 = d * sc; const float m2 = min * m; + for (int l = 0; l < 32; ++l) *y++ = d1 * (q[l] & 0xF) - m1; + for (int l = 0; l < 32; ++l) *y++ = d2 * (q[l] >> 4) - m2; + q += 32; is += 2; + } +#else + const float dall = GGML_FP16_TO_FP32(x[i].d[0]); + const float mall = GGML_FP16_TO_FP32(x[i].d[1]); + const float d1 = dall * (x[i].scales[0] & 0xF), m1 = mall * (x[i].scales[0] >> 4); + const float d2 = dall * (x[i].scales[1] & 0xF), m2 = mall * (x[i].scales[1] >> 4); + for (int l = 0; l < 32; ++l) { + y[l+ 0] = d1 * (q[l] & 0xF) - m1; + y[l+32] = d2 * (q[l] >> 4) - m2; + } + y += QK_K; +#endif + + } +} + +void quantize_row_q4_K(const float * restrict x, void * restrict vy, int k) { + assert(k % QK_K == 0); + block_q4_K * restrict y = vy; + quantize_row_q4_K_reference(x, y, k); +} + +size_t ggml_quantize_q4_K(const float * restrict src, void * restrict dst, int n, int k, int64_t * restrict hist) { + assert(k % QK_K == 0); + (void)hist; // TODO: collect histograms + + for (int j = 0; j < n; j += k) { + block_q4_K * restrict y = (block_q4_K *)dst + j/QK_K; + quantize_row_q4_K_reference(src + j, y, k); + } + return (n/QK_K*sizeof(block_q4_K)); +} + +// ====================== 5-bit (de)-quantization + +void quantize_row_q5_K_reference(const float * restrict x, block_q5_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + +#if QK_K == 256 + uint8_t L[QK_K]; + float mins[QK_K/32]; + float scales[QK_K/32]; + float weights[32]; + uint8_t Laux[32]; +#else + int8_t L[QK_K]; + float scales[QK_K/16]; +#endif + + for (int i = 0; i < nb; i++) { + +#if QK_K == 256 + + float max_scale = 0; // as we are deducting the min, scales are always positive + float max_min = 0; + for (int j = 0; j < QK_K/32; ++j) { + //scales[j] = make_qkx1_quants(32, 31, x + 32*j, L + 32*j, &mins[j], 9, 0.5f); + float sum_x2 = 0; + for (int l = 0; l < 32; ++l) sum_x2 += x[32*j + l] * x[32*j + l]; + float av_x = sqrtf(sum_x2/32); + for (int l = 0; l < 32; ++l) weights[l] = av_x + fabsf(x[32*j + l]); + scales[j] = make_qkx2_quants(32, 31, x + 32*j, weights, L + 32*j, &mins[j], Laux, -0.5f, 0.1f, 15, false); + float scale = scales[j]; + if (scale > max_scale) { + max_scale = scale; + } + float min = mins[j]; + if (min > max_min) { + max_min = min; + } + } + + float inv_scale = max_scale > 0 ? 63.f/max_scale : 0.f; + float inv_min = max_min > 0 ? 63.f/max_min : 0.f; + for (int j = 0; j < QK_K/32; ++j) { + uint8_t ls = nearest_int(inv_scale*scales[j]); + uint8_t lm = nearest_int(inv_min*mins[j]); + ls = MIN(63, ls); + lm = MIN(63, lm); + if (j < 4) { + y[i].scales[j] = ls; + y[i].scales[j+4] = lm; + } else { + y[i].scales[j+4] = (ls & 0xF) | ((lm & 0xF) << 4); + y[i].scales[j-4] |= ((ls >> 4) << 6); + y[i].scales[j-0] |= ((lm >> 4) << 6); + } + } + y[i].d = GGML_FP32_TO_FP16(max_scale/63.f); + y[i].dmin = GGML_FP32_TO_FP16(max_min/63.f); + + uint8_t sc, m; + for (int j = 0; j < QK_K/32; ++j) { + get_scale_min_k4(j, y[i].scales, &sc, &m); + const float d = GGML_FP16_TO_FP32(y[i].d) * sc; + if (!d) continue; + const float dm = GGML_FP16_TO_FP32(y[i].dmin) * m; + for (int ii = 0; ii < 32; ++ii) { + int l = nearest_int((x[32*j + ii] + dm)/d); + l = MAX(0, MIN(31, l)); + L[32*j + ii] = l; + } + } + + uint8_t * restrict qh = y[i].qh; + uint8_t * restrict ql = y[i].qs; + memset(qh, 0, QK_K/8); + + uint8_t m1 = 1, m2 = 2; + for (int n = 0; n < QK_K; n += 64) { + for (int j = 0; j < 32; ++j) { + int l1 = L[n + j]; + if (l1 > 15) { + l1 -= 16; qh[j] |= m1; + } + int l2 = L[n + j + 32]; + if (l2 > 15) { + l2 -= 16; qh[j] |= m2; + } + ql[j] = l1 | (l2 << 4); + } + m1 <<= 2; m2 <<= 2; + ql += 32; + } +#else + float max_scale = 0, amax = 0; + for (int j = 0; j < QK_K/16; ++j) { + scales[j] = make_qx_quants(16, 16, x + 16*j, L + 16*j, 1); + float abs_scale = fabsf(scales[j]); + if (abs_scale > amax) { + amax = abs_scale; + max_scale = scales[j]; + } + } + + float iscale = -128.f/max_scale; + for (int j = 0; j < QK_K/16; ++j) { + int l = nearest_int(iscale*scales[j]); + y[i].scales[j] = MAX(-128, MIN(127, l)); + } + y[i].d = GGML_FP32_TO_FP16(1/iscale); + + for (int j = 0; j < QK_K/16; ++j) { + const float d = GGML_FP16_TO_FP32(y[i].d) * y[i].scales[j]; + if (!d) continue; + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-16, MIN(15, l)); + L[16*j + ii] = l + 16; + } + } + + uint8_t * restrict qh = y[i].qh; + uint8_t * restrict ql = y[i].qs; + memset(qh, 0, QK_K/8); + + for (int j = 0; j < 32; ++j) { + int jm = j%8; + int is = j/8; + int l1 = L[j]; + if (l1 > 15) { + l1 -= 16; qh[jm] |= (1 << is); + } + int l2 = L[j + 32]; + if (l2 > 15) { + l2 -= 16; qh[jm] |= (1 << (4 + is)); + } + ql[j] = l1 | (l2 << 4); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q5_K(const block_q5_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const uint8_t * ql = x[i].qs; + const uint8_t * qh = x[i].qh; + +#if QK_K == 256 + + const float d = GGML_FP16_TO_FP32(x[i].d); + const float min = GGML_FP16_TO_FP32(x[i].dmin); + + int is = 0; + uint8_t sc, m; + uint8_t u1 = 1, u2 = 2; + for (int j = 0; j < QK_K; j += 64) { + get_scale_min_k4(is + 0, x[i].scales, &sc, &m); + const float d1 = d * sc; const float m1 = min * m; + get_scale_min_k4(is + 1, x[i].scales, &sc, &m); + const float d2 = d * sc; const float m2 = min * m; + for (int l = 0; l < 32; ++l) *y++ = d1 * ((ql[l] & 0xF) + (qh[l] & u1 ? 16 : 0)) - m1; + for (int l = 0; l < 32; ++l) *y++ = d2 * ((ql[l] >> 4) + (qh[l] & u2 ? 16 : 0)) - m2; + ql += 32; is += 2; + u1 <<= 2; u2 <<= 2; + } +#else + float d = GGML_FP16_TO_FP32(x[i].d); + const int8_t * restrict s = x[i].scales; + for (int l = 0; l < 8; ++l) { + y[l+ 0] = d * s[0] * ((ql[l+ 0] & 0xF) - (qh[l] & 0x01 ? 0 : 16)); + y[l+ 8] = d * s[0] * ((ql[l+ 8] & 0xF) - (qh[l] & 0x02 ? 0 : 16)); + y[l+16] = d * s[1] * ((ql[l+16] & 0xF) - (qh[l] & 0x04 ? 0 : 16)); + y[l+24] = d * s[1] * ((ql[l+24] & 0xF) - (qh[l] & 0x08 ? 0 : 16)); + y[l+32] = d * s[2] * ((ql[l+ 0] >> 4) - (qh[l] & 0x10 ? 0 : 16)); + y[l+40] = d * s[2] * ((ql[l+ 8] >> 4) - (qh[l] & 0x20 ? 0 : 16)); + y[l+48] = d * s[3] * ((ql[l+16] >> 4) - (qh[l] & 0x40 ? 0 : 16)); + y[l+56] = d * s[3] * ((ql[l+24] >> 4) - (qh[l] & 0x80 ? 0 : 16)); + } + y += QK_K; +#endif + } +} + +void quantize_row_q5_K(const float * restrict x, void * restrict vy, int k) { + assert(k % QK_K == 0); + block_q5_K * restrict y = vy; + quantize_row_q5_K_reference(x, y, k); +} + +size_t ggml_quantize_q5_K(const float * restrict src, void * restrict dst, int n, int k, int64_t * restrict hist) { + assert(k % QK_K == 0); + (void)hist; // TODO: collect histograms + + for (int j = 0; j < n; j += k) { + block_q5_K * restrict y = (block_q5_K *)dst + j/QK_K; + quantize_row_q5_K_reference(src + j, y, k); + } + return (n/QK_K*sizeof(block_q5_K)); +} + +// ====================== 6-bit (de)-quantization + +void quantize_row_q6_K_reference(const float * restrict x, block_q6_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + int8_t L[QK_K]; + float scales[QK_K/16]; + + for (int i = 0; i < nb; i++) { + + float max_scale = 0; + float max_abs_scale = 0; + + for (int ib = 0; ib < QK_K/16; ++ib) { + + const float scale = make_qx_quants(16, 32, x + 16*ib, L + 16*ib, 1); + scales[ib] = scale; + + const float abs_scale = fabsf(scale); + if (abs_scale > max_abs_scale) { + max_abs_scale = abs_scale; + max_scale = scale; + } + + } + + if (!max_abs_scale) { + memset(&y[i], 0, sizeof(block_q6_K)); + y[i].d = GGML_FP32_TO_FP16(0.f); + x += QK_K; + continue; + } + + float iscale = -128.f/max_scale; + y[i].d = GGML_FP32_TO_FP16(1/iscale); + for (int ib = 0; ib < QK_K/16; ++ib) { + y[i].scales[ib] = MIN(127, nearest_int(iscale*scales[ib])); + } + + for (int j = 0; j < QK_K/16; ++j) { + float d = GGML_FP16_TO_FP32(y[i].d) * y[i].scales[j]; + if (!d) { + continue; + } + for (int ii = 0; ii < 16; ++ii) { + int l = nearest_int(x[16*j + ii]/d); + l = MAX(-32, MIN(31, l)); + L[16*j + ii] = l + 32; + } + } + + uint8_t * restrict ql = y[i].ql; + uint8_t * restrict qh = y[i].qh; +#if QK_K == 256 + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + const uint8_t q1 = L[j + l + 0] & 0xF; + const uint8_t q2 = L[j + l + 32] & 0xF; + const uint8_t q3 = L[j + l + 64] & 0xF; + const uint8_t q4 = L[j + l + 96] & 0xF; + ql[l+ 0] = q1 | (q3 << 4); + ql[l+32] = q2 | (q4 << 4); + qh[l] = (L[j + l] >> 4) | ((L[j + l + 32] >> 4) << 2) | ((L[j + l + 64] >> 4) << 4) | ((L[j + l + 96] >> 4) << 6); + } + ql += 64; + qh += 32; + } +#else + for (int l = 0; l < 32; ++l) { + const uint8_t q1 = L[l + 0] & 0xF; + const uint8_t q2 = L[l + 32] & 0xF; + ql[l] = q1 | (q2 << 4); + } + for (int l = 0; l < 16; ++l) { + qh[l] = (L[l] >> 4) | ((L[l + 16] >> 4) << 2) | ((L[l + 32] >> 4) << 4) | ((L[l + 48] >> 4) << 6); + } +#endif + + x += QK_K; + + } +} + +void dequantize_row_q6_K(const block_q6_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + const float d = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict ql = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict sc = x[i].scales; + +#if QK_K == 256 + for (int n = 0; n < QK_K; n += 128) { + for (int l = 0; l < 32; ++l) { + int is = l/16; + const int8_t q1 = (int8_t)((ql[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + const int8_t q2 = (int8_t)((ql[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + const int8_t q3 = (int8_t)((ql[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + const int8_t q4 = (int8_t)((ql[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + y[l + 0] = d * sc[is + 0] * q1; + y[l + 32] = d * sc[is + 2] * q2; + y[l + 64] = d * sc[is + 4] * q3; + y[l + 96] = d * sc[is + 6] * q4; + } + y += 128; + ql += 64; + qh += 32; + sc += 8; + } +#else + for (int l = 0; l < 16; ++l) { + const int8_t q1 = (int8_t)((ql[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + const int8_t q2 = (int8_t)((ql[l+16] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + const int8_t q3 = (int8_t)((ql[l+ 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + const int8_t q4 = (int8_t)((ql[l+16] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + y[l+ 0] = d * sc[0] * q1; + y[l+16] = d * sc[1] * q2; + y[l+32] = d * sc[2] * q3; + y[l+48] = d * sc[3] * q4; + } + y += 64; +#endif + + } +} + +void quantize_row_q6_K(const float * restrict x, void * restrict vy, int k) { + assert(k % QK_K == 0); + block_q6_K * restrict y = vy; + quantize_row_q6_K_reference(x, y, k); +} + +size_t ggml_quantize_q6_K(const float * src, void * dst, int n, int k, int64_t * hist) { + assert(k % QK_K == 0); + (void)hist; // TODO: collect histograms + + for (int j = 0; j < n; j += k) { + block_q6_K * restrict y = (block_q6_K *)dst + j/QK_K; + quantize_row_q6_K_reference(src + j, y, k); + } + return (n/QK_K*sizeof(block_q6_K)); +} + +//===================================== Q8_K ============================================== + +void quantize_row_q8_K_reference(const float * restrict x, block_q8_K * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + + float max = 0; + float amax = 0; + for (int j = 0; j < QK_K; ++j) { + float ax = fabsf(x[j]); + if (ax > amax) { + amax = ax; max = x[j]; + } + } + if (!amax) { + y[i].d = 0; + memset(y[i].qs, 0, QK_K); + x += QK_K; + continue; + } + const float iscale = -128.f/max; + for (int j = 0; j < QK_K; ++j) { + int v = nearest_int(iscale*x[j]); + y[i].qs[j] = MIN(127, v); + } + for (int j = 0; j < QK_K/16; ++j) { + int sum = 0; + for (int ii = 0; ii < 16; ++ii) { + sum += y[i].qs[j*16 + ii]; + } + y[i].bsums[j] = sum; + } + y[i].d = 1/iscale; + x += QK_K; + } +} + +void dequantize_row_q8_K(const block_q8_K * restrict x, float * restrict y, int k) { + assert(k % QK_K == 0); + const int nb = k / QK_K; + + for (int i = 0; i < nb; i++) { + for (int j = 0; j < QK_K; ++j) { + *y++ = x[i].d * x[i].qs[j]; + } + } +} + +void quantize_row_q8_K(const float * restrict x, void * restrict y, int k) { + quantize_row_q8_K_reference(x, y, k); +} + +//===================================== Dot ptoducts ================================= + +// +// Helper functions +// +#if __AVX__ || __AVX2__ || __AVX512F__ + +// shuffles to pick the required scales in dot products +static inline __m256i get_scale_shuffle_q3k(int i) { + static const uint8_t k_shuffle[128] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11, + 12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13, 14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15, + }; + return _mm256_loadu_si256((const __m256i*)k_shuffle + i); +} +static inline __m256i get_scale_shuffle_k4(int i) { + static const uint8_t k_shuffle[256] = { + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, 4, 5, + 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, 6, 7, + 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, 8, 9, + 10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11,10,11, + 12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13,12,13, + 14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15,14,15 + }; + return _mm256_loadu_si256((const __m256i*)k_shuffle + i); +} +static inline __m128i get_scale_shuffle(int i) { + static const uint8_t k_shuffle[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 10,10,10,10,10,10,10,10, 11,11,11,11,11,11,11,11, + 12,12,12,12,12,12,12,12, 13,13,13,13,13,13,13,13, + 14,14,14,14,14,14,14,14, 15,15,15,15,15,15,15,15 + }; + return _mm_loadu_si128((const __m128i*)k_shuffle + i); +} +#endif + +void ggml_vec_dot_q4_0_q8_0(int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); + + const block_q4_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q4_0 * restrict x0 = &x[i + 0]; + const block_q4_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i + 0]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + const int8x16_t s8b = vdupq_n_s8(0x8); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // sub 8 + const int8x16_t v0_0ls = vsubq_s8(v0_0l, s8b); + const int8x16_t v0_0hs = vsubq_s8(v0_0h, s8b); + const int8x16_t v0_1ls = vsubq_s8(v0_1l, s8b); + const int8x16_t v0_1hs = vsubq_s8(v0_1h, s8b); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + +#if defined(__ARM_FEATURE_DOTPROD) + // dot product into int32x4_t + const int32x4_t p_0 = vdotq_s32(vdotq_s32(vdupq_n_s32(0), v0_0ls, v1_0l), v0_0hs, v1_0h); + const int32x4_t p_1 = vdotq_s32(vdotq_s32(vdupq_n_s32(0), v0_1ls, v1_1l), v0_1hs, v1_1h); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(p_0), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(p_1), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); +#else + const int16x8_t pl0l = vmull_s8(vget_low_s8 (v0_0ls), vget_low_s8 (v1_0l)); + const int16x8_t pl0h = vmull_s8(vget_high_s8(v0_0ls), vget_high_s8(v1_0l)); + const int16x8_t ph0l = vmull_s8(vget_low_s8 (v0_0hs), vget_low_s8 (v1_0h)); + const int16x8_t ph0h = vmull_s8(vget_high_s8(v0_0hs), vget_high_s8(v1_0h)); + + const int16x8_t pl1l = vmull_s8(vget_low_s8 (v0_1ls), vget_low_s8 (v1_1l)); + const int16x8_t pl1h = vmull_s8(vget_high_s8(v0_1ls), vget_high_s8(v1_1l)); + const int16x8_t ph1l = vmull_s8(vget_low_s8 (v0_1hs), vget_low_s8 (v1_1h)); + const int16x8_t ph1h = vmull_s8(vget_high_s8(v0_1hs), vget_high_s8(v1_1h)); + + const int32x4_t pl0 = vaddq_s32(vpaddlq_s16(pl0l), vpaddlq_s16(pl0h)); + const int32x4_t ph0 = vaddq_s32(vpaddlq_s16(ph0l), vpaddlq_s16(ph0h)); + const int32x4_t pl1 = vaddq_s32(vpaddlq_s16(pl1l), vpaddlq_s16(pl1h)); + const int32x4_t ph1 = vaddq_s32(vpaddlq_s16(ph1l), vpaddlq_s16(ph1h)); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32(pl0, ph0)), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32(pl1, ph1)), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); +#endif + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + __m256i bx = bytes_from_nibbles_32(x[i].qs); + + // Now we have a vector with bytes in [ 0 .. 15 ] interval. Offset them into [ -8 .. +7 ] interval. + const __m256i off = _mm256_set1_epi8( 8 ); + bx = _mm256_sub_epi8( bx, off ); + + __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(bx, by); + + /* Multiply q with scale and accumulate */ + acc = _mm256_fmadd_ps( d, q, acc ); + } + + *s = hsum_float_8(acc); +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + // Compute combined scale for the block + const __m256 d = _mm256_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + const __m128i lowMask = _mm_set1_epi8(0xF); + const __m128i off = _mm_set1_epi8(8); + + const __m128i tmp = _mm_loadu_si128((const __m128i *)x[i].qs); + + __m128i bx = _mm_and_si128(lowMask, tmp); + __m128i by = _mm_loadu_si128((const __m128i *)y[i].qs); + bx = _mm_sub_epi8(bx, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx, by); + + bx = _mm_and_si128(lowMask, _mm_srli_epi64(tmp, 4)); + by = _mm_loadu_si128((const __m128i *)(y[i].qs + 16)); + bx = _mm_sub_epi8(bx, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx, by); + + // Convert int32_t to float + __m256 p = _mm256_cvtepi32_ps(MM256_SET_M128I(i32_0, i32_1)); + + // Apply the scale, and accumulate + acc = _mm256_add_ps(_mm256_mul_ps( d, p ), acc); + } + + *s = hsum_float_8(acc); +#elif defined(__SSSE3__) + // set constants + const __m128i lowMask = _mm_set1_epi8(0xF); + const __m128i off = _mm_set1_epi8(8); + + // Initialize accumulator with zeros + __m128 acc_0 = _mm_setzero_ps(); + __m128 acc_1 = _mm_setzero_ps(); + __m128 acc_2 = _mm_setzero_ps(); + __m128 acc_3 = _mm_setzero_ps(); + + // First round without accumulation + { + _mm_prefetch(&x[0] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[0] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 0 and 1 + const __m128 d_0_1 = _mm_set1_ps( GGML_FP16_TO_FP32(x[0].d) * GGML_FP16_TO_FP32(y[0].d) ); + + const __m128i tmp_0_1 = _mm_loadu_si128((const __m128i *)x[0].qs); + + __m128i bx_0 = _mm_and_si128(lowMask, tmp_0_1); + __m128i by_0 = _mm_loadu_si128((const __m128i *)y[0].qs); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx_0, by_0); + + __m128i bx_1 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_0_1, 4)); + __m128i by_1 = _mm_loadu_si128((const __m128i *)(y[0].qs + 16)); + bx_1 = _mm_sub_epi8(bx_1, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx_1, by_1); + + _mm_prefetch(&x[1] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[1] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 2 and 3 + const __m128 d_2_3 = _mm_set1_ps( GGML_FP16_TO_FP32(x[1].d) * GGML_FP16_TO_FP32(y[1].d) ); + + const __m128i tmp_2_3 = _mm_loadu_si128((const __m128i *)x[1].qs); + + __m128i bx_2 = _mm_and_si128(lowMask, tmp_2_3); + __m128i by_2 = _mm_loadu_si128((const __m128i *)y[1].qs); + bx_2 = _mm_sub_epi8(bx_2, off); + const __m128i i32_2 = mul_sum_i8_pairs(bx_2, by_2); + + __m128i bx_3 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_2_3, 4)); + __m128i by_3 = _mm_loadu_si128((const __m128i *)(y[1].qs + 16)); + bx_3 = _mm_sub_epi8(bx_3, off); + const __m128i i32_3 = mul_sum_i8_pairs(bx_3, by_3); + + // Convert int32_t to float + __m128 p0 = _mm_cvtepi32_ps(i32_0); + __m128 p1 = _mm_cvtepi32_ps(i32_1); + __m128 p2 = _mm_cvtepi32_ps(i32_2); + __m128 p3 = _mm_cvtepi32_ps(i32_3); + + // Apply the scale + acc_0 = _mm_mul_ps( d_0_1, p0 ); + acc_1 = _mm_mul_ps( d_0_1, p1 ); + acc_2 = _mm_mul_ps( d_2_3, p2 ); + acc_3 = _mm_mul_ps( d_2_3, p3 ); + } + + assert(nb % 2 == 0); // TODO: handle odd nb + + // Main loop + for (int i = 2; i < nb; i+=2) { + _mm_prefetch(&x[i] + sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[i] + sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 0 and 1 + const __m128 d_0_1 = _mm_set1_ps( GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d) ); + + const __m128i tmp_0_1 = _mm_loadu_si128((const __m128i *)x[i].qs); + + __m128i bx_0 = _mm_and_si128(lowMask, tmp_0_1); + __m128i by_0 = _mm_loadu_si128((const __m128i *)y[i].qs); + bx_0 = _mm_sub_epi8(bx_0, off); + const __m128i i32_0 = mul_sum_i8_pairs(bx_0, by_0); + + __m128i bx_1 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_0_1, 4)); + __m128i by_1 = _mm_loadu_si128((const __m128i *)(y[i].qs + 16)); + bx_1 = _mm_sub_epi8(bx_1, off); + const __m128i i32_1 = mul_sum_i8_pairs(bx_1, by_1); + + _mm_prefetch(&x[i] + 2 * sizeof(block_q4_0), _MM_HINT_T0); + _mm_prefetch(&y[i] + 2 * sizeof(block_q8_0), _MM_HINT_T0); + + // Compute combined scale for the block 2 and 3 + const __m128 d_2_3 = _mm_set1_ps( GGML_FP16_TO_FP32(x[i + 1].d) * GGML_FP16_TO_FP32(y[i + 1].d) ); + + const __m128i tmp_2_3 = _mm_loadu_si128((const __m128i *)x[i + 1].qs); + + __m128i bx_2 = _mm_and_si128(lowMask, tmp_2_3); + __m128i by_2 = _mm_loadu_si128((const __m128i *)y[i + 1].qs); + bx_2 = _mm_sub_epi8(bx_2, off); + const __m128i i32_2 = mul_sum_i8_pairs(bx_2, by_2); + + __m128i bx_3 = _mm_and_si128(lowMask, _mm_srli_epi64(tmp_2_3, 4)); + __m128i by_3 = _mm_loadu_si128((const __m128i *)(y[i + 1].qs + 16)); + bx_3 = _mm_sub_epi8(bx_3, off); + const __m128i i32_3 = mul_sum_i8_pairs(bx_3, by_3); + + // Convert int32_t to float + __m128 p0 = _mm_cvtepi32_ps(i32_0); + __m128 p1 = _mm_cvtepi32_ps(i32_1); + __m128 p2 = _mm_cvtepi32_ps(i32_2); + __m128 p3 = _mm_cvtepi32_ps(i32_3); + + // Apply the scale + __m128 p0_d = _mm_mul_ps( d_0_1, p0 ); + __m128 p1_d = _mm_mul_ps( d_0_1, p1 ); + __m128 p2_d = _mm_mul_ps( d_2_3, p2 ); + __m128 p3_d = _mm_mul_ps( d_2_3, p3 ); + + // Acummulate + acc_0 = _mm_add_ps(p0_d, acc_0); + acc_1 = _mm_add_ps(p1_d, acc_1); + acc_2 = _mm_add_ps(p2_d, acc_2); + acc_3 = _mm_add_ps(p3_d, acc_3); + } + + *s = hsum_float_4x4(acc_0, acc_1, acc_2, acc_3); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + for (int i = 0; i < nb; i++) { + // load elements + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + // mask and store lower part of x, and then upper part + vuint8mf2_t x_a = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_l = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vint8mf2_t x_ai = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t x_li = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + // subtract offset + vint8mf2_t v0 = __riscv_vsub_vx_i8mf2(x_ai, 8, vl); + vint8mf2_t v1 = __riscv_vsub_vx_i8mf2(x_li, 8, vl); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += sumi*GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const int v0 = (x[i].qs[j] & 0x0F) - 8; + const int v1 = (x[i].qs[j] >> 4) - 8; + + sumi += (v0 * y[i].qs[j]) + (v1 * y[i].qs[j + qk/2]); + } + + sumf += sumi*GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d); + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q4_1_q8_1(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + const int qk = QK8_1; + const int nb = n / qk; + + assert(n % qk == 0); + + const block_q4_1 * restrict x = vx; + const block_q8_1 * restrict y = vy; + + // TODO: add WASM SIMD +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + float summs = 0; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q4_1 * restrict x0 = &x[i + 0]; + const block_q4_1 * restrict x1 = &x[i + 1]; + const block_q8_1 * restrict y0 = &y[i + 0]; + const block_q8_1 * restrict y1 = &y[i + 1]; + + summs += GGML_FP16_TO_FP32(x0->m) * y0->s + GGML_FP16_TO_FP32(x1->m) * y1->s; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + +#if defined(__ARM_FEATURE_DOTPROD) + // dot product into int32x4_t + const int32x4_t p_0 = vdotq_s32(vdotq_s32(vdupq_n_s32(0), v0_0l, v1_0l), v0_0h, v1_0h); + const int32x4_t p_1 = vdotq_s32(vdotq_s32(vdupq_n_s32(0), v0_1l, v1_1l), v0_1h, v1_1h); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(p_0), GGML_FP16_TO_FP32(x0->d)*y0->d); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(p_1), GGML_FP16_TO_FP32(x1->d)*y1->d); +#else + const int16x8_t pl0l = vmull_s8(vget_low_s8 (v0_0l), vget_low_s8 (v1_0l)); + const int16x8_t pl0h = vmull_s8(vget_high_s8(v0_0l), vget_high_s8(v1_0l)); + const int16x8_t ph0l = vmull_s8(vget_low_s8 (v0_0h), vget_low_s8 (v1_0h)); + const int16x8_t ph0h = vmull_s8(vget_high_s8(v0_0h), vget_high_s8(v1_0h)); + + const int16x8_t pl1l = vmull_s8(vget_low_s8 (v0_1l), vget_low_s8 (v1_1l)); + const int16x8_t pl1h = vmull_s8(vget_high_s8(v0_1l), vget_high_s8(v1_1l)); + const int16x8_t ph1l = vmull_s8(vget_low_s8 (v0_1h), vget_low_s8 (v1_1h)); + const int16x8_t ph1h = vmull_s8(vget_high_s8(v0_1h), vget_high_s8(v1_1h)); + + const int32x4_t pl0 = vaddq_s32(vpaddlq_s16(pl0l), vpaddlq_s16(pl0h)); + const int32x4_t ph0 = vaddq_s32(vpaddlq_s16(ph0l), vpaddlq_s16(ph0h)); + const int32x4_t pl1 = vaddq_s32(vpaddlq_s16(pl1l), vpaddlq_s16(pl1h)); + const int32x4_t ph1 = vaddq_s32(vpaddlq_s16(ph1l), vpaddlq_s16(ph1h)); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32(pl0, ph0)), GGML_FP16_TO_FP32(x0->d)*y0->d); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32(pl1, ph1)), GGML_FP16_TO_FP32(x1->d)*y1->d); +#endif + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1) + summs; +#elif defined(__AVX2__) || defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + // Main loop + for (int i = 0; i < nb; ++i) { + const float d0 = GGML_FP16_TO_FP32(x[i].d); + const float d1 = y[i].d; + + summs += GGML_FP16_TO_FP32(x[i].m) * y[i].s; + + const __m256 d0v = _mm256_set1_ps( d0 ); + const __m256 d1v = _mm256_set1_ps( d1 ); + + // Compute combined scales + const __m256 d0d1 = _mm256_mul_ps( d0v, d1v ); + + // Load 16 bytes, and unpack 4 bit fields into bytes, making 32 bytes + const __m256i bx = bytes_from_nibbles_32(x[i].qs); + const __m256i by = _mm256_loadu_si256( (const __m256i *)y[i].qs ); + + const __m256 xy = mul_sum_us8_pairs_float(bx, by); + + // Accumulate d0*d1*x*y +#if defined(__AVX2__) + acc = _mm256_fmadd_ps( d0d1, xy, acc ); +#else + acc = _mm256_add_ps( _mm256_mul_ps( d0d1, xy ), acc ); +#endif + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + for (int i = 0; i < nb; i++) { + // load elements + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + // mask and store lower part of x, and then upper part + vuint8mf2_t x_a = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_l = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vint8mf2_t v0 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t v1 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*y[i].d)*sumi + GGML_FP16_TO_FP32(x[i].m)*y[i].s; + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const int v0 = (x[i].qs[j] & 0x0F); + const int v1 = (x[i].qs[j] >> 4); + + sumi += (v0 * y[i].qs[j]) + (v1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*y[i].d)*sumi + GGML_FP16_TO_FP32(x[i].m)*y[i].s; + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q5_0_q8_0(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); + assert(qk == QK5_0); + + const block_q5_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + uint32_t qh0; + uint32_t qh1; + + uint64_t tmp0[4]; + uint64_t tmp1[4]; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q5_0 * restrict x0 = &x[i]; + const block_q5_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + // extract the 5th bit via lookup table ((!b) << 4) + memcpy(&qh0, x0->qh, sizeof(qh0)); + memcpy(&qh1, x1->qh, sizeof(qh1)); + + tmp0[0] = table_b2b_1[(qh0 >> 0) & 0xFF]; + tmp0[1] = table_b2b_1[(qh0 >> 8) & 0xFF]; + tmp0[2] = table_b2b_1[(qh0 >> 16) & 0xFF]; + tmp0[3] = table_b2b_1[(qh0 >> 24) ]; + + tmp1[0] = table_b2b_1[(qh1 >> 0) & 0xFF]; + tmp1[1] = table_b2b_1[(qh1 >> 8) & 0xFF]; + tmp1[2] = table_b2b_1[(qh1 >> 16) & 0xFF]; + tmp1[3] = table_b2b_1[(qh1 >> 24) ]; + + const int8x16_t qhl0 = vld1q_s8((const int8_t *)(tmp0 + 0)); + const int8x16_t qhh0 = vld1q_s8((const int8_t *)(tmp0 + 2)); + const int8x16_t qhl1 = vld1q_s8((const int8_t *)(tmp1 + 0)); + const int8x16_t qhh1 = vld1q_s8((const int8_t *)(tmp1 + 2)); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // add high bit and sub 16 (equivalent to sub 0x10 when bit is zero) + const int8x16_t v0_0lf = vsubq_s8(v0_0l, qhl0); + const int8x16_t v0_0hf = vsubq_s8(v0_0h, qhh0); + const int8x16_t v0_1lf = vsubq_s8(v0_1l, qhl1); + const int8x16_t v0_1hf = vsubq_s8(v0_1h, qhh1); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + +#if defined(__ARM_FEATURE_DOTPROD) + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), v0_0lf, v1_0l), + vdotq_s32(vdupq_n_s32(0), v0_0hf, v1_0h))), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), v0_1lf, v1_1l), + vdotq_s32(vdupq_n_s32(0), v0_1hf, v1_1h))), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); +#else + const int16x8_t pl0l = vmull_s8(vget_low_s8 (v0_0lf), vget_low_s8 (v1_0l)); + const int16x8_t pl0h = vmull_s8(vget_high_s8(v0_0lf), vget_high_s8(v1_0l)); + const int16x8_t ph0l = vmull_s8(vget_low_s8 (v0_0hf), vget_low_s8 (v1_0h)); + const int16x8_t ph0h = vmull_s8(vget_high_s8(v0_0hf), vget_high_s8(v1_0h)); + + const int16x8_t pl1l = vmull_s8(vget_low_s8 (v0_1lf), vget_low_s8 (v1_1l)); + const int16x8_t pl1h = vmull_s8(vget_high_s8(v0_1lf), vget_high_s8(v1_1l)); + const int16x8_t ph1l = vmull_s8(vget_low_s8 (v0_1hf), vget_low_s8 (v1_1h)); + const int16x8_t ph1h = vmull_s8(vget_high_s8(v0_1hf), vget_high_s8(v1_1h)); + + const int32x4_t pl0 = vaddq_s32(vpaddlq_s16(pl0l), vpaddlq_s16(pl0h)); + const int32x4_t ph0 = vaddq_s32(vpaddlq_s16(ph0l), vpaddlq_s16(ph0h)); + const int32x4_t pl1 = vaddq_s32(vpaddlq_s16(pl1l), vpaddlq_s16(pl1h)); + const int32x4_t ph1 = vaddq_s32(vpaddlq_s16(ph1l), vpaddlq_s16(ph1h)); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32(pl0, ph0)), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32(pl1, ph1)), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); +#endif + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__wasm_simd128__) + v128_t sumv = wasm_f32x4_splat(0.0f); + + uint32_t qh; + uint64_t tmp[4]; + + // TODO: check if unrolling this is better + for (int i = 0; i < nb; ++i) { + const block_q5_0 * restrict x0 = &x[i]; + const block_q8_0 * restrict y0 = &y[i]; + + const v128_t m4b = wasm_i8x16_splat(0x0F); + + // extract the 5th bit + memcpy(&qh, x0->qh, sizeof(qh)); + + tmp[0] = table_b2b_1[(qh >> 0) & 0xFF]; + tmp[1] = table_b2b_1[(qh >> 8) & 0xFF]; + tmp[2] = table_b2b_1[(qh >> 16) & 0xFF]; + tmp[3] = table_b2b_1[(qh >> 24) ]; + + const v128_t qhl = wasm_v128_load(tmp + 0); + const v128_t qhh = wasm_v128_load(tmp + 2); + + const v128_t v0 = wasm_v128_load(x0->qs); + + // 4-bit -> 8-bit + const v128_t v0l = wasm_v128_and (v0, m4b); + const v128_t v0h = wasm_u8x16_shr(v0, 4); + + // add high bit and sub 16 (equivalent to sub 0x10 when bit is zero) + const v128_t v0lf = wasm_i8x16_sub(v0l, qhl); + const v128_t v0hf = wasm_i8x16_sub(v0h, qhh); + + // load y + const v128_t v1l = wasm_v128_load(y0->qs); + const v128_t v1h = wasm_v128_load(y0->qs + 16); + + // int8x16 -> int16x8 + const v128_t v0lfl = wasm_i16x8_extend_low_i8x16 (v0lf); + const v128_t v0lfh = wasm_i16x8_extend_high_i8x16(v0lf); + const v128_t v0hfl = wasm_i16x8_extend_low_i8x16 (v0hf); + const v128_t v0hfh = wasm_i16x8_extend_high_i8x16(v0hf); + + const v128_t v1ll = wasm_i16x8_extend_low_i8x16 (v1l); + const v128_t v1lh = wasm_i16x8_extend_high_i8x16(v1l); + const v128_t v1hl = wasm_i16x8_extend_low_i8x16 (v1h); + const v128_t v1hh = wasm_i16x8_extend_high_i8x16(v1h); + + // dot product + sumv = wasm_f32x4_add(sumv, wasm_f32x4_mul(wasm_f32x4_convert_i32x4( + wasm_i32x4_add( + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0lfl, v1ll), + wasm_i32x4_dot_i16x8(v0lfh, v1lh)), + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0hfl, v1hl), + wasm_i32x4_dot_i16x8(v0hfh, v1hh)))), + wasm_f32x4_splat(GGML_FP16_TO_FP32(x0->d) * GGML_FP16_TO_FP32(y0->d)))); + } + + *s = wasm_f32x4_extract_lane(sumv, 0) + wasm_f32x4_extract_lane(sumv, 1) + + wasm_f32x4_extract_lane(sumv, 2) + wasm_f32x4_extract_lane(sumv, 3); +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; i++) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + + __m256i bx = bytes_from_nibbles_32(x[i].qs); + __m256i bxhi = bytes_from_bits_32(x[i].qh); + bxhi = _mm256_andnot_si256(bxhi, _mm256_set1_epi8((char)0xF0)); + bx = _mm256_or_si256(bx, bxhi); + + __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(bx, by); + + /* Multiply q with scale and accumulate */ + acc = _mm256_fmadd_ps(d, q, acc); + } + + *s = hsum_float_8(acc); +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + __m128i mask = _mm_set1_epi8((char)0xF0); + + // Main loop + for (int i = 0; i < nb; i++) { + /* Compute combined scale for the block */ + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + + __m256i bx = bytes_from_nibbles_32(x[i].qs); + const __m256i bxhi = bytes_from_bits_32(x[i].qh); + __m128i bxhil = _mm256_castsi256_si128(bxhi); + __m128i bxhih = _mm256_extractf128_si256(bxhi, 1); + bxhil = _mm_andnot_si128(bxhil, mask); + bxhih = _mm_andnot_si128(bxhih, mask); + __m128i bxl = _mm256_castsi256_si128(bx); + __m128i bxh = _mm256_extractf128_si256(bx, 1); + bxl = _mm_or_si128(bxl, bxhil); + bxh = _mm_or_si128(bxh, bxhih); + bx = MM256_SET_M128I(bxh, bxl); + + const __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(bx, by); + + /* Multiply q with scale and accumulate */ + acc = _mm256_add_ps(_mm256_mul_ps(d, q), acc); + } + + *s = hsum_float_8(acc); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + uint32_t qh; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + // These tempory registers are for masking and shift operations + vuint32m2_t vt_1 = __riscv_vid_v_u32m2(vl); + vuint32m2_t vt_2 = __riscv_vsll_vv_u32m2(__riscv_vmv_v_x_u32m2(1, vl), vt_1, vl); + + vuint32m2_t vt_3 = __riscv_vsll_vx_u32m2(vt_2, 16, vl); + vuint32m2_t vt_4 = __riscv_vadd_vx_u32m2(vt_1, 12, vl); + + for (int i = 0; i < nb; i++) { + memcpy(&qh, x[i].qh, sizeof(uint32_t)); + + // ((qh & (1u << (j + 0 ))) >> (j + 0 )) << 4; + vuint32m2_t xha_0 = __riscv_vand_vx_u32m2(vt_2, qh, vl); + vuint32m2_t xhr_0 = __riscv_vsrl_vv_u32m2(xha_0, vt_1, vl); + vuint32m2_t xhl_0 = __riscv_vsll_vx_u32m2(xhr_0, 4, vl); + + // ((qh & (1u << (j + 16))) >> (j + 12)); + vuint32m2_t xha_1 = __riscv_vand_vx_u32m2(vt_3, qh, vl); + vuint32m2_t xhl_1 = __riscv_vsrl_vv_u32m2(xha_1, vt_4, vl); + + // narrowing + vuint16m1_t xhc_0 = __riscv_vncvt_x_x_w_u16m1(xhl_0, vl); + vuint8mf2_t xh_0 = __riscv_vncvt_x_x_w_u8mf2(xhc_0, vl); + + vuint16m1_t xhc_1 = __riscv_vncvt_x_x_w_u16m1(xhl_1, vl); + vuint8mf2_t xh_1 = __riscv_vncvt_x_x_w_u8mf2(xhc_1, vl); + + // load + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + vuint8mf2_t x_at = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_lt = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vuint8mf2_t x_a = __riscv_vor_vv_u8mf2(x_at, xh_0, vl); + vuint8mf2_t x_l = __riscv_vor_vv_u8mf2(x_lt, xh_1, vl); + + vint8mf2_t x_ai = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t x_li = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint8mf2_t v0 = __riscv_vsub_vx_i8mf2(x_ai, 16, vl); + vint8mf2_t v1 = __riscv_vsub_vx_i8mf2(x_li, 16, vl); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)) * sumi; + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh & (1u << (j + 0 ))) >> (j + 0 )) << 4; + const uint8_t xh_1 = ((qh & (1u << (j + 16))) >> (j + 12)); + + const int32_t x0 = ((x[i].qs[j] & 0x0F) | xh_0) - 16; + const int32_t x1 = ((x[i].qs[j] >> 4) | xh_1) - 16; + + sumi += (x0 * y[i].qs[j]) + (x1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)) * sumi; + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q5_1_q8_1(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + const int qk = QK8_1; + const int nb = n / qk; + + assert(n % qk == 0); + assert(qk == QK5_1); + + const block_q5_1 * restrict x = vx; + const block_q8_1 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + float summs0 = 0.0f; + float summs1 = 0.0f; + + uint32_t qh0; + uint32_t qh1; + + uint64_t tmp0[4]; + uint64_t tmp1[4]; + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q5_1 * restrict x0 = &x[i]; + const block_q5_1 * restrict x1 = &x[i + 1]; + const block_q8_1 * restrict y0 = &y[i]; + const block_q8_1 * restrict y1 = &y[i + 1]; + + const uint8x16_t m4b = vdupq_n_u8(0x0F); + + summs0 += GGML_FP16_TO_FP32(x0->m) * y0->s; + summs1 += GGML_FP16_TO_FP32(x1->m) * y1->s; + + // extract the 5th bit via lookup table ((b) << 4) + memcpy(&qh0, x0->qh, sizeof(qh0)); + memcpy(&qh1, x1->qh, sizeof(qh1)); + + tmp0[0] = table_b2b_0[(qh0 >> 0) & 0xFF]; + tmp0[1] = table_b2b_0[(qh0 >> 8) & 0xFF]; + tmp0[2] = table_b2b_0[(qh0 >> 16) & 0xFF]; + tmp0[3] = table_b2b_0[(qh0 >> 24) ]; + + tmp1[0] = table_b2b_0[(qh1 >> 0) & 0xFF]; + tmp1[1] = table_b2b_0[(qh1 >> 8) & 0xFF]; + tmp1[2] = table_b2b_0[(qh1 >> 16) & 0xFF]; + tmp1[3] = table_b2b_0[(qh1 >> 24) ]; + + const int8x16_t qhl0 = vld1q_s8((const int8_t *)(tmp0 + 0)); + const int8x16_t qhh0 = vld1q_s8((const int8_t *)(tmp0 + 2)); + const int8x16_t qhl1 = vld1q_s8((const int8_t *)(tmp1 + 0)); + const int8x16_t qhh1 = vld1q_s8((const int8_t *)(tmp1 + 2)); + + const uint8x16_t v0_0 = vld1q_u8(x0->qs); + const uint8x16_t v0_1 = vld1q_u8(x1->qs); + + // 4-bit -> 8-bit + const int8x16_t v0_0l = vreinterpretq_s8_u8(vandq_u8 (v0_0, m4b)); + const int8x16_t v0_0h = vreinterpretq_s8_u8(vshrq_n_u8(v0_0, 4)); + const int8x16_t v0_1l = vreinterpretq_s8_u8(vandq_u8 (v0_1, m4b)); + const int8x16_t v0_1h = vreinterpretq_s8_u8(vshrq_n_u8(v0_1, 4)); + + // add high bit + const int8x16_t v0_0lf = vorrq_s8(v0_0l, qhl0); + const int8x16_t v0_0hf = vorrq_s8(v0_0h, qhh0); + const int8x16_t v0_1lf = vorrq_s8(v0_1l, qhl1); + const int8x16_t v0_1hf = vorrq_s8(v0_1h, qhh1); + + // load y + const int8x16_t v1_0l = vld1q_s8(y0->qs); + const int8x16_t v1_0h = vld1q_s8(y0->qs + 16); + const int8x16_t v1_1l = vld1q_s8(y1->qs); + const int8x16_t v1_1h = vld1q_s8(y1->qs + 16); + +#if defined(__ARM_FEATURE_DOTPROD) + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), v0_0lf, v1_0l), + vdotq_s32(vdupq_n_s32(0), v0_0hf, v1_0h))), GGML_FP16_TO_FP32(x0->d)*y0->d); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), v0_1lf, v1_1l), + vdotq_s32(vdupq_n_s32(0), v0_1hf, v1_1h))), GGML_FP16_TO_FP32(x1->d)*y1->d); +#else + const int16x8_t pl0l = vmull_s8(vget_low_s8 (v0_0lf), vget_low_s8 (v1_0l)); + const int16x8_t pl0h = vmull_s8(vget_high_s8(v0_0lf), vget_high_s8(v1_0l)); + const int16x8_t ph0l = vmull_s8(vget_low_s8 (v0_0hf), vget_low_s8 (v1_0h)); + const int16x8_t ph0h = vmull_s8(vget_high_s8(v0_0hf), vget_high_s8(v1_0h)); + + const int16x8_t pl1l = vmull_s8(vget_low_s8 (v0_1lf), vget_low_s8 (v1_1l)); + const int16x8_t pl1h = vmull_s8(vget_high_s8(v0_1lf), vget_high_s8(v1_1l)); + const int16x8_t ph1l = vmull_s8(vget_low_s8 (v0_1hf), vget_low_s8 (v1_1h)); + const int16x8_t ph1h = vmull_s8(vget_high_s8(v0_1hf), vget_high_s8(v1_1h)); + + const int32x4_t pl0 = vaddq_s32(vpaddlq_s16(pl0l), vpaddlq_s16(pl0h)); + const int32x4_t ph0 = vaddq_s32(vpaddlq_s16(ph0l), vpaddlq_s16(ph0h)); + const int32x4_t pl1 = vaddq_s32(vpaddlq_s16(pl1l), vpaddlq_s16(pl1h)); + const int32x4_t ph1 = vaddq_s32(vpaddlq_s16(ph1l), vpaddlq_s16(ph1h)); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32(pl0, ph0)), GGML_FP16_TO_FP32(x0->d)*y0->d); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32(pl1, ph1)), GGML_FP16_TO_FP32(x1->d)*y1->d); +#endif + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1) + summs0 + summs1; +#elif defined(__wasm_simd128__) + v128_t sumv = wasm_f32x4_splat(0.0f); + + float summs = 0.0f; + + uint32_t qh; + uint64_t tmp[4]; + + // TODO: check if unrolling this is better + for (int i = 0; i < nb; ++i) { + const block_q5_1 * restrict x0 = &x[i]; + const block_q8_1 * restrict y0 = &y[i]; + + summs += GGML_FP16_TO_FP32(x0->m) * y0->s; + + const v128_t m4b = wasm_i8x16_splat(0x0F); + + // extract the 5th bit + memcpy(&qh, x0->qh, sizeof(qh)); + + tmp[0] = table_b2b_0[(qh >> 0) & 0xFF]; + tmp[1] = table_b2b_0[(qh >> 8) & 0xFF]; + tmp[2] = table_b2b_0[(qh >> 16) & 0xFF]; + tmp[3] = table_b2b_0[(qh >> 24) ]; + + const v128_t qhl = wasm_v128_load(tmp + 0); + const v128_t qhh = wasm_v128_load(tmp + 2); + + const v128_t v0 = wasm_v128_load(x0->qs); + + // 4-bit -> 8-bit + const v128_t v0l = wasm_v128_and (v0, m4b); + const v128_t v0h = wasm_u8x16_shr(v0, 4); + + // add high bit + const v128_t v0lf = wasm_v128_or(v0l, qhl); + const v128_t v0hf = wasm_v128_or(v0h, qhh); + + // load y + const v128_t v1l = wasm_v128_load(y0->qs); + const v128_t v1h = wasm_v128_load(y0->qs + 16); + + // int8x16 -> int16x8 + const v128_t v0lfl = wasm_i16x8_extend_low_i8x16 (v0lf); + const v128_t v0lfh = wasm_i16x8_extend_high_i8x16(v0lf); + const v128_t v0hfl = wasm_i16x8_extend_low_i8x16 (v0hf); + const v128_t v0hfh = wasm_i16x8_extend_high_i8x16(v0hf); + + const v128_t v1ll = wasm_i16x8_extend_low_i8x16 (v1l); + const v128_t v1lh = wasm_i16x8_extend_high_i8x16(v1l); + const v128_t v1hl = wasm_i16x8_extend_low_i8x16 (v1h); + const v128_t v1hh = wasm_i16x8_extend_high_i8x16(v1h); + + // dot product + sumv = wasm_f32x4_add(sumv, + wasm_f32x4_mul(wasm_f32x4_convert_i32x4(wasm_i32x4_add( + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0lfl, v1ll), + wasm_i32x4_dot_i16x8(v0lfh, v1lh)), + wasm_i32x4_add(wasm_i32x4_dot_i16x8(v0hfl, v1hl), + wasm_i32x4_dot_i16x8(v0hfh, v1hh)))), + wasm_f32x4_splat(GGML_FP16_TO_FP32(x0->d) * y0->d))); + } + + *s = wasm_f32x4_extract_lane(sumv, 0) + wasm_f32x4_extract_lane(sumv, 1) + + wasm_f32x4_extract_lane(sumv, 2) + wasm_f32x4_extract_lane(sumv, 3) + summs; +#elif defined(__AVX2__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.0f; + + // Main loop + for (int i = 0; i < nb; i++) { + const __m256 dx = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d)); + + summs += GGML_FP16_TO_FP32(x[i].m) * y[i].s; + + __m256i bx = bytes_from_nibbles_32(x[i].qs); + __m256i bxhi = bytes_from_bits_32(x[i].qh); + bxhi = _mm256_and_si256(bxhi, _mm256_set1_epi8(0x10)); + bx = _mm256_or_si256(bx, bxhi); + + const __m256 dy = _mm256_set1_ps(y[i].d); + const __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_us8_pairs_float(bx, by); + + acc = _mm256_fmadd_ps(q, _mm256_mul_ps(dx, dy), acc); + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + __m128i mask = _mm_set1_epi8(0x10); + + float summs = 0.0f; + + // Main loop + for (int i = 0; i < nb; i++) { + const __m256 dx = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d)); + + summs += GGML_FP16_TO_FP32(x[i].m) * y[i].s; + + __m256i bx = bytes_from_nibbles_32(x[i].qs); + const __m256i bxhi = bytes_from_bits_32(x[i].qh); + __m128i bxhil = _mm256_castsi256_si128(bxhi); + __m128i bxhih = _mm256_extractf128_si256(bxhi, 1); + bxhil = _mm_and_si128(bxhil, mask); + bxhih = _mm_and_si128(bxhih, mask); + __m128i bxl = _mm256_castsi256_si128(bx); + __m128i bxh = _mm256_extractf128_si256(bx, 1); + bxl = _mm_or_si128(bxl, bxhil); + bxh = _mm_or_si128(bxh, bxhih); + bx = MM256_SET_M128I(bxh, bxl); + + const __m256 dy = _mm256_set1_ps(y[i].d); + const __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_us8_pairs_float(bx, by); + + acc = _mm256_add_ps(_mm256_mul_ps(q, _mm256_mul_ps(dx, dy)), acc); + } + + *s = hsum_float_8(acc) + summs; +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + + uint32_t qh; + + size_t vl = __riscv_vsetvl_e8m1(qk/2); + + // temporary registers for shift operations + vuint32m2_t vt_1 = __riscv_vid_v_u32m2(vl); + vuint32m2_t vt_2 = __riscv_vadd_vx_u32m2(vt_1, 12, vl); + + for (int i = 0; i < nb; i++) { + memcpy(&qh, x[i].qh, sizeof(uint32_t)); + + // load qh + vuint32m2_t vqh = __riscv_vmv_v_x_u32m2(qh, vl); + + // ((qh >> (j + 0)) << 4) & 0x10; + vuint32m2_t xhr_0 = __riscv_vsrl_vv_u32m2(vqh, vt_1, vl); + vuint32m2_t xhl_0 = __riscv_vsll_vx_u32m2(xhr_0, 4, vl); + vuint32m2_t xha_0 = __riscv_vand_vx_u32m2(xhl_0, 0x10, vl); + + // ((qh >> (j + 12)) ) & 0x10; + vuint32m2_t xhr_1 = __riscv_vsrl_vv_u32m2(vqh, vt_2, vl); + vuint32m2_t xha_1 = __riscv_vand_vx_u32m2(xhr_1, 0x10, vl); + + // narrowing + vuint16m1_t xhc_0 = __riscv_vncvt_x_x_w_u16m1(xha_0, vl); + vuint8mf2_t xh_0 = __riscv_vncvt_x_x_w_u8mf2(xhc_0, vl); + + vuint16m1_t xhc_1 = __riscv_vncvt_x_x_w_u16m1(xha_1, vl); + vuint8mf2_t xh_1 = __riscv_vncvt_x_x_w_u8mf2(xhc_1, vl); + + // load + vuint8mf2_t tx = __riscv_vle8_v_u8mf2(x[i].qs, vl); + + vint8mf2_t y0 = __riscv_vle8_v_i8mf2(y[i].qs, vl); + vint8mf2_t y1 = __riscv_vle8_v_i8mf2(y[i].qs+16, vl); + + vuint8mf2_t x_at = __riscv_vand_vx_u8mf2(tx, 0x0F, vl); + vuint8mf2_t x_lt = __riscv_vsrl_vx_u8mf2(tx, 0x04, vl); + + vuint8mf2_t x_a = __riscv_vor_vv_u8mf2(x_at, xh_0, vl); + vuint8mf2_t x_l = __riscv_vor_vv_u8mf2(x_lt, xh_1, vl); + + vint8mf2_t v0 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_a); + vint8mf2_t v1 = __riscv_vreinterpret_v_u8mf2_i8mf2(x_l); + + vint16m1_t vec_mul1 = __riscv_vwmul_vv_i16m1(v0, y0, vl); + vint16m1_t vec_mul2 = __riscv_vwmul_vv_i16m1(v1, y1, vl); + + vint32m1_t vec_zero = __riscv_vmv_v_x_i32m1(0, vl); + + vint32m1_t vs1 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul1, vec_zero, vl); + vint32m1_t vs2 = __riscv_vwredsum_vs_i16m1_i32m1(vec_mul2, vs1, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(vs2); + + sumf += (GGML_FP16_TO_FP32(x[i].d)*y[i].d)*sumi + GGML_FP16_TO_FP32(x[i].m)*y[i].s; + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + uint32_t qh; + memcpy(&qh, x[i].qh, sizeof(qh)); + + int sumi = 0; + + for (int j = 0; j < qk/2; ++j) { + const uint8_t xh_0 = ((qh >> (j + 0)) << 4) & 0x10; + const uint8_t xh_1 = ((qh >> (j + 12)) ) & 0x10; + + const int32_t x0 = (x[i].qs[j] & 0xF) | xh_0; + const int32_t x1 = (x[i].qs[j] >> 4) | xh_1; + + sumi += (x0 * y[i].qs[j]) + (x1 * y[i].qs[j + qk/2]); + } + + sumf += (GGML_FP16_TO_FP32(x[i].d)*y[i].d)*sumi + GGML_FP16_TO_FP32(x[i].m)*y[i].s; + } + + *s = sumf; +#endif +} + +void ggml_vec_dot_q8_0_q8_0(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + const int qk = QK8_0; + const int nb = n / qk; + + assert(n % qk == 0); + + const block_q8_0 * restrict x = vx; + const block_q8_0 * restrict y = vy; + +#if defined(__ARM_NEON) + float32x4_t sumv0 = vdupq_n_f32(0.0f); + float32x4_t sumv1 = vdupq_n_f32(0.0f); + + assert(nb % 2 == 0); // TODO: handle odd nb + + for (int i = 0; i < nb; i += 2) { + const block_q8_0 * restrict x0 = &x[i + 0]; + const block_q8_0 * restrict x1 = &x[i + 1]; + const block_q8_0 * restrict y0 = &y[i + 0]; + const block_q8_0 * restrict y1 = &y[i + 1]; + + const int8x16_t x0_0 = vld1q_s8(x0->qs); + const int8x16_t x0_1 = vld1q_s8(x0->qs + 16); + const int8x16_t x1_0 = vld1q_s8(x1->qs); + const int8x16_t x1_1 = vld1q_s8(x1->qs + 16); + + // load y + const int8x16_t y0_0 = vld1q_s8(y0->qs); + const int8x16_t y0_1 = vld1q_s8(y0->qs + 16); + const int8x16_t y1_0 = vld1q_s8(y1->qs); + const int8x16_t y1_1 = vld1q_s8(y1->qs + 16); + +#if defined(__ARM_FEATURE_DOTPROD) + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), x0_0, y0_0), + vdotq_s32(vdupq_n_s32(0), x0_1, y0_1))), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32( + vdotq_s32(vdupq_n_s32(0), x1_0, y1_0), + vdotq_s32(vdupq_n_s32(0), x1_1, y1_1))), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); + +#else + const int16x8_t p0_0 = vmull_s8(vget_low_s8 (x0_0), vget_low_s8 (y0_0)); + const int16x8_t p0_1 = vmull_s8(vget_high_s8(x0_0), vget_high_s8(y0_0)); + const int16x8_t p0_2 = vmull_s8(vget_low_s8 (x0_1), vget_low_s8 (y0_1)); + const int16x8_t p0_3 = vmull_s8(vget_high_s8(x0_1), vget_high_s8(y0_1)); + + const int16x8_t p1_0 = vmull_s8(vget_low_s8 (x1_0), vget_low_s8 (y1_0)); + const int16x8_t p1_1 = vmull_s8(vget_high_s8(x1_0), vget_high_s8(y1_0)); + const int16x8_t p1_2 = vmull_s8(vget_low_s8 (x1_1), vget_low_s8 (y1_1)); + const int16x8_t p1_3 = vmull_s8(vget_high_s8(x1_1), vget_high_s8(y1_1)); + + const int32x4_t p0 = vaddq_s32(vpaddlq_s16(p0_0), vpaddlq_s16(p0_1)); + const int32x4_t p1 = vaddq_s32(vpaddlq_s16(p0_2), vpaddlq_s16(p0_3)); + const int32x4_t p2 = vaddq_s32(vpaddlq_s16(p1_0), vpaddlq_s16(p1_1)); + const int32x4_t p3 = vaddq_s32(vpaddlq_s16(p1_2), vpaddlq_s16(p1_3)); + + sumv0 = vmlaq_n_f32(sumv0, vcvtq_f32_s32(vaddq_s32(p0, p1)), GGML_FP16_TO_FP32(x0->d)*GGML_FP16_TO_FP32(y0->d)); + sumv1 = vmlaq_n_f32(sumv1, vcvtq_f32_s32(vaddq_s32(p2, p3)), GGML_FP16_TO_FP32(x1->d)*GGML_FP16_TO_FP32(y1->d)); +#endif + } + + *s = vaddvq_f32(sumv0) + vaddvq_f32(sumv1); +#elif defined(__AVX2__) || defined(__AVX__) + // Initialize accumulator with zeros + __m256 acc = _mm256_setzero_ps(); + + // Main loop + for (int i = 0; i < nb; ++i) { + // Compute combined scale for the block + const __m256 d = _mm256_set1_ps(GGML_FP16_TO_FP32(x[i].d) * GGML_FP16_TO_FP32(y[i].d)); + __m256i bx = _mm256_loadu_si256((const __m256i *)x[i].qs); + __m256i by = _mm256_loadu_si256((const __m256i *)y[i].qs); + + const __m256 q = mul_sum_i8_pairs_float(bx, by); + + // Multiply q with scale and accumulate +#if defined(__AVX2__) + acc = _mm256_fmadd_ps( d, q, acc ); +#else + acc = _mm256_add_ps( _mm256_mul_ps( d, q ), acc ); +#endif + } + + *s = hsum_float_8(acc); +#elif defined(__riscv_v_intrinsic) + float sumf = 0.0; + size_t vl = __riscv_vsetvl_e8m1(qk); + + for (int i = 0; i < nb; i++) { + // load elements + vint8m1_t bx = __riscv_vle8_v_i8m1(x[i].qs, vl); + vint8m1_t by = __riscv_vle8_v_i8m1(y[i].qs, vl); + + vint16m2_t vw_mul = __riscv_vwmul_vv_i16m2(bx, by, vl); + + vint32m1_t v_zero = __riscv_vmv_v_x_i32m1(0, vl); + vint32m1_t v_sum = __riscv_vwredsum_vs_i16m2_i32m1(vw_mul, v_zero, vl); + + int sumi = __riscv_vmv_x_s_i32m1_i32(v_sum); + + sumf += sumi*(GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)); + } + + *s = sumf; +#else + // scalar + float sumf = 0.0; + + for (int i = 0; i < nb; i++) { + int sumi = 0; + + for (int j = 0; j < qk; j++) { + sumi += x[i].qs[j]*y[i].qs[j]; + } + + sumf += sumi*(GGML_FP16_TO_FP32(x[i].d)*GGML_FP16_TO_FP32(y[i].d)); + } + + *s = sumf; +#endif +} + +#if QK_K == 256 +void ggml_vec_dot_q2_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + + const block_q2_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + const uint8x16_t m3 = vdupq_n_u8(0x3); + const uint8x16_t m4 = vdupq_n_u8(0xF); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t vzero = vdupq_n_s32(0); +#endif + + int8x16x2_t q2bytes; + uint8_t aux[16]; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint8_t * restrict sc = x[i].scales; + + const uint8x16_t mins_and_scales = vld1q_u8(sc); + const uint8x16_t scales = vandq_u8(mins_and_scales, m4); + vst1q_u8(aux, scales); + + const uint8x16_t mins = vshrq_n_u8(mins_and_scales, 4); + const int16x8x2_t q8sums = vld1q_s16_x2(y[i].bsums); + const int16x8x2_t mins16 = {vreinterpretq_s16_u16(vmovl_u8(vget_low_u8(mins))), vreinterpretq_s16_u16(vmovl_u8(vget_high_u8(mins)))}; + const int32x4_t s0 = vaddq_s32(vmull_s16(vget_low_s16 (mins16.val[0]), vget_low_s16 (q8sums.val[0])), + vmull_s16(vget_high_s16(mins16.val[0]), vget_high_s16(q8sums.val[0]))); + const int32x4_t s1 = vaddq_s32(vmull_s16(vget_low_s16 (mins16.val[1]), vget_low_s16 (q8sums.val[1])), + vmull_s16(vget_high_s16(mins16.val[1]), vget_high_s16(q8sums.val[1]))); + sum += dmin * vaddvq_s32(vaddq_s32(s0, s1)); + + int isum = 0; + int is = 0; + +// We use this macro instead of a function call because for some reason +// the code runs 2-3% slower, even if the function is declared inline +#if defined(__ARM_FEATURE_DOTPROD) +#define MULTIPLY_ACCUM_WITH_SCALE(index)\ + isum += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[0], q8bytes.val[0])) * aux[is+(index)];\ + isum += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[1], q8bytes.val[1])) * aux[is+1+(index)]; +#else +#define MULTIPLY_ACCUM_WITH_SCALE(index)\ + {\ + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[0]), vget_low_s8 (q8bytes.val[0])),\ + vmull_s8(vget_high_s8(q2bytes.val[0]), vget_high_s8(q8bytes.val[0])));\ + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[1]), vget_low_s8 (q8bytes.val[1])),\ + vmull_s8(vget_high_s8(q2bytes.val[1]), vget_high_s8(q8bytes.val[1])));\ + isum += vaddvq_s16(p1) * aux[is+(index)] + vaddvq_s16(p2) * aux[is+1+(index)];\ + } +#endif + +#define SHIFT_MULTIPLY_ACCUM_WITH_SCALE(shift, index)\ + q8bytes = vld1q_s8_x2(q8); q8 += 32;\ + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits.val[0], (shift)), m3));\ + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits.val[1], (shift)), m3));\ + MULTIPLY_ACCUM_WITH_SCALE((index)); + + + for (int j = 0; j < QK_K/128; ++j) { + + const uint8x16x2_t q2bits = vld1q_u8_x2(q2); q2 += 32; + + int8x16x2_t q8bytes = vld1q_s8_x2(q8); q8 += 32; + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(q2bits.val[0], m3)); + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(q2bits.val[1], m3)); + MULTIPLY_ACCUM_WITH_SCALE(0); + + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(2, 2); + + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(4, 4); + + SHIFT_MULTIPLY_ACCUM_WITH_SCALE(6, 6); + + is += 8; + } + sum += d * isum; + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m128i m4 = _mm_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m128i mins_and_scales = _mm_loadu_si128((const __m128i*)x[i].scales); + const __m128i scales8 = _mm_and_si128(mins_and_scales, m4); + const __m128i mins8 = _mm_and_si128(_mm_srli_epi16(mins_and_scales, 4), m4); + const __m256i mins = _mm256_cvtepi8_epi16(mins8); + const __m256i prod = _mm256_madd_epi16(mins, _mm256_loadu_si256((const __m256i*)y[i].bsums)); + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&dmin), _mm256_cvtepi32_ps(prod), acc); + + const __m256i all_scales = _mm256_cvtepi8_epi16(scales8); + const __m128i l_scales = _mm256_extracti128_si256(all_scales, 0); + const __m128i h_scales = _mm256_extracti128_si256(all_scales, 1); + const __m256i scales[2] = {MM256_SET_M128I(l_scales, l_scales), MM256_SET_M128I(h_scales, h_scales)}; + + __m256i sumi = _mm256_setzero_si256(); + + for (int j = 0; j < QK_K/128; ++j) { + + const __m256i q2bits = _mm256_loadu_si256((const __m256i*)q2); q2 += 32; + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + const __m256i q2_0 = _mm256_and_si256(q2bits, m3); + const __m256i q2_1 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 2), m3); + const __m256i q2_2 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 4), m3); + const __m256i q2_3 = _mm256_and_si256(_mm256_srli_epi16(q2bits, 6), m3); + + __m256i p0 = _mm256_maddubs_epi16(q2_0, q8_0); + __m256i p1 = _mm256_maddubs_epi16(q2_1, q8_1); + __m256i p2 = _mm256_maddubs_epi16(q2_2, q8_2); + __m256i p3 = _mm256_maddubs_epi16(q2_3, q8_3); + + p0 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(0)), p0); + p1 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(1)), p1); + p2 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(2)), p2); + p3 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(3)), p3); + + p0 = _mm256_add_epi32(p0, p1); + p2 = _mm256_add_epi32(p2, p3); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p0, p2)); + } + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(0x3); + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(0x2); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // load mins and scales from block_q2_K.scales[QK_K/16] + const __m128i mins_and_scales = _mm_loadu_si128((const __m128i*)x[i].scales); + const __m128i scales16 = _mm_and_si128(mins_and_scales, m4); + const __m128i mins16 = _mm_and_si128(_mm_srli_epi16(mins_and_scales, 4), m4); + const __m128i mins_0 = _mm_cvtepi8_epi16(mins16); + const __m128i mins_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(mins16, mins16)); + + // summs = y[i].bsums * (x[i].scales >> 4) in 16bits*8*2 to 32bits*4*2 + const __m128i summs_0 = _mm_madd_epi16(mins_0, _mm_loadu_si128((const __m128i*)&y[i].bsums[0])); + const __m128i summs_1 = _mm_madd_epi16(mins_1, _mm_loadu_si128((const __m128i*)&y[i].bsums[8])); + + // sumf += -dmin * summs in 32bits*8 + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&dmin), _mm256_cvtepi32_ps(MM256_SET_M128I(summs_1, summs_0))), acc); + + const __m128i scales_0 = _mm_cvtepi8_epi16(scales16); + const __m128i scales_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(scales16, scales16)); + const __m128i scales[2] = { scales_0, scales_1 }; + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + for (int j = 0; j < QK_K/128; ++j) { + + // load Q8 quants int8*16*8 from block_q8_K.qs[QK_K] + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + // load 2bits*16*8 from block_q2_K.qs[QK_K/4] + __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); q2 += 16; + const __m128i q2_0 = _mm_and_si128(q2bits, m3); + const __m128i q2_2 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_4 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_6 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + q2bits = _mm_loadu_si128((const __m128i*)q2); q2 += 16; + const __m128i q2_1 = _mm_and_si128(q2bits, m3); + const __m128i q2_3 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_5 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_7 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + + // isuml = q8[l] * ((q2[l] >> shift) & 3) in 8bits*16*8 to 16bits*8*8 + __m128i p0 = _mm_maddubs_epi16(q2_0, q8_0); + __m128i p1 = _mm_maddubs_epi16(q2_1, q8_1); + __m128i p2 = _mm_maddubs_epi16(q2_2, q8_2); + __m128i p3 = _mm_maddubs_epi16(q2_3, q8_3); + __m128i p4 = _mm_maddubs_epi16(q2_4, q8_4); + __m128i p5 = _mm_maddubs_epi16(q2_5, q8_5); + __m128i p6 = _mm_maddubs_epi16(q2_6, q8_6); + __m128i p7 = _mm_maddubs_epi16(q2_7, q8_7); + + // isum += (x[i].scales[is++] & 0xF) * isuml in 16bits*8*8 to 32bits*4*8 + __m128i shuffle = _mm_set1_epi16(0x0100); + p0 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p0); + shuffle = _mm_add_epi16(shuffle, m2); + p1 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p1); + shuffle = _mm_add_epi16(shuffle, m2); + p2 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p2); + shuffle = _mm_add_epi16(shuffle, m2); + p3 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p3); + shuffle = _mm_add_epi16(shuffle, m2); + p4 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p4); + shuffle = _mm_add_epi16(shuffle, m2); + p5 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p5); + shuffle = _mm_add_epi16(shuffle, m2); + p6 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p6); + shuffle = _mm_add_epi16(shuffle, m2); + p7 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p7); + + p0 = _mm_add_epi32(p0, p1); + p2 = _mm_add_epi32(p2, p3); + p4 = _mm_add_epi32(p4, p5); + p6 = _mm_add_epi32(p6, p7); + + // isum in 32bits*4*2 + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p0, p2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p4, p6)); + } + + // sumf += dall * isum - dmin * summs in 32bits + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&dall), _mm256_cvtepi32_ps(sumi)), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + uint8_t temp_01[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + size_t vl = 16; + + vuint8m1_t scales = __riscv_vle8_v_u8m1(sc, vl); + vuint8m1_t aux = __riscv_vand_vx_u8m1(scales, 0x0F, vl); + + vint16m1_t q8sums = __riscv_vle16_v_i16m1(y[i].bsums, vl); + + vuint8mf2_t scales_2 = __riscv_vle8_v_u8mf2(sc, vl); + vuint8mf2_t mins8 = __riscv_vsrl_vx_u8mf2(scales_2, 0x4, vl); + vint16m1_t mins = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2_u16m1(mins8, vl)); + vint32m2_t prod = __riscv_vwmul_vv_i32m2(q8sums, mins, vl); + vint32m1_t vsums = __riscv_vredsum_vs_i32m2_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + + sumf += dmin * __riscv_vmv_x_s_i32m1_i32(vsums); + + vl = 32; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t v_b = __riscv_vle8_v_u8m1(temp_01, vl); + + uint8_t is=0; + int isum=0; + + for (int j = 0; j < QK_K/128; ++j) { + // load Q2 + vuint8m1_t q2_x = __riscv_vle8_v_u8m1(q2, vl); + + vuint8m1_t q2_0 = __riscv_vand_vx_u8m1(q2_x, 0x03, vl); + vuint8m1_t q2_1 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x2, vl), 0x03 , vl); + vuint8m1_t q2_2 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x4, vl), 0x03 , vl); + vuint8m1_t q2_3 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q2_x, 0x6, vl), 0x03 , vl); + + // duplicate scale elements for product + vuint8m1_t sc0 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 0+is, vl), vl); + vuint8m1_t sc1 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 2+is, vl), vl); + vuint8m1_t sc2 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 4+is, vl), vl); + vuint8m1_t sc3 = __riscv_vrgather_vv_u8m1(aux, __riscv_vadd_vx_u8m1(v_b, 6+is, vl), vl); + + vint16m2_t p0 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_0, sc0, vl)); + vint16m2_t p1 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_1, sc1, vl)); + vint16m2_t p2 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_2, sc2, vl)); + vint16m2_t p3 = __riscv_vreinterpret_v_u16m2_i16m2(__riscv_vwmulu_vv_u16m2(q2_3, sc3, vl)); + + // load Q8 + vint8m1_t q8_0 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q8_1 = __riscv_vle8_v_i8m1(q8+32, vl); + vint8m1_t q8_2 = __riscv_vle8_v_i8m1(q8+64, vl); + vint8m1_t q8_3 = __riscv_vle8_v_i8m1(q8+96, vl); + + vint32m4_t s0 = __riscv_vwmul_vv_i32m4(p0, __riscv_vwcvt_x_x_v_i16m2(q8_0, vl), vl); + vint32m4_t s1 = __riscv_vwmul_vv_i32m4(p1, __riscv_vwcvt_x_x_v_i16m2(q8_1, vl), vl); + vint32m4_t s2 = __riscv_vwmul_vv_i32m4(p2, __riscv_vwcvt_x_x_v_i16m2(q8_2, vl), vl); + vint32m4_t s3 = __riscv_vwmul_vv_i32m4(p3, __riscv_vwcvt_x_x_v_i16m2(q8_3, vl), vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m4_i32m1(__riscv_vadd_vv_i32m4(s0, s1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m4_i32m1(__riscv_vadd_vv_i32m4(s2, s3, vl), isum0, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(isum1); + + q2+=32; q8+=128; is=8; + + } + + sumf += dall * isum; + + } + + *s = sumf; + +#else + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + int summs = 0; + for (int j = 0; j < 16; ++j) { + summs += y[i].bsums[j] * (sc[j] >> 4); + } + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + int isum = 0; + int is = 0; + int d; + for (int k = 0; k < QK_K/128; ++k) { + int shift = 0; + for (int j = 0; j < 4; ++j) { + d = sc[is++] & 0xF; + int isuml = 0; + for (int l = 0; l < 16; ++l) isuml += q8[l] * ((q2[l] >> shift) & 3); + isum += d * isuml; + d = sc[is++] & 0xF; + isuml = 0; + for (int l = 16; l < 32; ++l) isuml += q8[l] * ((q2[l] >> shift) & 3); + isum += d * isuml; + shift += 2; + q8 += 32; + } + q2 += 32; + } + sumf += dall * isum - dmin * summs; + } + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q2_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + + const block_q2_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + const uint8x16_t m3 = vdupq_n_u8(0x3); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t vzero = vdupq_n_s32(0); +#endif + + int8x16x4_t q2bytes; + + uint32_t aux32[2]; + const uint8_t * scales = (const uint8_t *)aux32; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * (float)x[i].d; + const float dmin = -y[i].d * (float)x[i].dmin; + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + + aux32[0] = sc[0] & 0x0f0f0f0f; + aux32[1] = (sc[0] >> 4) & 0x0f0f0f0f; + + sum += dmin * (scales[4] * y[i].bsums[0] + scales[5] * y[i].bsums[1] + scales[6] * y[i].bsums[2] + scales[7] * y[i].bsums[3]); + + int isum1 = 0, isum2 = 0; + + const uint8x16_t q2bits = vld1q_u8(q2); + + const int8x16x4_t q8bytes = vld1q_s8_x4(q8); + + q2bytes.val[0] = vreinterpretq_s8_u8(vandq_u8(q2bits, m3)); + q2bytes.val[1] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 2), m3)); + q2bytes.val[2] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 4), m3)); + q2bytes.val[3] = vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q2bits, 6), m3)); + +#if defined(__ARM_FEATURE_DOTPROD) + isum1 += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[0], q8bytes.val[0])) * scales[0]; + isum2 += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[1], q8bytes.val[1])) * scales[1]; + isum1 += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[2], q8bytes.val[2])) * scales[2]; + isum2 += vaddvq_s32(vdotq_s32(vzero, q2bytes.val[3], q8bytes.val[3])) * scales[3]; +#else + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q2bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q2bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + isum1 += vaddvq_s16(p1) * scales[0]; + isum2 += vaddvq_s16(p2) * scales[1]; + + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q2bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + const int16x8_t p4 = vaddq_s16(vmull_s8(vget_low_s8 (q2bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q2bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + isum1 += vaddvq_s16(p3) * scales[2]; + isum2 += vaddvq_s16(p4) * scales[3]; +#endif + sum += d * (isum1 + isum2); + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t ud, um; + const uint8_t * restrict db = (const uint8_t *)&ud; + const uint8_t * restrict mb = (const uint8_t *)&um; + + float summs = 0; + + // TODO: optimize this + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + ud = (sc[0] >> 0) & 0x0f0f0f0f; + um = (sc[0] >> 4) & 0x0f0f0f0f; + + int32_t smin = mb[0] * y[i].bsums[0] + mb[1] * y[i].bsums[1] + mb[2] * y[i].bsums[2] + mb[3] * y[i].bsums[3]; + summs += dmin * smin; + + const __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); + const __m256i q2_0 = _mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q2bits, 2), q2bits), m3); + const __m256i q2_1 = _mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q2bits, 6), _mm_srli_epi16(q2bits, 4)), m3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p0 = _mm256_maddubs_epi16(q2_0, q8_0); + const __m256i p1 = _mm256_maddubs_epi16(q2_1, q8_1); + + const __m256i p_0 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p0, 0)); + const __m256i p_1 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p0, 1)); + const __m256i p_2 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p1, 0)); + const __m256i p_3 = _mm256_cvtepi16_epi32(_mm256_extracti128_si256(p1, 1)); + + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[0]), _mm256_cvtepi32_ps(p_0), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[1]), _mm256_cvtepi32_ps(p_1), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[2]), _mm256_cvtepi32_ps(p_2), acc); + acc = _mm256_fmadd_ps(_mm256_set1_ps(d * db[3]), _mm256_cvtepi32_ps(p_3), acc); + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t ud, um; + const uint8_t * restrict db = (const uint8_t *)&ud; + const uint8_t * restrict mb = (const uint8_t *)&um; + + float summs = 0; + + // TODO: optimize this + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + ud = (sc[0] >> 0) & 0x0f0f0f0f; + um = (sc[0] >> 4) & 0x0f0f0f0f; + + int32_t smin = mb[0] * y[i].bsums[0] + mb[1] * y[i].bsums[1] + mb[2] * y[i].bsums[2] + mb[3] * y[i].bsums[3]; + summs += dmin * smin; + + const __m128i q2bits = _mm_loadu_si128((const __m128i*)q2); + const __m128i q2_0 = _mm_and_si128(q2bits, m3); + const __m128i q2_1 = _mm_and_si128(_mm_srli_epi16(q2bits, 2), m3); + const __m128i q2_2 = _mm_and_si128(_mm_srli_epi16(q2bits, 4), m3); + const __m128i q2_3 = _mm_and_si128(_mm_srli_epi16(q2bits, 6), m3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p0 = _mm_maddubs_epi16(q2_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i p1 = _mm_maddubs_epi16(q2_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i p2 = _mm_maddubs_epi16(q2_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i p3 = _mm_maddubs_epi16(q2_3, _mm256_extractf128_si256(q8_1, 1)); + + const __m256i p_0 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p0, p0)), _mm_cvtepi16_epi32(p0)); + const __m256i p_1 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p1, p1)), _mm_cvtepi16_epi32(p1)); + const __m256i p_2 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p2, p2)), _mm_cvtepi16_epi32(p2)); + const __m256i p_3 = MM256_SET_M128I(_mm_cvtepi16_epi32(_mm_unpackhi_epi64(p3, p3)), _mm_cvtepi16_epi32(p3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[0]), _mm256_cvtepi32_ps(p_0)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[1]), _mm256_cvtepi32_ps(p_1)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[2]), _mm256_cvtepi32_ps(p_2)), acc); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d * db[3]), _mm256_cvtepi32_ps(p_3)), acc); + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __riscv_v_intrinsic + + uint32_t aux32[2]; + const uint8_t * scales = (const uint8_t *)aux32; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * (float)x[i].d; + const float dmin = -y[i].d * (float)x[i].dmin; + + const uint8_t * restrict q2 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + const uint32_t * restrict sc = (const uint32_t *)x[i].scales; + + aux32[0] = sc[0] & 0x0f0f0f0f; + aux32[1] = (sc[0] >> 4) & 0x0f0f0f0f; + + sumf += dmin * (scales[4] * y[i].bsums[0] + scales[5] * y[i].bsums[1] + scales[6] * y[i].bsums[2] + scales[7] * y[i].bsums[3]); + + int isum1 = 0; + int isum2 = 0; + + size_t vl = 16; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + // load Q2 + vuint8mf2_t q2_x = __riscv_vle8_v_u8mf2(q2, vl); + + vint8mf2_t q2_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q2_x, 0x03, vl)); + vint8mf2_t q2_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x2, vl), 0x03 , vl)); + vint8mf2_t q2_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x4, vl), 0x03 , vl)); + vint8mf2_t q2_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q2_x, 0x6, vl), 0x03 , vl)); + + // load Q8, and take product with Q2 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q2_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q2_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q2_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q2_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint16m1_t vs_0 = __riscv_vredsum_vs_i16m1_i16m1(p0, vzero, vl); + vint16m1_t vs_1 = __riscv_vredsum_vs_i16m1_i16m1(p1, vzero, vl); + vint16m1_t vs_2 = __riscv_vredsum_vs_i16m1_i16m1(p2, vzero, vl); + vint16m1_t vs_3 = __riscv_vredsum_vs_i16m1_i16m1(p3, vzero, vl); + + isum1 += __riscv_vmv_x_s_i16m1_i16(vs_0) * scales[0]; + isum2 += __riscv_vmv_x_s_i16m1_i16(vs_1) * scales[1]; + isum1 += __riscv_vmv_x_s_i16m1_i16(vs_2) * scales[2]; + isum2 += __riscv_vmv_x_s_i16m1_i16(vs_3) * scales[3]; + + sumf += d * (isum1 + isum2); + + } + + *s = sumf; + +#else + + float sumf = 0; + + int isum[4]; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * q2 = x[i].qs; + const int8_t * q8 = y[i].qs; + const uint8_t * sc = x[i].scales; + + int summs = 0; + for (int j = 0; j < QK_K/16; ++j) { + summs += y[i].bsums[j] * (sc[j] >> 4); + } + + const float dall = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + isum[0] = isum[1] = isum[2] = isum[3] = 0; + for (int l = 0; l < 16; ++l) { + isum[0] += q8[l+ 0] * ((q2[l] >> 0) & 3); + isum[1] += q8[l+16] * ((q2[l] >> 2) & 3); + isum[2] += q8[l+32] * ((q2[l] >> 4) & 3); + isum[3] += q8[l+48] * ((q2[l] >> 6) & 3); + } + for (int l = 0; l < 4; ++l) { + isum[l] *= (sc[l] & 0xF); + } + sumf += dall * (isum[0] + isum[1] + isum[2] + isum[3]) - dmin * summs; + } + *s = sumf; +#endif +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q3_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const uint32_t kmask1 = 0x03030303; + const uint32_t kmask2 = 0x0f0f0f0f; + + const block_q3_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + uint32_t aux[3]; + uint32_t utmp[4]; + + const uint8x16_t m3b = vdupq_n_u8(0x3); +#ifdef __ARM_FEATURE_DOTPROD + const int32x4_t vzero = vdupq_n_s32(0); +#endif + + const uint8x16_t m0 = vdupq_n_u8(1); + const uint8x16_t m1 = vshlq_n_u8(m0, 1); + const uint8x16_t m2 = vshlq_n_u8(m0, 2); + const uint8x16_t m3 = vshlq_n_u8(m0, 3); + const int8_t m32 = 32; + + int8x16x4_t q3bytes; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict qh = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + + uint8x16x2_t qhbits = vld1q_u8_x2(qh); + + uint8x16x4_t q3h; + + int32_t isum = 0; + + // Set up scales + memcpy(aux, x[i].scales, 12); + utmp[3] = ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4); + utmp[2] = ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4); + utmp[1] = (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4); + utmp[0] = (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4); + + int8_t * scale = (int8_t *)utmp; + for (int j = 0; j < 16; ++j) scale[j] -= m32; + + for (int j = 0; j < QK_K/128; ++j) { + + const uint8x16x2_t q3bits = vld1q_u8_x2(q3); q3 += 32; + const int8x16x4_t q8bytes_1 = vld1q_s8_x4(q8); q8 += 64; + const int8x16x4_t q8bytes_2 = vld1q_s8_x4(q8); q8 += 64; + + q3h.val[0] = vshlq_n_u8(vbicq_u8(m0, qhbits.val[0]), 2); + q3h.val[1] = vshlq_n_u8(vbicq_u8(m0, qhbits.val[1]), 2); + q3h.val[2] = vshlq_n_u8(vbicq_u8(m1, qhbits.val[0]), 1); + q3h.val[3] = vshlq_n_u8(vbicq_u8(m1, qhbits.val[1]), 1); + + q3bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q3bits.val[0], m3b)), vreinterpretq_s8_u8(q3h.val[0])); + q3bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q3bits.val[1], m3b)), vreinterpretq_s8_u8(q3h.val[1])); + q3bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 2), m3b)), vreinterpretq_s8_u8(q3h.val[2])); + q3bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 2), m3b)), vreinterpretq_s8_u8(q3h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[0], q8bytes_1.val[0])) * scale[0]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[1], q8bytes_1.val[1])) * scale[1]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[2], q8bytes_1.val[2])) * scale[2]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[3], q8bytes_1.val[3])) * scale[3]; +#else + int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[0]), vget_low_s8 (q8bytes_1.val[0])), + vmull_s8(vget_high_s8(q3bytes.val[0]), vget_high_s8(q8bytes_1.val[0]))); + int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[1]), vget_low_s8 (q8bytes_1.val[1])), + vmull_s8(vget_high_s8(q3bytes.val[1]), vget_high_s8(q8bytes_1.val[1]))); + int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[2]), vget_low_s8 (q8bytes_1.val[2])), + vmull_s8(vget_high_s8(q3bytes.val[2]), vget_high_s8(q8bytes_1.val[2]))); + int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[3]), vget_low_s8 (q8bytes_1.val[3])), + vmull_s8(vget_high_s8(q3bytes.val[3]), vget_high_s8(q8bytes_1.val[3]))); + isum += vaddvq_s16(p0) * scale[0] + vaddvq_s16(p1) * scale[1] + vaddvq_s16(p2) * scale[2] + vaddvq_s16(p3) * scale[3]; +#endif + scale += 4; + + q3h.val[0] = vbicq_u8(m2, qhbits.val[0]); + q3h.val[1] = vbicq_u8(m2, qhbits.val[1]); + q3h.val[2] = vshrq_n_u8(vbicq_u8(m3, qhbits.val[0]), 1); + q3h.val[3] = vshrq_n_u8(vbicq_u8(m3, qhbits.val[1]), 1); + + q3bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 4), m3b)), vreinterpretq_s8_u8(q3h.val[0])); + q3bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 4), m3b)), vreinterpretq_s8_u8(q3h.val[1])); + q3bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[0], 6), m3b)), vreinterpretq_s8_u8(q3h.val[2])); + q3bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(vshrq_n_u8(q3bits.val[1], 6), m3b)), vreinterpretq_s8_u8(q3h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[0], q8bytes_2.val[0])) * scale[0]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[1], q8bytes_2.val[1])) * scale[1]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[2], q8bytes_2.val[2])) * scale[2]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[3], q8bytes_2.val[3])) * scale[3]; +#else + p0 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[0]), vget_low_s8 (q8bytes_2.val[0])), + vmull_s8(vget_high_s8(q3bytes.val[0]), vget_high_s8(q8bytes_2.val[0]))); + p1 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[1]), vget_low_s8 (q8bytes_2.val[1])), + vmull_s8(vget_high_s8(q3bytes.val[1]), vget_high_s8(q8bytes_2.val[1]))); + p2 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[2]), vget_low_s8 (q8bytes_2.val[2])), + vmull_s8(vget_high_s8(q3bytes.val[2]), vget_high_s8(q8bytes_2.val[2]))); + p3 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[3]), vget_low_s8 (q8bytes_2.val[3])), + vmull_s8(vget_high_s8(q3bytes.val[3]), vget_high_s8(q8bytes_2.val[3]))); + isum += vaddvq_s16(p0) * scale[0] + vaddvq_s16(p1) * scale[1] + vaddvq_s16(p2) * scale[2] + vaddvq_s16(p3) * scale[3]; +#endif + scale += 4; + + if (j == 0) { + qhbits.val[0] = vshrq_n_u8(qhbits.val[0], 4); + qhbits.val[1] = vshrq_n_u8(qhbits.val[1], 4); + } + + } + sum += d * isum; + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m256i mone = _mm256_set1_epi8(1); + const __m128i m32 = _mm_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + uint32_t aux[3]; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // Set up scales + memcpy(aux, x[i].scales, 12); + __m128i scales128 = _mm_set_epi32( + ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4), + ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4), + (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4), + (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4)); + scales128 = _mm_sub_epi8(scales128, m32); + const __m256i all_scales = _mm256_cvtepi8_epi16(scales128); + const __m128i l_scales = _mm256_extracti128_si256(all_scales, 0); + const __m128i h_scales = _mm256_extracti128_si256(all_scales, 1); + const __m256i scales[2] = {MM256_SET_M128I(l_scales, l_scales), MM256_SET_M128I(h_scales, h_scales)}; + + // high bit + const __m256i hbits = _mm256_loadu_si256((const __m256i*)x[i].hmask); + + // integer accumulator + __m256i sumi = _mm256_setzero_si256(); + + int bit = 0; + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + // load low 2 bits + const __m256i q3bits = _mm256_loadu_si256((const __m256i*)q3); q3 += 32; + + // prepare low and high bits + const __m256i q3l_0 = _mm256_and_si256(q3bits, m3); + const __m256i q3h_0 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_1 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 2), m3); + const __m256i q3h_1 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_2 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 4), m3); + const __m256i q3h_2 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + const __m256i q3l_3 = _mm256_and_si256(_mm256_srli_epi16(q3bits, 6), m3); + const __m256i q3h_3 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_andnot_si256(hbits, _mm256_slli_epi16(mone, bit)), bit), 2); + ++bit; + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + __m256i q8s_0 = _mm256_maddubs_epi16(q3h_0, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(q3h_1, q8_1); + __m256i q8s_2 = _mm256_maddubs_epi16(q3h_2, q8_2); + __m256i q8s_3 = _mm256_maddubs_epi16(q3h_3, q8_3); + + __m256i p16_0 = _mm256_maddubs_epi16(q3l_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q3l_1, q8_1); + __m256i p16_2 = _mm256_maddubs_epi16(q3l_2, q8_2); + __m256i p16_3 = _mm256_maddubs_epi16(q3l_3, q8_3); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + p16_2 = _mm256_sub_epi16(p16_2, q8s_2); + p16_3 = _mm256_sub_epi16(p16_3, q8s_3); + + // multiply with scales + p16_0 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 0)), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 1)), p16_1); + p16_2 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 2)), p16_2); + p16_3 = _mm256_madd_epi16(_mm256_shuffle_epi8(scales[j], get_scale_shuffle_q3k(is + 3)), p16_3); + + // accumulate + p16_0 = _mm256_add_epi32(p16_0, p16_1); + p16_2 = _mm256_add_epi32(p16_2, p16_3); + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_2)); + + } + + // multiply with block scale and accumulate + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + const __m128i mone = _mm_set1_epi8(1); + const __m128i m32 = _mm_set1_epi8(32); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + const uint32_t *aux; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + // Set up scales + aux = (const uint32_t *)x[i].scales; + __m128i scales128 = _mm_set_epi32( + ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4), + ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4), + (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4), + (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4)); + scales128 = _mm_sub_epi8(scales128, m32); + const __m128i scales_0 = _mm_cvtepi8_epi16(scales128); + const __m128i scales_1 = _mm_cvtepi8_epi16(_mm_unpackhi_epi64(scales128, scales128)); + const __m128i scales[2] = { scales_0, scales_1 }; + + // high bit *128*2 from block_q3_K.hmask[QK_K/8] + const __m128i hbits_0 = _mm_loadu_si128((const __m128i*)&x[i].hmask[0]); + const __m128i hbits_1 = _mm_loadu_si128((const __m128i*)&x[i].hmask[16]); + + // integer accumulator + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + for (int j = 0; j < QK_K/128; ++j) { + // load low 2 bits *64*2 from block_q3_K.qs[QK_K/4] + const __m128i q3bits_0 = _mm_loadu_si128((const __m128i*)q3); q3 += 16; + const __m128i q3bits_1 = _mm_loadu_si128((const __m128i*)q3); q3 += 16; + + // prepare low and high bits + const int bit = j << 2; + + const __m128i q3l_0 = _mm_and_si128(q3bits_0, m3); + const __m128i q3l_1 = _mm_and_si128(q3bits_1, m3); + const __m128i q3h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit)), bit), 2); + const __m128i q3h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit)), bit), 2); + + const __m128i q3l_2 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 2), m3); + const __m128i q3l_3 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 2), m3); + const __m128i q3h_2 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+1)), bit+1), 2); + const __m128i q3h_3 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+1)), bit+1), 2); + + const __m128i q3l_4 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 4), m3); + const __m128i q3l_5 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 4), m3); + const __m128i q3h_4 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+2)), bit+2), 2); + const __m128i q3h_5 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+2)), bit+2), 2); + + const __m128i q3l_6 = _mm_and_si128(_mm_srli_epi16(q3bits_0, 6), m3); + const __m128i q3l_7 = _mm_and_si128(_mm_srli_epi16(q3bits_1, 6), m3); + const __m128i q3h_6 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_0, _mm_slli_epi16(mone, bit+3)), bit+3), 2); + const __m128i q3h_7 = _mm_slli_epi16(_mm_srli_epi16(_mm_andnot_si128(hbits_1, _mm_slli_epi16(mone, bit+3)), bit+3), 2); + + // load Q8 quants from block_q8_K.qs[QK_K] + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + __m128i q8s_0 = _mm_maddubs_epi16(q3h_0, q8_0); + __m128i q8s_1 = _mm_maddubs_epi16(q3h_1, q8_1); + __m128i q8s_2 = _mm_maddubs_epi16(q3h_2, q8_2); + __m128i q8s_3 = _mm_maddubs_epi16(q3h_3, q8_3); + __m128i q8s_4 = _mm_maddubs_epi16(q3h_4, q8_4); + __m128i q8s_5 = _mm_maddubs_epi16(q3h_5, q8_5); + __m128i q8s_6 = _mm_maddubs_epi16(q3h_6, q8_6); + __m128i q8s_7 = _mm_maddubs_epi16(q3h_7, q8_7); + + __m128i p16_0 = _mm_maddubs_epi16(q3l_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q3l_1, q8_1); + __m128i p16_2 = _mm_maddubs_epi16(q3l_2, q8_2); + __m128i p16_3 = _mm_maddubs_epi16(q3l_3, q8_3); + __m128i p16_4 = _mm_maddubs_epi16(q3l_4, q8_4); + __m128i p16_5 = _mm_maddubs_epi16(q3l_5, q8_5); + __m128i p16_6 = _mm_maddubs_epi16(q3l_6, q8_6); + __m128i p16_7 = _mm_maddubs_epi16(q3l_7, q8_7); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + p16_4 = _mm_sub_epi16(p16_4, q8s_4); + p16_5 = _mm_sub_epi16(p16_5, q8s_5); + p16_6 = _mm_sub_epi16(p16_6, q8s_6); + p16_7 = _mm_sub_epi16(p16_7, q8s_7); + + // multiply with scales + __m128i shuffle = _mm_set1_epi16(0x0100); + p16_0 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_0); + shuffle = _mm_add_epi16(shuffle, m2); + p16_1 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_1); + shuffle = _mm_add_epi16(shuffle, m2); + p16_2 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_2); + shuffle = _mm_add_epi16(shuffle, m2); + p16_3 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_3); + shuffle = _mm_add_epi16(shuffle, m2); + p16_4 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_4); + shuffle = _mm_add_epi16(shuffle, m2); + p16_5 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_5); + shuffle = _mm_add_epi16(shuffle, m2); + p16_6 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_6); + shuffle = _mm_add_epi16(shuffle, m2); + p16_7 = _mm_madd_epi16(_mm_shuffle_epi8(scales[j], shuffle), p16_7); + + // accumulate + p16_0 = _mm_add_epi32(p16_0, p16_1); + p16_2 = _mm_add_epi32(p16_2, p16_3); + p16_4 = _mm_add_epi32(p16_4, p16_5); + p16_6 = _mm_add_epi32(p16_6, p16_7); + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_4, p16_6)); + + } + + // multiply with block scale and accumulate + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi)), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + uint32_t aux[3]; + uint32_t utmp[4]; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict qh = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + + memcpy(aux, x[i].scales, 12); + utmp[3] = ((aux[1] >> 4) & kmask2) | (((aux[2] >> 6) & kmask1) << 4); + utmp[2] = ((aux[0] >> 4) & kmask2) | (((aux[2] >> 4) & kmask1) << 4); + utmp[1] = (aux[1] & kmask2) | (((aux[2] >> 2) & kmask1) << 4); + utmp[0] = (aux[0] & kmask2) | (((aux[2] >> 0) & kmask1) << 4); + + int8_t * scale = (int8_t *)utmp; + for (int j = 0; j < 16; ++j) scale[j] -= 32; + + + size_t vl = 32; + uint8_t m = 1; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t vqh = __riscv_vle8_v_u8m1(qh, vl); + + int sum_t = 0; + + for (int j = 0; j < QK_K; j += 128) { + + vl = 32; + + // load Q3 + vuint8m1_t q3_x = __riscv_vle8_v_u8m1(q3, vl); + + vint8m1_t q3_0 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q3_x, 0x03, vl)); + vint8m1_t q3_1 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x2, vl), 0x03 , vl)); + vint8m1_t q3_2 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x4, vl), 0x03 , vl)); + vint8m1_t q3_3 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(q3_x, 0x6, vl), 0x03 , vl)); + + // compute mask for subtraction + vuint8m1_t qh_m0 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_0 = __riscv_vmseq_vx_u8m1_b8(qh_m0, 0, vl); + vint8m1_t q3_m0 = __riscv_vsub_vx_i8m1_m(vmask_0, q3_0, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m1 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_1 = __riscv_vmseq_vx_u8m1_b8(qh_m1, 0, vl); + vint8m1_t q3_m1 = __riscv_vsub_vx_i8m1_m(vmask_1, q3_1, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m2 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_2 = __riscv_vmseq_vx_u8m1_b8(qh_m2, 0, vl); + vint8m1_t q3_m2 = __riscv_vsub_vx_i8m1_m(vmask_2, q3_2, 0x4, vl); + m <<= 1; + + vuint8m1_t qh_m3 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_3 = __riscv_vmseq_vx_u8m1_b8(qh_m3, 0, vl); + vint8m1_t q3_m3 = __riscv_vsub_vx_i8m1_m(vmask_3, q3_3, 0x4, vl); + m <<= 1; + + // load Q8 and take product with Q3 + vint16m2_t a0 = __riscv_vwmul_vv_i16m2(q3_m0, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m2_t a1 = __riscv_vwmul_vv_i16m2(q3_m1, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m2_t a2 = __riscv_vwmul_vv_i16m2(q3_m2, __riscv_vle8_v_i8m1(q8+64, vl), vl); + vint16m2_t a3 = __riscv_vwmul_vv_i16m2(q3_m3, __riscv_vle8_v_i8m1(q8+96, vl), vl); + + vl = 16; + + // retreive lane to multiply with scale + vint32m2_t aux0_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a0, 0), (scale[0]), vl); + vint32m2_t aux0_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a0, 1), (scale[1]), vl); + vint32m2_t aux1_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a1, 0), (scale[2]), vl); + vint32m2_t aux1_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a1, 1), (scale[3]), vl); + vint32m2_t aux2_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a2, 0), (scale[4]), vl); + vint32m2_t aux2_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a2, 1), (scale[5]), vl); + vint32m2_t aux3_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a3, 0), (scale[6]), vl); + vint32m2_t aux3_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(a3, 1), (scale[7]), vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux0_0, aux0_1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux1_0, aux1_1, vl), isum0, vl); + vint32m1_t isum2 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux2_0, aux2_1, vl), isum1, vl); + vint32m1_t isum3 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(aux3_0, aux3_1, vl), isum2, vl); + + sum_t += __riscv_vmv_x_s_i32m1_i32(isum3); + + q3 += 32; q8 += 128; scale += 8; + + } + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + + sumf += d*sum_t; + + } + + *s = sumf; + +#else + // scalar version + // This function is written like this so the compiler can manage to vectorize most of it + // Using -Ofast, GCC and clang manage to produce code that is within a factor of 2 or so from the + // manually vectorized version above. Every other version I tried would run at least 4 times slower. + // The ideal situation would be if we could just write the code once, and the compiler would + // automatically produce the best possible set of machine instructions, instead of us having to manually + // write vectorized versions for AVX, ARM_NEON, etc. + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + uint32_t auxs[4]; + const int8_t * scales = (const int8_t*)auxs; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + uint8_t m = 1; + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) a[l] = q3[l] & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 2) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 4) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (q3[l] >> 6) & 3; + for (int l = 0; l < 32; ++l) a[l] -= (hm[l] & m ? 0 : 4); + a += 32; m <<= 1; + q3 += 32; + } + a = aux8; + + memcpy(auxs, x[i].scales, 12); + uint32_t tmp = auxs[2]; + auxs[2] = ((auxs[0] >> 4) & kmask2) | (((tmp >> 4) & kmask1) << 4); + auxs[3] = ((auxs[1] >> 4) & kmask2) | (((tmp >> 6) & kmask1) << 4); + auxs[0] = (auxs[0] & kmask2) | (((tmp >> 0) & kmask1) << 4); + auxs[1] = (auxs[1] & kmask2) | (((tmp >> 2) & kmask1) << 4); + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += (scales[j] - 32) * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += (scales[j] - 32) * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; + +#endif + +} + +#else + +void ggml_vec_dot_q3_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q3_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + +#ifdef __ARM_FEATURE_DOTPROD + const int32x4_t vzero = vdupq_n_s32(0); +#endif + + const uint8x16_t m3b = vdupq_n_u8(0x3); + const uint8x16_t mh = vdupq_n_u8(4); + + int8x16x4_t q3bytes; + + uint16_t aux16[2]; + int8_t * scales = (int8_t *)aux16; + + float sum = 0; + + for (int i = 0; i < nb; ++i) { + + uint8x16x4_t q3h; + + const uint8x8_t hbits = vld1_u8(x[i].hmask); + const uint8x16_t q3bits = vld1q_u8(x[i].qs); + const int8x16x4_t q8bytes = vld1q_s8_x4(y[i].qs); + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + for (int j = 0; j < 4; ++j) scales[j] -= 8; + + int32_t isum = -4*(scales[0] * y[i].bsums[0] + scales[2] * y[i].bsums[1] + scales[1] * y[i].bsums[2] + scales[3] * y[i].bsums[3]); + + const float d = y[i].d * (float)x[i].d; + + const uint8x16_t htmp = vcombine_u8(hbits, vshr_n_u8(hbits, 1)); + q3h.val[0] = vandq_u8(mh, vshlq_n_u8(htmp, 2)); + q3h.val[1] = vandq_u8(mh, htmp); + q3h.val[2] = vandq_u8(mh, vshrq_n_u8(htmp, 2)); + q3h.val[3] = vandq_u8(mh, vshrq_n_u8(htmp, 4)); + + q3bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q3bits, m3b), q3h.val[0])); + q3bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(vshrq_n_u8(q3bits, 2), m3b), q3h.val[1])); + q3bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(vshrq_n_u8(q3bits, 4), m3b), q3h.val[2])); + q3bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q3bits, 6), q3h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[0], q8bytes.val[0])) * scales[0]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[1], q8bytes.val[1])) * scales[2]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[2], q8bytes.val[2])) * scales[1]; + isum += vaddvq_s32(vdotq_s32(vzero, q3bytes.val[3], q8bytes.val[3])) * scales[3]; +#else + const int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q3bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q3bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q3bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q3bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q3bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + isum += vaddvq_s16(p0) * scales[0] + vaddvq_s16(p1) * scales[2] + vaddvq_s16(p2) * scales[1] + vaddvq_s16(p3) * scales[3]; +#endif + + sum += d * isum; + + } + + *s = sum; + +#elif defined __AVX2__ + + const __m256i m3 = _mm256_set1_epi8(3); + const __m256i m1 = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + uint64_t aux64; + + uint16_t aux16[2]; + const int8_t * aux8 = (const int8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + const __m256i scale_0 = MM256_SET_M128I(_mm_set1_epi16(aux8[2] - 8), _mm_set1_epi16(aux8[0] - 8)); + const __m256i scale_1 = MM256_SET_M128I(_mm_set1_epi16(aux8[3] - 8), _mm_set1_epi16(aux8[1] - 8)); + + memcpy(&aux64, x[i].hmask, 8); + + const __m128i haux = _mm_set_epi64x(aux64 >> 1, aux64 >> 0); + __m256i q3h_0 = MM256_SET_M128I(_mm_srli_epi16(haux, 2), haux); + __m256i q3h_1 = _mm256_srli_epi16(q3h_0, 4); + q3h_0 = _mm256_slli_epi16(_mm256_andnot_si256(q3h_0, m1), 2); + q3h_1 = _mm256_slli_epi16(_mm256_andnot_si256(q3h_1, m1), 2); + + // load low 2 bits + const __m128i q3bits = _mm_loadu_si128((const __m128i*)q3); + + // prepare low and high bits + const __m256i q3aux = MM256_SET_M128I(_mm_srli_epi16(q3bits, 2), q3bits); + const __m256i q3l_0 = _mm256_and_si256(q3aux, m3); + const __m256i q3l_1 = _mm256_and_si256(_mm256_srli_epi16(q3aux, 4), m3); + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm256_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + const __m256i q8s_0 = _mm256_maddubs_epi16(q3h_0, q8_0); + const __m256i q8s_1 = _mm256_maddubs_epi16(q3h_1, q8_1); + + __m256i p16_0 = _mm256_maddubs_epi16(q3l_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q3l_1, q8_1); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + + // multiply with scales + p16_0 = _mm256_madd_epi16(scale_0, p16_0); + p16_1 = _mm256_madd_epi16(scale_1, p16_1); + + p16_0 = _mm256_add_epi32(p16_0, p16_1); + + // multiply with block scale and accumulate + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(p16_0), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m3 = _mm_set1_epi8(3); + const __m128i m1 = _mm_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + uint64_t aux64; + + uint16_t aux16[2]; + const int8_t * aux8 = (const int8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + const __m128i scale_0 = _mm_set1_epi16(aux8[0] - 8); + const __m128i scale_1 = _mm_set1_epi16(aux8[2] - 8); + const __m128i scale_2 = _mm_set1_epi16(aux8[1] - 8); + const __m128i scale_3 = _mm_set1_epi16(aux8[3] - 8); + + memcpy(&aux64, x[i].hmask, 8); + + __m128i q3h_0 = _mm_set_epi64x(aux64 >> 1, aux64 >> 0); + __m128i q3h_1 = _mm_srli_epi16(q3h_0, 2); + __m128i q3h_2 = _mm_srli_epi16(q3h_0, 4); + __m128i q3h_3 = _mm_srli_epi16(q3h_0, 6); + q3h_0 = _mm_slli_epi16(_mm_andnot_si128(q3h_0, m1), 2); + q3h_1 = _mm_slli_epi16(_mm_andnot_si128(q3h_1, m1), 2); + q3h_2 = _mm_slli_epi16(_mm_andnot_si128(q3h_2, m1), 2); + q3h_3 = _mm_slli_epi16(_mm_andnot_si128(q3h_3, m1), 2); + + // load low 2 bits + const __m128i q3bits = _mm_loadu_si128((const __m128i*)q3); + + // prepare low and high bits + const __m128i q3l_0 = _mm_and_si128(q3bits, m3); + const __m128i q3l_1 = _mm_and_si128(_mm_srli_epi16(q3bits, 2), m3); + const __m128i q3l_2 = _mm_and_si128(_mm_srli_epi16(q3bits, 4), m3); + const __m128i q3l_3 = _mm_and_si128(_mm_srli_epi16(q3bits, 6), m3); + + // load Q8 quants + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + // Dot product: we multiply the 2 low bits and 1 high bit part separately, so we can use _mm_maddubs_epi16, + // and then subtract. The high bit part has the 2 already subtracted (and so, it is zero if the high bit was not set, + // and 2 if the high bit was set) + const __m128i q8s_0 = _mm_maddubs_epi16(q3h_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i q8s_1 = _mm_maddubs_epi16(q3h_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i q8s_2 = _mm_maddubs_epi16(q3h_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i q8s_3 = _mm_maddubs_epi16(q3h_3, _mm256_extractf128_si256(q8_1, 1)); + + __m128i p16_0 = _mm_maddubs_epi16(q3l_0, _mm256_extractf128_si256(q8_0, 0)); + __m128i p16_1 = _mm_maddubs_epi16(q3l_1, _mm256_extractf128_si256(q8_0, 1)); + __m128i p16_2 = _mm_maddubs_epi16(q3l_2, _mm256_extractf128_si256(q8_1, 0)); + __m128i p16_3 = _mm_maddubs_epi16(q3l_3, _mm256_extractf128_si256(q8_1, 1)); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + + // multiply with scales + p16_0 = _mm_madd_epi16(scale_0, p16_0); + p16_1 = _mm_madd_epi16(scale_1, p16_1); + p16_2 = _mm_madd_epi16(scale_2, p16_2); + p16_3 = _mm_madd_epi16(scale_3, p16_3); + + p16_0 = _mm_add_epi32(p16_0, p16_2); + p16_1 = _mm_add_epi32(p16_1, p16_3); + __m256i p16 = MM256_SET_M128I(p16_1, p16_0); + + // multiply with block scale and accumulate + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(p16)), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + uint16_t aux16[2]; + int8_t * scales = (int8_t *)aux16; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q3 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t a = *(const uint16_t *)x[i].scales; + aux16[0] = a & 0x0f0f; + aux16[1] = (a >> 4) & 0x0f0f; + + for (int j = 0; j < 4; ++j) scales[j] -= 8; + + int32_t isum = -4*(scales[0] * y[i].bsums[0] + scales[2] * y[i].bsums[1] + scales[1] * y[i].bsums[2] + scales[3] * y[i].bsums[3]); + + const float d = y[i].d * (float)x[i].d; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load qh + vuint8mf4_t qh_x1 = __riscv_vle8_v_u8mf4(x[i].hmask, 8); + vuint8mf2_t qh_x2 = __riscv_vlmul_ext_v_u8mf4_u8mf2(__riscv_vsrl_vx_u8mf4(qh_x1, 1, 8)); + + size_t vl = 16; + + // extend and combine both qh_x1 and qh_x2 + vuint8mf2_t qh_x = __riscv_vslideup_vx_u8mf2(__riscv_vlmul_ext_v_u8mf4_u8mf2(qh_x1), qh_x2, vl/2, vl); + + vuint8mf2_t qh_0 = __riscv_vand_vx_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x2, vl), 0x4, vl); + vuint8mf2_t qh_1 = __riscv_vand_vx_u8mf2(qh_x, 0x4, vl); + vuint8mf2_t qh_2 = __riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl), 0x4, vl); + vuint8mf2_t qh_3 = __riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x4, vl), 0x4, vl); + + // load Q3 + vuint8mf2_t q3_x = __riscv_vle8_v_u8mf2(q3, vl); + + vuint8mf2_t q3h_0 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q3_x, 0x3, vl), qh_0, vl); + vuint8mf2_t q3h_1 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 2, vl), 0x3, vl), qh_1, vl); + vuint8mf2_t q3h_2 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 4, vl), 0x3, vl), qh_2, vl); + vuint8mf2_t q3h_3 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q3_x, 0x6, vl), qh_3, vl); + + vint8mf2_t q3_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_0); + vint8mf2_t q3_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_1); + vint8mf2_t q3_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_2); + vint8mf2_t q3_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(q3h_3); + + // load Q8 and take product with Q3 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q3_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q3_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q3_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q3_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(vs_0) * scales[0]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_1) * scales[2]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_2) * scales[1]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_3) * scales[3]; + + sumf += d * isum; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + int32_t scales[4]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q3 = x[i].qs; + const uint8_t * restrict hm = x[i].hmask; + const int8_t * restrict q8 = y[i].qs; + int8_t * restrict a = aux8; + for (int l = 0; l < 8; ++l) { + a[l+ 0] = (int8_t)((q3[l+0] >> 0) & 3) - (hm[l] & 0x01 ? 0 : 4); + a[l+ 8] = (int8_t)((q3[l+8] >> 0) & 3) - (hm[l] & 0x02 ? 0 : 4); + a[l+16] = (int8_t)((q3[l+0] >> 2) & 3) - (hm[l] & 0x04 ? 0 : 4); + a[l+24] = (int8_t)((q3[l+8] >> 2) & 3) - (hm[l] & 0x08 ? 0 : 4); + a[l+32] = (int8_t)((q3[l+0] >> 4) & 3) - (hm[l] & 0x10 ? 0 : 4); + a[l+40] = (int8_t)((q3[l+8] >> 4) & 3) - (hm[l] & 0x20 ? 0 : 4); + a[l+48] = (int8_t)((q3[l+0] >> 6) & 3) - (hm[l] & 0x40 ? 0 : 4); + a[l+56] = (int8_t)((q3[l+8] >> 6) & 3) - (hm[l] & 0x80 ? 0 : 4); + } + + scales[0] = (x[i].scales[0] & 0xF) - 8; + scales[1] = (x[i].scales[0] >> 4) - 8; + scales[2] = (x[i].scales[1] & 0xF) - 8; + scales[3] = (x[i].scales[1] >> 4) - 8; + + memset(aux32, 0, 8*sizeof(int32_t)); + for (int j = 0; j < QK_K/16; ++j) { + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] += q8[l] * a[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux32[l] += scales[j] * aux16[l]; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; + +#endif + +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q4_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q4_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + + static const uint32_t kmask1 = 0x3f3f3f3f; + static const uint32_t kmask2 = 0x0f0f0f0f; + static const uint32_t kmask3 = 0x03030303; + + uint32_t utmp[4]; + +#ifdef __ARM_NEON + + const uint8x16_t m4b = vdupq_n_u8(0xf); +#ifdef __ARM_FEATURE_DOTPROD + const int32x4_t mzero = vdupq_n_s32(0); +#endif + + int8x16x2_t q4bytes; + int8x16x2_t q8bytes; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const int16x8_t q8sums = vpaddq_s16(vld1q_s16(y[i].bsums), vld1q_s16(y[i].bsums + 8)); + + memcpy(utmp, x[i].scales, 12); + + uint32x2_t mins8 = { 0 }; + mins8 = vset_lane_u32(utmp[1] & kmask1, mins8, 0); + mins8 = vset_lane_u32(((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4), mins8, 1); + + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[0] &= kmask1; + + const int16x8_t mins = vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(mins8))); + const int32x4_t prod = vaddq_s32(vmull_s16(vget_low_s16 (q8sums), vget_low_s16 (mins)), + vmull_s16(vget_high_s16(q8sums), vget_high_s16(mins))); + sumf -= dmin * vaddvq_s32(prod); + + const uint8_t * scales = (const uint8_t *)utmp; + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + int32_t sumi1 = 0; + int32_t sumi2 = 0; + + for (int j = 0; j < QK_K/64; ++j) { + + const uint8x16x2_t q4bits = vld1q_u8_x2(q4); q4 += 32; + +#ifdef __ARM_FEATURE_DOTPROD + q8bytes = vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + + const int32x4_t p1 = vdotq_s32(vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + sumi1 += vaddvq_s32(p1) * scales[2*j+0]; + + q8bytes = vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + + const int32x4_t p2 = vdotq_s32(vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + + sumi2 += vaddvq_s32(p2) * scales[2*j+1]; +#else + q8bytes = vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + const int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q4bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q4bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + sumi1 += vaddvq_s16(vaddq_s16(p0, p1)) * scales[2*j+0]; + + q8bytes = vld1q_s8_x2(q8); q8 += 32; + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q4bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q4bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + sumi2 += vaddvq_s16(vaddq_s16(p2, p3)) * scales[2*j+1]; + +#endif + } + + sumf += d * (sumi1 + sumi2); + + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + __m128 acc_m = _mm_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i mins_and_scales = _mm256_cvtepu8_epi16(_mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0])); + + const __m256i q8sums = _mm256_loadu_si256((const __m256i*)y[i].bsums); + const __m128i q8s = _mm_hadd_epi16(_mm256_extracti128_si256(q8sums, 0), _mm256_extracti128_si256(q8sums, 1)); + const __m128i prod = _mm_madd_epi16(_mm256_extracti128_si256(mins_and_scales, 1), q8s); + acc_m = _mm_fmadd_ps(_mm_set1_ps(dmin), _mm_cvtepi32_ps(prod), acc_m); + + const __m128i sc128 = _mm256_extracti128_si256(mins_and_scales, 0); + const __m256i scales = MM256_SET_M128I(sc128, sc128); + + __m256i sumi = _mm256_setzero_si256(); + + for (int j = 0; j < QK_K/64; ++j) { + + const __m256i scale_l = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+0)); + const __m256i scale_h = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+1)); + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4l = _mm256_and_si256(q4bits, m4); + const __m256i q4h = _mm256_and_si256(_mm256_srli_epi16(q4bits, 4), m4); + + const __m256i q8l = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + __m256i p16l = _mm256_maddubs_epi16(q4l, q8l); + p16l = _mm256_madd_epi16(scale_l, p16l); + + const __m256i q8h = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + __m256i p16h = _mm256_maddubs_epi16(q4h, q8h); + p16h = _mm256_madd_epi16(scale_h, p16h); + const __m256i sumj = _mm256_add_epi32(p16l, p16h); + + sumi = _mm256_add_epi32(sumi, sumj); + } + + __m256 vd = _mm256_set1_ps(d); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(sumi), acc); + + } + + acc_m = _mm_add_ps(acc_m, _mm_movehl_ps(acc_m, acc_m)); + acc_m = _mm_add_ss(acc_m, _mm_movehdup_ps(acc_m)); + + *s = hsum_float_8(acc) + _mm_cvtss_f32(acc_m); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(0x2); + + __m256 acc = _mm256_setzero_ps(); + __m128 acc_m = _mm_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const __m128i utmps = _mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0]); + const __m128i scales = _mm_cvtepu8_epi16(utmps); + const __m128i mins = _mm_cvtepu8_epi16(_mm_unpackhi_epi64(utmps, utmps)); + + const __m128i q8sums_0 = _mm_loadu_si128((const __m128i*)&y[i].bsums[0]); + const __m128i q8sums_1 = _mm_loadu_si128((const __m128i*)&y[i].bsums[8]); + const __m128i q8s = _mm_hadd_epi16(q8sums_0, q8sums_1); + const __m128i prod = _mm_madd_epi16(mins, q8s); + acc_m = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(dmin), _mm_cvtepi32_ps(prod)), acc_m); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + __m128i shuffle = _mm_set1_epi16(0x0100); + for (int j = 0; j < QK_K/64; ++j) { + + const __m128i scale_l = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + const __m128i scale_h = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + + __m128i q4bits = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4l_0 = _mm_and_si128(q4bits, m4); + const __m128i q4h_0 = _mm_and_si128(_mm_srli_epi16(q4bits, 4), m4); + q4bits = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4l_1 = _mm_and_si128(q4bits, m4); + const __m128i q4h_1 = _mm_and_si128(_mm_srli_epi16(q4bits, 4), m4); + + const __m128i q8l_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16l = _mm_maddubs_epi16(q4l_0, q8l_0); + p16l = _mm_madd_epi16(scale_l, p16l); + sumi_0 = _mm_add_epi32(sumi_0, p16l); + const __m128i q8l_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + p16l = _mm_maddubs_epi16(q4l_1, q8l_1); + p16l = _mm_madd_epi16(scale_l, p16l); + sumi_1 = _mm_add_epi32(sumi_1, p16l); + + const __m128i q8h_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16h = _mm_maddubs_epi16(q4h_0, q8h_0); + p16h = _mm_madd_epi16(scale_h, p16h); + sumi_0 = _mm_add_epi32(sumi_0, p16h); + const __m128i q8h_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + p16h = _mm_maddubs_epi16(q4h_1, q8h_1); + p16h = _mm_madd_epi16(scale_h, p16h); + sumi_1 = _mm_add_epi32(sumi_1, p16h); + + } + + __m256 vd = _mm256_set1_ps(d); + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(sumi)), acc); + + } + + acc_m = _mm_add_ps(acc_m, _mm_movehl_ps(acc_m, acc_m)); + acc_m = _mm_add_ss(acc_m, _mm_movehdup_ps(acc_m)); + + *s = hsum_float_8(acc) + _mm_cvtss_f32(acc_m); + +#elif defined __riscv_v_intrinsic + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + size_t vl = 8; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + vint16mf2_t q8sums_0 = __riscv_vlse16_v_i16mf2(y[i].bsums, 4, vl); + vint16mf2_t q8sums_1 = __riscv_vlse16_v_i16mf2(y[i].bsums+1, 4, vl); + vint16mf2_t q8sums = __riscv_vadd_vv_i16mf2(q8sums_0, q8sums_1, vl); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + vuint8mf4_t mins8 = __riscv_vle8_v_u8mf4(mins, vl); + vint16mf2_t v_mins = __riscv_vreinterpret_v_u16mf2_i16mf2(__riscv_vzext_vf2_u16mf2(mins8, vl)); + vint32m1_t prod = __riscv_vwmul_vv_i32m1(q8sums, v_mins, vl); + + vint32m1_t sumi = __riscv_vredsum_vs_i32m1_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + sumf -= dmin * __riscv_vmv_x_s_i32m1_i32(sumi); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + vl = 32; + + int32_t sum_1 = 0; + int32_t sum_2 = 0; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + for (int j = 0; j < QK_K/64; ++j) { + // load Q4 + vuint8m1_t q4_x = __riscv_vle8_v_u8m1(q4, vl); + + // load Q8 and multiply it with lower Q4 nibble + vint8m1_t q8_0 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q4_0 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q4_x, 0x0F, vl)); + vint16m2_t qv_0 = __riscv_vwmul_vv_i16m2(q4_0, q8_0, vl); + vint16m1_t vs_0 = __riscv_vredsum_vs_i16m2_i16m1(qv_0, vzero, vl); + + sum_1 += __riscv_vmv_x_s_i16m1_i16(vs_0) * scales[2*j+0]; + + // load Q8 and multiply it with upper Q4 nibble + vint8m1_t q8_1 = __riscv_vle8_v_i8m1(q8+32, vl); + vint8m1_t q4_1 = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q4_x, 0x04, vl)); + vint16m2_t qv_1 = __riscv_vwmul_vv_i16m2(q4_1, q8_1, vl); + vint16m1_t vs_1 = __riscv_vredsum_vs_i16m2_i16m1(qv_1, vzero, vl); + + sum_2 += __riscv_vmv_x_s_i16m1_i16(vs_1) * scales[2*j+1]; + + q4 += 32; q8 += 64; + + } + + sumf += d*(sum_1 + sum_2); + + } + + *s = sumf; + +#else + + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int j = 0; j < QK_K/64; ++j) { + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] & 0xF); + a += 32; + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] >> 4); + a += 32; q4 += 32; + } + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + int sumi = 0; + for (int j = 0; j < QK_K/16; ++j) sumi += y[i].bsums[j] * mins[j/2]; + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/32; ++j) { + int32_t scale = scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + sumf -= dmin * sumi; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#else +void ggml_vec_dot_q4_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q4_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + const uint8x16_t m4b = vdupq_n_u8(0xf); + +#ifdef __ARM_FEATURE_DOTPROD + const int32x4_t mzero = vdupq_n_s32(0); +#endif + + float sumf = 0; + + int8x16x2_t q4bytes; + int8x16x4_t q8bytes; + + float sum_mins = 0.f; + + uint16_t aux16[2]; + const uint8_t * restrict scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t * restrict a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + const int32_t summi = scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3]); + sum_mins += y[i].d * (float)x[i].d[1] * summi; + + const float d = y[i].d * (float)x[i].d[0]; + + const uint8x16x2_t q4bits = vld1q_u8_x2(q4); + +#ifdef __ARM_FEATURE_DOTPROD + q8bytes = vld1q_s8_x4(q8); + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + + const int32x4_t p1 = vdotq_s32(vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[0]), q4bytes.val[1], q8bytes.val[1]); + const int32_t sumi1 = vaddvq_s32(p1) * scales[0]; + + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + + const int32x4_t p2 = vdotq_s32(vdotq_s32(mzero, q4bytes.val[0], q8bytes.val[2]), q4bytes.val[1], q8bytes.val[3]); + const int32_t sumi2 = vaddvq_s32(p2) * scales[1]; + +#else + q8bytes = vld1q_s8_x4(q8); + q4bytes.val[0] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[0], m4b)); + q4bytes.val[1] = vreinterpretq_s8_u8(vandq_u8 (q4bits.val[1], m4b)); + const int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q4bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q4bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + int32_t sumi1 = vaddvq_s16(vaddq_s16(p0, p1)) * scales[0]; + + q4bytes.val[0] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[0], 4)); + q4bytes.val[1] = vreinterpretq_s8_u8(vshrq_n_u8(q4bits.val[1], 4)); + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[0]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q4bytes.val[0]), vget_high_s8(q8bytes.val[2]))); + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q4bytes.val[1]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q4bytes.val[1]), vget_high_s8(q8bytes.val[3]))); + int32_t sumi2 = vaddvq_s16(vaddq_s16(p2, p3)) * scales[1]; + +#endif + sumf += d * (sumi1 + sumi2); + + } + + *s = sumf - sum_mins; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + uint16_t aux16[2]; + const uint8_t * scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d[0]) * y[i].d; + const float m = GGML_FP16_TO_FP32(x[i].d[1]) * y[i].d; + const __m256 vd = _mm256_set1_ps(d); + + const uint16_t * a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + summs += m * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); + const __m256i q4l = _mm256_and_si256(q4bits, m4); + const __m256i q4h = _mm256_and_si256(_mm256_srli_epi16(q4bits, 4), m4); + + const __m256i q8l = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8h = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p16l = _mm256_maddubs_epi16(q4l, q8l); + const __m256i p16h = _mm256_maddubs_epi16(q4h, q8h); + + const __m256i p32l = _mm256_madd_epi16(_mm256_set1_epi16(scales[0]), p16l); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(p32l), acc); + + const __m256i p32h = _mm256_madd_epi16(_mm256_set1_epi16(scales[1]), p16h); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(p32h), acc); + + } + + *s = hsum_float_8(acc) - summs; + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0; + + uint16_t aux16[2]; + const uint8_t * scales = (const uint8_t *)aux16; + + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d[0]) * y[i].d; + const float m = GGML_FP16_TO_FP32(x[i].d[1]) * y[i].d; + const __m256 vd = _mm256_set1_ps(d); + + const uint16_t * a = (const uint16_t *)x[i].scales; + aux16[0] = a[0] & 0x0f0f; + aux16[1] = (a[0] >> 4) & 0x0f0f; + + summs += m * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const __m256i q4bits = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bits_0 = _mm256_extractf128_si256(q4bits, 0); + const __m128i q4bits_1 = _mm256_extractf128_si256(q4bits, 1); + const __m128i q4_0 = _mm_and_si128(q4bits_0, m4); + const __m128i q4_1 = _mm_and_si128(q4bits_1, m4); + const __m128i q4_2 = _mm_and_si128(_mm_srli_epi16(q4bits_0, 4), m4); + const __m128i q4_3 = _mm_and_si128(_mm_srli_epi16(q4bits_1, 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p16_0 = _mm_maddubs_epi16(q4_0, _mm256_extractf128_si256(q8_0, 0)); + const __m128i p16_1 = _mm_maddubs_epi16(q4_1, _mm256_extractf128_si256(q8_0, 1)); + const __m128i p16_2 = _mm_maddubs_epi16(q4_2, _mm256_extractf128_si256(q8_1, 0)); + const __m128i p16_3 = _mm_maddubs_epi16(q4_3, _mm256_extractf128_si256(q8_1, 1)); + + const __m128i p32_0 = _mm_madd_epi16(_mm_set1_epi16(scales[0]), p16_0); + const __m128i p32_1 = _mm_madd_epi16(_mm_set1_epi16(scales[0]), p16_1); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(MM256_SET_M128I(p32_1, p32_0))), acc); + + const __m128i p32_2 = _mm_madd_epi16(_mm_set1_epi16(scales[1]), p16_2); + const __m128i p32_3 = _mm_madd_epi16(_mm_set1_epi16(scales[1]), p16_3); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(MM256_SET_M128I(p32_3, p32_2))), acc); + + } + + *s = hsum_float_8(acc) - summs; + +#elif defined __riscv_v_intrinsic + + uint16_t s16[2]; + const uint8_t * restrict scales = (const uint8_t *)s16; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const uint16_t * restrict b = (const uint16_t *)x[i].scales; + s16[0] = b[0] & 0x0f0f; + s16[1] = (b[0] >> 4) & 0x0f0f; + + sumf -= y[i].d * GGML_FP16_TO_FP32(x[i].d[1]) * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d[0]); + + size_t vl = 32; + + vint16m1_t vzero = __riscv_vmv_v_x_i16m1(0, 1); + + // load Q4 + vuint8m1_t q4_x = __riscv_vle8_v_u8m1(q4, vl); + + // load Q8 and multiply it with lower Q4 nibble + vint8m1_t q4_a = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q4_x, 0x0F, vl)); + vint16m2_t va_0 = __riscv_vwmul_vv_i16m2(q4_a, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m1_t aux1 = __riscv_vredsum_vs_i16m2_i16m1(va_0, vzero, vl); + + sumf += d*scales[0]*__riscv_vmv_x_s_i16m1_i16(aux1); + + // load Q8 and multiply it with upper Q4 nibble + vint8m1_t q4_s = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q4_x, 0x04, vl)); + vint16m2_t va_1 = __riscv_vwmul_vv_i16m2(q4_s, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m1_t aux2 = __riscv_vredsum_vs_i16m2_i16m1(va_1, vzero, vl); + + sumf += d*scales[1]*__riscv_vmv_x_s_i16m1_i16(aux2); + + } + + *s = sumf; + +#else + + uint8_t aux8[QK_K]; + int16_t aux16[16]; + float sums [8]; + memset(sums, 0, 8*sizeof(float)); + + uint16_t s16[2]; + const uint8_t * restrict scales = (const uint8_t *)s16; + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + uint8_t * restrict a = aux8; + for (int l = 0; l < 32; ++l) a[l+ 0] = q4[l] & 0xF; + for (int l = 0; l < 32; ++l) a[l+32] = q4[l] >> 4; + + const uint16_t * restrict b = (const uint16_t *)x[i].scales; + s16[0] = b[0] & 0x0f0f; + s16[1] = (b[0] >> 4) & 0x0f0f; + + sumf -= y[i].d * GGML_FP16_TO_FP32(x[i].d[1]) * (scales[2] * (y[i].bsums[0] + y[i].bsums[1]) + scales[3] * (y[i].bsums[2] + y[i].bsums[3])); + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d[0]); + + for (int j = 0; j < QK_K/32; ++j) { + for (int l = 0; l < 16; ++l) aux16[l] = q8[l] * a[l]; + q8 += 16; a += 16; + for (int l = 0; l < 16; ++l) aux16[l] += q8[l] * a[l]; + q8 += 16; a += 16; + const float dl = d * scales[j]; + for (int l = 0; l < 8; ++l) sums[l] += dl * (aux16[l] + aux16[l+8]); + } + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#endif + +#if QK_K == 256 +void ggml_vec_dot_q5_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q5_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + + static const uint32_t kmask1 = 0x3f3f3f3f; + static const uint32_t kmask2 = 0x0f0f0f0f; + static const uint32_t kmask3 = 0x03030303; + + uint32_t utmp[4]; + + +#ifdef __ARM_NEON + + const uint8x16_t m4b = vdupq_n_u8(0xf); + const uint8x16_t mone = vdupq_n_u8(1); + const uint8x16_t mtwo = vdupq_n_u8(2); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t mzero = vdupq_n_s32(0); +#endif + + int8x16x4_t q5bytes; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const int16x8_t q8sums = vpaddq_s16(vld1q_s16(y[i].bsums), vld1q_s16(y[i].bsums + 8)); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const uint8x8_t mins8 = vld1_u8((const uint8_t*)utmp + 8); + const int16x8_t mins = vreinterpretq_s16_u16(vmovl_u8(mins8)); + const int32x4_t prod = vaddq_s32(vmull_s16(vget_low_s16 (q8sums), vget_low_s16 (mins)), + vmull_s16(vget_high_s16(q8sums), vget_high_s16(mins))); + int32_t sumi_mins = vaddvq_s32(prod); + + const uint8_t * scales = (const uint8_t *)utmp; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + uint8x16x2_t qhbits = vld1q_u8_x2(qh); + + uint8x16x4_t q5h; + + int32_t sumi = 0; + + for (int j = 0; j < QK_K/64; ++j) { + + const uint8x16x2_t q5bits = vld1q_u8_x2(q5); q5 += 32; + const int8x16x4_t q8bytes = vld1q_s8_x4(q8); q8 += 64; + + q5h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits.val[0]), 4); + q5h.val[1] = vshlq_n_u8(vandq_u8(mone, qhbits.val[1]), 4); + q5h.val[2] = vshlq_n_u8(vandq_u8(mtwo, qhbits.val[0]), 3); + q5h.val[3] = vshlq_n_u8(vandq_u8(mtwo, qhbits.val[1]), 3); + qhbits.val[0] = vshrq_n_u8(qhbits.val[0], 2); + qhbits.val[1] = vshrq_n_u8(qhbits.val[1], 2); + + q5bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q5bits.val[0], m4b), q5h.val[0])); + q5bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q5bits.val[1], m4b), q5h.val[1])); + q5bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q5bits.val[0], 4), q5h.val[2])); + q5bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q5bits.val[1], 4), q5h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + + sumi += vaddvq_s32(vdotq_s32(vdotq_s32(mzero, q5bytes.val[0], q8bytes.val[0]), q5bytes.val[1], q8bytes.val[1])) * *scales++; + sumi += vaddvq_s32(vdotq_s32(vdotq_s32(mzero, q5bytes.val[2], q8bytes.val[2]), q5bytes.val[3], q8bytes.val[3])) * *scales++; +#else + + const int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q5bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q5bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + sumi += vaddvq_s16(vaddq_s16(p0, p1)) * *scales++; + + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q5bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q5bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + sumi += vaddvq_s16(vaddq_s16(p2, p3)) * *scales++; +#endif + } + + sumf += d * sumi - dmin * sumi_mins; + + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m128i mzero = _mm_setzero_si128(); + const __m256i mone = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.f; + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + +#if QK_K == 256 + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; +#else + // TODO + const float d = 0, dmin = 0; +#endif + + const __m256i mins_and_scales = _mm256_cvtepu8_epi16(_mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0])); + + const __m256i q8sums = _mm256_loadu_si256((const __m256i*)y[i].bsums); + const __m128i q8s = _mm_hadd_epi16(_mm256_extracti128_si256(q8sums, 0), _mm256_extracti128_si256(q8sums, 1)); + const __m128i prod = _mm_madd_epi16(_mm256_extracti128_si256(mins_and_scales, 1), q8s); + const __m128i hsum = _mm_hadd_epi32(_mm_hadd_epi32(prod, mzero), mzero); + summs += dmin * _mm_extract_epi32(hsum, 0); + + const __m128i sc128 = _mm256_extracti128_si256(mins_and_scales, 0); + const __m256i scales = MM256_SET_M128I(sc128, sc128); + + const __m256i hbits = _mm256_loadu_si256((const __m256i*)x[i].qh); + __m256i hmask = mone; + + __m256i sumi = _mm256_setzero_si256(); + + int bit = 0; + + for (int j = 0; j < QK_K/64; ++j) { + + const __m256i scale_0 = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+0)); + const __m256i scale_1 = _mm256_shuffle_epi8(scales, get_scale_shuffle_k4(2*j+1)); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); q5 += 32; + + const __m256i q5l_0 = _mm256_and_si256(q5bits, m4); + const __m256i q5h_0 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_and_si256(hbits, hmask), bit++), 4); + const __m256i q5_0 = _mm256_add_epi8(q5l_0, q5h_0); + hmask = _mm256_slli_epi16(hmask, 1); + + const __m256i q5l_1 = _mm256_and_si256(_mm256_srli_epi16(q5bits, 4), m4); + const __m256i q5h_1 = _mm256_slli_epi16(_mm256_srli_epi16(_mm256_and_si256(hbits, hmask), bit++), 4); + const __m256i q5_1 = _mm256_add_epi8(q5l_1, q5h_1); + hmask = _mm256_slli_epi16(hmask, 1); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + __m256i p16_0 = _mm256_maddubs_epi16(q5_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q5_1, q8_1); + + p16_0 = _mm256_madd_epi16(scale_0, p16_0); + p16_1 = _mm256_madd_epi16(scale_1, p16_1); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + + } + + __m256 vd = _mm256_set1_ps(d); + acc = _mm256_fmadd_ps(vd, _mm256_cvtepi32_ps(sumi), acc); + + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i mzero = _mm_setzero_si128(); + const __m128i mone = _mm_set1_epi8(1); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + float summs = 0.f; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const float dmin = -y[i].d * GGML_FP16_TO_FP32(x[i].dmin); + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + const __m128i utmps = _mm_set_epi32(utmp[3], utmp[2], utmp[1], utmp[0]); + const __m128i scales = _mm_cvtepu8_epi16(utmps); + const __m128i mins = _mm_cvtepu8_epi16(_mm_unpackhi_epi64(utmps, utmps)); + + const __m128i q8sums_0 = _mm_loadu_si128((const __m128i*)&y[i].bsums[0]); + const __m128i q8sums_1 = _mm_loadu_si128((const __m128i*)&y[i].bsums[8]); + const __m128i q8s = _mm_hadd_epi16(q8sums_0, q8sums_1); + const __m128i prod = _mm_madd_epi16(mins, q8s); + const __m128i hsum = _mm_hadd_epi32(_mm_hadd_epi32(prod, mzero), mzero); + summs += dmin * _mm_extract_epi32(hsum, 0); + + const __m128i hbits_0 = _mm_loadu_si128((const __m128i*)&x[i].qh[0]); + const __m128i hbits_1 = _mm_loadu_si128((const __m128i*)&x[i].qh[16]); + __m128i hmask = mone; + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + int bit = 0; + + __m128i shuffle = _mm_set1_epi16(0x0100); + for (int j = 0; j < QK_K/64; ++j) { + + const __m128i scale_0 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + const __m128i scale_1 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi16(shuffle, m2); + + const __m128i q5bits_0 = _mm_loadu_si128((const __m128i*)q5); q5 += 16; + const __m128i q5bits_1 = _mm_loadu_si128((const __m128i*)q5); q5 += 16; + + __m128i q5l_0 = _mm_and_si128(q5bits_0, m4); + __m128i q5l_1 = _mm_and_si128(q5bits_1, m4); + __m128i q5h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_0, hmask), bit), 4); + __m128i q5h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_1, hmask), bit++), 4); + __m128i q5_0 = _mm_add_epi8(q5l_0, q5h_0); + __m128i q5_1 = _mm_add_epi8(q5l_1, q5h_1); + hmask = _mm_slli_epi16(hmask, 1); + + __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16_0 = _mm_maddubs_epi16(q5_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q5_1, q8_1); + p16_0 = _mm_madd_epi16(scale_0, p16_0); + p16_1 = _mm_madd_epi16(scale_0, p16_1); + + q5l_0 = _mm_and_si128(_mm_srli_epi16(q5bits_0, 4), m4); + q5l_1 = _mm_and_si128(_mm_srli_epi16(q5bits_1, 4), m4); + q5h_0 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_0, hmask), bit), 4); + q5h_1 = _mm_slli_epi16(_mm_srli_epi16(_mm_and_si128(hbits_1, hmask), bit++), 4); + q5_0 = _mm_add_epi8(q5l_0, q5h_0); + q5_1 = _mm_add_epi8(q5l_1, q5h_1); + hmask = _mm_slli_epi16(hmask, 1); + + q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + __m128i p16_2 = _mm_maddubs_epi16(q5_0, q8_0); + __m128i p16_3 = _mm_maddubs_epi16(q5_1, q8_1); + p16_2 = _mm_madd_epi16(scale_1, p16_2); + p16_3 = _mm_madd_epi16(scale_1, p16_3); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + + } + + __m256 vd = _mm256_set1_ps(d); + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(vd, _mm256_cvtepi32_ps(sumi)), acc); + + } + + *s = hsum_float_8(acc) + summs; + +#elif defined __riscv_v_intrinsic + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + float sumf = 0; + float sums = 0.0; + + size_t vl; + + for (int i = 0; i < nb; ++i) { + + vl = 8; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + + vint16mf2_t q8sums_0 = __riscv_vlse16_v_i16mf2(y[i].bsums, 4, vl); + vint16mf2_t q8sums_1 = __riscv_vlse16_v_i16mf2(y[i].bsums+1, 4, vl); + vint16mf2_t q8sums = __riscv_vadd_vv_i16mf2(q8sums_0, q8sums_1, vl); + + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + vuint8mf4_t mins8 = __riscv_vle8_v_u8mf4(mins, vl); + vint16mf2_t v_mins = __riscv_vreinterpret_v_u16mf2_i16mf2(__riscv_vzext_vf2_u16mf2(mins8, vl)); + vint32m1_t prod = __riscv_vwmul_vv_i32m1(q8sums, v_mins, vl); + + vint32m1_t sumi = __riscv_vredsum_vs_i32m1_i32m1(prod, __riscv_vmv_v_x_i32m1(0, 1), vl); + sumf -= dmin * __riscv_vmv_x_s_i32m1_i32(sumi); + + vl = 32; + int32_t aux32 = 0; + int is = 0; + + uint8_t m = 1; + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + vuint8m1_t vqh = __riscv_vle8_v_u8m1(hm, vl); + + for (int j = 0; j < QK_K/64; ++j) { + // load Q5 and Q8 + vuint8m1_t q5_x = __riscv_vle8_v_u8m1(q5, vl); + vint8m1_t q8_y1 = __riscv_vle8_v_i8m1(q8, vl); + vint8m1_t q8_y2 = __riscv_vle8_v_i8m1(q8+32, vl); + + // compute mask for addition + vint8m1_t q5_a = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vand_vx_u8m1(q5_x, 0x0F, vl)); + vuint8m1_t qh_m1 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_1 = __riscv_vmsne_vx_u8m1_b8(qh_m1, 0, vl); + vint8m1_t q5_m1 = __riscv_vadd_vx_i8m1_m(vmask_1, q5_a, 16, vl); + m <<= 1; + + vint8m1_t q5_l = __riscv_vreinterpret_v_u8m1_i8m1(__riscv_vsrl_vx_u8m1(q5_x, 0x04, vl)); + vuint8m1_t qh_m2 = __riscv_vand_vx_u8m1(vqh, m, vl); + vbool8_t vmask_2 = __riscv_vmsne_vx_u8m1_b8(qh_m2, 0, vl); + vint8m1_t q5_m2 = __riscv_vadd_vx_i8m1_m(vmask_2, q5_l, 16, vl); + m <<= 1; + + vint16m2_t v0 = __riscv_vwmul_vv_i16m2(q5_m1, q8_y1, vl); + vint16m2_t v1 = __riscv_vwmul_vv_i16m2(q5_m2, q8_y2, vl); + + vint32m4_t vs1 = __riscv_vwmul_vx_i32m4(v0, scales[is++], vl); + vint32m4_t vs2 = __riscv_vwmul_vx_i32m4(v1, scales[is++], vl); + + vint32m1_t vacc1 = __riscv_vredsum_vs_i32m4_i32m1(vs1, vzero, vl); + vint32m1_t vacc2 = __riscv_vredsum_vs_i32m4_i32m1(vs2, vzero, vl); + + aux32 += __riscv_vmv_x_s_i32m1_i32(vacc1) + __riscv_vmv_x_s_i32m1_i32(vacc2); + q5 += 32; q8 += 64; + + } + + vfloat32m1_t vaux = __riscv_vfmul_vf_f32m1(__riscv_vfmv_v_f_f32m1(aux32, 1), d, 1); + sums += __riscv_vfmv_f_s_f32m1_f32(vaux); + + } + + *s = sumf+sums; + +#else + + const uint8_t * scales = (const uint8_t*)&utmp[0]; + const uint8_t * mins = (const uint8_t*)&utmp[2]; + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + uint8_t m = 1; + for (int j = 0; j < QK_K/64; ++j) { + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] & 0xF); + for (int l = 0; l < 32; ++l) a[l] += (hm[l] & m ? 16 : 0); + a += 32; m <<= 1; + for (int l = 0; l < 32; ++l) a[l] = (int8_t)(q4[l] >> 4); + for (int l = 0; l < 32; ++l) a[l] += (hm[l] & m ? 16 : 0); + a += 32; m <<= 1; + q4 += 32; + } + memcpy(utmp, x[i].scales, 12); + utmp[3] = ((utmp[2] >> 4) & kmask2) | (((utmp[1] >> 6) & kmask3) << 4); + const uint32_t uaux = utmp[1] & kmask1; + utmp[1] = (utmp[2] & kmask2) | (((utmp[0] >> 6) & kmask3) << 4); + utmp[2] = uaux; + utmp[0] &= kmask1; + + int sumi = 0; + for (int j = 0; j < QK_K/16; ++j) sumi += y[i].bsums[j] * mins[j/2]; + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/32; ++j) { + int32_t scale = scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + const float dmin = GGML_FP16_TO_FP32(x[i].dmin) * y[i].d; + sumf -= dmin * sumi; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q5_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q5_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + const uint8x16_t m4b = vdupq_n_u8(0xf); + const uint8x16_t mh = vdupq_n_u8(16); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t mzero = vdupq_n_s32(0); +#endif + + int8x16x4_t q5bytes; + uint8x16x4_t q5h; + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * (float)x[i].d; + const int8_t * sc = x[i].scales; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const uint8x8_t qhbits = vld1_u8(qh); + + const uint8x16x2_t q5bits = vld1q_u8_x2(q5); + const int8x16x4_t q8bytes = vld1q_s8_x4(q8); + + const uint8x16_t htmp = vcombine_u8(qhbits, vshr_n_u8(qhbits, 1)); + q5h.val[0] = vbicq_u8(mh, vshlq_n_u8(htmp, 4)); + q5h.val[1] = vbicq_u8(mh, vshlq_n_u8(htmp, 2)); + q5h.val[2] = vbicq_u8(mh, htmp); + q5h.val[3] = vbicq_u8(mh, vshrq_n_u8(htmp, 2)); + + q5bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q5bits.val[0], m4b)), vreinterpretq_s8_u8(q5h.val[0])); + q5bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vandq_u8(q5bits.val[1], m4b)), vreinterpretq_s8_u8(q5h.val[1])); + q5bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vshrq_n_u8(q5bits.val[0], 4)), vreinterpretq_s8_u8(q5h.val[2])); + q5bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vshrq_n_u8(q5bits.val[1], 4)), vreinterpretq_s8_u8(q5h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + + int32_t sumi1 = sc[0] * vaddvq_s32(vdotq_s32(mzero, q5bytes.val[0], q8bytes.val[0])); + int32_t sumi2 = sc[1] * vaddvq_s32(vdotq_s32(mzero, q5bytes.val[1], q8bytes.val[1])); + int32_t sumi3 = sc[2] * vaddvq_s32(vdotq_s32(mzero, q5bytes.val[2], q8bytes.val[2])); + int32_t sumi4 = sc[3] * vaddvq_s32(vdotq_s32(mzero, q5bytes.val[3], q8bytes.val[3])); + + sumf += d * (sumi1 + sumi2 + sumi3 + sumi4); + +#else + + const int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q5bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + const int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q5bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + int32_t sumi = sc[0] * vaddvq_s16(p0) + sc[1] * vaddvq_s16(p1); + + const int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q5bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + const int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q5bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q5bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + sumi += sc[2] * vaddvq_s16(p2) + sc[3] * vaddvq_s16(p3); + + sumf += d*sumi; +#endif + + } + + *s = sumf; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i mone = _mm256_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); + + const __m256i scale_l = MM256_SET_M128I(_mm_set1_epi16(x[i].scales[1]), _mm_set1_epi16(x[i].scales[0])); + const __m256i scale_h = MM256_SET_M128I(_mm_set1_epi16(x[i].scales[3]), _mm_set1_epi16(x[i].scales[2])); + + int64_t aux64; + memcpy(&aux64, x[i].qh, 8); + const __m128i haux128 = _mm_set_epi64x(aux64 >> 1, aux64); + const __m256i haux256 = MM256_SET_M128I(_mm_srli_epi16(haux128, 2), haux128); + + const __m256i q5h_0 = _mm256_slli_epi16(_mm256_andnot_si256(haux256, mone), 4); + const __m256i q5h_1 = _mm256_slli_epi16(_mm256_andnot_si256(_mm256_srli_epi16(haux256, 4), mone), 4); + + const __m256i q5l_0 = _mm256_and_si256(q5bits, m4); + const __m256i q5l_1 = _mm256_and_si256(_mm256_srli_epi16(q5bits, 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m256i p16_0 = _mm256_madd_epi16(scale_l, _mm256_maddubs_epi16(q5l_0, q8_0)); + const __m256i p16_1 = _mm256_madd_epi16(scale_h, _mm256_maddubs_epi16(q5l_1, q8_1)); + const __m256i s16_0 = _mm256_madd_epi16(scale_l, _mm256_maddubs_epi16(q5h_0, q8_0)); + const __m256i s16_1 = _mm256_madd_epi16(scale_h, _mm256_maddubs_epi16(q5h_1, q8_1)); + + const __m256i dot = _mm256_sub_epi32(_mm256_add_epi32(p16_0, p16_1), _mm256_add_epi32(s16_0, s16_1)); + + acc = _mm256_fmadd_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(dot), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i mone = _mm_set1_epi8(1); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const uint8_t * restrict q5 = x[i].qs; + const int8_t * restrict q8 = y[i].qs; + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const __m256i q5bits = _mm256_loadu_si256((const __m256i*)q5); + + const __m128i scale_0 = _mm_set1_epi16(x[i].scales[0]); + const __m128i scale_1 = _mm_set1_epi16(x[i].scales[1]); + const __m128i scale_2 = _mm_set1_epi16(x[i].scales[2]); + const __m128i scale_3 = _mm_set1_epi16(x[i].scales[3]); + + int64_t aux64; + memcpy(&aux64, x[i].qh, 8); + const __m128i haux128_0 = _mm_set_epi64x(aux64 >> 1, aux64); + const __m128i haux128_1 = _mm_srli_epi16(haux128_0, 2); + + const __m128i q5h_0 = _mm_slli_epi16(_mm_andnot_si128(haux128_0, mone), 4); + const __m128i q5h_1 = _mm_slli_epi16(_mm_andnot_si128(haux128_1, mone), 4); + const __m128i q5h_2 = _mm_slli_epi16(_mm_andnot_si128(_mm_srli_epi16(haux128_0, 4), mone), 4); + const __m128i q5h_3 = _mm_slli_epi16(_mm_andnot_si128(_mm_srli_epi16(haux128_1, 4), mone), 4); + + const __m128i q5l_0 = _mm_and_si128(_mm256_extractf128_si256(q5bits, 0), m4); + const __m128i q5l_1 = _mm_and_si128(_mm256_extractf128_si256(q5bits, 1), m4); + const __m128i q5l_2 = _mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q5bits, 0), 4), m4); + const __m128i q5l_3 = _mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q5bits, 1), 4), m4); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + const __m128i p16_0 = _mm_madd_epi16(scale_0, _mm_maddubs_epi16(q5l_0, _mm256_extractf128_si256(q8_0, 0))); + const __m128i p16_1 = _mm_madd_epi16(scale_1, _mm_maddubs_epi16(q5l_1, _mm256_extractf128_si256(q8_0, 1))); + const __m128i p16_2 = _mm_madd_epi16(scale_2, _mm_maddubs_epi16(q5l_2, _mm256_extractf128_si256(q8_1, 0))); + const __m128i p16_3 = _mm_madd_epi16(scale_3, _mm_maddubs_epi16(q5l_3, _mm256_extractf128_si256(q8_1, 1))); + const __m128i s16_0 = _mm_madd_epi16(scale_0, _mm_maddubs_epi16(q5h_0, _mm256_extractf128_si256(q8_0, 0))); + const __m128i s16_1 = _mm_madd_epi16(scale_1, _mm_maddubs_epi16(q5h_1, _mm256_extractf128_si256(q8_0, 1))); + const __m128i s16_2 = _mm_madd_epi16(scale_2, _mm_maddubs_epi16(q5h_2, _mm256_extractf128_si256(q8_1, 0))); + const __m128i s16_3 = _mm_madd_epi16(scale_3, _mm_maddubs_epi16(q5h_3, _mm256_extractf128_si256(q8_1, 1))); + + const __m128i dot_0 = _mm_sub_epi32(_mm_add_epi32(p16_0, p16_2), _mm_add_epi32(s16_0, s16_2)); + const __m128i dot_1 = _mm_sub_epi32(_mm_add_epi32(p16_1, p16_3), _mm_add_epi32(s16_1, s16_3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_set1_ps(d), _mm256_cvtepi32_ps(MM256_SET_M128I(dot_1, dot_0))), acc); + + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * (float)x[i].d; + const int8_t * sc = x[i].scales; + + const uint8_t * restrict q5 = x[i].qs; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load qh + vuint8mf4_t qh_x1 = __riscv_vle8_v_u8mf4(qh, 8); + vuint8mf2_t qh_x2 = __riscv_vlmul_ext_v_u8mf4_u8mf2(__riscv_vsrl_vx_u8mf4(qh_x1, 1, 8)); + + size_t vl = 16; + + // combine both qh_1 and qh_2 + vuint8mf2_t qh_x = __riscv_vslideup_vx_u8mf2(__riscv_vlmul_ext_v_u8mf4_u8mf2(qh_x1), qh_x2, vl/2, vl); + + vuint8mf2_t qh_h0 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x4, vl), vl), 16, vl); + vuint8mf2_t qh_h1 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsll_vx_u8mf2(qh_x, 0x2, vl), vl), 16, vl); + vuint8mf2_t qh_h2 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(qh_x, vl), 16, vl); + vuint8mf2_t qh_h3 = __riscv_vand_vx_u8mf2(__riscv_vnot_v_u8mf2(__riscv_vsrl_vx_u8mf2(qh_x, 0x4, vl), vl), 16, vl); + + vint8mf2_t qh_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h0); + vint8mf2_t qh_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h1); + vint8mf2_t qh_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h2); + vint8mf2_t qh_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(qh_h3); + + // load q5 + vuint8mf2_t q5_x1 = __riscv_vle8_v_u8mf2(q5, vl); + vuint8mf2_t q5_x2 = __riscv_vle8_v_u8mf2(q5+16, vl); + + vint8mf2_t q5s_0 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q5_x1, 0xF, vl)); + vint8mf2_t q5s_1 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vand_vx_u8mf2(q5_x2, 0xF, vl)); + vint8mf2_t q5s_2 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vsrl_vx_u8mf2(q5_x1, 0x4, vl)); + vint8mf2_t q5s_3 = __riscv_vreinterpret_v_u8mf2_i8mf2(__riscv_vsrl_vx_u8mf2(q5_x2, 0x4, vl)); + + vint8mf2_t q5_0 = __riscv_vsub_vv_i8mf2(q5s_0, qh_0, vl); + vint8mf2_t q5_1 = __riscv_vsub_vv_i8mf2(q5s_1, qh_1, vl); + vint8mf2_t q5_2 = __riscv_vsub_vv_i8mf2(q5s_2, qh_2, vl); + vint8mf2_t q5_3 = __riscv_vsub_vv_i8mf2(q5s_3, qh_3, vl); + + // load Q8 and multiply it with Q5 + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q5_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q5_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q5_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q5_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + int32_t sumi1 = sc[0] * __riscv_vmv_x_s_i32m1_i32(vs_0); + int32_t sumi2 = sc[1] * __riscv_vmv_x_s_i32m1_i32(vs_1); + int32_t sumi3 = sc[2] * __riscv_vmv_x_s_i32m1_i32(vs_2); + int32_t sumi4 = sc[3] * __riscv_vmv_x_s_i32m1_i32(vs_3); + + sumf += d * (sumi1 + sumi2 + sumi3 + sumi4); + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[16]; + float sums [8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].qs; + const uint8_t * restrict hm = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + int8_t * restrict a = aux8; + for (int l = 0; l < 32; ++l) { + a[l+ 0] = q4[l] & 0xF; + a[l+32] = q4[l] >> 4; + } + for (int is = 0; is < 8; ++is) { + uint8_t m = 1 << is; + for (int l = 0; l < 8; ++l) a[8*is + l] -= (hm[l] & m ? 0 : 16); + } + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + const int8_t * restrict sc = x[i].scales; + + for (int j = 0; j < QK_K/16; ++j) { + const float dl = d * sc[j]; + for (int l = 0; l < 16; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) sums[l] += dl * (aux16[l] + aux16[8+l]); + q8 += 16; a += 16; + } + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} +#endif + + +#if QK_K == 256 +void ggml_vec_dot_q6_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q6_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + float sum = 0; + + const uint8x16_t m4b = vdupq_n_u8(0xF); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t vzero = vdupq_n_s32(0); +#endif + //const int8x16_t m32s = vdupq_n_s8(32); + + const uint8x16_t mone = vdupq_n_u8(3); + + int8x16x4_t q6bytes; + uint8x16x4_t q6h; + + for (int i = 0; i < nb; ++i) { + + const float d_all = GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + const int16x8x2_t q8sums = vld1q_s16_x2(y[i].bsums); + const int8x16_t scales = vld1q_s8(scale); + const int16x8x2_t q6scales = {vmovl_s8(vget_low_s8(scales)), vmovl_s8(vget_high_s8(scales))}; + + const int32x4_t prod = vaddq_s32(vaddq_s32(vmull_s16(vget_low_s16 (q8sums.val[0]), vget_low_s16 (q6scales.val[0])), + vmull_s16(vget_high_s16(q8sums.val[0]), vget_high_s16(q6scales.val[0]))), + vaddq_s32(vmull_s16(vget_low_s16 (q8sums.val[1]), vget_low_s16 (q6scales.val[1])), + vmull_s16(vget_high_s16(q8sums.val[1]), vget_high_s16(q6scales.val[1])))); + int32_t isum_mins = vaddvq_s32(prod); + + int32_t isum = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + uint8x16x2_t qhbits = vld1q_u8_x2(qh); qh += 32; + uint8x16x4_t q6bits = vld1q_u8_x4(q6); q6 += 64; + int8x16x4_t q8bytes = vld1q_s8_x4(q8); q8 += 64; + + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits.val[0]), 4); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, qhbits.val[1]), 4); + uint8x16_t shifted = vshrq_n_u8(qhbits.val[0], 2); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 2); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + //q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])), m32s); + //q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])), m32s); + //q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[2], m4b), q6h.val[2])), m32s); + //q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[3], m4b), q6h.val[3])), m32s); + q6bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])); + q6bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])); + q6bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[2], m4b), q6h.val[2])); + q6bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[3], m4b), q6h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + + isum += vaddvq_s32(vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; + scale += 4; + +#else + + int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q6bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q6bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + isum += vaddvq_s16(p0) * scale[0] + vaddvq_s16(p1) * scale[1]; + scale += 2; + + int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q6bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q6bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + isum += vaddvq_s16(p2) * scale[0] + vaddvq_s16(p3) * scale[1]; + scale += 2; +#endif + + q8bytes = vld1q_s8_x4(q8); q8 += 64; + + shifted = vshrq_n_u8(qhbits.val[0], 4); + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 4); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[0], 6); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits.val[1], 6); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + //q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[0])), m32s); + //q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[1])), m32s); + //q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[2], 4), q6h.val[2])), m32s); + //q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[3], 4), q6h.val[3])), m32s); + q6bytes.val[0] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[0])); + q6bytes.val[1] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[1])); + q6bytes.val[2] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[2], 4), q6h.val[2])); + q6bytes.val[3] = vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[3], 4), q6h.val[3])); + +#if defined(__ARM_FEATURE_DOTPROD) + + isum += vaddvq_s32(vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; + scale += 4; + + //for (int l = 0; l < 4; ++l) { + // const int32x4_t p = vdotq_s32(vzero, q6bytes.val[l], q8bytes.val[l]); + // isum += vaddvq_s32(p) * *scale++; + //} +#else + p0 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q6bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + p1 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q6bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + isum += vaddvq_s16(p0) * scale[0] + vaddvq_s16(p1) * scale[1]; + scale += 2; + + p2 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q6bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + p3 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q6bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + isum += vaddvq_s16(p2) * scale[0] + vaddvq_s16(p3) * scale[1]; + scale += 2; +#endif + + } + //sum += isum * d_all * y[i].d; + sum += d_all * y[i].d * (isum - 32 * isum_mins); + + } + *s = sum; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i m2 = _mm256_set1_epi8(3); + const __m256i m32s = _mm256_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m128i scales = _mm_loadu_si128((const __m128i*)x[i].scales); + + __m256i sumi = _mm256_setzero_si256(); + + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + const __m128i scale_0 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 0)); + const __m128i scale_1 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 1)); + const __m128i scale_2 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 2)); + const __m128i scale_3 = _mm_shuffle_epi8(scales, get_scale_shuffle(is + 3)); + is += 4; + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4bits2 = _mm256_loadu_si256((const __m256i*)q4); q4 += 32; + const __m256i q4bitsH = _mm256_loadu_si256((const __m256i*)qh); qh += 32; + + const __m256i q4h_0 = _mm256_slli_epi16(_mm256_and_si256(q4bitsH, m2), 4); + const __m256i q4h_1 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 2), m2), 4); + const __m256i q4h_2 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 4), m2), 4); + const __m256i q4h_3 = _mm256_slli_epi16(_mm256_and_si256(_mm256_srli_epi16(q4bitsH, 6), m2), 4); + + const __m256i q4_0 = _mm256_or_si256(_mm256_and_si256(q4bits1, m4), q4h_0); + const __m256i q4_1 = _mm256_or_si256(_mm256_and_si256(q4bits2, m4), q4h_1); + const __m256i q4_2 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits1, 4), m4), q4h_2); + const __m256i q4_3 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits2, 4), m4), q4h_3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_2 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + const __m256i q8_3 = _mm256_loadu_si256((const __m256i*)q8); q8 += 32; + + __m256i q8s_0 = _mm256_maddubs_epi16(m32s, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(m32s, q8_1); + __m256i q8s_2 = _mm256_maddubs_epi16(m32s, q8_2); + __m256i q8s_3 = _mm256_maddubs_epi16(m32s, q8_3); + + __m256i p16_0 = _mm256_maddubs_epi16(q4_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q4_1, q8_1); + __m256i p16_2 = _mm256_maddubs_epi16(q4_2, q8_2); + __m256i p16_3 = _mm256_maddubs_epi16(q4_3, q8_3); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + p16_2 = _mm256_sub_epi16(p16_2, q8s_2); + p16_3 = _mm256_sub_epi16(p16_3, q8s_3); + + p16_0 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_1), p16_1); + p16_2 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_2), p16_2); + p16_3 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_3), p16_3); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_2, p16_3)); + + } + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m3 = _mm_set1_epi8(3); + const __m128i m32s = _mm_set1_epi8(32); + const __m128i m2 = _mm_set1_epi8(2); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m128i scales = _mm_loadu_si128((const __m128i*)x[i].scales); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + __m128i shuffle = _mm_set_epi64x(0x0101010101010101, 0x0000000000000000); + for (int j = 0; j < QK_K/128; ++j) { + + const __m128i q4bitsH_0 = _mm_loadu_si128((const __m128i*)qh); qh += 16; + const __m128i q4bitsH_1 = _mm_loadu_si128((const __m128i*)qh); qh += 16; + + const __m128i q4h_0 = _mm_slli_epi16(_mm_and_si128(q4bitsH_0, m3), 4); + const __m128i q4h_1 = _mm_slli_epi16(_mm_and_si128(q4bitsH_1, m3), 4); + const __m128i q4h_2 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 2), m3), 4); + const __m128i q4h_3 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 2), m3), 4); + const __m128i q4h_4 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 4), m3), 4); + const __m128i q4h_5 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 4), m3), 4); + const __m128i q4h_6 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_0, 6), m3), 4); + const __m128i q4h_7 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH_1, 6), m3), 4); + + const __m128i q4bits1_0 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits1_1 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits2_0 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + const __m128i q4bits2_1 = _mm_loadu_si128((const __m128i*)q4); q4 += 16; + + const __m128i q4_0 = _mm_or_si128(_mm_and_si128(q4bits1_0, m4), q4h_0); + const __m128i q4_1 = _mm_or_si128(_mm_and_si128(q4bits1_1, m4), q4h_1); + const __m128i q4_2 = _mm_or_si128(_mm_and_si128(q4bits2_0, m4), q4h_2); + const __m128i q4_3 = _mm_or_si128(_mm_and_si128(q4bits2_1, m4), q4h_3); + const __m128i q4_4 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits1_0, 4), m4), q4h_4); + const __m128i q4_5 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits1_1, 4), m4), q4h_5); + const __m128i q4_6 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits2_0, 4), m4), q4h_6); + const __m128i q4_7 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(q4bits2_1, 4), m4), q4h_7); + + const __m128i q8_0 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_1 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_2 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_3 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_4 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_5 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_6 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + const __m128i q8_7 = _mm_loadu_si128((const __m128i*)q8); q8 += 16; + + __m128i q8s_0 = _mm_maddubs_epi16(m32s, q8_0); + __m128i q8s_1 = _mm_maddubs_epi16(m32s, q8_1); + __m128i q8s_2 = _mm_maddubs_epi16(m32s, q8_2); + __m128i q8s_3 = _mm_maddubs_epi16(m32s, q8_3); + __m128i q8s_4 = _mm_maddubs_epi16(m32s, q8_4); + __m128i q8s_5 = _mm_maddubs_epi16(m32s, q8_5); + __m128i q8s_6 = _mm_maddubs_epi16(m32s, q8_6); + __m128i q8s_7 = _mm_maddubs_epi16(m32s, q8_7); + + __m128i p16_0 = _mm_maddubs_epi16(q4_0, q8_0); + __m128i p16_1 = _mm_maddubs_epi16(q4_1, q8_1); + __m128i p16_2 = _mm_maddubs_epi16(q4_2, q8_2); + __m128i p16_3 = _mm_maddubs_epi16(q4_3, q8_3); + __m128i p16_4 = _mm_maddubs_epi16(q4_4, q8_4); + __m128i p16_5 = _mm_maddubs_epi16(q4_5, q8_5); + __m128i p16_6 = _mm_maddubs_epi16(q4_6, q8_6); + __m128i p16_7 = _mm_maddubs_epi16(q4_7, q8_7); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + p16_4 = _mm_sub_epi16(p16_4, q8s_4); + p16_5 = _mm_sub_epi16(p16_5, q8s_5); + p16_6 = _mm_sub_epi16(p16_6, q8s_6); + p16_7 = _mm_sub_epi16(p16_7, q8s_7); + + const __m128i scale_0 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_1 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_2 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + const __m128i scale_3 = _mm_shuffle_epi8(scales, shuffle); + shuffle = _mm_add_epi8(shuffle, m2); + + p16_0 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_0, scale_0)), p16_1); + p16_2 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_1), p16_2); + p16_3 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_1, scale_1)), p16_3); + p16_4 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_2), p16_4); + p16_5 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_2, scale_2)), p16_5); + p16_6 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_3), p16_6); + p16_7 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_3, scale_3)), p16_7); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_4, p16_6)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_5, p16_7)); + + } + + __m256i sumi = MM256_SET_M128I(sumi_1, sumi_0); + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi)), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + size_t vl; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + int sum_t = 0; + int is = 0; + + for (int j = 0; j < QK_K/128; ++j) { + + vl = 32; + + // load qh + vuint8m1_t qh_x = __riscv_vle8_v_u8m1(qh, vl); + + // load Q6 + vuint8m1_t q6_0 = __riscv_vle8_v_u8m1(q6, vl); + vuint8m1_t q6_1 = __riscv_vle8_v_u8m1(q6+32, vl); + + vuint8m1_t q6a_0 = __riscv_vand_vx_u8m1(q6_0, 0x0F, vl); + vuint8m1_t q6a_1 = __riscv_vand_vx_u8m1(q6_1, 0x0F, vl); + vuint8m1_t q6s_0 = __riscv_vsrl_vx_u8m1(q6_0, 0x04, vl); + vuint8m1_t q6s_1 = __riscv_vsrl_vx_u8m1(q6_1, 0x04, vl); + + vuint8m1_t qh_0 = __riscv_vand_vx_u8m1(qh_x, 0x03, vl); + vuint8m1_t qh_1 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x2, vl), 0x03 , vl); + vuint8m1_t qh_2 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x4, vl), 0x03 , vl); + vuint8m1_t qh_3 = __riscv_vand_vx_u8m1(__riscv_vsrl_vx_u8m1(qh_x, 0x6, vl), 0x03 , vl); + + vuint8m1_t qhi_0 = __riscv_vor_vv_u8m1(q6a_0, __riscv_vsll_vx_u8m1(qh_0, 0x04, vl), vl); + vuint8m1_t qhi_1 = __riscv_vor_vv_u8m1(q6a_1, __riscv_vsll_vx_u8m1(qh_1, 0x04, vl), vl); + vuint8m1_t qhi_2 = __riscv_vor_vv_u8m1(q6s_0, __riscv_vsll_vx_u8m1(qh_2, 0x04, vl), vl); + vuint8m1_t qhi_3 = __riscv_vor_vv_u8m1(q6s_1, __riscv_vsll_vx_u8m1(qh_3, 0x04, vl), vl); + + vint8m1_t a_0 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_0), 32, vl); + vint8m1_t a_1 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_1), 32, vl); + vint8m1_t a_2 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_2), 32, vl); + vint8m1_t a_3 = __riscv_vsub_vx_i8m1(__riscv_vreinterpret_v_u8m1_i8m1(qhi_3), 32, vl); + + // load Q8 and take product + vint16m2_t va_q_0 = __riscv_vwmul_vv_i16m2(a_0, __riscv_vle8_v_i8m1(q8, vl), vl); + vint16m2_t va_q_1 = __riscv_vwmul_vv_i16m2(a_1, __riscv_vle8_v_i8m1(q8+32, vl), vl); + vint16m2_t va_q_2 = __riscv_vwmul_vv_i16m2(a_2, __riscv_vle8_v_i8m1(q8+64, vl), vl); + vint16m2_t va_q_3 = __riscv_vwmul_vv_i16m2(a_3, __riscv_vle8_v_i8m1(q8+96, vl), vl); + + vl = 16; + + vint32m2_t vaux_0 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_0, 0), scale[is+0], vl); + vint32m2_t vaux_1 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_0, 1), scale[is+1], vl); + vint32m2_t vaux_2 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_1, 0), scale[is+2], vl); + vint32m2_t vaux_3 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_1, 1), scale[is+3], vl); + vint32m2_t vaux_4 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_2, 0), scale[is+4], vl); + vint32m2_t vaux_5 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_2, 1), scale[is+5], vl); + vint32m2_t vaux_6 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_3, 0), scale[is+6], vl); + vint32m2_t vaux_7 = __riscv_vwmul_vx_i32m2(__riscv_vget_v_i16m2_i16m1(va_q_3, 1), scale[is+7], vl); + + vint32m1_t isum0 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_0, vaux_1, vl), vzero, vl); + vint32m1_t isum1 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_2, vaux_3, vl), isum0, vl); + vint32m1_t isum2 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_4, vaux_5, vl), isum1, vl); + vint32m1_t isum3 = __riscv_vredsum_vs_i32m2_i32m1(__riscv_vadd_vv_i32m2(vaux_6, vaux_7, vl), isum2, vl); + + sum_t += __riscv_vmv_x_s_i32m1_i32(isum3); + + q6 += 64; qh += 32; q8 += 128; is=8; + + } + + sumf += d * sum_t; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int j = 0; j < QK_K; j += 128) { + for (int l = 0; l < 32; ++l) { + a[l + 0] = (int8_t)((q4[l + 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + a[l + 32] = (int8_t)((q4[l + 32] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + a[l + 64] = (int8_t)((q4[l + 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + a[l + 96] = (int8_t)((q4[l + 32] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + } + a += 128; + q4 += 64; + qh += 32; + } + a = aux8; + int is = 0; + for (int j = 0; j < QK_K/16; ++j) { + int scale = x[i].scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#else + +void ggml_vec_dot_q6_K_q8_K(const int n, float * restrict s, const void * restrict vx, const void * restrict vy) { + assert(n % QK_K == 0); + + const block_q6_K * restrict x = vx; + const block_q8_K * restrict y = vy; + + const int nb = n / QK_K; + +#ifdef __ARM_NEON + + float sum = 0; + + const uint8x16_t m4b = vdupq_n_u8(0xF); + const int8x16_t m32s = vdupq_n_s8(32); +#if defined(__ARM_FEATURE_DOTPROD) + const int32x4_t vzero = vdupq_n_s32(0); +#endif + + const uint8x16_t mone = vdupq_n_u8(3); + + int8x16x4_t q6bytes; + uint8x16x4_t q6h; + + for (int i = 0; i < nb; ++i) { + + const float d_all = (float)x[i].d; + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + int32_t isum = 0; + + uint8x16_t qhbits = vld1q_u8(qh); + uint8x16x2_t q6bits = vld1q_u8_x2(q6); + int8x16x4_t q8bytes = vld1q_s8_x4(q8); + + q6h.val[0] = vshlq_n_u8(vandq_u8(mone, qhbits), 4); + uint8x16_t shifted = vshrq_n_u8(qhbits, 2); + q6h.val[1] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits, 4); + q6h.val[2] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + shifted = vshrq_n_u8(qhbits, 6); + q6h.val[3] = vshlq_n_u8(vandq_u8(mone, shifted), 4); + + q6bytes.val[0] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[0], m4b), q6h.val[0])), m32s); + q6bytes.val[1] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vandq_u8(q6bits.val[1], m4b), q6h.val[1])), m32s); + q6bytes.val[2] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[0], 4), q6h.val[2])), m32s); + q6bytes.val[3] = vsubq_s8(vreinterpretq_s8_u8(vorrq_u8(vshrq_n_u8(q6bits.val[1], 4), q6h.val[3])), m32s); + +#if defined(__ARM_FEATURE_DOTPROD) + + isum += vaddvq_s32(vdotq_s32(vzero, q6bytes.val[0], q8bytes.val[0])) * scale[0] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[1], q8bytes.val[1])) * scale[1] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[2], q8bytes.val[2])) * scale[2] + + vaddvq_s32(vdotq_s32(vzero, q6bytes.val[3], q8bytes.val[3])) * scale[3]; +#else + + int16x8_t p0 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[0]), vget_low_s8 (q8bytes.val[0])), + vmull_s8(vget_high_s8(q6bytes.val[0]), vget_high_s8(q8bytes.val[0]))); + int16x8_t p1 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[1]), vget_low_s8 (q8bytes.val[1])), + vmull_s8(vget_high_s8(q6bytes.val[1]), vget_high_s8(q8bytes.val[1]))); + isum += vaddvq_s16(p0) * scale[0] + vaddvq_s16(p1) * scale[1]; + + int16x8_t p2 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[2]), vget_low_s8 (q8bytes.val[2])), + vmull_s8(vget_high_s8(q6bytes.val[2]), vget_high_s8(q8bytes.val[2]))); + int16x8_t p3 = vaddq_s16(vmull_s8(vget_low_s8 (q6bytes.val[3]), vget_low_s8 (q8bytes.val[3])), + vmull_s8(vget_high_s8(q6bytes.val[3]), vget_high_s8(q8bytes.val[3]))); + isum += vaddvq_s16(p2) * scale[2] + vaddvq_s16(p3) * scale[3]; +#endif + + sum += isum * d_all * y[i].d; + + } + *s = sum; + +#elif defined __AVX2__ + + const __m256i m4 = _mm256_set1_epi8(0xF); + const __m256i m2 = _mm256_set1_epi8(3); + const __m256i m32s = _mm256_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m64 scales_1 = _mm_set1_pi8(x[i].scales[0]); + const __m64 scales_2 = _mm_set1_pi8(x[i].scales[1]); + const __m64 scales_3 = _mm_set1_pi8(x[i].scales[2]); + const __m64 scales_4 = _mm_set1_pi8(x[i].scales[3]); + + __m256i sumi = _mm256_setzero_si256(); + + const __m128i scale_0 = _mm_set_epi64(scales_2, scales_1); + const __m128i scale_1 = _mm_set_epi64(scales_4, scales_3); + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bitsH = _mm_loadu_si128((const __m128i*)qh); + + const __m256i q4h_0 = _mm256_slli_epi16(_mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q4bitsH, 2), q4bitsH), m2), 4); + const __m256i q4h_1 = _mm256_slli_epi16(_mm256_and_si256(MM256_SET_M128I(_mm_srli_epi16(q4bitsH, 6), _mm_srli_epi16(q4bitsH, 4)), m2), 4); + + const __m256i q4_0 = _mm256_or_si256(_mm256_and_si256(q4bits1, m4), q4h_0); + const __m256i q4_1 = _mm256_or_si256(_mm256_and_si256(_mm256_srli_epi16(q4bits1, 4), m4), q4h_1); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + __m256i q8s_0 = _mm256_maddubs_epi16(m32s, q8_0); + __m256i q8s_1 = _mm256_maddubs_epi16(m32s, q8_1); + + __m256i p16_0 = _mm256_maddubs_epi16(q4_0, q8_0); + __m256i p16_1 = _mm256_maddubs_epi16(q4_1, q8_1); + + p16_0 = _mm256_sub_epi16(p16_0, q8s_0); + p16_1 = _mm256_sub_epi16(p16_1, q8s_1); + + p16_0 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm256_madd_epi16(_mm256_cvtepi8_epi16(scale_1), p16_1); + + sumi = _mm256_add_epi32(sumi, _mm256_add_epi32(p16_0, p16_1)); + + acc = _mm256_fmadd_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(sumi), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __AVX__ + + const __m128i m4 = _mm_set1_epi8(0xF); + const __m128i m2 = _mm_set1_epi8(3); + const __m128i m32s = _mm_set1_epi8(32); + + __m256 acc = _mm256_setzero_ps(); + + for (int i = 0; i < nb; ++i) { + + const float d = y[i].d * GGML_FP16_TO_FP32(x[i].d); + + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const __m64 scales_1 = _mm_set1_pi8(x[i].scales[0]); + const __m64 scales_2 = _mm_set1_pi8(x[i].scales[1]); + const __m64 scales_3 = _mm_set1_pi8(x[i].scales[2]); + const __m64 scales_4 = _mm_set1_pi8(x[i].scales[3]); + + __m128i sumi_0 = _mm_setzero_si128(); + __m128i sumi_1 = _mm_setzero_si128(); + + const __m128i scale_0 = _mm_set_epi64(scales_2, scales_1); + const __m128i scale_1 = _mm_set_epi64(scales_4, scales_3); + + const __m256i q4bits1 = _mm256_loadu_si256((const __m256i*)q4); + const __m128i q4bitsH = _mm_loadu_si128((const __m128i*)qh); + + const __m128i q4h_0 = _mm_slli_epi16(_mm_and_si128(q4bitsH, m2), 4); + const __m128i q4h_1 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 2), m2), 4); + const __m128i q4h_2 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 4), m2), 4); + const __m128i q4h_3 = _mm_slli_epi16(_mm_and_si128(_mm_srli_epi16(q4bitsH, 6), m2), 4); + + const __m128i q4_0 = _mm_or_si128(_mm_and_si128(_mm256_extractf128_si256(q4bits1, 0), m4), q4h_0); + const __m128i q4_1 = _mm_or_si128(_mm_and_si128(_mm256_extractf128_si256(q4bits1, 1), m4), q4h_1); + const __m128i q4_2 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q4bits1, 0), 4), m4), q4h_2); + const __m128i q4_3 = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(_mm256_extractf128_si256(q4bits1, 1), 4), m4), q4h_3); + + const __m256i q8_0 = _mm256_loadu_si256((const __m256i*)(q8+ 0)); + const __m256i q8_1 = _mm256_loadu_si256((const __m256i*)(q8+32)); + + __m128i q8s_0 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_0, 0)); + __m128i q8s_1 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_0, 1)); + __m128i q8s_2 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_1, 0)); + __m128i q8s_3 = _mm_maddubs_epi16(m32s, _mm256_extractf128_si256(q8_1, 1)); + + __m128i p16_0 = _mm_maddubs_epi16(q4_0, _mm256_extractf128_si256(q8_0, 0)); + __m128i p16_1 = _mm_maddubs_epi16(q4_1, _mm256_extractf128_si256(q8_0, 1)); + __m128i p16_2 = _mm_maddubs_epi16(q4_2, _mm256_extractf128_si256(q8_1, 0)); + __m128i p16_3 = _mm_maddubs_epi16(q4_3, _mm256_extractf128_si256(q8_1, 1)); + + p16_0 = _mm_sub_epi16(p16_0, q8s_0); + p16_1 = _mm_sub_epi16(p16_1, q8s_1); + p16_2 = _mm_sub_epi16(p16_2, q8s_2); + p16_3 = _mm_sub_epi16(p16_3, q8s_3); + + p16_0 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_0), p16_0); + p16_1 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_0, scale_0)), p16_1); + p16_2 = _mm_madd_epi16(_mm_cvtepi8_epi16(scale_1), p16_2); + p16_3 = _mm_madd_epi16(_mm_cvtepi8_epi16(_mm_unpackhi_epi64(scale_1, scale_1)), p16_3); + + sumi_0 = _mm_add_epi32(sumi_0, _mm_add_epi32(p16_0, p16_2)); + sumi_1 = _mm_add_epi32(sumi_1, _mm_add_epi32(p16_1, p16_3)); + + acc = _mm256_add_ps(_mm256_mul_ps(_mm256_broadcast_ss(&d), _mm256_cvtepi32_ps(MM256_SET_M128I(sumi_1, sumi_0))), acc); + } + + *s = hsum_float_8(acc); + +#elif defined __riscv_v_intrinsic + + float sumf = 0; + + for (int i = 0; i < nb; ++i) { + + const float d_all = (float)x[i].d; + + const uint8_t * restrict q6 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + + const int8_t * restrict scale = x[i].scales; + + int32_t isum = 0; + + size_t vl = 16; + + vint32m1_t vzero = __riscv_vmv_v_x_i32m1(0, 1); + + // load Q6 + vuint8mf2_t q6_0 = __riscv_vle8_v_u8mf2(q6, vl); + vuint8mf2_t q6_1 = __riscv_vle8_v_u8mf2(q6+16, vl); + + // load qh + vuint8mf2_t qh_x = __riscv_vle8_v_u8mf2(qh, vl); + + vuint8mf2_t qh0 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh1 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh2 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + qh_x = __riscv_vsrl_vx_u8mf2(qh_x, 0x2, vl); + vuint8mf2_t qh3 = __riscv_vsll_vx_u8mf2(__riscv_vand_vx_u8mf2(qh_x, 0x3, vl), 0x4, vl); + + vuint8mf2_t q6h_0 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q6_0, 0xF, vl), qh0, vl); + vuint8mf2_t q6h_1 = __riscv_vor_vv_u8mf2(__riscv_vand_vx_u8mf2(q6_1, 0xF, vl), qh1, vl); + vuint8mf2_t q6h_2 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q6_0, 0x4, vl), qh2, vl); + vuint8mf2_t q6h_3 = __riscv_vor_vv_u8mf2(__riscv_vsrl_vx_u8mf2(q6_1, 0x4, vl), qh3, vl); + + vint8mf2_t q6v_0 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_0), 32, vl); + vint8mf2_t q6v_1 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_1), 32, vl); + vint8mf2_t q6v_2 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_2), 32, vl); + vint8mf2_t q6v_3 = __riscv_vsub_vx_i8mf2(__riscv_vreinterpret_v_u8mf2_i8mf2(q6h_3), 32, vl); + + // load Q8 and take product + vint16m1_t p0 = __riscv_vwmul_vv_i16m1(q6v_0, __riscv_vle8_v_i8mf2(q8, vl), vl); + vint16m1_t p1 = __riscv_vwmul_vv_i16m1(q6v_1, __riscv_vle8_v_i8mf2(q8+16, vl), vl); + vint16m1_t p2 = __riscv_vwmul_vv_i16m1(q6v_2, __riscv_vle8_v_i8mf2(q8+32, vl), vl); + vint16m1_t p3 = __riscv_vwmul_vv_i16m1(q6v_3, __riscv_vle8_v_i8mf2(q8+48, vl), vl); + + vint32m1_t vs_0 = __riscv_vwredsum_vs_i16m1_i32m1(p0, vzero, vl); + vint32m1_t vs_1 = __riscv_vwredsum_vs_i16m1_i32m1(p1, vzero, vl); + vint32m1_t vs_2 = __riscv_vwredsum_vs_i16m1_i32m1(p2, vzero, vl); + vint32m1_t vs_3 = __riscv_vwredsum_vs_i16m1_i32m1(p3, vzero, vl); + + isum += __riscv_vmv_x_s_i32m1_i32(vs_0) * scale[0]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_1) * scale[1]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_2) * scale[2]; + isum += __riscv_vmv_x_s_i32m1_i32(vs_3) * scale[3]; + + sumf += isum * d_all * y[i].d; + + } + + *s = sumf; + +#else + + int8_t aux8[QK_K]; + int16_t aux16[8]; + float sums [8]; + int32_t aux32[8]; + memset(sums, 0, 8*sizeof(float)); + + float sumf = 0; + for (int i = 0; i < nb; ++i) { + const uint8_t * restrict q4 = x[i].ql; + const uint8_t * restrict qh = x[i].qh; + const int8_t * restrict q8 = y[i].qs; + memset(aux32, 0, 8*sizeof(int32_t)); + int8_t * restrict a = aux8; + for (int l = 0; l < 16; ++l) { + a[l+ 0] = (int8_t)((q4[l+ 0] & 0xF) | (((qh[l] >> 0) & 3) << 4)) - 32; + a[l+16] = (int8_t)((q4[l+16] & 0xF) | (((qh[l] >> 2) & 3) << 4)) - 32; + a[l+32] = (int8_t)((q4[l+ 0] >> 4) | (((qh[l] >> 4) & 3) << 4)) - 32; + a[l+48] = (int8_t)((q4[l+16] >> 4) | (((qh[l] >> 6) & 3) << 4)) - 32; + } + int is = 0; + for (int j = 0; j < QK_K/16; ++j) { + int scale = x[i].scales[is++]; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + for (int l = 0; l < 8; ++l) aux16[l] = q8[l] * a[l]; + for (int l = 0; l < 8; ++l) aux32[l] += scale * aux16[l]; + q8 += 8; a += 8; + } + const float d = GGML_FP16_TO_FP32(x[i].d) * y[i].d; + for (int l = 0; l < 8; ++l) sums[l] += d * aux32[l]; + } + for (int l = 0; l < 8; ++l) sumf += sums[l]; + *s = sumf; +#endif +} + +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.h b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.h new file mode 100644 index 0000000..70c12c2 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ggml-quants.h @@ -0,0 +1,224 @@ +#pragma once + +#include "ggml-impl.h" + +// GGML internal header + +#include +#include + +#define QK4_0 32 +typedef struct { + ggml_fp16_t d; // delta + uint8_t qs[QK4_0 / 2]; // nibbles / quants +} block_q4_0; +static_assert(sizeof(block_q4_0) == sizeof(ggml_fp16_t) + QK4_0 / 2, "wrong q4_0 block size/padding"); + +#define QK4_1 32 +typedef struct { + ggml_fp16_t d; // delta + ggml_fp16_t m; // min + uint8_t qs[QK4_1 / 2]; // nibbles / quants +} block_q4_1; +static_assert(sizeof(block_q4_1) == 2 * sizeof(ggml_fp16_t) + QK4_1 / 2, "wrong q4_1 block size/padding"); + +#define QK5_0 32 +typedef struct { + ggml_fp16_t d; // delta + uint8_t qh[4]; // 5-th bit of quants + uint8_t qs[QK5_0 / 2]; // nibbles / quants +} block_q5_0; +static_assert(sizeof(block_q5_0) == sizeof(ggml_fp16_t) + sizeof(uint32_t) + QK5_0 / 2, "wrong q5_0 block size/padding"); + +#define QK5_1 32 +typedef struct { + ggml_fp16_t d; // delta + ggml_fp16_t m; // min + uint8_t qh[4]; // 5-th bit of quants + uint8_t qs[QK5_1 / 2]; // nibbles / quants +} block_q5_1; +static_assert(sizeof(block_q5_1) == 2 * sizeof(ggml_fp16_t) + sizeof(uint32_t) + QK5_1 / 2, "wrong q5_1 block size/padding"); + +#define QK8_0 32 +typedef struct { + ggml_fp16_t d; // delta + int8_t qs[QK8_0]; // quants +} block_q8_0; +static_assert(sizeof(block_q8_0) == sizeof(ggml_fp16_t) + QK8_0, "wrong q8_0 block size/padding"); + +#define QK8_1 32 +typedef struct { + float d; // delta + float s; // d * sum(qs[i]) + int8_t qs[QK8_1]; // quants +} block_q8_1; +static_assert(sizeof(block_q8_1) == 2*sizeof(float) + QK8_1, "wrong q8_1 block size/padding"); + +// +// Super-block quantization structures +// + +// Super-block size +#ifdef GGML_QKK_64 +#define QK_K 64 +#define K_SCALE_SIZE 4 +#else +#define QK_K 256 +#define K_SCALE_SIZE 12 +#endif + +// 2-bit quantization +// weight is represented as x = a * q + b +// 16 blocks of 16 elements each +// Effectively 2.5625 bits per weight +typedef struct { + uint8_t scales[QK_K/16]; // scales and mins, quantized with 4 bits + uint8_t qs[QK_K/4]; // quants + ggml_fp16_t d; // super-block scale for quantized scales + ggml_fp16_t dmin; // super-block scale for quantized mins +} block_q2_K; +static_assert(sizeof(block_q2_K) == 2*sizeof(ggml_fp16_t) + QK_K/16 + QK_K/4, "wrong q2_K block size/padding"); + +// 3-bit quantization +// weight is represented as x = a * q +// 16 blocks of 16 elements each +// Effectively 3.4375 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + uint8_t hmask[QK_K/8]; // quants - high bit + uint8_t qs[QK_K/4]; // quants - low 2 bits + uint8_t scales[2]; + ggml_fp16_t d; // super-block scale +} block_q3_K; +static_assert(sizeof(block_q3_K) == sizeof(ggml_fp16_t) + QK_K / 4 + QK_K / 8 + 2, "wrong q3_K block size/padding"); +#else +typedef struct { + uint8_t hmask[QK_K/8]; // quants - high bit + uint8_t qs[QK_K/4]; // quants - low 2 bits + uint8_t scales[12]; // scales, quantized with 6 bits + ggml_fp16_t d; // super-block scale +} block_q3_K; +static_assert(sizeof(block_q3_K) == sizeof(ggml_fp16_t) + QK_K / 4 + QK_K / 8 + 12, "wrong q3_K block size/padding"); +#endif + +// 4-bit quantization +// 8 blocks of 32 elements each +// weight is represented as x = a * q + b +// Effectively 4.5 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + ggml_fp16_t d[2]; // super-block scales/mins + uint8_t scales[2]; // 4-bit block scales/mins + uint8_t qs[QK_K/2]; // 4--bit quants +} block_q4_K; +static_assert(sizeof(block_q4_K) == 2*sizeof(ggml_fp16_t) + QK_K/2 + 2, "wrong q4_K block size/padding"); +#else +typedef struct { + ggml_fp16_t d; // super-block scale for quantized scales + ggml_fp16_t dmin; // super-block scale for quantized mins + uint8_t scales[K_SCALE_SIZE]; // scales and mins, quantized with 6 bits + uint8_t qs[QK_K/2]; // 4--bit quants +} block_q4_K; +static_assert(sizeof(block_q4_K) == 2*sizeof(ggml_fp16_t) + K_SCALE_SIZE + QK_K/2, "wrong q4_K block size/padding"); +#endif + +// 5-bit quantization +// 8 blocks of 32 elements each +// weight is represented as x = a * q + b +// Effectively 5.5 bits per weight +#ifdef GGML_QKK_64 +typedef struct { + ggml_fp16_t d; // super-block scale + int8_t scales[QK_K/16]; // 8-bit block scales + uint8_t qh[QK_K/8]; // quants, high bit + uint8_t qs[QK_K/2]; // quants, low 4 bits +} block_q5_K; +static_assert(sizeof(block_q5_K) == sizeof(ggml_fp16_t) + QK_K/2 + QK_K/8 + QK_K/16, "wrong q5_K block size/padding"); +#else +typedef struct { + ggml_fp16_t d; // super-block scale for quantized scales + ggml_fp16_t dmin; // super-block scale for quantized mins + uint8_t scales[K_SCALE_SIZE]; // scales and mins, quantized with 6 bits + uint8_t qh[QK_K/8]; // quants, high bit + uint8_t qs[QK_K/2]; // quants, low 4 bits +} block_q5_K; +static_assert(sizeof(block_q5_K) == 2*sizeof(ggml_fp16_t) + K_SCALE_SIZE + QK_K/2 + QK_K/8, "wrong q5_K block size/padding"); +#endif + +// 6-bit quantization +// weight is represented as x = a * q +// 16 blocks of 16 elements each +// Effectively 6.5625 bits per weight +typedef struct { + uint8_t ql[QK_K/2]; // quants, lower 4 bits + uint8_t qh[QK_K/4]; // quants, upper 2 bits + int8_t scales[QK_K/16]; // scales, quantized with 8 bits + ggml_fp16_t d; // super-block scale +} block_q6_K; +static_assert(sizeof(block_q6_K) == sizeof(ggml_fp16_t) + QK_K / 16 + 3*QK_K/4, "wrong q6_K block size/padding"); + +// This is only used for intermediate quantization and dot products +typedef struct { + float d; // delta + int8_t qs[QK_K]; // quants + int16_t bsums[QK_K/16]; // sum of quants in groups of 16 +} block_q8_K; +static_assert(sizeof(block_q8_K) == sizeof(float) + QK_K + QK_K/16*sizeof(int16_t), "wrong q8_K block size/padding"); + + +// Quantization +void quantize_row_q4_0_reference(const float * restrict x, block_q4_0 * restrict y, int k); +void quantize_row_q4_1_reference(const float * restrict x, block_q4_1 * restrict y, int k); +void quantize_row_q5_0_reference(const float * restrict x, block_q5_0 * restrict y, int k); +void quantize_row_q5_1_reference(const float * restrict x, block_q5_1 * restrict y, int k); +void quantize_row_q8_0_reference(const float * restrict x, block_q8_0 * restrict y, int k); +void quantize_row_q8_1_reference(const float * restrict x, block_q8_1 * restrict y, int k); + +void quantize_row_q2_K_reference(const float * restrict x, block_q2_K * restrict y, int k); +void quantize_row_q3_K_reference(const float * restrict x, block_q3_K * restrict y, int k); +void quantize_row_q4_K_reference(const float * restrict x, block_q4_K * restrict y, int k); +void quantize_row_q5_K_reference(const float * restrict x, block_q5_K * restrict y, int k); +void quantize_row_q6_K_reference(const float * restrict x, block_q6_K * restrict y, int k); +void quantize_row_q8_K_reference(const float * restrict x, block_q8_K * restrict y, int k); + +void quantize_row_q4_0(const float * restrict x, void * restrict y, int k); +void quantize_row_q4_1(const float * restrict x, void * restrict y, int k); +void quantize_row_q5_0(const float * restrict x, void * restrict y, int k); +void quantize_row_q5_1(const float * restrict x, void * restrict y, int k); +void quantize_row_q8_0(const float * restrict x, void * restrict y, int k); +void quantize_row_q8_1(const float * restrict x, void * restrict y, int k); + +void quantize_row_q2_K(const float * restrict x, void * restrict y, int k); +void quantize_row_q3_K(const float * restrict x, void * restrict y, int k); +void quantize_row_q4_K(const float * restrict x, void * restrict y, int k); +void quantize_row_q5_K(const float * restrict x, void * restrict y, int k); +void quantize_row_q6_K(const float * restrict x, void * restrict y, int k); +void quantize_row_q8_K(const float * restrict x, void * restrict y, int k); + +// Dequantization +void dequantize_row_q4_0(const block_q4_0 * restrict x, float * restrict y, int k); +void dequantize_row_q4_1(const block_q4_1 * restrict x, float * restrict y, int k); +void dequantize_row_q5_0(const block_q5_0 * restrict x, float * restrict y, int k); +void dequantize_row_q5_1(const block_q5_1 * restrict x, float * restrict y, int k); +void dequantize_row_q8_0(const block_q8_0 * restrict x, float * restrict y, int k); +//void dequantize_row_q8_1(const block_q8_1 * restrict x, float * restrict y, int k); + +void dequantize_row_q2_K(const block_q2_K * restrict x, float * restrict y, int k); +void dequantize_row_q3_K(const block_q3_K * restrict x, float * restrict y, int k); +void dequantize_row_q4_K(const block_q4_K * restrict x, float * restrict y, int k); +void dequantize_row_q5_K(const block_q5_K * restrict x, float * restrict y, int k); +void dequantize_row_q6_K(const block_q6_K * restrict x, float * restrict y, int k); +void dequantize_row_q8_K(const block_q8_K * restrict x, float * restrict y, int k); + +// Dot product +void ggml_vec_dot_q4_0_q8_0(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q4_1_q8_1(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q5_0_q8_0(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q5_1_q8_1(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q8_0_q8_0(int n, float * restrict s, const void * restrict vx, const void * restrict vy); + +void ggml_vec_dot_q2_K_q8_K(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q3_K_q8_K(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q4_K_q8_K(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q5_K_q8_K(int n, float * restrict s, const void * restrict vx, const void * restrict vy); +void ggml_vec_dot_q6_K_q8_K(int n, float * restrict s, const void * restrict vx, const void * restrict vy); diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.cpp b/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.cpp new file mode 100644 index 0000000..86af939 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.cpp @@ -0,0 +1,426 @@ +#include +#include "ruby_whisper.h" +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOOL_PARAMS_SETTER(self, prop, value) \ + ruby_whisper_params *rwp; \ + Data_Get_Struct(self, ruby_whisper_params, rwp); \ + if (value == Qfalse || value == Qnil) { \ + rwp->params.prop = false; \ + } else { \ + rwp->params.prop = true; \ + } \ + return value; \ + +#define BOOL_PARAMS_GETTER(self, prop) \ + ruby_whisper_params *rwp; \ + Data_Get_Struct(self, ruby_whisper_params, rwp); \ + if (rwp->params.prop) { \ + return Qtrue; \ + } else { \ + return Qfalse; \ + } + +VALUE mWhisper; +VALUE cContext; +VALUE cParams; + +static void ruby_whisper_free(ruby_whisper *rw) { + if (rw->context) { + whisper_free(rw->context); + rw->context = NULL; + } +} +static void ruby_whisper_params_free(ruby_whisper_params *rwp) { +} + +void rb_whisper_mark(ruby_whisper *rw) { + // call rb_gc_mark on any ruby references in rw +} + +void rb_whisper_free(ruby_whisper *rw) { + ruby_whisper_free(rw); + free(rw); +} + +void rb_whisper_params_mark(ruby_whisper_params *rwp) { +} + +void rb_whisper_params_free(ruby_whisper_params *rwp) { + ruby_whisper_params_free(rwp); + free(rwp); +} + +static VALUE ruby_whisper_allocate(VALUE klass) { + ruby_whisper *rw; + rw = ALLOC(ruby_whisper); + rw->context = NULL; + return Data_Wrap_Struct(klass, rb_whisper_mark, rb_whisper_free, rw); +} + +static VALUE ruby_whisper_params_allocate(VALUE klass) { + ruby_whisper_params *rwp; + rwp = ALLOC(ruby_whisper_params); + rwp->params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + return Data_Wrap_Struct(klass, rb_whisper_params_mark, rb_whisper_params_free, rwp); +} + +static VALUE ruby_whisper_initialize(int argc, VALUE *argv, VALUE self) { + ruby_whisper *rw; + VALUE whisper_model_file_path; + + // TODO: we can support init from buffer here too maybe another ruby object to expose + rb_scan_args(argc, argv, "01", &whisper_model_file_path); + Data_Get_Struct(self, ruby_whisper, rw); + + if (!rb_respond_to(whisper_model_file_path, rb_intern("to_s"))) { + rb_raise(rb_eRuntimeError, "Expected file path to model to initialize Whisper::Context"); + } + rw->context = whisper_init_from_file_with_params(StringValueCStr(whisper_model_file_path), whisper_context_default_params()); + if (rw->context == nullptr) { + rb_raise(rb_eRuntimeError, "error: failed to initialize whisper context"); + } + return self; +} + +/* + * transcribe a single file + * can emit to a block results + * + **/ +static VALUE ruby_whisper_transcribe(int argc, VALUE *argv, VALUE self) { + ruby_whisper *rw; + ruby_whisper_params *rwp; + VALUE wave_file_path, blk, params; + + rb_scan_args(argc, argv, "02&", &wave_file_path, ¶ms, &blk); + Data_Get_Struct(self, ruby_whisper, rw); + Data_Get_Struct(params, ruby_whisper_params, rwp); + + if (!rb_respond_to(wave_file_path, rb_intern("to_s"))) { + rb_raise(rb_eRuntimeError, "Expected file path to wave file"); + } + + std::string fname_inp = StringValueCStr(wave_file_path); + + std::vector pcmf32; // mono-channel F32 PCM + std::vector> pcmf32s; // stereo-channel F32 PCM + + // WAV input - this is directly from main.cpp example + { + drwav wav; + std::vector wav_data; // used for pipe input from stdin + + if (fname_inp == "-") { + { + uint8_t buf[1024]; + while (true) { + const size_t n = fread(buf, 1, sizeof(buf), stdin); + if (n == 0) { + break; + } + wav_data.insert(wav_data.end(), buf, buf + n); + } + } + + if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) { + fprintf(stderr, "error: failed to open WAV file from stdin\n"); + return self; + } + + fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, wav_data.size()); + } else if (drwav_init_file(&wav, fname_inp.c_str(), nullptr) == false) { + fprintf(stderr, "error: failed to open '%s' as WAV file\n", fname_inp.c_str()); + return self; + } + + if (wav.channels != 1 && wav.channels != 2) { + fprintf(stderr, "WAV file '%s' must be mono or stereo\n", fname_inp.c_str()); + return self; + } + + if (rwp->diarize && wav.channels != 2 && rwp->params.print_timestamps == false) { + fprintf(stderr, "WAV file '%s' must be stereo for diarization and timestamps have to be enabled\n", fname_inp.c_str()); + return self; + } + + if (wav.sampleRate != WHISPER_SAMPLE_RATE) { + fprintf(stderr, "WAV file '%s' must be %i kHz\n", fname_inp.c_str(), WHISPER_SAMPLE_RATE/1000); + return self; + } + + if (wav.bitsPerSample != 16) { + fprintf(stderr, "WAV file '%s' must be 16-bit\n", fname_inp.c_str()); + return self; + } + + const uint64_t n = wav_data.empty() ? wav.totalPCMFrameCount : wav_data.size()/(wav.channels*wav.bitsPerSample/8); + + std::vector pcm16; + pcm16.resize(n*wav.channels); + drwav_read_pcm_frames_s16(&wav, n, pcm16.data()); + drwav_uninit(&wav); + + // convert to mono, float + pcmf32.resize(n); + if (wav.channels == 1) { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[i])/32768.0f; + } + } else { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[2*i] + pcm16[2*i + 1])/65536.0f; + } + } + + if (rwp->diarize) { + // convert to stereo, float + pcmf32s.resize(2); + + pcmf32s[0].resize(n); + pcmf32s[1].resize(n); + for (uint64_t i = 0; i < n; i++) { + pcmf32s[0][i] = float(pcm16[2*i])/32768.0f; + pcmf32s[1][i] = float(pcm16[2*i + 1])/32768.0f; + } + } + } + { + static bool is_aborted = false; // NOTE: this should be atomic to avoid data race + + rwp->params.encoder_begin_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, void * user_data) { + bool is_aborted = *(bool*)user_data; + return !is_aborted; + }; + rwp->params.encoder_begin_callback_user_data = &is_aborted; + } + + if (whisper_full_parallel(rw->context, rwp->params, pcmf32.data(), pcmf32.size(), 1) != 0) { + fprintf(stderr, "failed to process audio\n"); + return self; + } + const int n_segments = whisper_full_n_segments(rw->context); + VALUE output = rb_str_new2(""); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(rw->context, i); + output = rb_str_concat(output, rb_str_new2(text)); + } + VALUE idCall = rb_intern("call"); + if (blk != Qnil) { + rb_funcall(blk, idCall, 1, output); + } + return self; +} + +/* + * params.language = "auto" | "en", etc... + */ +static VALUE ruby_whisper_params_set_language(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (value == Qfalse || value == Qnil) { + rwp->params.language = "auto"; + } else { + rwp->params.language = StringValueCStr(value); + } + return value; +} +static VALUE ruby_whisper_params_get_language(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (rwp->params.language) { + return rb_str_new2(rwp->params.language); + } else { + return rb_str_new2("auto"); + } +} +static VALUE ruby_whisper_params_set_translate(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, translate, value) +} +static VALUE ruby_whisper_params_get_translate(VALUE self) { + BOOL_PARAMS_GETTER(self, translate) +} +static VALUE ruby_whisper_params_set_no_context(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, no_context, value) +} +static VALUE ruby_whisper_params_get_no_context(VALUE self) { + BOOL_PARAMS_GETTER(self, no_context) +} +static VALUE ruby_whisper_params_set_single_segment(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, single_segment, value) +} +static VALUE ruby_whisper_params_get_single_segment(VALUE self) { + BOOL_PARAMS_GETTER(self, single_segment) +} +static VALUE ruby_whisper_params_set_print_special(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_special, value) +} +static VALUE ruby_whisper_params_get_print_special(VALUE self) { + BOOL_PARAMS_GETTER(self, print_special) +} +static VALUE ruby_whisper_params_set_print_progress(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_progress, value) +} +static VALUE ruby_whisper_params_get_print_progress(VALUE self) { + BOOL_PARAMS_GETTER(self, print_progress) +} +static VALUE ruby_whisper_params_set_print_realtime(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_realtime, value) +} +static VALUE ruby_whisper_params_get_print_realtime(VALUE self) { + BOOL_PARAMS_GETTER(self, print_realtime) +} +static VALUE ruby_whisper_params_set_print_timestamps(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, print_timestamps, value) +} +static VALUE ruby_whisper_params_get_print_timestamps(VALUE self) { + BOOL_PARAMS_GETTER(self, print_timestamps) +} +static VALUE ruby_whisper_params_set_suppress_blank(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, suppress_blank, value) +} +static VALUE ruby_whisper_params_get_suppress_blank(VALUE self) { + BOOL_PARAMS_GETTER(self, suppress_blank) +} +static VALUE ruby_whisper_params_set_suppress_non_speech_tokens(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, suppress_non_speech_tokens, value) +} +static VALUE ruby_whisper_params_get_suppress_non_speech_tokens(VALUE self) { + BOOL_PARAMS_GETTER(self, suppress_non_speech_tokens) +} +static VALUE ruby_whisper_params_get_token_timestamps(VALUE self) { + BOOL_PARAMS_GETTER(self, token_timestamps) +} +static VALUE ruby_whisper_params_set_token_timestamps(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, token_timestamps, value) +} +static VALUE ruby_whisper_params_get_split_on_word(VALUE self) { + BOOL_PARAMS_GETTER(self, split_on_word) +} +static VALUE ruby_whisper_params_set_split_on_word(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, split_on_word, value) +} +static VALUE ruby_whisper_params_get_speed_up(VALUE self) { + BOOL_PARAMS_GETTER(self, speed_up) +} +static VALUE ruby_whisper_params_set_speed_up(VALUE self, VALUE value) { + BOOL_PARAMS_SETTER(self, speed_up, value) +} +static VALUE ruby_whisper_params_get_diarize(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (rwp->diarize) { + return Qtrue; + } else { + return Qfalse; + } +} +static VALUE ruby_whisper_params_set_diarize(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + if (value == Qfalse || value == Qnil) { + rwp->diarize = false; + } else { + rwp->diarize = true; + } \ + return value; +} + +static VALUE ruby_whisper_params_get_offset(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.offset_ms); +} +static VALUE ruby_whisper_params_set_offset(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.offset_ms = NUM2INT(value); + return value; +} +static VALUE ruby_whisper_params_get_duration(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.duration_ms); +} +static VALUE ruby_whisper_params_set_duration(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.duration_ms = NUM2INT(value); + return value; +} + +static VALUE ruby_whisper_params_get_max_text_tokens(VALUE self) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + return INT2NUM(rwp->params.n_max_text_ctx); +} +static VALUE ruby_whisper_params_set_max_text_tokens(VALUE self, VALUE value) { + ruby_whisper_params *rwp; + Data_Get_Struct(self, ruby_whisper_params, rwp); + rwp->params.n_max_text_ctx = NUM2INT(value); + return value; +} + +void Init_whisper() { + mWhisper = rb_define_module("Whisper"); + cContext = rb_define_class_under(mWhisper, "Context", rb_cObject); + cParams = rb_define_class_under(mWhisper, "Params", rb_cObject); + + rb_define_alloc_func(cContext, ruby_whisper_allocate); + rb_define_method(cContext, "initialize", ruby_whisper_initialize, -1); + + rb_define_method(cContext, "transcribe", ruby_whisper_transcribe, -1); + + rb_define_alloc_func(cParams, ruby_whisper_params_allocate); + + rb_define_method(cParams, "language=", ruby_whisper_params_set_language, 1); + rb_define_method(cParams, "language", ruby_whisper_params_get_language, 0); + rb_define_method(cParams, "translate=", ruby_whisper_params_set_translate, 1); + rb_define_method(cParams, "translate", ruby_whisper_params_get_translate, 0); + rb_define_method(cParams, "no_context=", ruby_whisper_params_set_no_context, 1); + rb_define_method(cParams, "no_context", ruby_whisper_params_get_no_context, 0); + rb_define_method(cParams, "single_segment=", ruby_whisper_params_set_single_segment, 1); + rb_define_method(cParams, "single_segment", ruby_whisper_params_get_single_segment, 0); + rb_define_method(cParams, "print_special", ruby_whisper_params_get_print_special, 0); + rb_define_method(cParams, "print_special=", ruby_whisper_params_set_print_special, 1); + rb_define_method(cParams, "print_progress", ruby_whisper_params_get_print_progress, 0); + rb_define_method(cParams, "print_progress=", ruby_whisper_params_set_print_progress, 1); + rb_define_method(cParams, "print_realtime", ruby_whisper_params_get_print_realtime, 0); + rb_define_method(cParams, "print_realtime=", ruby_whisper_params_set_print_realtime, 1); + rb_define_method(cParams, "print_timestamps", ruby_whisper_params_get_print_timestamps, 0); + rb_define_method(cParams, "print_timestamps=", ruby_whisper_params_set_print_timestamps, 1); + rb_define_method(cParams, "suppress_blank", ruby_whisper_params_get_suppress_blank, 0); + rb_define_method(cParams, "suppress_blank=", ruby_whisper_params_set_suppress_blank, 1); + rb_define_method(cParams, "suppress_non_speech_tokens", ruby_whisper_params_get_suppress_non_speech_tokens, 0); + rb_define_method(cParams, "suppress_non_speech_tokens=", ruby_whisper_params_set_suppress_non_speech_tokens, 1); + rb_define_method(cParams, "token_timestamps", ruby_whisper_params_get_token_timestamps, 0); + rb_define_method(cParams, "token_timestamps=", ruby_whisper_params_set_token_timestamps, 1); + rb_define_method(cParams, "split_on_word", ruby_whisper_params_get_split_on_word, 0); + rb_define_method(cParams, "split_on_word=", ruby_whisper_params_set_split_on_word, 1); + rb_define_method(cParams, "speed_up", ruby_whisper_params_get_speed_up, 0); + rb_define_method(cParams, "speed_up=", ruby_whisper_params_set_speed_up, 1); + rb_define_method(cParams, "diarize", ruby_whisper_params_get_diarize, 0); + rb_define_method(cParams, "diarize=", ruby_whisper_params_set_diarize, 1); + + rb_define_method(cParams, "offset", ruby_whisper_params_get_offset, 0); + rb_define_method(cParams, "offset=", ruby_whisper_params_set_offset, 1); + rb_define_method(cParams, "duration", ruby_whisper_params_get_duration, 0); + rb_define_method(cParams, "duration=", ruby_whisper_params_set_duration, 1); + + rb_define_method(cParams, "max_text_tokens", ruby_whisper_params_get_max_text_tokens, 0); + rb_define_method(cParams, "max_text_tokens=", ruby_whisper_params_set_max_text_tokens, 1); +} +#ifdef __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.h b/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.h new file mode 100644 index 0000000..8c35b7c --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/ext/ruby_whisper.h @@ -0,0 +1,15 @@ +#ifndef __RUBY_WHISPER_H +#define __RUBY_WHISPER_H + +#include "whisper.h" + +typedef struct { + struct whisper_context *context; +} ruby_whisper; + +typedef struct { + struct whisper_full_params params; + bool diarize; +} ruby_whisper_params; + +#endif diff --git a/whisper.cpp-1.5.2/bindings/ruby/tests/test_whisper.rb b/whisper.cpp-1.5.2/bindings/ruby/tests/test_whisper.rb new file mode 100644 index 0000000..fa6a3e2 --- /dev/null +++ b/whisper.cpp-1.5.2/bindings/ruby/tests/test_whisper.rb @@ -0,0 +1,138 @@ +TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), '..')) +EXTDIR = File.join(TOPDIR, 'ext') +#$LIBDIR = File.join(TOPDIR, 'lib') +#$:.unshift(LIBDIR) +$:.unshift(EXTDIR) + +require 'whisper' +require 'test/unit' + +class TestWhisper < Test::Unit::TestCase + def setup + @params = Whisper::Params.new + end + + def test_language + @params.language = "en" + assert_equal @params.language, "en" + @params.language = "auto" + assert_equal @params.language, "auto" + end + + def test_offset + @params.offset = 10_000 + assert_equal @params.offset, 10_000 + @params.offset = 0 + assert_equal @params.offset, 0 + end + + def test_duration + @params.duration = 60_000 + assert_equal @params.duration, 60_000 + @params.duration = 0 + assert_equal @params.duration, 0 + end + + def test_max_text_tokens + @params.max_text_tokens = 300 + assert_equal @params.max_text_tokens, 300 + @params.max_text_tokens = 0 + assert_equal @params.max_text_tokens, 0 + end + + def test_translate + @params.translate = true + assert @params.translate + @params.translate = false + assert !@params.translate + end + + def test_no_context + @params.no_context = true + assert @params.no_context + @params.no_context = false + assert !@params.no_context + end + + def test_single_segment + @params.single_segment = true + assert @params.single_segment + @params.single_segment = false + assert !@params.single_segment + end + + def test_print_special + @params.print_special = true + assert @params.print_special + @params.print_special = false + assert !@params.print_special + end + + def test_print_progress + @params.print_progress = true + assert @params.print_progress + @params.print_progress = false + assert !@params.print_progress + end + + def test_print_realtime + @params.print_realtime = true + assert @params.print_realtime + @params.print_realtime = false + assert !@params.print_realtime + end + + def test_print_timestamps + @params.print_timestamps = true + assert @params.print_timestamps + @params.print_timestamps = false + assert !@params.print_timestamps + end + + def test_suppress_blank + @params.suppress_blank = true + assert @params.suppress_blank + @params.suppress_blank = false + assert !@params.suppress_blank + end + + def test_suppress_non_speech_tokens + @params.suppress_non_speech_tokens = true + assert @params.suppress_non_speech_tokens + @params.suppress_non_speech_tokens = false + assert !@params.suppress_non_speech_tokens + end + + def test_token_timestamps + @params.token_timestamps = true + assert @params.token_timestamps + @params.token_timestamps = false + assert !@params.token_timestamps + end + + def test_split_on_word + @params.split_on_word = true + assert @params.split_on_word + @params.split_on_word = false + assert !@params.split_on_word + end + + def test_speed_up + @params.speed_up = true + assert @params.speed_up + @params.speed_up = false + assert !@params.speed_up + end + + def test_whisper + @whisper = Whisper::Context.new(File.join(TOPDIR, '..', '..', 'models', 'ggml-base.en.bin')) + params = Whisper::Params.new + params.print_timestamps = false + + jfk = File.join(TOPDIR, '..', '..', 'samples', 'jfk.wav') + @whisper.transcribe(jfk, params) {|text| + assert_match /ask not what your country can do for you, ask what you can do for your country/, text + } + end + +end diff --git a/whisper.cpp-1.5.2/cmake/BuildTypes.cmake b/whisper.cpp-1.5.2/cmake/BuildTypes.cmake new file mode 100644 index 0000000..a9c7b6c --- /dev/null +++ b/whisper.cpp-1.5.2/cmake/BuildTypes.cmake @@ -0,0 +1,54 @@ +# Add new build types + +# ReleaseGG - Release with enabled asserts + +SET(CMAKE_CXX_FLAGS_RELEASEGG + "-O3" + CACHE STRING "Flags used by the c++ compiler during release builds with enabled asserts." + FORCE ) +SET(CMAKE_C_FLAGS_RELEASEGG + "-O3" + CACHE STRING "Flags used by the compiler during release builds with enabled asserts." + FORCE ) +SET(CMAKE_EXE_LINKER_FLAGS_RELEASEGG + "" + CACHE STRING "Flags used for linking binaries during release builds with enabled asserts." + FORCE ) +SET(CMAKE_SHARED_LINKER_FLAGS_RELEASEGG + "" + CACHE STRING "Flags used by the shared libraries linker during release builds with enabled asserts." + FORCE ) +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_RELEASEGG + CMAKE_C_FLAGS_RELEASEGG + CMAKE_EXE_LINKER_FLAGS_RELEASEGG + CMAKE_SHARED_LINKER_FLAGS_RELEASEGG ) + +# RelWithDebInfoGG - RelWithDebInfo with enabled asserts + +SET(CMAKE_CXX_FLAGS_RELWITHDEBINFOGG + "-O2 -g" + CACHE STRING "Flags used by the c++ compiler during release builds with debug symbols and enabled asserts." + FORCE ) +SET(CMAKE_C_FLAGS_RELWITHDEBINFOGG + "-O2 -g" + CACHE STRING "Flags used by the compiler during release builds with debug symbols and enabled asserts." + FORCE ) +SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFOGG + "" + CACHE STRING "Flags used for linking binaries during release builds with debug symbols and enabled asserts." + FORCE ) +SET(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFOGG + "" + CACHE STRING "Flags used by the shared libraries linker during release builds with debug symbols and enabled asserts." + FORCE ) +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_RELWITHDEBINFOGG + CMAKE_C_FLAGS_RELWITHDEBINFOGG + CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFOGG + CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFOGG ) + +if (NOT XCODE AND NOT MSVC AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo" "ReleaseGG" "RelWithDebInfoGG") +endif() diff --git a/whisper.cpp-1.5.2/cmake/DefaultTargetOptions.cmake b/whisper.cpp-1.5.2/cmake/DefaultTargetOptions.cmake new file mode 100644 index 0000000..b4e93e3 --- /dev/null +++ b/whisper.cpp-1.5.2/cmake/DefaultTargetOptions.cmake @@ -0,0 +1,17 @@ +# Set the default compile features and properties for a target. + +if (NOT TARGET) + message(FATAL_ERROR "TARGET not set before including DefaultTargetOptions") +endif() + +target_compile_features(${TARGET} + PRIVATE + cxx_std_11 + ) + +set_target_properties(${TARGET} + PROPERTIES + EXPORT_COMPILE_COMMANDS ON + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" + INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib" +) diff --git a/whisper.cpp-1.5.2/cmake/GitVars.cmake b/whisper.cpp-1.5.2/cmake/GitVars.cmake new file mode 100644 index 0000000..1a4c24e --- /dev/null +++ b/whisper.cpp-1.5.2/cmake/GitVars.cmake @@ -0,0 +1,22 @@ +find_package(Git) + +# the commit's SHA1 +execute_process(COMMAND + "${GIT_EXECUTABLE}" describe --match=NeVeRmAtCh --always --abbrev=8 + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_SHA1 + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + +# the date of the commit +execute_process(COMMAND + "${GIT_EXECUTABLE}" log -1 --format=%ad --date=local + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_DATE + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + +# the subject of the commit +execute_process(COMMAND + "${GIT_EXECUTABLE}" log -1 --format=%s + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE GIT_COMMIT_SUBJECT + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) diff --git a/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.h b/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.h new file mode 100644 index 0000000..c6f2e85 --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.h @@ -0,0 +1,146 @@ +// +// whisper-decoder-impl.h +// +// This file was automatically generated and should not be edited. +// + +#import +#import +#include +#include + +NS_ASSUME_NONNULL_BEGIN + + +/// Model Prediction Input Type +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_decoder_implInput : NSObject + +/// token_data as 1 by 1 matrix of 32-bit integers +@property (readwrite, nonatomic, strong) MLMultiArray * token_data; + +/// audio_data as 1 × 384 × 1 × 1500 4-dimensional array of floats +@property (readwrite, nonatomic, strong) MLMultiArray * audio_data; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithToken_data:(MLMultiArray *)token_data audio_data:(MLMultiArray *)audio_data NS_DESIGNATED_INITIALIZER; + +@end + + +/// Model Prediction Output Type +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_decoder_implOutput : NSObject + +/// var_1346 as multidimensional array of floats +@property (readwrite, nonatomic, strong) MLMultiArray * var_1346; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithVar_1346:(MLMultiArray *)var_1346 NS_DESIGNATED_INITIALIZER; + +@end + + +/// Class for model loading and prediction +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_decoder_impl : NSObject +@property (readonly, nonatomic, nullable) MLModel * model; + +/** + URL of the underlying .mlmodelc directory. +*/ ++ (nullable NSURL *)URLOfModelInThisBundle; + +/** + Initialize whisper_decoder_impl instance from an existing MLModel object. + + Usually the application does not use this initializer unless it makes a subclass of whisper_decoder_impl. + Such application may want to use `-[MLModel initWithContentsOfURL:configuration:error:]` and `+URLOfModelInThisBundle` to create a MLModel object to pass-in. +*/ +- (instancetype)initWithMLModel:(MLModel *)model NS_DESIGNATED_INITIALIZER; + +/** + Initialize whisper_decoder_impl instance with the model in this bundle. +*/ +- (nullable instancetype)init; + +/** + Initialize whisper_decoder_impl instance with the model in this bundle. + + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithConfiguration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Initialize whisper_decoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_decoder_impl. + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Initialize whisper_decoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_decoder_impl. + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Construct whisper_decoder_impl instance asynchronously with configuration. + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_decoder_impl instance or NSError object. +*/ ++ (void)loadWithConfiguration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_decoder_impl * _Nullable model, NSError * _Nullable error))handler; + +/** + Construct whisper_decoder_impl instance asynchronously with URL of .mlmodelc directory and optional configuration. + + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param modelURL The model URL. + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_decoder_impl instance or NSError object. +*/ ++ (void)loadContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_decoder_impl * _Nullable model, NSError * _Nullable error))handler; + +/** + Make a prediction using the standard interface + @param input an instance of whisper_decoder_implInput to predict from + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_decoder_implOutput +*/ +- (nullable whisper_decoder_implOutput *)predictionFromFeatures:(whisper_decoder_implInput *)input error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Make a prediction using the standard interface + @param input an instance of whisper_decoder_implInput to predict from + @param options prediction options + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_decoder_implOutput +*/ +- (nullable whisper_decoder_implOutput *)predictionFromFeatures:(whisper_decoder_implInput *)input options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Make a prediction using the convenience interface + @param token_data as 1 by 1 matrix of 32-bit integers: + @param audio_data as 1 × 384 × 1 × 1500 4-dimensional array of floats: + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_decoder_implOutput +*/ +- (nullable whisper_decoder_implOutput *)predictionFromToken_data:(MLMultiArray *)token_data audio_data:(MLMultiArray *)audio_data error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Batch prediction + @param inputArray array of whisper_decoder_implInput instances to obtain predictions from + @param options prediction options + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the predictions as NSArray +*/ +- (nullable NSArray *)predictionsFromInputs:(NSArray *)inputArray options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.m b/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.m new file mode 100644 index 0000000..34060e4 --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-decoder-impl.m @@ -0,0 +1,201 @@ +// +// whisper-decoder-impl.m +// +// This file was automatically generated and should not be edited. +// + +#if !__has_feature(objc_arc) +#error This file must be compiled with automatic reference counting enabled (-fobjc-arc) +#endif + +#import "whisper-decoder-impl.h" + +@implementation whisper_decoder_implInput + +- (instancetype)initWithToken_data:(MLMultiArray *)token_data audio_data:(MLMultiArray *)audio_data { + self = [super init]; + if (self) { + _token_data = token_data; + _audio_data = audio_data; + } + return self; +} + +- (NSSet *)featureNames { + return [NSSet setWithArray:@[@"token_data", @"audio_data"]]; +} + +- (nullable MLFeatureValue *)featureValueForName:(NSString *)featureName { + if ([featureName isEqualToString:@"token_data"]) { + return [MLFeatureValue featureValueWithMultiArray:self.token_data]; + } + if ([featureName isEqualToString:@"audio_data"]) { + return [MLFeatureValue featureValueWithMultiArray:self.audio_data]; + } + return nil; +} + +@end + +@implementation whisper_decoder_implOutput + +- (instancetype)initWithVar_1346:(MLMultiArray *)var_1346 { + self = [super init]; + if (self) { + _var_1346 = var_1346; + } + return self; +} + +- (NSSet *)featureNames { + return [NSSet setWithArray:@[@"var_1346"]]; +} + +- (nullable MLFeatureValue *)featureValueForName:(NSString *)featureName { + if ([featureName isEqualToString:@"var_1346"]) { + return [MLFeatureValue featureValueWithMultiArray:self.var_1346]; + } + return nil; +} + +@end + +@implementation whisper_decoder_impl + + +/** + URL of the underlying .mlmodelc directory. +*/ ++ (nullable NSURL *)URLOfModelInThisBundle { + NSString *assetPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"whisper_decoder_impl" ofType:@"mlmodelc"]; + if (nil == assetPath) { os_log_error(OS_LOG_DEFAULT, "Could not load whisper-decoder-impl.mlmodelc in the bundle resource"); return nil; } + return [NSURL fileURLWithPath:assetPath]; +} + + +/** + Initialize whisper_decoder_impl instance from an existing MLModel object. + + Usually the application does not use this initializer unless it makes a subclass of whisper_decoder_impl. + Such application may want to use `-[MLModel initWithContentsOfURL:configuration:error:]` and `+URLOfModelInThisBundle` to create a MLModel object to pass-in. +*/ +- (instancetype)initWithMLModel:(MLModel *)model { + self = [super init]; + if (!self) { return nil; } + _model = model; + if (_model == nil) { return nil; } + return self; +} + + +/** + Initialize whisper_decoder_impl instance with the model in this bundle. +*/ +- (nullable instancetype)init { + return [self initWithContentsOfURL:(NSURL * _Nonnull)self.class.URLOfModelInThisBundle error:nil]; +} + + +/** + Initialize whisper_decoder_impl instance with the model in this bundle. + + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithConfiguration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error { + return [self initWithContentsOfURL:(NSURL * _Nonnull)self.class.URLOfModelInThisBundle configuration:configuration error:error]; +} + + +/** + Initialize whisper_decoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_decoder_impl. + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL error:(NSError * _Nullable __autoreleasing * _Nullable)error { + MLModel *model = [MLModel modelWithContentsOfURL:modelURL error:error]; + if (model == nil) { return nil; } + return [self initWithMLModel:model]; +} + + +/** + Initialize whisper_decoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_decoder_impl. + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error { + MLModel *model = [MLModel modelWithContentsOfURL:modelURL configuration:configuration error:error]; + if (model == nil) { return nil; } + return [self initWithMLModel:model]; +} + + +/** + Construct whisper_decoder_impl instance asynchronously with configuration. + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_decoder_impl instance or NSError object. +*/ ++ (void)loadWithConfiguration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_decoder_impl * _Nullable model, NSError * _Nullable error))handler { + [self loadContentsOfURL:(NSURL * _Nonnull)[self URLOfModelInThisBundle] + configuration:configuration + completionHandler:handler]; +} + + +/** + Construct whisper_decoder_impl instance asynchronously with URL of .mlmodelc directory and optional configuration. + + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param modelURL The model URL. + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_decoder_impl instance or NSError object. +*/ ++ (void)loadContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_decoder_impl * _Nullable model, NSError * _Nullable error))handler { + [MLModel loadContentsOfURL:modelURL + configuration:configuration + completionHandler:^(MLModel *model, NSError *error) { + if (model != nil) { + whisper_decoder_impl *typedModel = [[whisper_decoder_impl alloc] initWithMLModel:model]; + handler(typedModel, nil); + } else { + handler(nil, error); + } + }]; +} + +- (nullable whisper_decoder_implOutput *)predictionFromFeatures:(whisper_decoder_implInput *)input error:(NSError * _Nullable __autoreleasing * _Nullable)error { + return [self predictionFromFeatures:input options:[[MLPredictionOptions alloc] init] error:error]; +} + +- (nullable whisper_decoder_implOutput *)predictionFromFeatures:(whisper_decoder_implInput *)input options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error { + id outFeatures = [self.model predictionFromFeatures:input options:options error:error]; + if (!outFeatures) { return nil; } + return [[whisper_decoder_implOutput alloc] initWithVar_1346:(MLMultiArray *)[outFeatures featureValueForName:@"var_1346"].multiArrayValue]; +} + +- (nullable whisper_decoder_implOutput *)predictionFromToken_data:(MLMultiArray *)token_data audio_data:(MLMultiArray *)audio_data error:(NSError * _Nullable __autoreleasing * _Nullable)error { + whisper_decoder_implInput *input_ = [[whisper_decoder_implInput alloc] initWithToken_data:token_data audio_data:audio_data]; + return [self predictionFromFeatures:input_ error:error]; +} + +- (nullable NSArray *)predictionsFromInputs:(NSArray *)inputArray options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error { + id inBatch = [[MLArrayBatchProvider alloc] initWithFeatureProviderArray:inputArray]; + id outBatch = [self.model predictionsFromBatch:inBatch options:options error:error]; + if (!outBatch) { return nil; } + NSMutableArray *results = [NSMutableArray arrayWithCapacity:(NSUInteger)outBatch.count]; + for (NSInteger i = 0; i < outBatch.count; i++) { + id resultProvider = [outBatch featuresAtIndex:i]; + whisper_decoder_implOutput * result = [[whisper_decoder_implOutput alloc] initWithVar_1346:(MLMultiArray *)[resultProvider featureValueForName:@"var_1346"].multiArrayValue]; + [results addObject:result]; + } + return results; +} + +@end diff --git a/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.h b/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.h new file mode 100644 index 0000000..7b83cd9 --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.h @@ -0,0 +1,142 @@ +// +// whisper-encoder-impl.h +// +// This file was automatically generated and should not be edited. +// + +#import +#import +#include +#include + +NS_ASSUME_NONNULL_BEGIN + + +/// Model Prediction Input Type +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_encoder_implInput : NSObject + +/// logmel_data as 1 × 80 × 3000 3-dimensional array of floats +@property (readwrite, nonatomic, strong) MLMultiArray * logmel_data; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithLogmel_data:(MLMultiArray *)logmel_data NS_DESIGNATED_INITIALIZER; + +@end + + +/// Model Prediction Output Type +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_encoder_implOutput : NSObject + +/// output as multidimensional array of floats +@property (readwrite, nonatomic, strong) MLMultiArray * output; +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithOutput:(MLMultiArray *)output NS_DESIGNATED_INITIALIZER; + +@end + + +/// Class for model loading and prediction +API_AVAILABLE(macos(12.0), ios(15.0), watchos(8.0), tvos(15.0)) __attribute__((visibility("hidden"))) +@interface whisper_encoder_impl : NSObject +@property (readonly, nonatomic, nullable) MLModel * model; + +/** + URL of the underlying .mlmodelc directory. +*/ ++ (nullable NSURL *)URLOfModelInThisBundle; + +/** + Initialize whisper_encoder_impl instance from an existing MLModel object. + + Usually the application does not use this initializer unless it makes a subclass of whisper_encoder_impl. + Such application may want to use `-[MLModel initWithContentsOfURL:configuration:error:]` and `+URLOfModelInThisBundle` to create a MLModel object to pass-in. +*/ +- (instancetype)initWithMLModel:(MLModel *)model NS_DESIGNATED_INITIALIZER; + +/** + Initialize whisper_encoder_impl instance with the model in this bundle. +*/ +- (nullable instancetype)init; + +/** + Initialize whisper_encoder_impl instance with the model in this bundle. + + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithConfiguration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Initialize whisper_encoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_encoder_impl. + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Initialize whisper_encoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_encoder_impl. + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Construct whisper_encoder_impl instance asynchronously with configuration. + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_encoder_impl instance or NSError object. +*/ ++ (void)loadWithConfiguration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_encoder_impl * _Nullable model, NSError * _Nullable error))handler; + +/** + Construct whisper_encoder_impl instance asynchronously with URL of .mlmodelc directory and optional configuration. + + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param modelURL The model URL. + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_encoder_impl instance or NSError object. +*/ ++ (void)loadContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_encoder_impl * _Nullable model, NSError * _Nullable error))handler; + +/** + Make a prediction using the standard interface + @param input an instance of whisper_encoder_implInput to predict from + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_encoder_implOutput +*/ +- (nullable whisper_encoder_implOutput *)predictionFromFeatures:(whisper_encoder_implInput *)input error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Make a prediction using the standard interface + @param input an instance of whisper_encoder_implInput to predict from + @param options prediction options + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_encoder_implOutput +*/ +- (nullable whisper_encoder_implOutput *)predictionFromFeatures:(whisper_encoder_implInput *)input options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Make a prediction using the convenience interface + @param logmel_data as 1 × n_mel × 3000 3-dimensional array of floats: + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the prediction as whisper_encoder_implOutput +*/ +- (nullable whisper_encoder_implOutput *)predictionFromLogmel_data:(MLMultiArray *)logmel_data error:(NSError * _Nullable __autoreleasing * _Nullable)error; + +/** + Batch prediction + @param inputArray array of whisper_encoder_implInput instances to obtain predictions from + @param options prediction options + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. + @return the predictions as NSArray +*/ +- (nullable NSArray *)predictionsFromInputs:(NSArray *)inputArray options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error; +@end + +NS_ASSUME_NONNULL_END diff --git a/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.m b/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.m new file mode 100644 index 0000000..ee8e506 --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-encoder-impl.m @@ -0,0 +1,197 @@ +// +// whisper-encoder-impl.m +// +// This file was automatically generated and should not be edited. +// + +#if !__has_feature(objc_arc) +#error This file must be compiled with automatic reference counting enabled (-fobjc-arc) +#endif + +#import "whisper-encoder-impl.h" + +@implementation whisper_encoder_implInput + +- (instancetype)initWithLogmel_data:(MLMultiArray *)logmel_data { + self = [super init]; + if (self) { + _logmel_data = logmel_data; + } + return self; +} + +- (NSSet *)featureNames { + return [NSSet setWithArray:@[@"logmel_data"]]; +} + +- (nullable MLFeatureValue *)featureValueForName:(NSString *)featureName { + if ([featureName isEqualToString:@"logmel_data"]) { + return [MLFeatureValue featureValueWithMultiArray:self.logmel_data]; + } + return nil; +} + +@end + +@implementation whisper_encoder_implOutput + +- (instancetype)initWithOutput:(MLMultiArray *)output { + self = [super init]; + if (self) { + _output = output; + } + return self; +} + +- (NSSet *)featureNames { + return [NSSet setWithArray:@[@"output"]]; +} + +- (nullable MLFeatureValue *)featureValueForName:(NSString *)featureName { + if ([featureName isEqualToString:@"output"]) { + return [MLFeatureValue featureValueWithMultiArray:self.output]; + } + return nil; +} + +@end + +@implementation whisper_encoder_impl + + +/** + URL of the underlying .mlmodelc directory. +*/ ++ (nullable NSURL *)URLOfModelInThisBundle { + NSString *assetPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"whisper_encoder_impl" ofType:@"mlmodelc"]; + if (nil == assetPath) { os_log_error(OS_LOG_DEFAULT, "Could not load whisper-encoder-impl.mlmodelc in the bundle resource"); return nil; } + return [NSURL fileURLWithPath:assetPath]; +} + + +/** + Initialize whisper_encoder_impl instance from an existing MLModel object. + + Usually the application does not use this initializer unless it makes a subclass of whisper_encoder_impl. + Such application may want to use `-[MLModel initWithContentsOfURL:configuration:error:]` and `+URLOfModelInThisBundle` to create a MLModel object to pass-in. +*/ +- (instancetype)initWithMLModel:(MLModel *)model { + self = [super init]; + if (!self) { return nil; } + _model = model; + if (_model == nil) { return nil; } + return self; +} + + +/** + Initialize whisper_encoder_impl instance with the model in this bundle. +*/ +- (nullable instancetype)init { + return [self initWithContentsOfURL:(NSURL * _Nonnull)self.class.URLOfModelInThisBundle error:nil]; +} + + +/** + Initialize whisper_encoder_impl instance with the model in this bundle. + + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithConfiguration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error { + return [self initWithContentsOfURL:(NSURL * _Nonnull)self.class.URLOfModelInThisBundle configuration:configuration error:error]; +} + + +/** + Initialize whisper_encoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_encoder_impl. + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL error:(NSError * _Nullable __autoreleasing * _Nullable)error { + MLModel *model = [MLModel modelWithContentsOfURL:modelURL error:error]; + if (model == nil) { return nil; } + return [self initWithMLModel:model]; +} + + +/** + Initialize whisper_encoder_impl instance from the model URL. + + @param modelURL URL to the .mlmodelc directory for whisper_encoder_impl. + @param configuration The model configuration object + @param error If an error occurs, upon return contains an NSError object that describes the problem. If you are not interested in possible errors, pass in NULL. +*/ +- (nullable instancetype)initWithContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration error:(NSError * _Nullable __autoreleasing * _Nullable)error { + MLModel *model = [MLModel modelWithContentsOfURL:modelURL configuration:configuration error:error]; + if (model == nil) { return nil; } + return [self initWithMLModel:model]; +} + + +/** + Construct whisper_encoder_impl instance asynchronously with configuration. + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_encoder_impl instance or NSError object. +*/ ++ (void)loadWithConfiguration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_encoder_impl * _Nullable model, NSError * _Nullable error))handler { + [self loadContentsOfURL:(NSURL * _Nonnull)[self URLOfModelInThisBundle] + configuration:configuration + completionHandler:handler]; +} + + +/** + Construct whisper_encoder_impl instance asynchronously with URL of .mlmodelc directory and optional configuration. + + Model loading may take time when the model content is not immediately available (e.g. encrypted model). Use this factory method especially when the caller is on the main thread. + + @param modelURL The model URL. + @param configuration The model configuration + @param handler When the model load completes successfully or unsuccessfully, the completion handler is invoked with a valid whisper_encoder_impl instance or NSError object. +*/ ++ (void)loadContentsOfURL:(NSURL *)modelURL configuration:(MLModelConfiguration *)configuration completionHandler:(void (^)(whisper_encoder_impl * _Nullable model, NSError * _Nullable error))handler { + [MLModel loadContentsOfURL:modelURL + configuration:configuration + completionHandler:^(MLModel *model, NSError *error) { + if (model != nil) { + whisper_encoder_impl *typedModel = [[whisper_encoder_impl alloc] initWithMLModel:model]; + handler(typedModel, nil); + } else { + handler(nil, error); + } + }]; +} + +- (nullable whisper_encoder_implOutput *)predictionFromFeatures:(whisper_encoder_implInput *)input error:(NSError * _Nullable __autoreleasing * _Nullable)error { + return [self predictionFromFeatures:input options:[[MLPredictionOptions alloc] init] error:error]; +} + +- (nullable whisper_encoder_implOutput *)predictionFromFeatures:(whisper_encoder_implInput *)input options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error { + id outFeatures = [self.model predictionFromFeatures:input options:options error:error]; + if (!outFeatures) { return nil; } + return [[whisper_encoder_implOutput alloc] initWithOutput:(MLMultiArray *)[outFeatures featureValueForName:@"output"].multiArrayValue]; +} + +- (nullable whisper_encoder_implOutput *)predictionFromLogmel_data:(MLMultiArray *)logmel_data error:(NSError * _Nullable __autoreleasing * _Nullable)error { + whisper_encoder_implInput *input_ = [[whisper_encoder_implInput alloc] initWithLogmel_data:logmel_data]; + return [self predictionFromFeatures:input_ error:error]; +} + +- (nullable NSArray *)predictionsFromInputs:(NSArray *)inputArray options:(MLPredictionOptions *)options error:(NSError * _Nullable __autoreleasing * _Nullable)error { + id inBatch = [[MLArrayBatchProvider alloc] initWithFeatureProviderArray:inputArray]; + id outBatch = [self.model predictionsFromBatch:inBatch options:options error:error]; + if (!outBatch) { return nil; } + NSMutableArray *results = [NSMutableArray arrayWithCapacity:(NSUInteger)outBatch.count]; + for (NSInteger i = 0; i < outBatch.count; i++) { + id resultProvider = [outBatch featuresAtIndex:i]; + whisper_encoder_implOutput * result = [[whisper_encoder_implOutput alloc] initWithOutput:(MLMultiArray *)[resultProvider featureValueForName:@"output"].multiArrayValue]; + [results addObject:result]; + } + return results; +} + +@end diff --git a/whisper.cpp-1.5.2/coreml/whisper-encoder.h b/whisper.cpp-1.5.2/coreml/whisper-encoder.h new file mode 100644 index 0000000..508df7c --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-encoder.h @@ -0,0 +1,26 @@ +// Wrapper of the Core ML Whisper Encoder model +// +// Code is derived from the work of Github user @wangchou +// ref: https://github.com/wangchou/callCoreMLFromCpp + +#include + +#if __cplusplus +extern "C" { +#endif + +struct whisper_coreml_context; + +struct whisper_coreml_context * whisper_coreml_init(const char * path_model); +void whisper_coreml_free(struct whisper_coreml_context * ctx); + +void whisper_coreml_encode( + const whisper_coreml_context * ctx, + int64_t n_ctx, + int64_t n_mel, + float * mel, + float * out); + +#if __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/coreml/whisper-encoder.mm b/whisper.cpp-1.5.2/coreml/whisper-encoder.mm new file mode 100644 index 0000000..8e93f18 --- /dev/null +++ b/whisper.cpp-1.5.2/coreml/whisper-encoder.mm @@ -0,0 +1,73 @@ +#if !__has_feature(objc_arc) +#error This file must be compiled with automatic reference counting enabled (-fobjc-arc) +#endif + +#import "whisper-encoder.h" +#import "whisper-encoder-impl.h" + +#import + +#include + +#if __cplusplus +extern "C" { +#endif + +struct whisper_coreml_context { + const void * data; +}; + +struct whisper_coreml_context * whisper_coreml_init(const char * path_model) { + NSString * path_model_str = [[NSString alloc] initWithUTF8String:path_model]; + + NSURL * url_model = [NSURL fileURLWithPath: path_model_str]; + + // select which device to run the Core ML model on + MLModelConfiguration *config = [[MLModelConfiguration alloc] init]; + config.computeUnits = MLComputeUnitsCPUAndGPU; + //config.computeUnits = MLComputeUnitsCPUAndNeuralEngine; + //config.computeUnits = MLComputeUnitsAll; + + const void * data = CFBridgingRetain([[whisper_encoder_impl alloc] initWithContentsOfURL:url_model configuration:config error:nil]); + + if (data == NULL) { + return NULL; + } + + whisper_coreml_context * ctx = new whisper_coreml_context; + + ctx->data = data; + + return ctx; +} + +void whisper_coreml_free(struct whisper_coreml_context * ctx) { + CFRelease(ctx->data); + delete ctx; +} + +void whisper_coreml_encode( + const whisper_coreml_context * ctx, + int64_t n_ctx, + int64_t n_mel, + float * mel, + float * out) { + MLMultiArray * inMultiArray = [ + [MLMultiArray alloc] initWithDataPointer: mel + shape: @[@1, @(n_mel), @(n_ctx)] + dataType: MLMultiArrayDataTypeFloat32 + strides: @[@(n_ctx*n_mel), @(n_ctx), @1] + deallocator: nil + error: nil + ]; + + @autoreleasepool { + whisper_encoder_implOutput * outCoreML = [(__bridge id) ctx->data predictionFromLogmel_data:inMultiArray error:nil]; + + memcpy(out, outCoreML.output.dataPointer, outCoreML.output.count * sizeof(float)); + } +} + +#if __cplusplus +} +#endif diff --git a/whisper.cpp-1.5.2/examples/CMakeLists.txt b/whisper.cpp-1.5.2/examples/CMakeLists.txt new file mode 100644 index 0000000..e6f837f --- /dev/null +++ b/whisper.cpp-1.5.2/examples/CMakeLists.txt @@ -0,0 +1,77 @@ +# dependencies + +find_package(Threads REQUIRED) + +# third-party + +if (WHISPER_SDL2) + # SDL2 + find_package(SDL2 REQUIRED) + + string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES) + + message(STATUS "SDL2_INCLUDE_DIRS = ${SDL2_INCLUDE_DIRS}") + message(STATUS "SDL2_LIBRARIES = ${SDL2_LIBRARIES}") +endif() + +# common + +set(TARGET common) + +add_library(${TARGET} STATIC + common.h + common.cpp + common-ggml.h + common-ggml.cpp + grammar-parser.cpp + ) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE whisper) + +set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON) + +if (WHISPER_SDL2) + # common-sdl + + set(TARGET common-sdl) + + add_library(${TARGET} STATIC + common-sdl.h + common-sdl.cpp + ) + + include(DefaultTargetOptions) + + target_include_directories(${TARGET} PUBLIC ${SDL2_INCLUDE_DIRS}) + target_link_libraries(${TARGET} PRIVATE ${SDL2_LIBRARIES}) + + set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif() + +# examples + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +if (EMSCRIPTEN) + add_subdirectory(whisper.wasm) + add_subdirectory(stream.wasm) + add_subdirectory(command.wasm) + add_subdirectory(talk.wasm) + add_subdirectory(bench.wasm) +elseif(CMAKE_JS_VERSION) + add_subdirectory(addon.node) +else() + add_subdirectory(main) + add_subdirectory(stream) + add_subdirectory(server) + add_subdirectory(command) + add_subdirectory(bench) + add_subdirectory(quantize) + add_subdirectory(talk) + add_subdirectory(talk-llama) + add_subdirectory(lsp) +endif() + +add_subdirectory(wchess) diff --git a/whisper.cpp-1.5.2/examples/addon.node/.gitignore b/whisper.cpp-1.5.2/examples/addon.node/.gitignore new file mode 100644 index 0000000..b456cad --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/.gitignore @@ -0,0 +1,3 @@ +.idea +node_modules +build diff --git a/whisper.cpp-1.5.2/examples/addon.node/CMakeLists.txt b/whisper.cpp-1.5.2/examples/addon.node/CMakeLists.txt new file mode 100644 index 0000000..aef7839 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/CMakeLists.txt @@ -0,0 +1,31 @@ +set(TARGET whisper-addon) + +# Base settings +#================================================================== +# env var supported by cmake-js +add_definitions(-DNAPI_VERSION=4) +include_directories(${CMAKE_JS_INC}) +#================================================================== + +add_library(${TARGET} SHARED ${CMAKE_JS_SRC} addon.cpp) +set_target_properties(${TARGET} PROPERTIES PREFIX "" SUFFIX ".node") + +include(DefaultTargetOptions) + +# Include N-API wrappers +#================================================================== +execute_process(COMMAND node -p "require('node-addon-api').include" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE NODE_ADDON_API_DIR + ) +string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) +string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) +target_include_directories(${TARGET} PRIVATE ${NODE_ADDON_API_DIR}) +#================================================================== + +target_link_libraries(${TARGET} ${CMAKE_JS_LIB} common whisper ${CMAKE_THREAD_LIBS_INIT}) + +if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET) + # Generate node.lib + execute_process(COMMAND ${CMAKE_AR} /def:${CMAKE_JS_NODELIB_DEF} /out:${CMAKE_JS_NODELIB_TARGET} ${CMAKE_STATIC_LINKER_FLAGS}) +endif() diff --git a/whisper.cpp-1.5.2/examples/addon.node/README.md b/whisper.cpp-1.5.2/examples/addon.node/README.md new file mode 100644 index 0000000..bdb1d25 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/README.md @@ -0,0 +1,37 @@ +# addon + +This is an addon demo that can **perform whisper model reasoning in `node` and `electron` environments**, based on [cmake-js](https://github.com/cmake-js/cmake-js). +It can be used as a reference for using the whisper.cpp project in other node projects. + +## Install + +```shell +npm install +``` + +## Compile + +Make sure it is in the project root directory and compiled with make-js. + +```shell +npx cmake-js compile -T whisper-addon -B Release +``` + +For Electron addon and cmake-js options, you can see [cmake-js](https://github.com/cmake-js/cmake-js) and make very few configuration changes. + +> Such as appointing special cmake path: +> ```shell +> npx cmake-js compile -c 'xxx/cmake' -T whisper-addon -B Release +> ``` + +## Run + +```shell +cd examples/addon.node + +node index.js --language='language' --model='model-path' --fname_inp='file-path' +``` + +Because this is a simple Demo, only the above parameters are set in the node environment. + +Other parameters can also be specified in the node environment. diff --git a/whisper.cpp-1.5.2/examples/addon.node/__test__/whisper.spec.js b/whisper.cpp-1.5.2/examples/addon.node/__test__/whisper.spec.js new file mode 100644 index 0000000..d102fe7 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/__test__/whisper.spec.js @@ -0,0 +1,24 @@ +const path = require("path"); +const { whisper } = require(path.join( + __dirname, + "../../../build/Release/whisper-addon" +)); +const { promisify } = require("util"); + +const whisperAsync = promisify(whisper); + +const whisperParamsMock = { + language: "en", + model: path.join(__dirname, "../../../models/ggml-base.en.bin"), + fname_inp: path.join(__dirname, "../../../samples/jfk.wav"), + use_gpu: true, +}; + +describe("Run whisper.node", () => { + test("it should receive a non-empty value", async () => { + let result = await whisperAsync(whisperParamsMock); + + expect(result.length).toBeGreaterThan(0); + }, 10000); +}); + diff --git a/whisper.cpp-1.5.2/examples/addon.node/addon.cpp b/whisper.cpp-1.5.2/examples/addon.node/addon.cpp new file mode 100644 index 0000000..30acbc6 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/addon.cpp @@ -0,0 +1,343 @@ +#include "napi.h" +#include "common.h" + +#include "whisper.h" + +#include +#include +#include +#include +#include + +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t n_processors = 1; + int32_t offset_t_ms = 0; + int32_t offset_n = 0; + int32_t duration_ms = 0; + int32_t max_context = -1; + int32_t max_len = 0; + int32_t best_of = 5; + int32_t beam_size = -1; + + float word_thold = 0.01f; + float entropy_thold = 2.4f; + float logprob_thold = -1.0f; + + bool speed_up = false; + bool translate = false; + bool diarize = false; + bool output_txt = false; + bool output_vtt = false; + bool output_srt = false; + bool output_wts = false; + bool output_csv = false; + bool print_special = false; + bool print_colors = false; + bool print_progress = false; + bool no_timestamps = false; + bool use_gpu = true; + + std::string language = "en"; + std::string prompt; + std::string model = "../../ggml-large.bin"; + + std::vector fname_inp = {}; + std::vector fname_out = {}; +}; + +struct whisper_print_user_data { + const whisper_params * params; + + const std::vector> * pcmf32s; +}; + +// 500 -> 00:05.000 +// 6000 -> 01:00.000 +std::string to_timestamp(int64_t t, bool comma = false) { + int64_t msec = t * 10; + int64_t hr = msec / (1000 * 60 * 60); + msec = msec - hr * (1000 * 60 * 60); + int64_t min = msec / (1000 * 60); + msec = msec - min * (1000 * 60); + int64_t sec = msec / 1000; + msec = msec - sec * 1000; + + char buf[32]; + snprintf(buf, sizeof(buf), "%02d:%02d:%02d%s%03d", (int) hr, (int) min, (int) sec, comma ? "," : ".", (int) msec); + + return std::string(buf); +} + +int timestamp_to_sample(int64_t t, int n_samples) { + return std::max(0, std::min((int) n_samples - 1, (int) ((t*WHISPER_SAMPLE_RATE)/100))); +} + +void whisper_print_segment_callback(struct whisper_context * ctx, struct whisper_state * state, int n_new, void * user_data) { + const auto & params = *((whisper_print_user_data *) user_data)->params; + const auto & pcmf32s = *((whisper_print_user_data *) user_data)->pcmf32s; + + const int n_segments = whisper_full_n_segments(ctx); + + std::string speaker = ""; + + int64_t t0; + int64_t t1; + + // print the last n_new segments + const int s0 = n_segments - n_new; + + if (s0 == 0) { + printf("\n"); + } + + for (int i = s0; i < n_segments; i++) { + if (!params.no_timestamps || params.diarize) { + t0 = whisper_full_get_segment_t0(ctx, i); + t1 = whisper_full_get_segment_t1(ctx, i); + } + + if (!params.no_timestamps) { + printf("[%s --> %s] ", to_timestamp(t0).c_str(), to_timestamp(t1).c_str()); + } + + if (params.diarize && pcmf32s.size() == 2) { + const int64_t n_samples = pcmf32s[0].size(); + + const int64_t is0 = timestamp_to_sample(t0, n_samples); + const int64_t is1 = timestamp_to_sample(t1, n_samples); + + double energy0 = 0.0f; + double energy1 = 0.0f; + + for (int64_t j = is0; j < is1; j++) { + energy0 += fabs(pcmf32s[0][j]); + energy1 += fabs(pcmf32s[1][j]); + } + + if (energy0 > 1.1*energy1) { + speaker = "(speaker 0)"; + } else if (energy1 > 1.1*energy0) { + speaker = "(speaker 1)"; + } else { + speaker = "(speaker ?)"; + } + + //printf("is0 = %lld, is1 = %lld, energy0 = %f, energy1 = %f, %s\n", is0, is1, energy0, energy1, speaker.c_str()); + } + + // colorful print bug + // + const char * text = whisper_full_get_segment_text(ctx, i); + printf("%s%s", speaker.c_str(), text); + + + // with timestamps or speakers: each segment on new line + if (!params.no_timestamps || params.diarize) { + printf("\n"); + } + + fflush(stdout); + } +} + +int run(whisper_params ¶ms, std::vector> &result) { + if (params.fname_inp.empty()) { + fprintf(stderr, "error: no input files specified\n"); + return 2; + } + + if (params.language != "auto" && whisper_lang_id(params.language.c_str()) == -1) { + fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str()); + exit(0); + } + + // whisper init + + struct whisper_context_params cparams; + cparams.use_gpu = params.use_gpu; + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + if (ctx == nullptr) { + fprintf(stderr, "error: failed to initialize whisper context\n"); + return 3; + } + + for (int f = 0; f < (int) params.fname_inp.size(); ++f) { + const auto fname_inp = params.fname_inp[f]; + const auto fname_out = f < (int)params.fname_out.size() && !params.fname_out[f].empty() ? params.fname_out[f] : params.fname_inp[f]; + + std::vector pcmf32; // mono-channel F32 PCM + std::vector> pcmf32s; // stereo-channel F32 PCM + + if (!::read_wav(fname_inp, pcmf32, pcmf32s, params.diarize)) { + fprintf(stderr, "error: failed to read WAV file '%s'\n", fname_inp.c_str()); + continue; + } + + // print system information + { + fprintf(stderr, "\n"); + fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", + params.n_threads*params.n_processors, std::thread::hardware_concurrency(), whisper_print_system_info()); + } + + // print some info about the processing + { + fprintf(stderr, "\n"); + if (!whisper_is_multilingual(ctx)) { + if (params.language != "en" || params.translate) { + params.language = "en"; + params.translate = false; + fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__); + } + } + fprintf(stderr, "%s: processing '%s' (%d samples, %.1f sec), %d threads, %d processors, lang = %s, task = %s, timestamps = %d ...\n", + __func__, fname_inp.c_str(), int(pcmf32.size()), float(pcmf32.size())/WHISPER_SAMPLE_RATE, + params.n_threads, params.n_processors, + params.language.c_str(), + params.translate ? "translate" : "transcribe", + params.no_timestamps ? 0 : 1); + + fprintf(stderr, "\n"); + } + + // run the inference + { + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + + wparams.strategy = params.beam_size > 1 ? WHISPER_SAMPLING_BEAM_SEARCH : WHISPER_SAMPLING_GREEDY; + + wparams.print_realtime = false; + wparams.print_progress = params.print_progress; + wparams.print_timestamps = !params.no_timestamps; + wparams.print_special = params.print_special; + wparams.translate = params.translate; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + wparams.n_max_text_ctx = params.max_context >= 0 ? params.max_context : wparams.n_max_text_ctx; + wparams.offset_ms = params.offset_t_ms; + wparams.duration_ms = params.duration_ms; + + wparams.token_timestamps = params.output_wts || params.max_len > 0; + wparams.thold_pt = params.word_thold; + wparams.entropy_thold = params.entropy_thold; + wparams.logprob_thold = params.logprob_thold; + wparams.max_len = params.output_wts && params.max_len == 0 ? 60 : params.max_len; + + wparams.speed_up = params.speed_up; + + wparams.greedy.best_of = params.best_of; + wparams.beam_search.beam_size = params.beam_size; + + wparams.initial_prompt = params.prompt.c_str(); + + whisper_print_user_data user_data = { ¶ms, &pcmf32s }; + + // this callback is called on each new segment + if (!wparams.print_realtime) { + wparams.new_segment_callback = whisper_print_segment_callback; + wparams.new_segment_callback_user_data = &user_data; + } + + // example for abort mechanism + // in this example, we do not abort the processing, but we could if the flag is set to true + // the callback is called before every encoder run - if it returns false, the processing is aborted + { + static bool is_aborted = false; // NOTE: this should be atomic to avoid data race + + wparams.encoder_begin_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, void * user_data) { + bool is_aborted = *(bool*)user_data; + return !is_aborted; + }; + wparams.encoder_begin_callback_user_data = &is_aborted; + } + + if (whisper_full_parallel(ctx, wparams, pcmf32.data(), pcmf32.size(), params.n_processors) != 0) { + fprintf(stderr, "failed to process audio\n"); + return 10; + } + } + } + + const int n_segments = whisper_full_n_segments(ctx); + result.resize(n_segments); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(ctx, i); + const int64_t t0 = whisper_full_get_segment_t0(ctx, i); + const int64_t t1 = whisper_full_get_segment_t1(ctx, i); + + result[i].emplace_back(to_timestamp(t0, true)); + result[i].emplace_back(to_timestamp(t1, true)); + result[i].emplace_back(text); + } + + whisper_print_timings(ctx); + whisper_free(ctx); + + return 0; +} + +class Worker : public Napi::AsyncWorker { + public: + Worker(Napi::Function& callback, whisper_params params) + : Napi::AsyncWorker(callback), params(params) {} + + void Execute() override { + run(params, result); + } + + void OnOK() override { + Napi::HandleScope scope(Env()); + Napi::Object res = Napi::Array::New(Env(), result.size()); + for (uint64_t i = 0; i < result.size(); ++i) { + Napi::Object tmp = Napi::Array::New(Env(), 3); + for (uint64_t j = 0; j < 3; ++j) { + tmp[j] = Napi::String::New(Env(), result[i][j]); + } + res[i] = tmp; + } + Callback().Call({Env().Null(), res}); + } + + private: + whisper_params params; + std::vector> result; +}; + + + +Napi::Value whisper(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + if (info.Length() <= 0 || !info[0].IsObject()) { + Napi::TypeError::New(env, "object expected").ThrowAsJavaScriptException(); + } + whisper_params params; + + Napi::Object whisper_params = info[0].As(); + std::string language = whisper_params.Get("language").As(); + std::string model = whisper_params.Get("model").As(); + std::string input = whisper_params.Get("fname_inp").As(); + bool use_gpu = whisper_params.Get("use_gpu").As(); + + params.language = language; + params.model = model; + params.fname_inp.emplace_back(input); + params.use_gpu = use_gpu; + + Napi::Function callback = info[1].As(); + Worker* worker = new Worker(callback, params); + worker->Queue(); + return env.Undefined(); +} + + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set( + Napi::String::New(env, "whisper"), + Napi::Function::New(env, whisper) + ); + return exports; +} + +NODE_API_MODULE(whisper, Init); diff --git a/whisper.cpp-1.5.2/examples/addon.node/index.js b/whisper.cpp-1.5.2/examples/addon.node/index.js new file mode 100644 index 0000000..3c64293 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/index.js @@ -0,0 +1,37 @@ +const path = require("path"); +const { whisper } = require(path.join( + __dirname, + "../../build/Release/whisper-addon" +)); +const { promisify } = require("util"); + +const whisperAsync = promisify(whisper); + +const whisperParams = { + language: "en", + model: path.join(__dirname, "../../models/ggml-base.en.bin"), + fname_inp: "../../samples/jfk.wav", + use_gpu: true, +}; + +const arguments = process.argv.slice(2); +const params = Object.fromEntries( + arguments.reduce((pre, item) => { + if (item.startsWith("--")) { + return [...pre, item.slice(2).split("=")]; + } + return pre; + }, []) +); + +for (const key in params) { + if (whisperParams.hasOwnProperty(key)) { + whisperParams[key] = params[key]; + } +} + +console.log("whisperParams =", whisperParams); + +whisperAsync(whisperParams).then((result) => { + console.log(`Result from whisper: ${result}`); +}); diff --git a/whisper.cpp-1.5.2/examples/addon.node/package.json b/whisper.cpp-1.5.2/examples/addon.node/package.json new file mode 100644 index 0000000..bf51f0b --- /dev/null +++ b/whisper.cpp-1.5.2/examples/addon.node/package.json @@ -0,0 +1,16 @@ +{ + "name": "whisper-addon", + "version": "0.0.0", + "description": "", + "main": "index.js", + "author": "Qanhe Chen", + "license": "MIT", + "scripts": { + "test": "jest" + }, + "devDependencies": { + "cmake-js": "^7.1.1", + "jest": "^29.4.0", + "node-addon-api": "^5.0.0" + } +} diff --git a/whisper.cpp-1.5.2/examples/bench.wasm/CMakeLists.txt b/whisper.cpp-1.5.2/examples/bench.wasm/CMakeLists.txt new file mode 100644 index 0000000..5e9f68d --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench.wasm/CMakeLists.txt @@ -0,0 +1,49 @@ +# +# libbench +# + +set(TARGET libbench) + +add_executable(${TARGET} + emscripten.cpp + ) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE + whisper + ) + +unset(EXTRA_FLAGS) + +if (WHISPER_WASM_SINGLE_FILE) + set(EXTRA_FLAGS "-s SINGLE_FILE=1") + message(STATUS "Embedding WASM inside bench.js") + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libbench.js + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/bench.wasm/bench.js + ) +endif() + +set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ + --bind \ + -s USE_PTHREADS=1 \ + -s PTHREAD_POOL_SIZE_STRICT=0 \ + -s INITIAL_MEMORY=2000MB \ + -s TOTAL_MEMORY=2000MB \ + -s FORCE_FILESYSTEM=1 \ + -s EXPORTED_RUNTIME_METHODS=\"['print', 'printErr', 'ccall', 'cwrap']\" \ + ${EXTRA_FLAGS} \ + ") + +# +# bench.wasm +# + +set(TARGET bench.wasm) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/index.html @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../helpers.js ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/helpers.js @ONLY) diff --git a/whisper.cpp-1.5.2/examples/bench.wasm/README.md b/whisper.cpp-1.5.2/examples/bench.wasm/README.md new file mode 100644 index 0000000..921b57c --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench.wasm/README.md @@ -0,0 +1,22 @@ +# bench.wasm + +Benchmark the performance of whisper.cpp in the browser using WebAssembly + +Link: https://whisper.ggerganov.com/bench/ + +Terminal version: [examples/bench](/examples/bench) + +## Build instructions + +```bash +# build using Emscripten (v3.1.2) +git clone https://github.com/ggerganov/whisper.cpp +cd whisper.cpp +mkdir build-em && cd build-em +emcmake cmake .. +make -j + +# copy the produced page to your HTTP path +cp bin/bench.wasm/* /path/to/html/ +cp bin/libbench.worker.js /path/to/html/ +``` diff --git a/whisper.cpp-1.5.2/examples/bench.wasm/emscripten.cpp b/whisper.cpp-1.5.2/examples/bench.wasm/emscripten.cpp new file mode 100644 index 0000000..083397d --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench.wasm/emscripten.cpp @@ -0,0 +1,87 @@ +#include "whisper.h" + +#include +#include + +#include +#include +#include +#include + +constexpr int N_THREAD = 8; + +// TODO: get rid of this vector of contexts - bad idea in the first place +std::vector g_contexts(4, nullptr); + +std::thread g_worker; + +void bench_main(size_t index) { + const int n_threads = std::min(N_THREAD, (int) std::thread::hardware_concurrency()); + + // whisper context + auto & ctx = g_contexts[index]; + + fprintf(stderr, "%s: running benchmark with %d threads - please wait...\n", __func__, n_threads); + + const int n_mels = whisper_model_n_mels(ctx); + + if (int ret = whisper_set_mel(ctx, nullptr, 0, n_mels)) { + fprintf(stderr, "error: failed to set mel: %d\n", ret); + return; + } + + { + fprintf(stderr, "\n"); + fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", n_threads, std::thread::hardware_concurrency(), whisper_print_system_info()); + } + + if (int ret = whisper_encode(ctx, 0, n_threads) != 0) { + fprintf(stderr, "error: failed to encode model: %d\n", ret); + return; + } + + whisper_print_timings(ctx); + + fprintf(stderr, "\n"); + fprintf(stderr, "If you wish, you can submit these results here:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " https://github.com/ggerganov/whisper.cpp/issues/89\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Please include the following information:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " - CPU model\n"); + fprintf(stderr, " - Operating system\n"); + fprintf(stderr, " - Browser\n"); + fprintf(stderr, "\n"); +} + +EMSCRIPTEN_BINDINGS(bench) { + emscripten::function("init", emscripten::optional_override([](const std::string & path_model) { + for (size_t i = 0; i < g_contexts.size(); ++i) { + if (g_contexts[i] == nullptr) { + g_contexts[i] = whisper_init_from_file_with_params(path_model.c_str(), whisper_context_default_params()); + if (g_contexts[i] != nullptr) { + if (g_worker.joinable()) { + g_worker.join(); + } + g_worker = std::thread([i]() { + bench_main(i); + }); + + return i + 1; + } else { + return (size_t) 0; + } + } + } + + return (size_t) 0; + })); + + emscripten::function("free", emscripten::optional_override([](size_t index) { + if (index < g_contexts.size()) { + whisper_free(g_contexts[index]); + g_contexts[index] = nullptr; + } + })); +} diff --git a/whisper.cpp-1.5.2/examples/bench.wasm/index-tmpl.html b/whisper.cpp-1.5.2/examples/bench.wasm/index-tmpl.html new file mode 100644 index 0000000..ca7a013 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench.wasm/index-tmpl.html @@ -0,0 +1,283 @@ + + + + bench : Benchmark whisper.cpp performance in the browser + + + + +
+ bench : Benchmark whisper.cpp performance in the browser + +

+ + You can find more about this project on GitHub. + +

+ + More examples: + main | + bench | + stream | + command | + talk | + +

+ +
+ + Select the model you would like to use and click the "Bench" button.
+ The results will be displayed in the textarea below. + +

+ +
+ Whisper model: + + + + +

+ Quantized models:

+ + + + + + +
+ +
+ +
+ + +
+ +
+ + Debug output: + + +
+ + Troubleshooting + +

+ + The page does some heavy computations, so make sure: + +
    +
  • To use a modern web browser (e.g. Chrome, Firefox)
  • +
  • To use a fast desktop or laptop computer (i.e. not a mobile phone)
  • +
  • Your browser supports WASM Fixed-width SIMD
  • +
+ +
+ + | + Build time: @GIT_DATE@ | + Commit hash: @GIT_SHA1@ | + Commit subject: @GIT_COMMIT_SUBJECT@ | + Source Code | + +
+
+ + + + + + diff --git a/whisper.cpp-1.5.2/examples/bench/CMakeLists.txt b/whisper.cpp-1.5.2/examples/bench/CMakeLists.txt new file mode 100644 index 0000000..f8a72ff --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench/CMakeLists.txt @@ -0,0 +1,6 @@ +set(TARGET bench) +add_executable(${TARGET} bench.cpp) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE whisper ${CMAKE_THREAD_LIBS_INIT}) diff --git a/whisper.cpp-1.5.2/examples/bench/README.md b/whisper.cpp-1.5.2/examples/bench/README.md new file mode 100644 index 0000000..5b42cb4 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench/README.md @@ -0,0 +1,54 @@ +# bench + +A very basic tool for benchmarking the inference performance on your device. The tool simply runs the Encoder part of +the transformer on some random audio data and records the execution time. This way we can have an objective comparison +of the performance of the model for various setups. + +Benchmark results are tracked in the following Github issue: https://github.com/ggerganov/whisper.cpp/issues/89 + +```bash +# build the bench tool +$ make bench + +# run it on the small.en model using 4 threads +$ ./bench -m ./models/ggml-small.en.bin -t 4 + +whisper_model_load: loading model from './models/ggml-small.en.bin' +whisper_model_load: n_vocab = 51864 +whisper_model_load: n_audio_ctx = 1500 +whisper_model_load: n_audio_state = 768 +whisper_model_load: n_audio_head = 12 +whisper_model_load: n_audio_layer = 12 +whisper_model_load: n_text_ctx = 448 +whisper_model_load: n_text_state = 768 +whisper_model_load: n_text_head = 12 +whisper_model_load: n_text_layer = 12 +whisper_model_load: n_mels = 80 +whisper_model_load: f16 = 1 +whisper_model_load: type = 3 +whisper_model_load: mem_required = 1048.00 MB +whisper_model_load: adding 1607 extra tokens +whisper_model_load: ggml ctx size = 533.05 MB +whisper_model_load: memory size = 68.48 MB +whisper_model_load: model size = 464.44 MB + +whisper_print_timings: load time = 240.82 ms +whisper_print_timings: mel time = 0.00 ms +whisper_print_timings: sample time = 0.00 ms +whisper_print_timings: encode time = 1062.21 ms / 88.52 ms per layer +whisper_print_timings: decode time = 0.00 ms / 0.00 ms per layer +whisper_print_timings: total time = 1303.04 ms + +system_info: n_threads = 4 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | + +If you wish, you can submit these results here: + + https://github.com/ggerganov/whisper.cpp/issues/89 + +Please include the following information: + + - CPU model + - Operating system + - Compiler + +``` diff --git a/whisper.cpp-1.5.2/examples/bench/bench.cpp b/whisper.cpp-1.5.2/examples/bench/bench.cpp new file mode 100644 index 0000000..949e573 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/bench/bench.cpp @@ -0,0 +1,170 @@ +#include "whisper.h" + +#include +#include +#include +#include + +// command-line parameters +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t what = 0; // what to benchmark: 0 - whisper ecoder, 1 - memcpy, 2 - ggml_mul_mat + + std::string model = "models/ggml-base.en.bin"; + + bool use_gpu = true; +}; + +void whisper_print_usage(int argc, char ** argv, const whisper_params & params); + +bool whisper_params_parse(int argc, char ** argv, whisper_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") { + whisper_print_usage(argc, argv, params); + exit(0); + } + else if (arg == "-t" || arg == "--threads") { params.n_threads = std::stoi(argv[++i]); } + else if (arg == "-m" || arg == "--model") { params.model = argv[++i]; } + else if (arg == "-w" || arg == "--what") { params.what = atoi(argv[++i]); } + else if (arg == "-ng" || arg == "--no-gpu") { params.use_gpu = false; } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help [default] show this help message and exit\n"); + fprintf(stderr, " -t N, --threads N [%-7d] number of threads to use during computation\n", params.n_threads); + fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str()); + fprintf(stderr, " -w N, --what N [%-7d] what to benchmark:\n", params.what); + fprintf(stderr, " -ng, --no-gpu [%-7s] disable GPU\n", params.use_gpu ? "false" : "true"); + fprintf(stderr, " %-7s 0 - whisper\n", ""); + fprintf(stderr, " %-7s 1 - memcpy\n", ""); + fprintf(stderr, " %-7s 2 - ggml_mul_mat\n", ""); + fprintf(stderr, "\n"); +} + +int whisper_bench_full(const whisper_params & params) { + // whisper init + + struct whisper_context_params cparams; + cparams.use_gpu = params.use_gpu; + + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + { + fprintf(stderr, "\n"); + fprintf(stderr, "system_info: n_threads = %d / %d | %s\n", params.n_threads, std::thread::hardware_concurrency(), whisper_print_system_info()); + } + + if (ctx == nullptr) { + fprintf(stderr, "error: failed to initialize whisper context\n"); + return 2; + } + + const int n_mels = whisper_model_n_mels(ctx); + + if (int ret = whisper_set_mel(ctx, nullptr, 0, n_mels)) { + fprintf(stderr, "error: failed to set mel: %d\n", ret); + return 3; + } + // heat encoder + if (int ret = whisper_encode(ctx, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to encode: %d\n", ret); + return 4; + } + + whisper_token tokens[512]; + memset(tokens, 0, sizeof(tokens)); + + // prompt heat + if (int ret = whisper_decode(ctx, tokens, 256, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + + // text-generation heat + if (int ret = whisper_decode(ctx, tokens, 1, 256, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + + whisper_reset_timings(ctx); + + // actual run + if (int ret = whisper_encode(ctx, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to encode: %d\n", ret); + return 4; + } + + // text-generation + for (int i = 0; i < 256; i++) { + if (int ret = whisper_decode(ctx, tokens, 1, i, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + // batched decoding + for (int i = 0; i < 64; i++) { + if (int ret = whisper_decode(ctx, tokens, 5, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + // prompt processing + for (int i = 0; i < 16; i++) { + if (int ret = whisper_decode(ctx, tokens, 256, 0, params.n_threads) != 0) { + fprintf(stderr, "error: failed to decode: %d\n", ret); + return 4; + } + } + + whisper_print_timings(ctx); + whisper_free(ctx); + + fprintf(stderr, "\n"); + fprintf(stderr, "If you wish, you can submit these results here:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " https://github.com/ggerganov/whisper.cpp/issues/89\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "Please include the following information:\n"); + fprintf(stderr, "\n"); + fprintf(stderr, " - CPU model\n"); + fprintf(stderr, " - Operating system\n"); + fprintf(stderr, " - Compiler\n"); + fprintf(stderr, "\n"); + + return 0; +} + +int main(int argc, char ** argv) { + whisper_params params; + + if (whisper_params_parse(argc, argv, params) == false) { + return 1; + } + + int ret = -1; + + switch (params.what) { + case 0: ret = whisper_bench_full(params); break; + case 1: ret = whisper_bench_memcpy(params.n_threads); break; + case 2: ret = whisper_bench_ggml_mul_mat(params.n_threads); break; + default: fprintf(stderr, "error: unknown benchmark: %d\n", params.what); break; + } + + return ret; +} diff --git a/whisper.cpp-1.5.2/examples/command.wasm/CMakeLists.txt b/whisper.cpp-1.5.2/examples/command.wasm/CMakeLists.txt new file mode 100644 index 0000000..3117e16 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command.wasm/CMakeLists.txt @@ -0,0 +1,50 @@ +# +# libcommand +# + +set(TARGET libcommand) + +add_executable(${TARGET} + emscripten.cpp + ) + +include(DefaultTargetOptions) + +target_link_libraries(${TARGET} PRIVATE + common + whisper + ) + +unset(EXTRA_FLAGS) + +if (WHISPER_WASM_SINGLE_FILE) + set(EXTRA_FLAGS "-s SINGLE_FILE=1") + message(STATUS "Embedding WASM inside command.js") + + add_custom_command( + TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_BINARY_DIR}/bin/libcommand.js + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/command.wasm/command.js + ) +endif() + +set_target_properties(${TARGET} PROPERTIES LINK_FLAGS " \ + --bind \ + -s USE_PTHREADS=1 \ + -s PTHREAD_POOL_SIZE=8 \ + -s INITIAL_MEMORY=1024MB \ + -s TOTAL_MEMORY=1024MB \ + -s FORCE_FILESYSTEM=1 \ + -s EXPORTED_RUNTIME_METHODS=\"['print', 'printErr', 'ccall', 'cwrap']\" \ + ${EXTRA_FLAGS} \ + ") + +# +# command.wasm +# + +set(TARGET command.wasm) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/index-tmpl.html ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/index.html @ONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../helpers.js ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}/helpers.js @ONLY) diff --git a/whisper.cpp-1.5.2/examples/command.wasm/README.md b/whisper.cpp-1.5.2/examples/command.wasm/README.md new file mode 100644 index 0000000..d317f3a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command.wasm/README.md @@ -0,0 +1,23 @@ +# command.wasm + +This is a basic Voice Assistant example that accepts voice commands from the microphone. +It runs in fully in the browser via WebAseembly. + +Online demo: https://whisper.ggerganov.com/command/ + +Terminal version: [examples/command](/examples/command) + +## Build instructions + +```bash +# build using Emscripten (v3.1.2) +git clone https://github.com/ggerganov/whisper.cpp +cd whisper.cpp +mkdir build-em && cd build-em +emcmake cmake .. +make -j + +# copy the produced page to your HTTP path +cp bin/command.wasm/* /path/to/html/ +cp bin/libcommand.worker.js /path/to/html/ +``` diff --git a/whisper.cpp-1.5.2/examples/command.wasm/emscripten.cpp b/whisper.cpp-1.5.2/examples/command.wasm/emscripten.cpp new file mode 100644 index 0000000..528ff6a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command.wasm/emscripten.cpp @@ -0,0 +1,327 @@ +#include "ggml.h" +#include "common.h" +#include "whisper.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +constexpr int N_THREAD = 8; + +std::vector g_contexts(4, nullptr); + +std::mutex g_mutex; +std::thread g_worker; + +std::atomic g_running(false); + +std::string g_status = ""; +std::string g_status_forced = ""; +std::string g_transcribed = ""; + +std::vector g_pcmf32; + +void command_set_status(const std::string & status) { + std::lock_guard lock(g_mutex); + g_status = status; +} + +std::string command_transcribe(whisper_context * ctx, const whisper_full_params & wparams, const std::vector & pcmf32, float & prob, int64_t & t_ms) { + const auto t_start = std::chrono::high_resolution_clock::now(); + + prob = 0.0f; + t_ms = 0; + + if (whisper_full(ctx, wparams, pcmf32.data(), pcmf32.size()) != 0) { + return ""; + } + + int prob_n = 0; + std::string result; + + const int n_segments = whisper_full_n_segments(ctx); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(ctx, i); + + result += text; + + const int n_tokens = whisper_full_n_tokens(ctx, i); + for (int j = 0; j < n_tokens; ++j) { + const auto token = whisper_full_get_token_data(ctx, i, j); + + prob += token.p; + ++prob_n; + } + } + + if (prob_n > 0) { + prob /= prob_n; + } + + const auto t_end = std::chrono::high_resolution_clock::now(); + t_ms = std::chrono::duration_cast(t_end - t_start).count(); + + return result; +} + +void command_get_audio(int ms, int sample_rate, std::vector & audio) { + const int64_t n_samples = (ms * sample_rate) / 1000; + + int64_t n_take = 0; + if (n_samples > (int) g_pcmf32.size()) { + n_take = g_pcmf32.size(); + } else { + n_take = n_samples; + } + + audio.resize(n_take); + std::copy(g_pcmf32.end() - n_take, g_pcmf32.end(), audio.begin()); +} + +void command_main(size_t index) { + command_set_status("loading data ..."); + + struct whisper_full_params wparams = whisper_full_default_params(whisper_sampling_strategy::WHISPER_SAMPLING_GREEDY); + + wparams.n_threads = std::min(N_THREAD, (int) std::thread::hardware_concurrency()); + wparams.offset_ms = 0; + wparams.translate = false; + wparams.no_context = true; + wparams.single_segment = true; + wparams.print_realtime = false; + wparams.print_progress = false; + wparams.print_timestamps = true; + wparams.print_special = false; + + wparams.max_tokens = 32; + wparams.audio_ctx = 768; // partial encoder context for better performance + + wparams.language = "en"; + + printf("command: using %d threads\n", wparams.n_threads); + + bool have_prompt = false; + bool ask_prompt = true; + bool print_energy = false; + + float prob0 = 0.0f; + float prob = 0.0f; + + std::vector pcmf32_cur; + std::vector pcmf32_prompt; + + const std::string k_prompt = "Ok Whisper, start listening for commands."; + + // whisper context + auto & ctx = g_contexts[index]; + + const int32_t vad_ms = 2000; + const int32_t prompt_ms = 5000; + const int32_t command_ms = 4000; + + const float vad_thold = 0.1f; + const float freq_thold = -1.0f; + + while (g_running) { + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if (ask_prompt) { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: Say the following phrase: '%s%s%s'\n", __func__, "\033[1m", k_prompt.c_str(), "\033[0m"); + fprintf(stdout, "\n"); + + { + char txt[1024]; + snprintf(txt, sizeof(txt), "Say the following phrase: '%s'", k_prompt.c_str()); + command_set_status(txt); + } + + ask_prompt = false; + } + + int64_t t_ms = 0; + + { + command_get_audio(vad_ms, WHISPER_SAMPLE_RATE, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, vad_thold, freq_thold, print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + command_set_status("Speech detected! Processing ..."); + + if (!have_prompt) { + command_get_audio(prompt_ms, WHISPER_SAMPLE_RATE, pcmf32_cur); + + const auto txt = ::trim(::command_transcribe(ctx, wparams, pcmf32_cur, prob0, t_ms)); + + fprintf(stdout, "%s: Heard '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", txt.c_str(), "\033[0m", (int) t_ms); + + const float sim = similarity(txt, k_prompt); + + if (txt.length() < 0.8*k_prompt.length() || txt.length() > 1.2*k_prompt.length() || sim < 0.8f) { + fprintf(stdout, "%s: WARNING: prompt not recognized, try again\n", __func__); + ask_prompt = true; + } else { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: The prompt has been recognized!\n", __func__); + fprintf(stdout, "%s: Waiting for voice commands ...\n", __func__); + fprintf(stdout, "\n"); + + { + char txt[1024]; + snprintf(txt, sizeof(txt), "Success! Waiting for voice commands ..."); + command_set_status(txt); + } + + // save the audio for the prompt + pcmf32_prompt = pcmf32_cur; + have_prompt = true; + } + } else { + command_get_audio(command_ms, WHISPER_SAMPLE_RATE, pcmf32_cur); + + // prepend the prompt audio + pcmf32_cur.insert(pcmf32_cur.begin(), pcmf32_prompt.begin(), pcmf32_prompt.end()); + + const auto txt = ::trim(::command_transcribe(ctx, wparams, pcmf32_cur, prob, t_ms)); + + prob = 100.0f*(prob - prob0); + + fprintf(stdout, "%s: heard '%s'\n", __func__, txt.c_str()); + + // find the prompt in the text + float best_sim = 0.0f; + size_t best_len = 0; + for (int n = 0.8*k_prompt.size(); n <= 1.2*k_prompt.size(); ++n) { + const auto prompt = txt.substr(0, n); + + const float sim = similarity(prompt, k_prompt); + + //fprintf(stderr, "%s: prompt = '%s', sim = %f\n", __func__, prompt.c_str(), sim); + + if (sim > best_sim) { + best_sim = sim; + best_len = n; + } + } + + const std::string command = ::trim(txt.substr(best_len)); + + fprintf(stdout, "%s: Command '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", command.c_str(), "\033[0m", (int) t_ms); + fprintf(stdout, "\n"); + + { + char txt[1024]; + snprintf(txt, sizeof(txt), "Command '%s', (t = %d ms)", command.c_str(), (int) t_ms); + command_set_status(txt); + } + { + std::lock_guard lock(g_mutex); + g_transcribed = command; + } + } + + g_pcmf32.clear(); + } + } + } + + if (index < g_contexts.size()) { + whisper_free(g_contexts[index]); + g_contexts[index] = nullptr; + } +} + +EMSCRIPTEN_BINDINGS(command) { + emscripten::function("init", emscripten::optional_override([](const std::string & path_model) { + for (size_t i = 0; i < g_contexts.size(); ++i) { + if (g_contexts[i] == nullptr) { + g_contexts[i] = whisper_init_from_file_with_params(path_model.c_str(), whisper_context_default_params()); + if (g_contexts[i] != nullptr) { + g_running = true; + if (g_worker.joinable()) { + g_worker.join(); + } + g_worker = std::thread([i]() { + command_main(i); + }); + + return i + 1; + } else { + return (size_t) 0; + } + } + } + + return (size_t) 0; + })); + + emscripten::function("free", emscripten::optional_override([](size_t index) { + if (g_running) { + g_running = false; + } + })); + + emscripten::function("set_audio", emscripten::optional_override([](size_t index, const emscripten::val & audio) { + --index; + + if (index >= g_contexts.size()) { + return -1; + } + + if (g_contexts[index] == nullptr) { + return -2; + } + + { + std::lock_guard lock(g_mutex); + const int n = audio["length"].as(); + + emscripten::val heap = emscripten::val::module_property("HEAPU8"); + emscripten::val memory = heap["buffer"]; + + g_pcmf32.resize(n); + + emscripten::val memoryView = audio["constructor"].new_(memory, reinterpret_cast(g_pcmf32.data()), n); + memoryView.call("set", audio); + } + + return 0; + })); + + emscripten::function("get_transcribed", emscripten::optional_override([]() { + std::string transcribed; + + { + std::lock_guard lock(g_mutex); + transcribed = std::move(g_transcribed); + } + + return transcribed; + })); + + emscripten::function("get_status", emscripten::optional_override([]() { + std::string status; + + { + std::lock_guard lock(g_mutex); + status = g_status_forced.empty() ? g_status : g_status_forced; + } + + return status; + })); + + emscripten::function("set_status", emscripten::optional_override([](const std::string & status) { + { + std::lock_guard lock(g_mutex); + g_status_forced = status; + } + })); +} diff --git a/whisper.cpp-1.5.2/examples/command.wasm/index-tmpl.html b/whisper.cpp-1.5.2/examples/command.wasm/index-tmpl.html new file mode 100644 index 0000000..9e74012 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command.wasm/index-tmpl.html @@ -0,0 +1,413 @@ + + + + command : Voice assistant example using Whisper + WebAssembly + + + + +
+ command : Voice assistant example using Whisper + WebAssembly + +

+ + You can find more about this project on GitHub. + +

+ + More examples: + main | + bench | + stream | + command | + talk | + +

+ +
+ + Select the model you would like to use, click the "Start" button and follow the instructions. + +

+ +
+ Whisper model: + + +

+ Quantized models:

+ + + + + +
+ +
+ +
+ + + +
+ +
+ +
+ Status: not started + +
[The recognized voice commands will be displayed here]
+
+ +
+ + Debug output: + + +
+ + Troubleshooting + +

+ + The page does some heavy computations, so make sure: + +
    +
  • To use a modern web browser (e.g. Chrome, Firefox)
  • +
  • To use a fast desktop or laptop computer (i.e. not a mobile phone)
  • +
  • Your browser supports WASM Fixed-width SIMD
  • +
+ +
+ + | + Build time: @GIT_DATE@ | + Commit hash: @GIT_SHA1@ | + Commit subject: @GIT_COMMIT_SUBJECT@ | + Source Code | + +
+
+ + + + + + diff --git a/whisper.cpp-1.5.2/examples/command/CMakeLists.txt b/whisper.cpp-1.5.2/examples/command/CMakeLists.txt new file mode 100644 index 0000000..40f278c --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command/CMakeLists.txt @@ -0,0 +1,9 @@ +if (WHISPER_SDL2) + # command + set(TARGET command) + add_executable(${TARGET} command.cpp) + + include(DefaultTargetOptions) + + target_link_libraries(${TARGET} PRIVATE common common-sdl whisper ${CMAKE_THREAD_LIBS_INIT}) +endif () diff --git a/whisper.cpp-1.5.2/examples/command/README.md b/whisper.cpp-1.5.2/examples/command/README.md new file mode 100644 index 0000000..d291d1a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command/README.md @@ -0,0 +1,47 @@ +# command + +This is a basic Voice Assistant example that accepts voice commands from the microphone. +More info is available in [issue #171](https://github.com/ggerganov/whisper.cpp/issues/171). + +```bash +# Run with default arguments and small model +./command -m ./models/ggml-small.en.bin -t 8 + +# On Raspberry Pi, use tiny or base models + "-ac 768" for better performance +./command -m ./models/ggml-tiny.en.bin -ac 768 -t 3 -c 0 +``` + +https://user-images.githubusercontent.com/1991296/204038393-2f846eae-c255-4099-a76d-5735c25c49da.mp4 + +Web version: [examples/command.wasm](/examples/command.wasm) + +## Guided mode + +"Guided mode" allows you to specify a list of commands (i.e. strings) and the transcription will be guided to classify your command into one from the list. This can be useful in situations where a device is listening only for a small subset of commands. + +Initial tests show that this approach might be extremely efficient in terms of performance, since it integrates very well with the "partial Encoder" idea from #137. + +```bash +# Run in guided mode, the list of allowed commands is in commands.txt +./command -m ./models/ggml-base.en.bin -cmd ./examples/command/commands.txt + +# On Raspberry Pi, in guided mode you can use "-ac 128" for extra performance +./command -m ./models/ggml-tiny.en.bin -cmd ./examples/command/commands.txt -ac 128 -t 3 -c 0 +``` + +https://user-images.githubusercontent.com/1991296/207435352-8fc4ed3f-bde5-4555-9b8b-aeeb76bee969.mp4 + + +## Building + +The `command` tool depends on SDL2 library to capture audio from the microphone. You can build it like this: + +```bash +# Install SDL2 on Linux +sudo apt-get install libsdl2-dev + +# Install SDL2 on Mac OS +brew install sdl2 + +make command +``` diff --git a/whisper.cpp-1.5.2/examples/command/command.cpp b/whisper.cpp-1.5.2/examples/command/command.cpp new file mode 100644 index 0000000..51d800a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command/command.cpp @@ -0,0 +1,775 @@ +// Voice assistant example +// +// Speak short text commands to the microphone. +// This program will detect your voice command and convert them to text. +// +// ref: https://github.com/ggerganov/whisper.cpp/issues/171 +// + +#include "common-sdl.h" +#include "common.h" +#include "whisper.h" +#include "grammar-parser.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool file_exists(const std::string & fname) { + std::ifstream f(fname.c_str()); + return f.good(); +} + +// command-line parameters +struct whisper_params { + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t prompt_ms = 5000; + int32_t command_ms = 8000; + int32_t capture_id = -1; + int32_t max_tokens = 32; + int32_t audio_ctx = 0; + + float vad_thold = 0.6f; + float freq_thold = 100.0f; + + float grammar_penalty = 100.0f; + + grammar_parser::parse_state grammar_parsed; + + bool speed_up = false; + bool translate = false; + bool print_special = false; + bool print_energy = false; + bool no_timestamps = true; + bool use_gpu = true; + + std::string language = "en"; + std::string model = "models/ggml-base.en.bin"; + std::string fname_out; + std::string commands; + std::string prompt; + std::string context; + std::string grammar; +}; + +void whisper_print_usage(int argc, char ** argv, const whisper_params & params); + +bool whisper_params_parse(int argc, char ** argv, whisper_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-h" || arg == "--help") { + whisper_print_usage(argc, argv, params); + exit(0); + } + else if (arg == "-t" || arg == "--threads") { params.n_threads = std::stoi(argv[++i]); } + else if (arg == "-pms" || arg == "--prompt-ms") { params.prompt_ms = std::stoi(argv[++i]); } + else if (arg == "-cms" || arg == "--command-ms") { params.command_ms = std::stoi(argv[++i]); } + else if (arg == "-c" || arg == "--capture") { params.capture_id = std::stoi(argv[++i]); } + else if (arg == "-mt" || arg == "--max-tokens") { params.max_tokens = std::stoi(argv[++i]); } + else if (arg == "-ac" || arg == "--audio-ctx") { params.audio_ctx = std::stoi(argv[++i]); } + else if (arg == "-vth" || arg == "--vad-thold") { params.vad_thold = std::stof(argv[++i]); } + else if (arg == "-fth" || arg == "--freq-thold") { params.freq_thold = std::stof(argv[++i]); } + else if (arg == "-su" || arg == "--speed-up") { params.speed_up = true; } + else if (arg == "-tr" || arg == "--translate") { params.translate = true; } + else if (arg == "-ps" || arg == "--print-special") { params.print_special = true; } + else if (arg == "-pe" || arg == "--print-energy") { params.print_energy = true; } + else if (arg == "-ng" || arg == "--no-gpu") { params.use_gpu = false; } + else if (arg == "-l" || arg == "--language") { params.language = argv[++i]; } + else if (arg == "-m" || arg == "--model") { params.model = argv[++i]; } + else if (arg == "-f" || arg == "--file") { params.fname_out = argv[++i]; } + else if (arg == "-cmd" || arg == "--commands") { params.commands = argv[++i]; } + else if (arg == "-p" || arg == "--prompt") { params.prompt = argv[++i]; } + else if (arg == "-ctx" || arg == "--context") { params.context = argv[++i]; } + else if ( arg == "--grammar") { params.grammar = argv[++i]; } + else if ( arg == "--grammar-penalty") { params.grammar_penalty = std::stof(argv[++i]); } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void whisper_print_usage(int /*argc*/, char ** argv, const whisper_params & params) { + fprintf(stderr, "\n"); + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help [default] show this help message and exit\n"); + fprintf(stderr, " -t N, --threads N [%-7d] number of threads to use during computation\n", params.n_threads); + fprintf(stderr, " -pms N, --prompt-ms N [%-7d] prompt duration in milliseconds\n", params.prompt_ms); + fprintf(stderr, " -cms N, --command-ms N [%-7d] command duration in milliseconds\n", params.command_ms); + fprintf(stderr, " -c ID, --capture ID [%-7d] capture device ID\n", params.capture_id); + fprintf(stderr, " -mt N, --max-tokens N [%-7d] maximum number of tokens per audio chunk\n", params.max_tokens); + fprintf(stderr, " -ac N, --audio-ctx N [%-7d] audio context size (0 - all)\n", params.audio_ctx); + fprintf(stderr, " -vth N, --vad-thold N [%-7.2f] voice activity detection threshold\n", params.vad_thold); + fprintf(stderr, " -fth N, --freq-thold N [%-7.2f] high-pass frequency cutoff\n", params.freq_thold); + fprintf(stderr, " -su, --speed-up [%-7s] speed up audio by x2 (reduced accuracy)\n", params.speed_up ? "true" : "false"); + fprintf(stderr, " -tr, --translate [%-7s] translate from source language to english\n", params.translate ? "true" : "false"); + fprintf(stderr, " -ps, --print-special [%-7s] print special tokens\n", params.print_special ? "true" : "false"); + fprintf(stderr, " -pe, --print-energy [%-7s] print sound energy (for debugging)\n", params.print_energy ? "true" : "false"); + fprintf(stderr, " -ng, --no-gpu [%-7s] disable GPU\n", params.use_gpu ? "false" : "true"); + fprintf(stderr, " -l LANG, --language LANG [%-7s] spoken language\n", params.language.c_str()); + fprintf(stderr, " -m FNAME, --model FNAME [%-7s] model path\n", params.model.c_str()); + fprintf(stderr, " -f FNAME, --file FNAME [%-7s] text output file name\n", params.fname_out.c_str()); + fprintf(stderr, " -cmd FNAME, --commands FNAME [%-7s] text file with allowed commands\n", params.commands.c_str()); + fprintf(stderr, " -p, --prompt [%-7s] the required activation prompt\n", params.prompt.c_str()); + fprintf(stderr, " -ctx, --context [%-7s] sample text to help the transcription\n", params.context.c_str()); + fprintf(stderr, " --grammar GRAMMAR [%-7s] GBNF grammar to guide decoding\n", params.grammar.c_str()); + fprintf(stderr, " --grammar-penalty N [%-7.1f] scales down logits of nongrammar tokens\n", params.grammar_penalty); + fprintf(stderr, "\n"); +} + +std::string transcribe( + whisper_context * ctx, + const whisper_params & params, + const std::vector & pcmf32, + const std::string & grammar_rule, + float & logprob_min, + float & logprob_sum, + int & n_tokens, + int64_t & t_ms) { + const auto t_start = std::chrono::high_resolution_clock::now(); + + logprob_min = 0.0f; + logprob_sum = 0.0f; + n_tokens = 0; + t_ms = 0; + + //whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_BEAM_SEARCH); + + wparams.print_progress = false; + wparams.print_special = params.print_special; + wparams.print_realtime = false; + wparams.print_timestamps = !params.no_timestamps; + wparams.translate = params.translate; + wparams.no_context = true; + wparams.no_timestamps = params.no_timestamps; + wparams.single_segment = true; + wparams.max_tokens = params.max_tokens; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + + wparams.audio_ctx = params.audio_ctx; + wparams.speed_up = params.speed_up; + + wparams.temperature = 0.4f; + wparams.temperature_inc = 1.0f; + wparams.greedy.best_of = 5; + + wparams.beam_search.beam_size = 5; + + wparams.initial_prompt = params.context.data(); + + const auto & grammar_parsed = params.grammar_parsed; + auto grammar_rules = grammar_parsed.c_rules(); + + if (!params.grammar_parsed.rules.empty() && !grammar_rule.empty()) { + if (grammar_parsed.symbol_ids.find(grammar_rule) == grammar_parsed.symbol_ids.end()) { + fprintf(stderr, "%s: warning: grammar rule '%s' not found - skipping grammar sampling\n", __func__, grammar_rule.c_str()); + } else { + wparams.grammar_rules = grammar_rules.data(); + wparams.n_grammar_rules = grammar_rules.size(); + wparams.i_start_rule = grammar_parsed.symbol_ids.at(grammar_rule); + wparams.grammar_penalty = params.grammar_penalty; + } + } + + if (whisper_full(ctx, wparams, pcmf32.data(), pcmf32.size()) != 0) { + return ""; + } + + std::string result; + + const int n_segments = whisper_full_n_segments(ctx); + for (int i = 0; i < n_segments; ++i) { + const char * text = whisper_full_get_segment_text(ctx, i); + + result += text; + + const int n = whisper_full_n_tokens(ctx, i); + for (int j = 0; j < n; ++j) { + const auto token = whisper_full_get_token_data(ctx, i, j); + + if(token.plog > 0.0f) exit(0); + logprob_min = std::min(logprob_min, token.plog); + logprob_sum += token.plog; + ++n_tokens; + } + } + + const auto t_end = std::chrono::high_resolution_clock::now(); + t_ms = std::chrono::duration_cast(t_end - t_start).count(); + + return result; +} + +std::vector read_allowed_commands(const std::string & fname) { + std::vector allowed_commands; + + std::ifstream ifs(fname); + if (!ifs.is_open()) { + return allowed_commands; + } + + std::string line; + while (std::getline(ifs, line)) { + line = ::trim(line); + if (line.empty()) { + continue; + } + + std::transform(line.begin(), line.end(),line.begin(), ::tolower); + allowed_commands.push_back(std::move(line)); + } + + return allowed_commands; +} + +std::vector get_words(const std::string &txt) { + std::vector words; + + std::istringstream iss(txt); + std::string word; + while (iss >> word) { + words.push_back(word); + } + + return words; +} + +// command-list mode +// guide the transcription to match the most likely command from a provided list +int process_command_list(struct whisper_context * ctx, audio_async &audio, const whisper_params ¶ms) { + fprintf(stderr, "\n"); + fprintf(stderr, "%s: guided mode\n", __func__); + + std::vector allowed_commands = read_allowed_commands(params.commands); + + if (allowed_commands.empty()) { + fprintf(stderr, "%s: error: failed to read allowed commands from '%s'\n", __func__, params.commands.c_str()); + return 2; + } + + int max_len = 0; + + std::vector> allowed_tokens; + + for (const auto & cmd : allowed_commands) { + whisper_token tokens[1024]; + allowed_tokens.emplace_back(); + + for (int l = 0; l < (int) cmd.size(); ++l) { + // NOTE: very important to add the whitespace ! + // the reason is that the first decoded token starts with a whitespace too! + std::string ss = std::string(" ") + cmd.substr(0, l + 1); + + const int n = whisper_tokenize(ctx, ss.c_str(), tokens, 1024); + if (n < 0) { + fprintf(stderr, "%s: error: failed to tokenize command '%s'\n", __func__, cmd.c_str()); + return 3; + } + + if (n == 1) { + allowed_tokens.back().push_back(tokens[0]); + } + } + + max_len = std::max(max_len, (int) cmd.size()); + } + + fprintf(stderr, "%s: allowed commands [ tokens ]:\n", __func__); + fprintf(stderr, "\n"); + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + fprintf(stderr, " - \033[1m%-*s\033[0m = [", max_len, allowed_commands[i].c_str()); + for (const auto & token : allowed_tokens[i]) { + fprintf(stderr, " %5d", token); + } + fprintf(stderr, " ]\n"); + } + + std::string k_prompt = "select one from the available words: "; + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + if (i > 0) { + k_prompt += ", "; + } + k_prompt += allowed_commands[i]; + } + k_prompt += ". selected word: "; + + // tokenize prompt + std::vector k_tokens; + { + k_tokens.resize(1024); + const int n = whisper_tokenize(ctx, k_prompt.c_str(), k_tokens.data(), 1024); + if (n < 0) { + fprintf(stderr, "%s: error: failed to tokenize prompt '%s'\n", __func__, k_prompt.c_str()); + return 4; + } + k_tokens.resize(n); + } + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: prompt: '%s'\n", __func__, k_prompt.c_str()); + fprintf(stderr, "%s: tokens: [", __func__); + for (const auto & token : k_tokens) { + fprintf(stderr, " %d", token); + } + fprintf(stderr, " ]\n"); + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: listening for a command ...\n", __func__); + fprintf(stderr, "\n"); + + bool is_running = true; + + std::vector pcmf32_cur; + std::vector pcmf32_prompt; + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + const auto t_start = std::chrono::high_resolution_clock::now(); + + whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY); + + wparams.print_progress = false; + wparams.print_special = params.print_special; + wparams.print_realtime = false; + wparams.print_timestamps = !params.no_timestamps; + wparams.translate = params.translate; + wparams.no_context = true; + wparams.single_segment = true; + wparams.max_tokens = 1; + wparams.language = params.language.c_str(); + wparams.n_threads = params.n_threads; + + wparams.audio_ctx = params.audio_ctx; + wparams.speed_up = params.speed_up; + + wparams.prompt_tokens = k_tokens.data(); + wparams.prompt_n_tokens = k_tokens.size(); + + // run the transformer and a single decoding pass + if (whisper_full(ctx, wparams, pcmf32_cur.data(), pcmf32_cur.size()) != 0) { + fprintf(stderr, "%s: ERROR: whisper_full() failed\n", __func__); + break; + } + + // estimate command probability + // NOTE: not optimal + { + const auto * logits = whisper_get_logits(ctx); + + std::vector probs(whisper_n_vocab(ctx), 0.0f); + + // compute probs from logits via softmax + { + float max = -1e9; + for (int i = 0; i < (int) probs.size(); ++i) { + max = std::max(max, logits[i]); + } + + float sum = 0.0f; + for (int i = 0; i < (int) probs.size(); ++i) { + probs[i] = expf(logits[i] - max); + sum += probs[i]; + } + + for (int i = 0; i < (int) probs.size(); ++i) { + probs[i] /= sum; + } + } + + std::vector> probs_id; + + double psum = 0.0; + for (int i = 0; i < (int) allowed_commands.size(); ++i) { + probs_id.emplace_back(probs[allowed_tokens[i][0]], i); + for (int j = 1; j < (int) allowed_tokens[i].size(); ++j) { + probs_id.back().first += probs[allowed_tokens[i][j]]; + } + probs_id.back().first /= allowed_tokens[i].size(); + psum += probs_id.back().first; + } + + // normalize + for (auto & p : probs_id) { + p.first /= psum; + } + + // sort descending + { + using pair_type = decltype(probs_id)::value_type; + std::sort(probs_id.begin(), probs_id.end(), [](const pair_type & a, const pair_type & b) { + return a.first > b.first; + }); + } + + // print the commands and the respective probabilities + { + fprintf(stdout, "\n"); + for (const auto & cmd : probs_id) { + fprintf(stdout, "%s: %s%-*s%s = %f | ", __func__, "\033[1m", max_len, allowed_commands[cmd.second].c_str(), "\033[0m", cmd.first); + for (int token : allowed_tokens[cmd.second]) { + fprintf(stdout, "'%4s' %f ", whisper_token_to_str(ctx, token), probs[token]); + } + fprintf(stdout, "\n"); + } + } + + // best command + { + const auto t_end = std::chrono::high_resolution_clock::now(); + + const float prob = probs_id[0].first; + const int index = probs_id[0].second; + + fprintf(stdout, "\n"); + fprintf(stdout, "%s: detected command: %s%s%s | p = %f | t = %d ms\n", __func__, + "\033[1m", allowed_commands[index].c_str(), "\033[0m", prob, + (int) std::chrono::duration_cast(t_end - t_start).count()); + fprintf(stdout, "\n"); + } + } + + audio.clear(); + } + } + + return 0; +} + +// always-prompt mode +// transcribe the voice into text after valid prompt +int always_prompt_transcription(struct whisper_context * ctx, audio_async & audio, const whisper_params & params) { + bool is_running = true; + bool ask_prompt = true; + + float logprob_min = 0.0f; + float logprob_sum = 0.0f; + int n_tokens = 0; + + std::vector pcmf32_cur; + + const std::string k_prompt = params.prompt; + + const int k_prompt_length = get_words(k_prompt).size(); + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: always-prompt mode\n", __func__); + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if (ask_prompt) { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: The prompt is: '%s%s%s'\n", __func__, "\033[1m", k_prompt.c_str(), "\033[0m"); + fprintf(stdout, "\n"); + + ask_prompt = false; + } + + { + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + int64_t t_ms = 0; + + // detect the commands + audio.get(params.command_ms, pcmf32_cur); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "", logprob_min, logprob_sum, n_tokens, t_ms)); + + const auto words = get_words(txt); + + std::string prompt; + std::string command; + + for (int i = 0; i < (int) words.size(); ++i) { + if (i < k_prompt_length) { + prompt += words[i] + " "; + } else { + command += words[i] + " "; + } + } + + const float sim = similarity(prompt, k_prompt); + + //debug + //fprintf(stdout, "command size: %i\n", command_length); + + if ((sim > 0.7f) && (command.size() > 0)) { + fprintf(stdout, "%s: Command '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", command.c_str(), "\033[0m", (int) t_ms); + } + + fprintf(stdout, "\n"); + + audio.clear(); + } + } + } + + return 0; +} + +// general-purpose mode +// freely transcribe the voice into text +int process_general_transcription(struct whisper_context * ctx, audio_async & audio, const whisper_params & params) { + bool is_running = true; + bool have_prompt = false; + bool ask_prompt = true; + + float logprob_min0 = 0.0f; + float logprob_min = 0.0f; + + float logprob_sum0 = 0.0f; + float logprob_sum = 0.0f; + + int n_tokens0 = 0; + int n_tokens = 0; + + std::vector pcmf32_cur; + std::vector pcmf32_prompt; + + std::string k_prompt = "Ok Whisper, start listening for commands."; + if (!params.prompt.empty()) { + k_prompt = params.prompt; + } + + fprintf(stderr, "\n"); + fprintf(stderr, "%s: general-purpose mode\n", __func__); + + // main loop + while (is_running) { + // handle Ctrl + C + is_running = sdl_poll_events(); + + // delay + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + if (ask_prompt) { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: Say the following phrase: '%s%s%s'\n", __func__, "\033[1m", k_prompt.c_str(), "\033[0m"); + fprintf(stdout, "\n"); + + ask_prompt = false; + } + + { + audio.get(2000, pcmf32_cur); + + if (::vad_simple(pcmf32_cur, WHISPER_SAMPLE_RATE, 1000, params.vad_thold, params.freq_thold, params.print_energy)) { + fprintf(stdout, "%s: Speech detected! Processing ...\n", __func__); + + int64_t t_ms = 0; + + if (!have_prompt) { + // wait for activation phrase + audio.get(params.prompt_ms, pcmf32_cur); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "prompt", logprob_min0, logprob_sum0, n_tokens0, t_ms)); + + const float p = 100.0f * std::exp(logprob_min0); + + fprintf(stdout, "%s: Heard '%s%s%s', (t = %d ms, p = %.2f%%)\n", __func__, "\033[1m", txt.c_str(), "\033[0m", (int) t_ms, p); + + const float sim = similarity(txt, k_prompt); + + if (txt.length() < 0.8*k_prompt.length() || txt.length() > 1.2*k_prompt.length() || sim < 0.8f) { + fprintf(stdout, "%s: WARNING: prompt not recognized, try again\n", __func__); + ask_prompt = true; + } else { + fprintf(stdout, "\n"); + fprintf(stdout, "%s: The prompt has been recognized!\n", __func__); + fprintf(stdout, "%s: Waiting for voice commands ...\n", __func__); + fprintf(stdout, "\n"); + + // save the audio for the prompt + pcmf32_prompt = pcmf32_cur; + have_prompt = true; + } + } else { + // we have heard the activation phrase, now detect the commands + audio.get(params.command_ms, pcmf32_cur); + + //printf("len prompt: %.4f\n", pcmf32_prompt.size() / (float) WHISPER_SAMPLE_RATE); + //printf("len command: %.4f\n", pcmf32_cur.size() / (float) WHISPER_SAMPLE_RATE); + + // prepend 3 second of silence + pcmf32_cur.insert(pcmf32_cur.begin(), 3.0f*WHISPER_SAMPLE_RATE, 0.0f); + + // prepend the prompt audio + pcmf32_cur.insert(pcmf32_cur.begin(), pcmf32_prompt.begin(), pcmf32_prompt.end()); + + const auto txt = ::trim(::transcribe(ctx, params, pcmf32_cur, "root", logprob_min, logprob_sum, n_tokens, t_ms)); + + //const float p = 100.0f * std::exp((logprob - logprob0) / (n_tokens - n_tokens0)); + const float p = 100.0f * std::exp(logprob_min); + + //fprintf(stdout, "%s: heard '%s'\n", __func__, txt.c_str()); + + // find the prompt in the text + float best_sim = 0.0f; + size_t best_len = 0; + for (size_t n = 0.8*k_prompt.size(); n <= 1.2*k_prompt.size(); ++n) { + if (n >= txt.size()) { + break; + } + + const auto prompt = txt.substr(0, n); + + const float sim = similarity(prompt, k_prompt); + + //fprintf(stderr, "%s: prompt = '%s', sim = %f\n", __func__, prompt.c_str(), sim); + + if (sim > best_sim) { + best_sim = sim; + best_len = n; + } + } + + fprintf(stdout, "%s: DEBUG: txt = '%s', prob = %.2f%%\n", __func__, txt.c_str(), p); + if (best_len == 0) { + fprintf(stdout, "%s: WARNING: command not recognized, try again\n", __func__); + } else { + // cut the prompt from the decoded text + const std::string command = ::trim(txt.substr(best_len)); + + fprintf(stdout, "%s: Command '%s%s%s', (t = %d ms)\n", __func__, "\033[1m", command.c_str(), "\033[0m", (int) t_ms); + } + + fprintf(stdout, "\n"); + } + + audio.clear(); + } + } + } + + return 0; +} + +int main(int argc, char ** argv) { + whisper_params params; + + if (whisper_params_parse(argc, argv, params) == false) { + return 1; + } + + if (whisper_lang_id(params.language.c_str()) == -1) { + fprintf(stderr, "error: unknown language '%s'\n", params.language.c_str()); + whisper_print_usage(argc, argv, params); + exit(0); + } + + // whisper init + + struct whisper_context_params cparams; + cparams.use_gpu = params.use_gpu; + + struct whisper_context * ctx = whisper_init_from_file_with_params(params.model.c_str(), cparams); + + // print some info about the processing + { + fprintf(stderr, "\n"); + if (!whisper_is_multilingual(ctx)) { + if (params.language != "en" || params.translate) { + params.language = "en"; + params.translate = false; + fprintf(stderr, "%s: WARNING: model is not multilingual, ignoring language and translation options\n", __func__); + } + } + fprintf(stderr, "%s: processing, %d threads, lang = %s, task = %s, timestamps = %d ...\n", + __func__, + params.n_threads, + params.language.c_str(), + params.translate ? "translate" : "transcribe", + params.no_timestamps ? 0 : 1); + + fprintf(stderr, "\n"); + } + + // init audio + + audio_async audio(30*1000); + if (!audio.init(params.capture_id, WHISPER_SAMPLE_RATE)) { + fprintf(stderr, "%s: audio.init() failed!\n", __func__); + return 1; + } + + audio.resume(); + + // wait for 1 second to avoid any buffered noise + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + audio.clear(); + + int ret_val = 0; + + if (!params.grammar.empty()) { + auto & grammar = params.grammar_parsed; + if (file_exists(params.grammar.c_str())) { + // read grammar from file + std::ifstream ifs(params.grammar.c_str()); + const std::string txt = std::string((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); + grammar = grammar_parser::parse(txt.c_str()); + } else { + // read grammar from string + grammar = grammar_parser::parse(params.grammar.c_str()); + } + + // will be empty (default) if there are parse errors + if (grammar.rules.empty()) { + ret_val = 1; + } else { + fprintf(stderr, "%s: grammar:\n", __func__); + grammar_parser::print_grammar(stderr, grammar); + fprintf(stderr, "\n"); + } + } + + if (ret_val == 0) { + if (!params.commands.empty()) { + ret_val = process_command_list(ctx, audio, params); + } else if (!params.prompt.empty() && params.grammar_parsed.rules.empty()) { + ret_val = always_prompt_transcription(ctx, audio, params); + } else { + ret_val = process_general_transcription(ctx, audio, params); + } + } + + audio.pause(); + + whisper_print_timings(ctx); + whisper_free(ctx); + + return ret_val; +} diff --git a/whisper.cpp-1.5.2/examples/command/commands.txt b/whisper.cpp-1.5.2/examples/command/commands.txt new file mode 100644 index 0000000..2653de6 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/command/commands.txt @@ -0,0 +1,9 @@ +enable +disable +cat +dog +apple +red +blue +green +lightblue diff --git a/whisper.cpp-1.5.2/examples/common-ggml.cpp b/whisper.cpp-1.5.2/examples/common-ggml.cpp new file mode 100644 index 0000000..e69bd51 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common-ggml.cpp @@ -0,0 +1,239 @@ +#include "common-ggml.h" + +#include +#include + +static const std::map GGML_FTYPE_MAP = { + {"q4_0", GGML_FTYPE_MOSTLY_Q4_0}, + {"q4_1", GGML_FTYPE_MOSTLY_Q4_1}, + {"q5_0", GGML_FTYPE_MOSTLY_Q5_0}, + {"q5_1", GGML_FTYPE_MOSTLY_Q5_1}, + {"q8_0", GGML_FTYPE_MOSTLY_Q8_0}, + {"q2_k", GGML_FTYPE_MOSTLY_Q2_K}, + {"q3_k", GGML_FTYPE_MOSTLY_Q3_K}, + {"q4_k", GGML_FTYPE_MOSTLY_Q4_K}, + {"q5_k", GGML_FTYPE_MOSTLY_Q5_K}, + {"q6_k", GGML_FTYPE_MOSTLY_Q6_K}, +}; + +void ggml_print_ftypes(FILE * fp) { + for (auto it = GGML_FTYPE_MAP.begin(); it != GGML_FTYPE_MAP.end(); it++) { + fprintf(fp, " type = \"%s\" or %d\n", it->first.c_str(), it->second); + } +} + +enum ggml_ftype ggml_parse_ftype(const char * str) { + enum ggml_ftype ftype; + if (str[0] == 'q') { + const auto it = GGML_FTYPE_MAP.find(str); + if (it == GGML_FTYPE_MAP.end()) { + fprintf(stderr, "%s: unknown ftype '%s'\n", __func__, str); + return GGML_FTYPE_UNKNOWN; + } + ftype = it->second; + } else { + ftype = (enum ggml_ftype) atoi(str); + } + + return ftype; +} + +bool ggml_common_quantize_0( + std::ifstream & finp, + std::ofstream & fout, + const ggml_ftype ftype, + const std::vector & to_quant, + const std::vector & to_skip) { + + ggml_type qtype = GGML_TYPE_F32; + + switch (ftype) { + case GGML_FTYPE_MOSTLY_Q4_0: qtype = GGML_TYPE_Q4_0; break; + case GGML_FTYPE_MOSTLY_Q4_1: qtype = GGML_TYPE_Q4_1; break; + case GGML_FTYPE_MOSTLY_Q5_0: qtype = GGML_TYPE_Q5_0; break; + case GGML_FTYPE_MOSTLY_Q5_1: qtype = GGML_TYPE_Q5_1; break; + case GGML_FTYPE_MOSTLY_Q8_0: qtype = GGML_TYPE_Q8_0; break; + case GGML_FTYPE_MOSTLY_Q2_K: qtype = GGML_TYPE_Q2_K; break; + case GGML_FTYPE_MOSTLY_Q3_K: qtype = GGML_TYPE_Q3_K; break; + case GGML_FTYPE_MOSTLY_Q4_K: qtype = GGML_TYPE_Q4_K; break; + case GGML_FTYPE_MOSTLY_Q5_K: qtype = GGML_TYPE_Q5_K; break; + case GGML_FTYPE_MOSTLY_Q6_K: qtype = GGML_TYPE_Q6_K; break; + case GGML_FTYPE_UNKNOWN: + case GGML_FTYPE_ALL_F32: + case GGML_FTYPE_MOSTLY_F16: + case GGML_FTYPE_MOSTLY_Q4_1_SOME_F16: + { + fprintf(stderr, "%s: invalid model type %d\n", __func__, ftype); + return false; + } + }; + + if (!ggml_is_quantized(qtype)) { + fprintf(stderr, "%s: invalid quantization type %d (%s)\n", __func__, qtype, ggml_type_name(qtype)); + return false; + } + + size_t total_size_org = 0; + size_t total_size_new = 0; + + std::vector work; + + std::vector data_u8; + std::vector data_f16; + std::vector data_f32; + + std::vector hist_all(1 << 4, 0); + + while (true) { + int32_t n_dims; + int32_t length; + int32_t ttype; + + finp.read(reinterpret_cast(&n_dims), sizeof(n_dims)); + finp.read(reinterpret_cast(&length), sizeof(length)); + finp.read(reinterpret_cast(&ttype), sizeof(ttype)); + + if (finp.eof()) { + break; + } + + int32_t nelements = 1; + int32_t ne[4] = { 1, 1, 1, 1 }; + for (int i = 0; i < n_dims; ++i) { + finp.read (reinterpret_cast(&ne[i]), sizeof(ne[i])); + nelements *= ne[i]; + } + + std::string name(length, 0); + finp.read (&name[0], length); + + printf("%64s - [%5d, %5d, %5d], type = %6s ", name.data(), ne[0], ne[1], ne[2], ggml_type_name((ggml_type) ttype)); + + bool quantize = false; + + // check if we should quantize this tensor + for (const auto & s : to_quant) { + if (std::regex_match(name, std::regex(s))) { + quantize = true; + break; + } + } + + // check if we should skip this tensor + for (const auto & s : to_skip) { + if (std::regex_match(name, std::regex(s))) { + quantize = false; + break; + } + } + + // quantize only 2D tensors + quantize &= (n_dims == 2); + + if (quantize) { + if (ttype != GGML_TYPE_F32 && ttype != GGML_TYPE_F16) { + fprintf(stderr, "%s: unsupported ttype %d (%s) for integer quantization\n", __func__, ttype, ggml_type_name((ggml_type) ttype)); + return false; + } + + if (ttype == GGML_TYPE_F16) { + data_f16.resize(nelements); + finp.read(reinterpret_cast(data_f16.data()), nelements * sizeof(ggml_fp16_t)); + data_f32.resize(nelements); + for (int i = 0; i < nelements; ++i) { + data_f32[i] = ggml_fp16_to_fp32(data_f16[i]); + } + } else { + data_f32.resize(nelements); + finp.read(reinterpret_cast(data_f32.data()), nelements * sizeof(float)); + } + + ttype = qtype; + } else { + const int bpe = (ttype == 0) ? sizeof(float) : sizeof(uint16_t); + + data_u8.resize(nelements*bpe); + finp.read(reinterpret_cast(data_u8.data()), nelements * bpe); + } + + fout.write(reinterpret_cast(&n_dims), sizeof(n_dims)); + fout.write(reinterpret_cast(&length), sizeof(length)); + fout.write(reinterpret_cast(&ttype), sizeof(ttype)); + for (int i = 0; i < n_dims; ++i) { + fout.write(reinterpret_cast(&ne[i]), sizeof(ne[i])); + } + fout.write(&name[0], length); + + if (quantize) { + work.resize(nelements); // for quantization + + size_t cur_size = 0; + std::vector hist_cur(1 << 4, 0); + + switch ((ggml_type) ttype) { + case GGML_TYPE_Q4_0: + case GGML_TYPE_Q4_1: + case GGML_TYPE_Q5_0: + case GGML_TYPE_Q5_1: + case GGML_TYPE_Q8_0: + case GGML_TYPE_Q2_K: + case GGML_TYPE_Q3_K: + case GGML_TYPE_Q4_K: + case GGML_TYPE_Q5_K: + case GGML_TYPE_Q6_K: + { + cur_size = ggml_quantize_chunk((ggml_type) ttype, data_f32.data(), work.data(), 0, nelements, hist_cur.data()); + } break; + case GGML_TYPE_F32: + case GGML_TYPE_F16: + case GGML_TYPE_I8: + case GGML_TYPE_I16: + case GGML_TYPE_I32: + case GGML_TYPE_Q8_1: + case GGML_TYPE_Q8_K: + case GGML_TYPE_COUNT: + { + fprintf(stderr, "%s: unsupported quantization type %d (%s)\n", __func__, ttype, ggml_type_name((ggml_type) ttype)); + return false; + } + } + + fout.write(reinterpret_cast(work.data()), cur_size); + total_size_new += cur_size; + + printf("size = %8.2f MB -> %8.2f MB | hist: ", nelements * sizeof(float)/1024.0/1024.0, cur_size/1024.0/1024.0); + for (int i = 0; i < (int) hist_cur.size(); ++i) { + hist_all[i] += hist_cur[i]; + } + + for (int i = 0; i < (int) hist_cur.size(); ++i) { + printf("%5.3f ", hist_cur[i] / (float)nelements); + } + printf("\n"); + } else { + printf("size = %8.3f MB\n", data_u8.size()/1024.0/1024.0); + fout.write(reinterpret_cast(data_u8.data()), data_u8.size()); + total_size_new += data_u8.size(); + } + + total_size_org += nelements * sizeof(float); + } + + printf("%s: model size = %8.2f MB\n", __func__, total_size_org/1024.0/1024.0); + printf("%s: quant size = %8.2f MB | ftype = %d (%s)\n", __func__, total_size_new/1024.0/1024.0, ftype, ggml_type_name(qtype)); + + { + int64_t sum_all = 0; + for (int i = 0; i < (int) hist_all.size(); ++i) { + sum_all += hist_all[i]; + } + + printf("%s: hist: ", __func__); + for (int i = 0; i < (int) hist_all.size(); ++i) { + printf("%5.3f ", hist_all[i] / (float)sum_all); + } + printf("\n"); + } + + return true; +} diff --git a/whisper.cpp-1.5.2/examples/common-ggml.h b/whisper.cpp-1.5.2/examples/common-ggml.h new file mode 100644 index 0000000..477de34 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common-ggml.h @@ -0,0 +1,18 @@ +#pragma once + +#include "ggml.h" + +#include +#include +#include + +enum ggml_ftype ggml_parse_ftype(const char * str); + +void ggml_print_ftypes(FILE * fp = stderr); + +bool ggml_common_quantize_0( + std::ifstream & finp, + std::ofstream & fout, + const ggml_ftype ftype, + const std::vector & to_quant, + const std::vector & to_skip); diff --git a/whisper.cpp-1.5.2/examples/common-sdl.cpp b/whisper.cpp-1.5.2/examples/common-sdl.cpp new file mode 100644 index 0000000..5fc28e5 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common-sdl.cpp @@ -0,0 +1,229 @@ +#include "common-sdl.h" + +audio_async::audio_async(int len_ms) { + m_len_ms = len_ms; + + m_running = false; +} + +audio_async::~audio_async() { + if (m_dev_id_in) { + SDL_CloseAudioDevice(m_dev_id_in); + } +} + +bool audio_async::init(int capture_id, int sample_rate) { + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); + + if (SDL_Init(SDL_INIT_AUDIO) < 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); + return false; + } + + SDL_SetHintWithPriority(SDL_HINT_AUDIO_RESAMPLING_MODE, "medium", SDL_HINT_OVERRIDE); + + { + int nDevices = SDL_GetNumAudioDevices(SDL_TRUE); + fprintf(stderr, "%s: found %d capture devices:\n", __func__, nDevices); + for (int i = 0; i < nDevices; i++) { + fprintf(stderr, "%s: - Capture device #%d: '%s'\n", __func__, i, SDL_GetAudioDeviceName(i, SDL_TRUE)); + } + } + + SDL_AudioSpec capture_spec_requested; + SDL_AudioSpec capture_spec_obtained; + + SDL_zero(capture_spec_requested); + SDL_zero(capture_spec_obtained); + + capture_spec_requested.freq = sample_rate; + capture_spec_requested.format = AUDIO_F32; + capture_spec_requested.channels = 1; + capture_spec_requested.samples = 1024; + capture_spec_requested.callback = [](void * userdata, uint8_t * stream, int len) { + audio_async * audio = (audio_async *) userdata; + audio->callback(stream, len); + }; + capture_spec_requested.userdata = this; + + if (capture_id >= 0) { + fprintf(stderr, "%s: attempt to open capture device %d : '%s' ...\n", __func__, capture_id, SDL_GetAudioDeviceName(capture_id, SDL_TRUE)); + m_dev_id_in = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(capture_id, SDL_TRUE), SDL_TRUE, &capture_spec_requested, &capture_spec_obtained, 0); + } else { + fprintf(stderr, "%s: attempt to open default capture device ...\n", __func__); + m_dev_id_in = SDL_OpenAudioDevice(nullptr, SDL_TRUE, &capture_spec_requested, &capture_spec_obtained, 0); + } + + if (!m_dev_id_in) { + fprintf(stderr, "%s: couldn't open an audio device for capture: %s!\n", __func__, SDL_GetError()); + m_dev_id_in = 0; + + return false; + } else { + fprintf(stderr, "%s: obtained spec for input device (SDL Id = %d):\n", __func__, m_dev_id_in); + fprintf(stderr, "%s: - sample rate: %d\n", __func__, capture_spec_obtained.freq); + fprintf(stderr, "%s: - format: %d (required: %d)\n", __func__, capture_spec_obtained.format, + capture_spec_requested.format); + fprintf(stderr, "%s: - channels: %d (required: %d)\n", __func__, capture_spec_obtained.channels, + capture_spec_requested.channels); + fprintf(stderr, "%s: - samples per frame: %d\n", __func__, capture_spec_obtained.samples); + } + + m_sample_rate = capture_spec_obtained.freq; + + m_audio.resize((m_sample_rate*m_len_ms)/1000); + + return true; +} + +bool audio_async::resume() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to resume!\n", __func__); + return false; + } + + if (m_running) { + fprintf(stderr, "%s: already running!\n", __func__); + return false; + } + + SDL_PauseAudioDevice(m_dev_id_in, 0); + + m_running = true; + + return true; +} + +bool audio_async::pause() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to pause!\n", __func__); + return false; + } + + if (!m_running) { + fprintf(stderr, "%s: already paused!\n", __func__); + return false; + } + + SDL_PauseAudioDevice(m_dev_id_in, 1); + + m_running = false; + + return true; +} + +bool audio_async::clear() { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to clear!\n", __func__); + return false; + } + + if (!m_running) { + fprintf(stderr, "%s: not running!\n", __func__); + return false; + } + + { + std::lock_guard lock(m_mutex); + + m_audio_pos = 0; + m_audio_len = 0; + } + + return true; +} + +// callback to be called by SDL +void audio_async::callback(uint8_t * stream, int len) { + if (!m_running) { + return; + } + + size_t n_samples = len / sizeof(float); + + if (n_samples > m_audio.size()) { + n_samples = m_audio.size(); + + stream += (len - (n_samples * sizeof(float))); + } + + //fprintf(stderr, "%s: %zu samples, pos %zu, len %zu\n", __func__, n_samples, m_audio_pos, m_audio_len); + + { + std::lock_guard lock(m_mutex); + + if (m_audio_pos + n_samples > m_audio.size()) { + const size_t n0 = m_audio.size() - m_audio_pos; + + memcpy(&m_audio[m_audio_pos], stream, n0 * sizeof(float)); + memcpy(&m_audio[0], stream + n0 * sizeof(float), (n_samples - n0) * sizeof(float)); + + m_audio_pos = (m_audio_pos + n_samples) % m_audio.size(); + m_audio_len = m_audio.size(); + } else { + memcpy(&m_audio[m_audio_pos], stream, n_samples * sizeof(float)); + + m_audio_pos = (m_audio_pos + n_samples) % m_audio.size(); + m_audio_len = std::min(m_audio_len + n_samples, m_audio.size()); + } + } +} + +void audio_async::get(int ms, std::vector & result) { + if (!m_dev_id_in) { + fprintf(stderr, "%s: no audio device to get audio from!\n", __func__); + return; + } + + if (!m_running) { + fprintf(stderr, "%s: not running!\n", __func__); + return; + } + + result.clear(); + + { + std::lock_guard lock(m_mutex); + + if (ms <= 0) { + ms = m_len_ms; + } + + size_t n_samples = (m_sample_rate * ms) / 1000; + if (n_samples > m_audio_len) { + n_samples = m_audio_len; + } + + result.resize(n_samples); + + int s0 = m_audio_pos - n_samples; + if (s0 < 0) { + s0 += m_audio.size(); + } + + if (s0 + n_samples > m_audio.size()) { + const size_t n0 = m_audio.size() - s0; + + memcpy(result.data(), &m_audio[s0], n0 * sizeof(float)); + memcpy(&result[n0], &m_audio[0], (n_samples - n0) * sizeof(float)); + } else { + memcpy(result.data(), &m_audio[s0], n_samples * sizeof(float)); + } + } +} + +bool sdl_poll_events() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + { + return false; + } break; + default: + break; + } + } + + return true; +} diff --git a/whisper.cpp-1.5.2/examples/common-sdl.h b/whisper.cpp-1.5.2/examples/common-sdl.h new file mode 100644 index 0000000..9ee8a32 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common-sdl.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +// +// SDL Audio capture +// + +class audio_async { +public: + audio_async(int len_ms); + ~audio_async(); + + bool init(int capture_id, int sample_rate); + + // start capturing audio via the provided SDL callback + // keep last len_ms seconds of audio in a circular buffer + bool resume(); + bool pause(); + bool clear(); + + // callback to be called by SDL + void callback(uint8_t * stream, int len); + + // get audio data from the circular buffer + void get(int ms, std::vector & audio); + +private: + SDL_AudioDeviceID m_dev_id_in = 0; + + int m_len_ms = 0; + int m_sample_rate = 0; + + std::atomic_bool m_running; + std::mutex m_mutex; + + std::vector m_audio; + size_t m_audio_pos = 0; + size_t m_audio_len = 0; +}; + +// Return false if need to quit +bool sdl_poll_events(); diff --git a/whisper.cpp-1.5.2/examples/common.cpp b/whisper.cpp-1.5.2/examples/common.cpp new file mode 100644 index 0000000..603c655 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common.cpp @@ -0,0 +1,817 @@ +#define _USE_MATH_DEFINES // for M_PI + +#include "common.h" + +// third-party utilities +// use your favorite implementations +#define DR_WAV_IMPLEMENTATION +#include "dr_wav.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#pragma warning(disable: 4244 4267) // possible loss of data +#endif + +// Function to check if the next argument exists +std::string get_next_arg(int& i, int argc, char** argv, const std::string& flag, gpt_params& params) { + if (i + 1 < argc && argv[i + 1][0] != '-') { + return argv[++i]; + } else { + fprintf(stderr, "error: %s requires one argument.\n", flag.c_str()); + gpt_print_usage(argc, argv, params); + exit(0); + } +} + +bool gpt_params_parse(int argc, char ** argv, gpt_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-s" || arg == "--seed") { + params.seed = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-t" || arg == "--threads") { + params.n_threads = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-p" || arg == "--prompt") { + params.prompt = get_next_arg(i, argc, argv, arg, params); + } else if (arg == "-n" || arg == "--n_predict") { + params.n_predict = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-np" || arg == "--n_parallel") { + params.n_parallel = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--top_k") { + params.top_k = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--top_p") { + params.top_p = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--temp") { + params.temp = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--repeat-last-n") { + params.repeat_last_n = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--repeat-penalty") { + params.repeat_penalty = std::stof(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-b" || arg == "--batch_size") { + params.n_batch= std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-c" || arg == "--context") { + params.n_ctx= std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-ngl" || arg == "--gpu-layers" || arg == "--n-gpu-layers") { + params.n_gpu_layers = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "--ignore-eos") { + params.ignore_eos = true; + } else if (arg == "-m" || arg == "--model") { + params.model = get_next_arg(i, argc, argv, arg, params); + } else if (arg == "-i" || arg == "--interactive") { + params.interactive = true; + } else if (arg == "-ip" || arg == "--interactive-port") { + params.interactive = true; + params.interactive_port = std::stoi(get_next_arg(i, argc, argv, arg, params)); + } else if (arg == "-h" || arg == "--help") { + gpt_print_usage(argc, argv, params); + exit(0); + } else if (arg == "-f" || arg == "--file") { + get_next_arg(i, argc, argv, arg, params); + std::ifstream file(argv[i]); + if (!file) { + fprintf(stderr, "error: failed to open file '%s'\n", argv[i]); + break; + } + std::copy(std::istreambuf_iterator(file), std::istreambuf_iterator(), back_inserter(params.prompt)); + if (params.prompt.back() == '\n') { + params.prompt.pop_back(); + } + } else if (arg == "-tt" || arg == "--token_test") { + params.token_test = get_next_arg(i, argc, argv, arg, params); + } + else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + gpt_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void gpt_print_usage(int /*argc*/, char ** argv, const gpt_params & params) { + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help show this help message and exit\n"); + fprintf(stderr, " -s SEED, --seed SEED RNG seed (default: -1)\n"); + fprintf(stderr, " -t N, --threads N number of threads to use during computation (default: %d)\n", params.n_threads); + fprintf(stderr, " -p PROMPT, --prompt PROMPT\n"); + fprintf(stderr, " prompt to start generation with (default: random)\n"); + fprintf(stderr, " -f FNAME, --file FNAME\n"); + fprintf(stderr, " load prompt from a file\n"); + fprintf(stderr, " -tt TOKEN_TEST, --token_test TOKEN_TEST\n"); + fprintf(stderr, " test tokenization\n"); + fprintf(stderr, " -n N, --n_predict N number of tokens to predict (default: %d)\n", params.n_predict); + fprintf(stderr, " --top_k N top-k sampling (default: %d)\n", params.top_k); + fprintf(stderr, " --top_p N top-p sampling (default: %.1f)\n", params.top_p); + fprintf(stderr, " --temp N temperature (default: %.1f)\n", params.temp); + fprintf(stderr, " --repeat-last-n N last n tokens to consider for penalize (default: %d, 0 = disabled)\n", params.repeat_last_n); + fprintf(stderr, " --repeat-penalty N penalize repeat sequence of tokens (default: %.2f, 1.0 = disabled)\n", (double)params.repeat_penalty); + fprintf(stderr, " -b N, --batch_size N batch size for prompt processing (default: %d)\n", params.n_batch); + fprintf(stderr, " -c N, --context N context / KV cache size (default: %d)\n", params.n_ctx); + fprintf(stderr, " --ignore-eos ignore EOS token during generation\n"); + fprintf(stderr, " -ngl N, --gpu-layers N number of layers to offload to GPU on supported models (default: %d)\n", params.n_gpu_layers); + fprintf(stderr, " -m FNAME, --model FNAME\n"); + fprintf(stderr, " model path (default: %s)\n", params.model.c_str()); + fprintf(stderr, "\n"); +} + +std::string gpt_random_prompt(std::mt19937 & rng) { + const int r = rng() % 10; + switch (r) { + case 0: return "So"; + case 1: return "Once upon a time"; + case 2: return "When"; + case 3: return "The"; + case 4: return "After"; + case 5: return "If"; + case 6: return "import"; + case 7: return "He"; + case 8: return "She"; + case 9: return "They"; + default: return "To"; + } + + return "The"; +} + +std::string trim(const std::string & s) { + std::regex e("^\\s+|\\s+$"); + return std::regex_replace(s, e, ""); +} + +std::string replace(const std::string & s, const std::string & from, const std::string & to) { + std::string result = s; + size_t pos = 0; + while ((pos = result.find(from, pos)) != std::string::npos) { + result.replace(pos, from.length(), to); + pos += to.length(); + } + return result; +} + +void gpt_vocab::add_special_token(const std::string & token) { + special_tokens.push_back(token); +} + +std::map json_parse(const std::string & fname) { + std::map result; + + // read file into string + std::string json; + { + std::ifstream ifs(fname); + if (!ifs) { + fprintf(stderr, "Failed to open %s\n", fname.c_str()); + exit(1); + } + + json = std::string((std::istreambuf_iterator(ifs)), + (std::istreambuf_iterator())); + } + + if (json[0] != '{') { + return result; + } + + // parse json + { + bool has_key = false; + bool in_token = false; + + std::string str_key = ""; + std::string str_val = ""; + + int n = json.size(); + for (int i = 1; i < n; ++i) { + if (!in_token) { + if (json[i] == ' ') continue; + if (json[i] == '"') { + in_token = true; + continue; + } + } else { + if (json[i] == '\\' && i+1 < n) { + if (has_key == false) { + str_key += json[i]; + } else { + str_val += json[i]; + } + ++i; + } else if (json[i] == '"') { + if (has_key == false) { + has_key = true; + ++i; + while (json[i] == ' ') ++i; + ++i; // : + while (json[i] == ' ') ++i; + if (json[i] != '\"') { + while (json[i] != ',' && json[i] != '}') { + str_val += json[i++]; + } + has_key = false; + } else { + in_token = true; + continue; + } + } else { + has_key = false; + } + + str_key = ::replace(str_key, "\\u0120", " " ); // \u0120 -> space + str_key = ::replace(str_key, "\\u010a", "\n"); // \u010a -> new line + str_key = ::replace(str_key, "\\\"", "\""); // \\\" -> " + + try { + result[str_key] = std::stoi(str_val); + } catch (...) { + //fprintf(stderr, "%s: ignoring key '%s' with value '%s'\n", fname.c_str(), str_key.c_str(), str_val.c_str()); + + } + str_key = ""; + str_val = ""; + in_token = false; + continue; + } + if (has_key == false) { + str_key += json[i]; + } else { + str_val += json[i]; + } + } + } + } + + return result; +} + +std::string convert_to_utf8(const std::wstring & input) { + std::wstring_convert> converter; + return converter.to_bytes(input); +} + + +std::wstring convert_to_wstring(const std::string & input) { + std::wstring_convert> converter; + return converter.from_bytes(input); +} + +void gpt_split_words(std::string str, std::vector& words) { + const std::string pattern = R"('s|'t|'re|'ve|'m|'ll|'d| ?[[:alpha:]]+| ?[[:digit:]]+| ?[^\s[:alpha:][:digit:]]+|\s+(?!\S)|\s+)"; + const std::regex re(pattern); + std::smatch m; + + while (std::regex_search(str, m, re)) { + for (auto x : m) { + words.push_back(x); + } + str = m.suffix(); + } +} + +std::vector gpt_tokenize(const gpt_vocab & vocab, const std::string & text) { + std::vector words; + + // first split the text into words + { + std::string str = text; + + // Generate the subpattern from the special_tokens vector if it's not empty + if (!vocab.special_tokens.empty()) { + const std::regex escape(R"([\[\\\^\$\.\|\?\*\+\(\)\{\}])"); + std::string special_tokens_subpattern; + for (const auto & token : vocab.special_tokens) { + if (!special_tokens_subpattern.empty()) { + special_tokens_subpattern += "|"; + } + special_tokens_subpattern += std::regex_replace(token, escape, R"(\$&)"); + } + + std::regex re(special_tokens_subpattern); + std::smatch m; + // Split the text by special tokens. + while (std::regex_search(str, m, re)) { + // Split the substrings in-between special tokens into words. + gpt_split_words(m.prefix(), words); + // Add matched special tokens as words. + for (auto x : m) { + words.push_back(x); + } + str = m.suffix(); + } + // Remaining text without special tokens will be handled below. + } + + gpt_split_words(str, words); + } + + // find the longest token that forms each word in words: + std::vector tokens; + for (const auto & word : words) { + for (int i = 0; i < (int) word.size(); ){ + for (int j = word.size() - 1; j >= i; j--){ + auto cand = word.substr(i, j-i+1); + auto it = vocab.token_to_id.find(cand); + if (it != vocab.token_to_id.end()){ // word.substr(i, j-i+1) in vocab + tokens.push_back(it->second); + i = j + 1; + break; + } + else if (j == i){ // word.substr(i, 1) has no matching + fprintf(stderr, "%s: unknown token '%s'\n", __func__, word.substr(i, 1).data()); + i++; + } + } + } + } + + return tokens; +} + +std::vector parse_tokens_from_string(const std::string& input, char delimiter) { + std::vector output; + std::stringstream ss(input); + std::string token; + + while (std::getline(ss, token, delimiter)) { + output.push_back(std::stoi(token)); + } + + return output; +} + +std::map> extract_tests_from_file(const std::string & fpath_test){ + if (fpath_test.empty()){ + fprintf(stderr, "%s : No test file found.\n", __func__); + return std::map>(); + } + + std::map> tests; + + auto fin = std::ifstream(fpath_test, std::ios_base::in); + const char * delimeter = " => "; + const char del_tok = ','; + std::string line; + while (std::getline(fin, line)) { + size_t delimiterPos = line.find(delimeter); + if (delimiterPos != std::string::npos) { + std::string text = line.substr(0, delimiterPos); + std::string s_tokens = line.substr(delimiterPos + std::strlen(delimeter)); + tests[text] = parse_tokens_from_string(s_tokens, del_tok); + } + } + return tests; +} + +void test_gpt_tokenizer(gpt_vocab & vocab, const std::string & fpath_test){ + std::map> tests = extract_tests_from_file(fpath_test); + + size_t n_fails = 0; + + for (const auto & test : tests) { + std::vector tokens = gpt_tokenize(vocab, test.first); + + if (tokens != test.second){ + n_fails++; + + // print out failure cases + fprintf(stderr, "%s : failed test: '%s'\n", __func__, test.first.c_str()); + fprintf(stderr, "%s : tokens in hf: ", __func__); + for (const auto & t : test.second) { + fprintf(stderr, "%s(%d), ", vocab.id_to_token[t].c_str(), t); + } + fprintf(stderr, "\n"); + fprintf(stderr, "%s : tokens in ggml: ", __func__); + for (const auto & t : tokens) { + fprintf(stderr, "%s(%d), ", vocab.id_to_token[t].c_str(), t); + } + fprintf(stderr, "\n"); + } + } + + fprintf(stderr, "%s : %zu tests failed out of %zu tests.\n", __func__, n_fails, tests.size()); +} + +bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab) { + printf("%s: loading vocab from '%s'\n", __func__, fname.c_str()); + + vocab.token_to_id = ::json_parse(fname); + + for (const auto & kv : vocab.token_to_id) { + vocab.id_to_token[kv.second] = kv.first; + } + + printf("%s: vocab size = %d\n", __func__, (int) vocab.token_to_id.size()); + + // print the vocabulary + //for (auto kv : vocab.token_to_id) { + // printf("'%s' -> %d\n", kv.first.data(), kv.second); + //} + + return true; +} + +gpt_vocab::id gpt_sample_top_k_top_p( + const gpt_vocab & vocab, + const float * logits, + int top_k, + double top_p, + double temp, + std::mt19937 & rng) { + int n_logits = vocab.id_to_token.size(); + + std::vector> logits_id; + logits_id.reserve(n_logits); + + { + const double scale = 1.0/temp; + for (int i = 0; i < n_logits; ++i) { + logits_id.push_back(std::make_pair(logits[i]*scale, i)); + } + } + + // find the top K tokens + std::partial_sort( + logits_id.begin(), + logits_id.begin() + top_k, logits_id.end(), + [](const std::pair & a, const std::pair & b) { + return a.first > b.first; + }); + + logits_id.resize(top_k); + + double maxl = -INFINITY; + for (const auto & kv : logits_id) { + maxl = std::max(maxl, kv.first); + } + + // compute probs for the top K tokens + std::vector probs; + probs.reserve(logits_id.size()); + + double sum = 0.0; + for (const auto & kv : logits_id) { + double p = exp(kv.first - maxl); + probs.push_back(p); + sum += p; + } + + // normalize the probs + for (auto & p : probs) { + p /= sum; + } + + if (top_p < 1.0f) { + double cumsum = 0.0f; + for (int i = 0; i < top_k; i++) { + cumsum += probs[i]; + if (cumsum >= top_p) { + top_k = i + 1; + probs.resize(top_k); + logits_id.resize(top_k); + break; + } + } + + cumsum = 1.0/cumsum; + for (int i = 0; i < (int) probs.size(); i++) { + probs[i] *= cumsum; + } + } + + //printf("\n"); + //for (int i = 0; i < (int) probs.size(); i++) { + // printf("%d: '%s' %f\n", i, vocab.id_to_token.at(logits_id[i].second).c_str(), probs[i]); + //} + //exit(0); + + std::discrete_distribution<> dist(probs.begin(), probs.end()); + int idx = dist(rng); + + return logits_id[idx].second; +} + +gpt_vocab::id gpt_sample_top_k_top_p_repeat( + const gpt_vocab & vocab, + const float * logits, + const int32_t * last_n_tokens_data, + size_t last_n_tokens_data_size, + int top_k, + double top_p, + double temp, + int repeat_last_n, + float repeat_penalty, + std::mt19937 & rng) { + + int n_logits = vocab.id_to_token.size(); + + const auto * plogits = logits; + + const auto last_n_tokens = std::vector(last_n_tokens_data, last_n_tokens_data + last_n_tokens_data_size); + + if (temp <= 0) { + // select the token with the highest logit directly + float max_logit = plogits[0]; + gpt_vocab::id max_id = 0; + + for (int i = 1; i < n_logits; ++i) { + if (plogits[i] > max_logit) { + max_logit = plogits[i]; + max_id = i; + } + } + return max_id; + } + + + std::vector> logits_id; + logits_id.reserve(n_logits); + + { + const float scale = 1.0f/temp; + for (int i = 0; i < n_logits; ++i) { + // repetition penalty from ctrl paper (https://arxiv.org/abs/1909.05858) + // credit https://github.com/facebookresearch/llama/compare/main...shawwn:llama:main + if (repeat_last_n > 0 && std::find(last_n_tokens.end()-repeat_last_n, last_n_tokens.end(), i) != last_n_tokens.end()) { + // if score < 0 then repetition penalty has to multiplied to reduce the previous token probability + if (plogits[i] < 0.0f) { + logits_id.push_back(std::make_pair(plogits[i]*scale*repeat_penalty, i)); + } else { + logits_id.push_back(std::make_pair(plogits[i]*scale/repeat_penalty, i)); + } + } else { + logits_id.push_back(std::make_pair(plogits[i]*scale, i)); + } + } + } + + // find the top K tokens + std::partial_sort( + logits_id.begin(), + logits_id.begin() + top_k, logits_id.end(), + [](const std::pair & a, const std::pair & b) { + return a.first > b.first; + }); + + logits_id.resize(top_k); + + double maxl = -INFINITY; + for (const auto & kv : logits_id) { + maxl = std::max(maxl, kv.first); + } + + // compute probs for the top K tokens + std::vector probs; + probs.reserve(logits_id.size()); + + double sum = 0.0; + for (const auto & kv : logits_id) { + double p = exp(kv.first - maxl); + probs.push_back(p); + sum += p; + } + + // normalize the probs + for (auto & p : probs) { + p /= sum; + } + + if (top_p < 1.0f) { + double cumsum = 0.0f; + for (int i = 0; i < top_k; i++) { + cumsum += probs[i]; + if (cumsum >= top_p) { + top_k = i + 1; + probs.resize(top_k); + logits_id.resize(top_k); + break; + } + } + + cumsum = 1.0/cumsum; + for (int i = 0; i < (int) probs.size(); i++) { + probs[i] *= cumsum; + } + } + +// printf("\n"); +// for (int i = 0; i < (int) probs.size(); i++) { +// for (int i = 0; i < 10; i++) { +// printf("%d: '%s' %f\n", i, vocab.id_to_token.at(logits_id[i].second).c_str(), probs[i]); +// } + + std::discrete_distribution<> dist(probs.begin(), probs.end()); + int idx = dist(rng); + + return logits_id[idx].second; + +} + +bool read_wav(const std::string & fname, std::vector& pcmf32, std::vector>& pcmf32s, bool stereo) { + drwav wav; + std::vector wav_data; // used for pipe input from stdin + + if (fname == "-") { + { + uint8_t buf[1024]; + while (true) + { + const size_t n = fread(buf, 1, sizeof(buf), stdin); + if (n == 0) { + break; + } + wav_data.insert(wav_data.end(), buf, buf + n); + } + } + + if (drwav_init_memory(&wav, wav_data.data(), wav_data.size(), nullptr) == false) { + fprintf(stderr, "error: failed to open WAV file from stdin\n"); + return false; + } + + fprintf(stderr, "%s: read %zu bytes from stdin\n", __func__, wav_data.size()); + } + else if (drwav_init_file(&wav, fname.c_str(), nullptr) == false) { + fprintf(stderr, "error: failed to open '%s' as WAV file\n", fname.c_str()); + return false; + } + + if (wav.channels != 1 && wav.channels != 2) { + fprintf(stderr, "%s: WAV file '%s' must be mono or stereo\n", __func__, fname.c_str()); + return false; + } + + if (stereo && wav.channels != 2) { + fprintf(stderr, "%s: WAV file '%s' must be stereo for diarization\n", __func__, fname.c_str()); + return false; + } + + if (wav.sampleRate != COMMON_SAMPLE_RATE) { + fprintf(stderr, "%s: WAV file '%s' must be %i kHz\n", __func__, fname.c_str(), COMMON_SAMPLE_RATE/1000); + return false; + } + + if (wav.bitsPerSample != 16) { + fprintf(stderr, "%s: WAV file '%s' must be 16-bit\n", __func__, fname.c_str()); + return false; + } + + const uint64_t n = wav_data.empty() ? wav.totalPCMFrameCount : wav_data.size()/(wav.channels*wav.bitsPerSample/8); + + std::vector pcm16; + pcm16.resize(n*wav.channels); + drwav_read_pcm_frames_s16(&wav, n, pcm16.data()); + drwav_uninit(&wav); + + // convert to mono, float + pcmf32.resize(n); + if (wav.channels == 1) { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[i])/32768.0f; + } + } else { + for (uint64_t i = 0; i < n; i++) { + pcmf32[i] = float(pcm16[2*i] + pcm16[2*i + 1])/65536.0f; + } + } + + if (stereo) { + // convert to stereo, float + pcmf32s.resize(2); + + pcmf32s[0].resize(n); + pcmf32s[1].resize(n); + for (uint64_t i = 0; i < n; i++) { + pcmf32s[0][i] = float(pcm16[2*i])/32768.0f; + pcmf32s[1][i] = float(pcm16[2*i + 1])/32768.0f; + } + } + + return true; +} + +void high_pass_filter(std::vector & data, float cutoff, float sample_rate) { + const float rc = 1.0f / (2.0f * M_PI * cutoff); + const float dt = 1.0f / sample_rate; + const float alpha = dt / (rc + dt); + + float y = data[0]; + + for (size_t i = 1; i < data.size(); i++) { + y = alpha * (y + data[i] - data[i - 1]); + data[i] = y; + } +} + +bool vad_simple(std::vector & pcmf32, int sample_rate, int last_ms, float vad_thold, float freq_thold, bool verbose) { + const int n_samples = pcmf32.size(); + const int n_samples_last = (sample_rate * last_ms) / 1000; + + if (n_samples_last >= n_samples) { + // not enough samples - assume no speech + return false; + } + + if (freq_thold > 0.0f) { + high_pass_filter(pcmf32, freq_thold, sample_rate); + } + + float energy_all = 0.0f; + float energy_last = 0.0f; + + for (int i = 0; i < n_samples; i++) { + energy_all += fabsf(pcmf32[i]); + + if (i >= n_samples - n_samples_last) { + energy_last += fabsf(pcmf32[i]); + } + } + + energy_all /= n_samples; + energy_last /= n_samples_last; + + if (verbose) { + fprintf(stderr, "%s: energy_all: %f, energy_last: %f, vad_thold: %f, freq_thold: %f\n", __func__, energy_all, energy_last, vad_thold, freq_thold); + } + + if (energy_last > vad_thold*energy_all) { + return false; + } + + return true; +} + +float similarity(const std::string & s0, const std::string & s1) { + const size_t len0 = s0.size() + 1; + const size_t len1 = s1.size() + 1; + + std::vector col(len1, 0); + std::vector prevCol(len1, 0); + + for (size_t i = 0; i < len1; i++) { + prevCol[i] = i; + } + + for (size_t i = 0; i < len0; i++) { + col[0] = i; + for (size_t j = 1; j < len1; j++) { + col[j] = std::min(std::min(1 + col[j - 1], 1 + prevCol[j]), prevCol[j - 1] + (i > 0 && s0[i - 1] == s1[j - 1] ? 0 : 1)); + } + col.swap(prevCol); + } + + const float dist = prevCol[len1 - 1]; + + return 1.0f - (dist / std::max(s0.size(), s1.size())); +} + +bool sam_params_parse(int argc, char ** argv, sam_params & params) { + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + + if (arg == "-s" || arg == "--seed") { + params.seed = std::stoi(argv[++i]); + } else if (arg == "-t" || arg == "--threads") { + params.n_threads = std::stoi(argv[++i]); + } else if (arg == "-m" || arg == "--model") { + params.model = argv[++i]; + } else if (arg == "-i" || arg == "--inp") { + params.fname_inp = argv[++i]; + } else if (arg == "-o" || arg == "--out") { + params.fname_out = argv[++i]; + } else if (arg == "-h" || arg == "--help") { + sam_print_usage(argc, argv, params); + exit(0); + } else { + fprintf(stderr, "error: unknown argument: %s\n", arg.c_str()); + sam_print_usage(argc, argv, params); + exit(0); + } + } + + return true; +} + +void sam_print_usage(int /*argc*/, char ** argv, const sam_params & params) { + fprintf(stderr, "usage: %s [options]\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "options:\n"); + fprintf(stderr, " -h, --help show this help message and exit\n"); + fprintf(stderr, " -s SEED, --seed SEED RNG seed (default: -1)\n"); + fprintf(stderr, " -t N, --threads N number of threads to use during computation (default: %d)\n", params.n_threads); + fprintf(stderr, " -m FNAME, --model FNAME\n"); + fprintf(stderr, " model path (default: %s)\n", params.model.c_str()); + fprintf(stderr, " -i FNAME, --inp FNAME\n"); + fprintf(stderr, " input file (default: %s)\n", params.fname_inp.c_str()); + fprintf(stderr, " -o FNAME, --out FNAME\n"); + fprintf(stderr, " output file (default: %s)\n", params.fname_out.c_str()); + fprintf(stderr, "\n"); +} diff --git a/whisper.cpp-1.5.2/examples/common.h b/whisper.cpp-1.5.2/examples/common.h new file mode 100644 index 0000000..54f0b00 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/common.h @@ -0,0 +1,279 @@ +// Various helper functions and utilities + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define COMMON_SAMPLE_RATE 16000 + +// +// GPT CLI argument parsing +// + +struct gpt_params { + int32_t seed = -1; // RNG seed + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + int32_t n_predict = 200; // new tokens to predict + int32_t n_parallel = 1; // number of parallel streams + int32_t n_batch = 8; // batch size for prompt processing + int32_t n_ctx = 2048; // context size (this is the KV cache max size) + int32_t n_gpu_layers = 0; // number of layers to offlload to the GPU + + bool ignore_eos = false; // ignore EOS token when generating text + + // sampling parameters + int32_t top_k = 40; + float top_p = 0.9f; + float temp = 0.9f; + int32_t repeat_last_n = 64; + float repeat_penalty = 1.00f; + + std::string model = "models/gpt-2-117M/ggml-model.bin"; // model path + std::string prompt = ""; + std::string token_test = ""; + + bool interactive = false; + int32_t interactive_port = -1; +}; + +bool gpt_params_parse(int argc, char ** argv, gpt_params & params); + +void gpt_print_usage(int argc, char ** argv, const gpt_params & params); + +std::string gpt_random_prompt(std::mt19937 & rng); + +// +// Vocab utils +// + +std::string trim(const std::string & s); + +std::string replace( + const std::string & s, + const std::string & from, + const std::string & to); + +struct gpt_vocab { + using id = int32_t; + using token = std::string; + + std::map token_to_id; + std::map id_to_token; + std::vector special_tokens; + + void add_special_token(const std::string & token); +}; + +// poor-man's JSON parsing +std::map json_parse(const std::string & fname); + +std::string convert_to_utf8(const std::wstring & input); + +std::wstring convert_to_wstring(const std::string & input); + +void gpt_split_words(std::string str, std::vector& words); + +// split text into tokens +// +// ref: https://github.com/openai/gpt-2/blob/a74da5d99abaaba920de8131d64da2862a8f213b/src/encoder.py#L53 +// +// Regex (Python): +// r"""'s|'t|'re|'ve|'m|'ll|'d| ?\p{L}+| ?\p{N}+| ?[^\s\p{L}\p{N}]+|\s+(?!\S)|\s+""" +// +// Regex (C++): +// R"('s|'t|'re|'ve|'m|'ll|'d| ?[[:alpha:]]+| ?[[:digit:]]+| ?[^\s[:alpha:][:digit:]]+|\s+(?!\S)|\s+)" +// +std::vector gpt_tokenize(const gpt_vocab & vocab, const std::string & text); + +// test outputs of gpt_tokenize +// +// - compare with tokens generated by the huggingface tokenizer +// - test cases are chosen based on the model's main language (under 'prompt' directory) +// - if all sentences are tokenized identically, print 'All tests passed.' +// - otherwise, print sentence, huggingface tokens, ggml tokens +// +void test_gpt_tokenizer(gpt_vocab & vocab, const std::string & fpath_test); + +// load the tokens from encoder.json +bool gpt_vocab_init(const std::string & fname, gpt_vocab & vocab); + +// sample next token given probabilities for each embedding +// +// - consider only the top K tokens +// - from them, consider only the top tokens with cumulative probability > P +// +// TODO: not sure if this implementation is correct +// TODO: temperature is not implemented +// +gpt_vocab::id gpt_sample_top_k_top_p( + const gpt_vocab & vocab, + const float * logits, + int top_k, + double top_p, + double temp, + std::mt19937 & rng); + +gpt_vocab::id gpt_sample_top_k_top_p_repeat( + const gpt_vocab & vocab, + const float * logits, + const int32_t * last_n_tokens_data, + size_t last_n_tokens_data_size, + int top_k, + double top_p, + double temp, + int repeat_last_n, + float repeat_penalty, + std::mt19937 & rng); + +// +// Audio utils +// + +// Read WAV audio file and store the PCM data into pcmf32 +// The sample rate of the audio must be equal to COMMON_SAMPLE_RATE +// If stereo flag is set and the audio has 2 channels, the pcmf32s will contain 2 channel PCM +bool read_wav( + const std::string & fname, + std::vector & pcmf32, + std::vector> & pcmf32s, + bool stereo); + +// Write PCM data into WAV audio file +class wav_writer { +private: + std::ofstream file; + uint32_t dataSize = 0; + std::string wav_filename; + + bool write_header(const uint32_t sample_rate, + const uint16_t bits_per_sample, + const uint16_t channels) { + + file.write("RIFF", 4); + file.write("\0\0\0\0", 4); // Placeholder for file size + file.write("WAVE", 4); + file.write("fmt ", 4); + + const uint32_t sub_chunk_size = 16; + const uint16_t audio_format = 1; // PCM format + const uint32_t byte_rate = sample_rate * channels * bits_per_sample / 8; + const uint16_t block_align = channels * bits_per_sample / 8; + + file.write(reinterpret_cast(&sub_chunk_size), 4); + file.write(reinterpret_cast(&audio_format), 2); + file.write(reinterpret_cast(&channels), 2); + file.write(reinterpret_cast(&sample_rate), 4); + file.write(reinterpret_cast(&byte_rate), 4); + file.write(reinterpret_cast(&block_align), 2); + file.write(reinterpret_cast(&bits_per_sample), 2); + file.write("data", 4); + file.write("\0\0\0\0", 4); // Placeholder for data size + + return true; + } + + // It is assumed that PCM data is normalized to a range from -1 to 1 + bool write_audio(const float * data, size_t length) { + for (size_t i = 0; i < length; ++i) { + const int16_t intSample = data[i] * 32767; + file.write(reinterpret_cast(&intSample), sizeof(int16_t)); + dataSize += sizeof(int16_t); + } + if (file.is_open()) { + file.seekp(4, std::ios::beg); + uint32_t fileSize = 36 + dataSize; + file.write(reinterpret_cast(&fileSize), 4); + file.seekp(40, std::ios::beg); + file.write(reinterpret_cast(&dataSize), 4); + file.seekp(0, std::ios::end); + } + return true; + } + + bool open_wav(const std::string & filename) { + if (filename != wav_filename) { + if (file.is_open()) { + file.close(); + } + } + if (!file.is_open()) { + file.open(filename, std::ios::binary); + wav_filename = filename; + dataSize = 0; + } + return file.is_open(); + } + +public: + bool open(const std::string & filename, + const uint32_t sample_rate, + const uint16_t bits_per_sample, + const uint16_t channels) { + + if (open_wav(filename)) { + write_header(sample_rate, bits_per_sample, channels); + } else { + return false; + } + + return true; + } + + bool close() { + file.close(); + return true; + } + + bool write(const float * data, size_t length) { + return write_audio(data, length); + } + + ~wav_writer() { + if (file.is_open()) { + file.close(); + } + } +}; + + +// Apply a high-pass frequency filter to PCM audio +// Suppresses frequencies below cutoff Hz +void high_pass_filter( + std::vector & data, + float cutoff, + float sample_rate); + +// Basic voice activity detection (VAD) using audio energy adaptive threshold +bool vad_simple( + std::vector & pcmf32, + int sample_rate, + int last_ms, + float vad_thold, + float freq_thold, + bool verbose); + +// compute similarity between two strings using Levenshtein distance +float similarity(const std::string & s0, const std::string & s1); + +// +// SAM argument parsing +// + +struct sam_params { + int32_t seed = -1; // RNG seed + int32_t n_threads = std::min(4, (int32_t) std::thread::hardware_concurrency()); + + std::string model = "models/sam-vit-b/ggml-model-f16.bin"; // model path + std::string fname_inp = "img.jpg"; + std::string fname_out = "img.out"; +}; + +bool sam_params_parse(int argc, char ** argv, sam_params & params); + +void sam_print_usage(int argc, char ** argv, const sam_params & params); diff --git a/whisper.cpp-1.5.2/examples/dr_wav.h b/whisper.cpp-1.5.2/examples/dr_wav.h new file mode 100644 index 0000000..fd3e95b --- /dev/null +++ b/whisper.cpp-1.5.2/examples/dr_wav.h @@ -0,0 +1,6434 @@ +/* +WAV audio loader and writer. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_wav - v0.12.16 - 2020-12-02 + +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +RELEASE NOTES - VERSION 0.12 +============================ +Version 0.12 includes breaking changes to custom chunk handling. + + +Changes to Chunk Callback +------------------------- +dr_wav supports the ability to fire a callback when a chunk is encounted (except for WAVE and FMT chunks). The callback has been updated to include both the +container (RIFF or Wave64) and the FMT chunk which contains information about the format of the data in the wave file. + +Previously, there was no direct way to determine the container, and therefore no way to discriminate against the different IDs in the chunk header (RIFF and +Wave64 containers encode chunk ID's differently). The `container` parameter can be used to know which ID to use. + +Sometimes it can be useful to know the data format at the time the chunk callback is fired. A pointer to a `drwav_fmt` object is now passed into the chunk +callback which will give you information about the data format. To determine the sample format, use `drwav_fmt_get_format()`. This will return one of the +`DR_WAVE_FORMAT_*` tokens. +*/ + +/* +Introduction +============ +This is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_WAV_IMPLEMENTATION + #include "dr_wav.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. Do something like the following to read audio data: + + ```c + drwav wav; + if (!drwav_init_file(&wav, "my_song.wav", NULL)) { + // Error opening WAV file. + } + + drwav_int32* pDecodedInterleavedPCMFrames = malloc(wav.totalPCMFrameCount * wav.channels * sizeof(drwav_int32)); + size_t numberOfSamplesActuallyDecoded = drwav_read_pcm_frames_s32(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + + ... + + drwav_uninit(&wav); + ``` + +If you just want to quickly open and read the audio data in a single operation you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drwav_uint64 totalPCMFrameCount; + float* pSampleData = drwav_open_file_and_read_pcm_frames_f32("my_song.wav", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Error opening and reading WAV file. + } + + ... + + drwav_free(pSampleData); + ``` + +The examples above use versions of the API that convert the audio data to a consistent format (32-bit signed PCM, in this case), but you can still output the +audio data in its internal format (see notes below for supported formats): + + ```c + size_t framesRead = drwav_read_pcm_frames(&wav, wav.totalPCMFrameCount, pDecodedInterleavedPCMFrames); + ``` + +You can also read the raw bytes of audio data, which could be useful if dr_wav does not have native support for a particular data format: + + ```c + size_t bytesRead = drwav_read_raw(&wav, bytesToRead, pRawDataBuffer); + ``` + +dr_wav can also be used to output WAV files. This does not currently support compressed formats. To use this, look at `drwav_init_write()`, +`drwav_init_file_write()`, etc. Use `drwav_write_pcm_frames()` to write samples, or `drwav_write_raw()` to write raw data in the "data" chunk. + + ```c + drwav_data_format format; + format.container = drwav_container_riff; // <-- drwav_container_riff = normal WAV files, drwav_container_w64 = Sony Wave64. + format.format = DR_WAVE_FORMAT_PCM; // <-- Any of the DR_WAVE_FORMAT_* codes. + format.channels = 2; + format.sampleRate = 44100; + format.bitsPerSample = 16; + drwav_init_file_write(&wav, "data/recording.wav", &format, NULL); + + ... + + drwav_uint64 framesWritten = drwav_write_pcm_frames(pWav, frameCount, pSamples); + ``` + +dr_wav has seamless support the Sony Wave64 format. The decoder will automatically detect it and it should Just Work without any manual intervention. + + +Build Options +============= +#define these options before including this file. + +#define DR_WAV_NO_CONVERSION_API + Disables conversion APIs such as `drwav_read_pcm_frames_f32()` and `drwav_s16_to_f32()`. + +#define DR_WAV_NO_STDIO + Disables APIs that initialize a decoder from a file such as `drwav_init_file()`, `drwav_init_file_write()`, etc. + + + +Notes +===== +- Samples are always interleaved. +- The default read function does not do any data conversion. Use `drwav_read_pcm_frames_f32()`, `drwav_read_pcm_frames_s32()` and `drwav_read_pcm_frames_s16()` + to read and convert audio data to 32-bit floating point, signed 32-bit integer and signed 16-bit integer samples respectively. Tested and supported internal + formats include the following: + - Unsigned 8-bit PCM + - Signed 12-bit PCM + - Signed 16-bit PCM + - Signed 24-bit PCM + - Signed 32-bit PCM + - IEEE 32-bit floating point + - IEEE 64-bit floating point + - A-law and u-law + - Microsoft ADPCM + - IMA ADPCM (DVI, format code 0x11) +- dr_wav will try to read the WAV file as best it can, even if it's not strictly conformant to the WAV format. +*/ + +#ifndef dr_wav_h +#define dr_wav_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRWAV_STRINGIFY(x) #x +#define DRWAV_XSTRINGIFY(x) DRWAV_STRINGIFY(x) + +#define DRWAV_VERSION_MAJOR 0 +#define DRWAV_VERSION_MINOR 12 +#define DRWAV_VERSION_REVISION 16 +#define DRWAV_VERSION_STRING DRWAV_XSTRINGIFY(DRWAV_VERSION_MAJOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_MINOR) "." DRWAV_XSTRINGIFY(DRWAV_VERSION_REVISION) + +#include /* For size_t. */ + +/* Sized types. */ +typedef signed char drwav_int8; +typedef unsigned char drwav_uint8; +typedef signed short drwav_int16; +typedef unsigned short drwav_uint16; +typedef signed int drwav_int32; +typedef unsigned int drwav_uint32; +#if defined(_MSC_VER) + typedef signed __int64 drwav_int64; + typedef unsigned __int64 drwav_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drwav_int64; + typedef unsigned long long drwav_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) + typedef drwav_uint64 drwav_uintptr; +#else + typedef drwav_uint32 drwav_uintptr; +#endif +typedef drwav_uint8 drwav_bool8; +typedef drwav_uint32 drwav_bool32; +#define DRWAV_TRUE 1 +#define DRWAV_FALSE 0 + +#if !defined(DRWAV_API) + #if defined(DRWAV_DLL) + #if defined(_WIN32) + #define DRWAV_DLL_IMPORT __declspec(dllimport) + #define DRWAV_DLL_EXPORT __declspec(dllexport) + #define DRWAV_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRWAV_DLL_IMPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_EXPORT __attribute__((visibility("default"))) + #define DRWAV_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRWAV_DLL_IMPORT + #define DRWAV_DLL_EXPORT + #define DRWAV_DLL_PRIVATE static + #endif + #endif + + #if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) + #define DRWAV_API DRWAV_DLL_EXPORT + #else + #define DRWAV_API DRWAV_DLL_IMPORT + #endif + #define DRWAV_PRIVATE DRWAV_DLL_PRIVATE + #else + #define DRWAV_API extern + #define DRWAV_PRIVATE static + #endif +#endif + +typedef drwav_int32 drwav_result; +#define DRWAV_SUCCESS 0 +#define DRWAV_ERROR -1 /* A generic error. */ +#define DRWAV_INVALID_ARGS -2 +#define DRWAV_INVALID_OPERATION -3 +#define DRWAV_OUT_OF_MEMORY -4 +#define DRWAV_OUT_OF_RANGE -5 +#define DRWAV_ACCESS_DENIED -6 +#define DRWAV_DOES_NOT_EXIST -7 +#define DRWAV_ALREADY_EXISTS -8 +#define DRWAV_TOO_MANY_OPEN_FILES -9 +#define DRWAV_INVALID_FILE -10 +#define DRWAV_TOO_BIG -11 +#define DRWAV_PATH_TOO_LONG -12 +#define DRWAV_NAME_TOO_LONG -13 +#define DRWAV_NOT_DIRECTORY -14 +#define DRWAV_IS_DIRECTORY -15 +#define DRWAV_DIRECTORY_NOT_EMPTY -16 +#define DRWAV_END_OF_FILE -17 +#define DRWAV_NO_SPACE -18 +#define DRWAV_BUSY -19 +#define DRWAV_IO_ERROR -20 +#define DRWAV_INTERRUPT -21 +#define DRWAV_UNAVAILABLE -22 +#define DRWAV_ALREADY_IN_USE -23 +#define DRWAV_BAD_ADDRESS -24 +#define DRWAV_BAD_SEEK -25 +#define DRWAV_BAD_PIPE -26 +#define DRWAV_DEADLOCK -27 +#define DRWAV_TOO_MANY_LINKS -28 +#define DRWAV_NOT_IMPLEMENTED -29 +#define DRWAV_NO_MESSAGE -30 +#define DRWAV_BAD_MESSAGE -31 +#define DRWAV_NO_DATA_AVAILABLE -32 +#define DRWAV_INVALID_DATA -33 +#define DRWAV_TIMEOUT -34 +#define DRWAV_NO_NETWORK -35 +#define DRWAV_NOT_UNIQUE -36 +#define DRWAV_NOT_SOCKET -37 +#define DRWAV_NO_ADDRESS -38 +#define DRWAV_BAD_PROTOCOL -39 +#define DRWAV_PROTOCOL_UNAVAILABLE -40 +#define DRWAV_PROTOCOL_NOT_SUPPORTED -41 +#define DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRWAV_SOCKET_NOT_SUPPORTED -44 +#define DRWAV_CONNECTION_RESET -45 +#define DRWAV_ALREADY_CONNECTED -46 +#define DRWAV_NOT_CONNECTED -47 +#define DRWAV_CONNECTION_REFUSED -48 +#define DRWAV_NO_HOST -49 +#define DRWAV_IN_PROGRESS -50 +#define DRWAV_CANCELLED -51 +#define DRWAV_MEMORY_ALREADY_MAPPED -52 +#define DRWAV_AT_END -53 + +/* Common data formats. */ +#define DR_WAVE_FORMAT_PCM 0x1 +#define DR_WAVE_FORMAT_ADPCM 0x2 +#define DR_WAVE_FORMAT_IEEE_FLOAT 0x3 +#define DR_WAVE_FORMAT_ALAW 0x6 +#define DR_WAVE_FORMAT_MULAW 0x7 +#define DR_WAVE_FORMAT_DVI_ADPCM 0x11 +#define DR_WAVE_FORMAT_EXTENSIBLE 0xFFFE + +/* Constants. */ +#ifndef DRWAV_MAX_SMPL_LOOPS +#define DRWAV_MAX_SMPL_LOOPS 1 +#endif + +/* Flags to pass into drwav_init_ex(), etc. */ +#define DRWAV_SEQUENTIAL 0x00000001 + +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision); +DRWAV_API const char* drwav_version_string(void); + +typedef enum +{ + drwav_seek_origin_start, + drwav_seek_origin_current +} drwav_seek_origin; + +typedef enum +{ + drwav_container_riff, + drwav_container_w64, + drwav_container_rf64 +} drwav_container; + +typedef struct +{ + union + { + drwav_uint8 fourcc[4]; + drwav_uint8 guid[16]; + } id; + + /* The size in bytes of the chunk. */ + drwav_uint64 sizeInBytes; + + /* + RIFF = 2 byte alignment. + W64 = 8 byte alignment. + */ + unsigned int paddingSize; +} drwav_chunk_header; + +typedef struct +{ + /* + The format tag exactly as specified in the wave file's "fmt" chunk. This can be used by applications + that require support for data formats not natively supported by dr_wav. + */ + drwav_uint16 formatTag; + + /* The number of channels making up the audio data. When this is set to 1 it is mono, 2 is stereo, etc. */ + drwav_uint16 channels; + + /* The sample rate. Usually set to something like 44100. */ + drwav_uint32 sampleRate; + + /* Average bytes per second. You probably don't need this, but it's left here for informational purposes. */ + drwav_uint32 avgBytesPerSec; + + /* Block align. This is equal to the number of channels * bytes per sample. */ + drwav_uint16 blockAlign; + + /* Bits per sample. */ + drwav_uint16 bitsPerSample; + + /* The size of the extended data. Only used internally for validation, but left here for informational purposes. */ + drwav_uint16 extendedSize; + + /* + The number of valid bits per sample. When is equal to WAVE_FORMAT_EXTENSIBLE, + is always rounded up to the nearest multiple of 8. This variable contains information about exactly how + many bits are valid per sample. Mainly used for informational purposes. + */ + drwav_uint16 validBitsPerSample; + + /* The channel mask. Not used at the moment. */ + drwav_uint32 channelMask; + + /* The sub-format, exactly as specified by the wave file. */ + drwav_uint8 subFormat[16]; +} drwav_fmt; + +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT); + + +/* +Callback for when data is read. Return value is the number of bytes actually read. + +pUserData [in] The user data that was passed to drwav_init() and family. +pBufferOut [out] The output buffer. +bytesToRead [in] The number of bytes to read. + +Returns the number of bytes actually read. + +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until +either the entire bytesToRead is filled or you have reached the end of the stream. +*/ +typedef size_t (* drwav_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); + +/* +Callback for when data is written. Returns value is the number of bytes actually written. + +pUserData [in] The user data that was passed to drwav_init_write() and family. +pData [out] A pointer to the data to write. +bytesToWrite [in] The number of bytes to write. + +Returns the number of bytes actually written. + +If the return value differs from bytesToWrite, it indicates an error. +*/ +typedef size_t (* drwav_write_proc)(void* pUserData, const void* pData, size_t bytesToWrite); + +/* +Callback for when data needs to be seeked. + +pUserData [in] The user data that was passed to drwav_init() and family. +offset [in] The number of bytes to move, relative to the origin. Will never be negative. +origin [in] The origin of the seek - the current position or the start of the stream. + +Returns whether or not the seek was successful. + +Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be either drwav_seek_origin_start or +drwav_seek_origin_current. +*/ +typedef drwav_bool32 (* drwav_seek_proc)(void* pUserData, int offset, drwav_seek_origin origin); + +/* +Callback for when drwav_init_ex() finds a chunk. + +pChunkUserData [in] The user data that was passed to the pChunkUserData parameter of drwav_init_ex() and family. +onRead [in] A pointer to the function to call when reading. +onSeek [in] A pointer to the function to call when seeking. +pReadSeekUserData [in] The user data that was passed to the pReadSeekUserData parameter of drwav_init_ex() and family. +pChunkHeader [in] A pointer to an object containing basic header information about the chunk. Use this to identify the chunk. +container [in] Whether or not the WAV file is a RIFF or Wave64 container. If you're unsure of the difference, assume RIFF. +pFMT [in] A pointer to the object containing the contents of the "fmt" chunk. + +Returns the number of bytes read + seeked. + +To read data from the chunk, call onRead(), passing in pReadSeekUserData as the first parameter. Do the same for seeking with onSeek(). The return value must +be the total number of bytes you have read _plus_ seeked. + +Use the `container` argument to discriminate the fields in `pChunkHeader->id`. If the container is `drwav_container_riff` or `drwav_container_rf64` you should +use `id.fourcc`, otherwise you should use `id.guid`. + +The `pFMT` parameter can be used to determine the data format of the wave file. Use `drwav_fmt_get_format()` to get the sample format, which will be one of the +`DR_WAVE_FORMAT_*` identifiers. + +The read pointer will be sitting on the first byte after the chunk's header. You must not attempt to read beyond the boundary of the chunk. +*/ +typedef drwav_uint64 (* drwav_chunk_proc)(void* pChunkUserData, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_chunk_header* pChunkHeader, drwav_container container, const drwav_fmt* pFMT); + +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drwav_allocation_callbacks; + +/* Structure for internal use. Only used for loaders opened with drwav_init_memory(). */ +typedef struct +{ + const drwav_uint8* data; + size_t dataSize; + size_t currentReadPos; +} drwav__memory_stream; + +/* Structure for internal use. Only used for writers opened with drwav_init_memory_write(). */ +typedef struct +{ + void** ppData; + size_t* pDataSize; + size_t dataSize; + size_t dataCapacity; + size_t currentWritePos; +} drwav__memory_stream_write; + +typedef struct +{ + drwav_container container; /* RIFF, W64. */ + drwav_uint32 format; /* DR_WAVE_FORMAT_* */ + drwav_uint32 channels; + drwav_uint32 sampleRate; + drwav_uint32 bitsPerSample; +} drwav_data_format; + + +/* See the following for details on the 'smpl' chunk: https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl */ +typedef struct +{ + drwav_uint32 cuePointId; + drwav_uint32 type; + drwav_uint32 start; + drwav_uint32 end; + drwav_uint32 fraction; + drwav_uint32 playCount; +} drwav_smpl_loop; + + typedef struct +{ + drwav_uint32 manufacturer; + drwav_uint32 product; + drwav_uint32 samplePeriod; + drwav_uint32 midiUnityNotes; + drwav_uint32 midiPitchFraction; + drwav_uint32 smpteFormat; + drwav_uint32 smpteOffset; + drwav_uint32 numSampleLoops; + drwav_uint32 samplerData; + drwav_smpl_loop loops[DRWAV_MAX_SMPL_LOOPS]; +} drwav_smpl; + +typedef struct +{ + /* A pointer to the function to call when more data is needed. */ + drwav_read_proc onRead; + + /* A pointer to the function to call when data needs to be written. Only used when the drwav object is opened in write mode. */ + drwav_write_proc onWrite; + + /* A pointer to the function to call when the wav file needs to be seeked. */ + drwav_seek_proc onSeek; + + /* The user data to pass to callbacks. */ + void* pUserData; + + /* Allocation callbacks. */ + drwav_allocation_callbacks allocationCallbacks; + + + /* Whether or not the WAV file is formatted as a standard RIFF file or W64. */ + drwav_container container; + + + /* Structure containing format information exactly as specified by the wav file. */ + drwav_fmt fmt; + + /* The sample rate. Will be set to something like 44100. */ + drwav_uint32 sampleRate; + + /* The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. */ + drwav_uint16 channels; + + /* The bits per sample. Will be set to something like 16, 24, etc. */ + drwav_uint16 bitsPerSample; + + /* Equal to fmt.formatTag, or the value specified by fmt.subFormat if fmt.formatTag is equal to 65534 (WAVE_FORMAT_EXTENSIBLE). */ + drwav_uint16 translatedFormatTag; + + /* The total number of PCM frames making up the audio data. */ + drwav_uint64 totalPCMFrameCount; + + + /* The size in bytes of the data chunk. */ + drwav_uint64 dataChunkDataSize; + + /* The position in the stream of the first byte of the data chunk. This is used for seeking. */ + drwav_uint64 dataChunkDataPos; + + /* The number of bytes remaining in the data chunk. */ + drwav_uint64 bytesRemaining; + + + /* + Only used in sequential write mode. Keeps track of the desired size of the "data" chunk at the point of initialization time. Always + set to 0 for non-sequential writes and when the drwav object is opened in read mode. Used for validation. + */ + drwav_uint64 dataChunkDataSizeTargetWrite; + + /* Keeps track of whether or not the wav writer was initialized in sequential mode. */ + drwav_bool32 isSequentialWrite; + + + /* smpl chunk. */ + drwav_smpl smpl; + + + /* A hack to avoid a DRWAV_MALLOC() when opening a decoder with drwav_init_memory(). */ + drwav__memory_stream memoryStream; + drwav__memory_stream_write memoryStreamWrite; + + /* Generic data for compressed formats. This data is shared across all block-compressed formats. */ + struct + { + drwav_uint64 iCurrentPCMFrame; /* The index of the next PCM frame that will be read by drwav_read_*(). This is used with "totalPCMFrameCount" to ensure we don't read excess samples at the end of the last block. */ + } compressed; + + /* Microsoft ADPCM specific data. */ + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_uint16 predictor[2]; + drwav_int32 delta[2]; + drwav_int32 cachedFrames[4]; /* Samples are stored in this cache during decoding. */ + drwav_uint32 cachedFrameCount; + drwav_int32 prevFrames[2][2]; /* The previous 2 samples for each channel (2 channels at most). */ + } msadpcm; + + /* IMA ADPCM specific data. */ + struct + { + drwav_uint32 bytesRemainingInBlock; + drwav_int32 predictor[2]; + drwav_int32 stepIndex[2]; + drwav_int32 cachedFrames[16]; /* Samples are stored in this cache during decoding. */ + drwav_uint32 cachedFrameCount; + } ima; +} drwav; + + +/* +Initializes a pre-allocated drwav object for reading. + +pWav [out] A pointer to the drwav object being initialized. +onRead [in] The function to call when data needs to be read from the client. +onSeek [in] The function to call when the read position of the client data needs to move. +onChunk [in, optional] The function to call when a chunk is enumerated at initialized time. +pUserData, pReadSeekUserData [in, optional] A pointer to application defined data that will be passed to onRead and onSeek. +pChunkUserData [in, optional] A pointer to application defined data that will be passed to onChunk. +flags [in, optional] A set of flags for controlling how things are loaded. + +Returns true if successful; false otherwise. + +Close the loader with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file() and drwav_init_memory() +to open the stream from a file or from a block of memory respectively. + +Possible values for flags: + DRWAV_SEQUENTIAL: Never perform a backwards seek while loading. This disables the chunk callback and will cause this function + to return as soon as the data chunk is found. Any chunks after the data chunk will be ignored. + +drwav_init() is equivalent to "drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0);". + +The onChunk callback is not called for the WAVE or FMT chunks. The contents of the FMT chunk can be read from pWav->fmt +after the function returns. + +See also: drwav_init_file(), drwav_init_memory(), drwav_uninit() +*/ +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Initializes a pre-allocated drwav object for writing. + +onWrite [in] The function to call when data needs to be written. +onSeek [in] The function to call when the write position needs to move. +pUserData [in, optional] A pointer to application defined data that will be passed to onWrite and onSeek. + +Returns true if successful; false otherwise. + +Close the writer with drwav_uninit(). + +This is the lowest level function for initializing a WAV file. You can also use drwav_init_file_write() and drwav_init_memory_write() +to open the stream from a file or from a block of memory respectively. + +If the total sample count is known, you can use drwav_init_write_sequential(). This avoids the need for dr_wav to perform +a post-processing step for storing the total sample count and the size of the data chunk which requires a backwards seek. + +See also: drwav_init_file_write(), drwav_init_memory_write(), drwav_uninit() +*/ +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Utility function to determine the target size of the entire data to be written (including all headers and chunks). + +Returns the target size in bytes. + +Useful if the application needs to know the size to allocate. + +Only writing to the RIFF chunk and one data chunk is currently supported. + +See also: drwav_init_write(), drwav_init_file_write(), drwav_init_memory_write() +*/ +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); + +/* +Uninitializes the given drwav object. + +Use this only for objects initialized with drwav_init*() functions (drwav_init(), drwav_init_ex(), drwav_init_write(), drwav_init_write_sequential()). +*/ +DRWAV_API drwav_result drwav_uninit(drwav* pWav); + + +/* +Reads raw audio data. + +This is the lowest level function for reading audio data. It simply reads the given number of +bytes of the raw internal sample data. + +Consider using drwav_read_pcm_frames_s16(), drwav_read_pcm_frames_s32() or drwav_read_pcm_frames_f32() for +reading sample data in a consistent format. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of bytes actually read. +*/ +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut); + +/* +Reads up to the specified number of PCM frames from the WAV file. + +The output data will be in the file's internal format, converted to native-endian byte order. Use +drwav_read_pcm_frames_s16/f32/s32() to read data in a specific format. + +If the return value is less than it means the end of the file has been reached or +you have requested more PCM frames than can possibly fit in the output buffer. + +This function will only work when sample data is of a fixed size and uncompressed. If you are +using a compressed format consider using drwav_read_raw() or drwav_read_pcm_frames_s16/s32/f32(). + +pBufferOut can be NULL in which case a seek will be performed. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut); + +/* +Seeks to the given PCM frame. + +Returns true if successful; false otherwise. +*/ +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex); + + +/* +Writes raw audio data. + +Returns the number of bytes actually written. If this differs from bytesToWrite, it indicates an error. +*/ +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData); + +/* +Writes PCM frames. + +Returns the number of PCM frames written. + +Input samples need to be in native-endian byte order. On big-endian architectures the input data will be converted to +little-endian. Use drwav_write_raw() to write raw audio data without performing any conversion. +*/ +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData); + + +/* Conversion Utilities */ +#ifndef DR_WAV_NO_CONVERSION_API + +/* +Reads a chunk of audio data and converts it to signed 16-bit PCM samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 32-bit PCM samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 32-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 16-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +/* +Reads a chunk of audio data and converts it to IEEE 32-bit floating point samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 16-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 32-bit PCM samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to IEEE 32-bit floating point samples. */ +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount); + + +/* +Reads a chunk of audio data and converts it to signed 32-bit PCM samples. + +pBufferOut can be NULL in which case a seek will be performed. + +Returns the number of PCM frames actually read. + +If the return value is less than it means the end of the file has been reached. +*/ +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut); + +/* Low-level function for converting unsigned 8-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting signed 16-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount); + +/* Low-level function for converting signed 24-bit PCM samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 32-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount); + +/* Low-level function for converting IEEE 64-bit floating point samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount); + +/* Low-level function for converting A-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +/* Low-level function for converting u-law samples to signed 32-bit PCM samples. */ +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount); + +#endif /* DR_WAV_NO_CONVERSION_API */ + + +/* High-Level Convenience Helpers */ + +#ifndef DR_WAV_NO_STDIO +/* +Helper for initializing a wave file for reading using stdio. + +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Helper for initializing a wave file for writing using stdio. + +This holds the internal FILE object until drwav_uninit() is called. Keep this in mind if you're caching drwav +objects because the operating system may restrict the number of file handles an application can have open at +any given time. +*/ +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif /* DR_WAV_NO_STDIO */ + +/* +Helper for initializing a loader from a pre-allocated memory buffer. + +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for +the lifetime of the drwav object. + +The buffer should contain the contents of the entire wave file, not just the sample data. +*/ +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* +Helper for initializing a writer which outputs data to a memory buffer. + +dr_wav will manage the memory allocations, however it is up to the caller to free the data with drwav_free(). + +The buffer will remain allocated even after drwav_uninit() is called. The buffer should not be considered valid +until after drwav_uninit() has been called. +*/ +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks); + + +#ifndef DR_WAV_NO_CONVERSION_API +/* +Opens and reads an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#ifndef DR_WAV_NO_STDIO +/* +Opens and decodes an entire wav file in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif +/* +Opens and decodes an entire wav file from a block of memory in a single operation. + +The return value is a heap-allocated buffer containing the audio data. Use drwav_free() to free the buffer. +*/ +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks); +#endif + +/* Frees data that was allocated internally by dr_wav. */ +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks); + +/* Converts bytes from a wav stream to a sized type of native endian. */ +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data); +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data); +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data); +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data); +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data); +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data); + +/* Compares a GUID for the purpose of checking the type of a Wave64 chunk. */ +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]); + +/* Compares a four-character-code for the purpose of checking the type of a RIFF chunk. */ +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b); + +#ifdef __cplusplus +} +#endif +#endif /* dr_wav_h */ + + +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_WAV_IMPLEMENTATION) || defined(DRWAV_IMPLEMENTATION) +#ifndef dr_wav_c +#define dr_wav_c + +#include +#include /* For memcpy(), memset() */ +#include /* For INT_MAX */ + +#ifndef DR_WAV_NO_STDIO +#include +#include +#endif + +/* Standard library stuff. */ +#ifndef DRWAV_ASSERT +#include +#define DRWAV_ASSERT(expression) assert(expression) +#endif +#ifndef DRWAV_MALLOC +#define DRWAV_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRWAV_REALLOC +#define DRWAV_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRWAV_FREE +#define DRWAV_FREE(p) free((p)) +#endif +#ifndef DRWAV_COPY_MEMORY +#define DRWAV_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRWAV_ZERO_MEMORY +#define DRWAV_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#ifndef DRWAV_ZERO_OBJECT +#define DRWAV_ZERO_OBJECT(p) DRWAV_ZERO_MEMORY((p), sizeof(*p)) +#endif + +#define drwav_countof(x) (sizeof(x) / sizeof(x[0])) +#define drwav_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) +#define drwav_min(a, b) (((a) < (b)) ? (a) : (b)) +#define drwav_max(a, b) (((a) > (b)) ? (a) : (b)) +#define drwav_clamp(x, lo, hi) (drwav_max((lo), drwav_min((hi), (x)))) + +#define DRWAV_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ + +/* CPU architecture. */ +#if defined(__x86_64__) || defined(_M_X64) + #define DRWAV_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRWAV_X86 +#elif defined(__arm__) || defined(_M_ARM) + #define DRWAV_ARM +#endif + +#ifdef _MSC_VER + #define DRWAV_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRWAV_INLINE __inline__ __attribute__((always_inline)) + #else + #define DRWAV_INLINE inline __attribute__((always_inline)) + #endif +#elif defined(__WATCOMC__) + #define DRWAV_INLINE __inline +#else + #define DRWAV_INLINE +#endif + +#if defined(SIZE_MAX) + #define DRWAV_SIZE_MAX SIZE_MAX +#else + #if defined(_WIN64) || defined(_LP64) || defined(__LP64__) + #define DRWAV_SIZE_MAX ((drwav_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRWAV_SIZE_MAX 0xFFFFFFFF + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRWAV_HAS_BYTESWAP32_INTRINSIC + #define DRWAV_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRWAV_HAS_BYTESWAP16_INTRINSIC + #endif +#endif + +DRWAV_API void drwav_version(drwav_uint32* pMajor, drwav_uint32* pMinor, drwav_uint32* pRevision) +{ + if (pMajor) { + *pMajor = DRWAV_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = DRWAV_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRWAV_VERSION_REVISION; + } +} + +DRWAV_API const char* drwav_version_string(void) +{ + return DRWAV_VERSION_STRING; +} + +/* +These limits are used for basic validation when initializing the decoder. If you exceed these limits, first of all: what on Earth are +you doing?! (Let me know, I'd be curious!) Second, you can adjust these by #define-ing them before the dr_wav implementation. +*/ +#ifndef DRWAV_MAX_SAMPLE_RATE +#define DRWAV_MAX_SAMPLE_RATE 384000 +#endif +#ifndef DRWAV_MAX_CHANNELS +#define DRWAV_MAX_CHANNELS 256 +#endif +#ifndef DRWAV_MAX_BITS_PER_SAMPLE +#define DRWAV_MAX_BITS_PER_SAMPLE 64 +#endif + +static const drwav_uint8 drwavGUID_W64_RIFF[16] = {0x72,0x69,0x66,0x66, 0x2E,0x91, 0xCF,0x11, 0xA5,0xD6, 0x28,0xDB,0x04,0xC1,0x00,0x00}; /* 66666972-912E-11CF-A5D6-28DB04C10000 */ +static const drwav_uint8 drwavGUID_W64_WAVE[16] = {0x77,0x61,0x76,0x65, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 65766177-ACF3-11D3-8CD1-00C04F8EDB8A */ +/*static const drwav_uint8 drwavGUID_W64_JUNK[16] = {0x6A,0x75,0x6E,0x6B, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A};*/ /* 6B6E756A-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FMT [16] = {0x66,0x6D,0x74,0x20, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 20746D66-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_FACT[16] = {0x66,0x61,0x63,0x74, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 74636166-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_DATA[16] = {0x64,0x61,0x74,0x61, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 61746164-ACF3-11D3-8CD1-00C04F8EDB8A */ +static const drwav_uint8 drwavGUID_W64_SMPL[16] = {0x73,0x6D,0x70,0x6C, 0xF3,0xAC, 0xD3,0x11, 0x8C,0xD1, 0x00,0xC0,0x4F,0x8E,0xDB,0x8A}; /* 6C706D73-ACF3-11D3-8CD1-00C04F8EDB8A */ + +static DRWAV_INLINE drwav_bool32 drwav__guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +{ + int i; + for (i = 0; i < 16; i += 1) { + if (a[i] != b[i]) { + return DRWAV_FALSE; + } + } + + return DRWAV_TRUE; +} + +static DRWAV_INLINE drwav_bool32 drwav__fourcc_equal(const drwav_uint8* a, const char* b) +{ + return + a[0] == b[0] && + a[1] == b[1] && + a[2] == b[2] && + a[3] == b[3]; +} + + + +static DRWAV_INLINE int drwav__is_little_endian(void) +{ +#if defined(DRWAV_X86) || defined(DRWAV_X64) + return DRWAV_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRWAV_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} + +static DRWAV_INLINE drwav_uint16 drwav__bytes_to_u16(const drwav_uint8* data) +{ + return (data[0] << 0) | (data[1] << 8); +} + +static DRWAV_INLINE drwav_int16 drwav__bytes_to_s16(const drwav_uint8* data) +{ + return (short)drwav__bytes_to_u16(data); +} + +static DRWAV_INLINE drwav_uint32 drwav__bytes_to_u32(const drwav_uint8* data) +{ + return (data[0] << 0) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +} + +static DRWAV_INLINE drwav_int32 drwav__bytes_to_s32(const drwav_uint8* data) +{ + return (drwav_int32)drwav__bytes_to_u32(data); +} + +static DRWAV_INLINE drwav_uint64 drwav__bytes_to_u64(const drwav_uint8* data) +{ + return + ((drwav_uint64)data[0] << 0) | ((drwav_uint64)data[1] << 8) | ((drwav_uint64)data[2] << 16) | ((drwav_uint64)data[3] << 24) | + ((drwav_uint64)data[4] << 32) | ((drwav_uint64)data[5] << 40) | ((drwav_uint64)data[6] << 48) | ((drwav_uint64)data[7] << 56); +} + +static DRWAV_INLINE drwav_int64 drwav__bytes_to_s64(const drwav_uint8* data) +{ + return (drwav_int64)drwav__bytes_to_u64(data); +} + +static DRWAV_INLINE void drwav__bytes_to_guid(const drwav_uint8* data, drwav_uint8* guid) +{ + int i; + for (i = 0; i < 16; ++i) { + guid[i] = data[i]; + } +} + + +static DRWAV_INLINE drwav_uint16 drwav__bswap16(drwav_uint16 n) +{ +#ifdef DRWAV_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} + +static DRWAV_INLINE drwav_uint32 drwav__bswap32(drwav_uint32 n) +{ +#ifdef DRWAV_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + #if defined(DRWAV_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRWAV_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ + /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ + drwav_uint32 r; + __asm__ __volatile__ ( + #if defined(DRWAV_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + +static DRWAV_INLINE drwav_uint64 drwav__bswap64(drwav_uint64 n) +{ +#ifdef DRWAV_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + return ((n & ((drwav_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drwav_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drwav_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drwav_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drwav_uint64)0xFF000000 )) << 8) | + ((n & ((drwav_uint64)0x00FF0000 )) << 24) | + ((n & ((drwav_uint64)0x0000FF00 )) << 40) | + ((n & ((drwav_uint64)0x000000FF )) << 56); +#endif +} + + +static DRWAV_INLINE drwav_int16 drwav__bswap_s16(drwav_int16 n) +{ + return (drwav_int16)drwav__bswap16((drwav_uint16)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s16(drwav_int16* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s16(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_s24(drwav_uint8* p) +{ + drwav_uint8 t; + t = p[0]; + p[0] = p[2]; + p[2] = t; +} + +static DRWAV_INLINE void drwav__bswap_samples_s24(drwav_uint8* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + drwav_uint8* pSample = pSamples + (iSample*3); + drwav__bswap_s24(pSample); + } +} + + +static DRWAV_INLINE drwav_int32 drwav__bswap_s32(drwav_int32 n) +{ + return (drwav_int32)drwav__bswap32((drwav_uint32)n); +} + +static DRWAV_INLINE void drwav__bswap_samples_s32(drwav_int32* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_s32(pSamples[iSample]); + } +} + + +static DRWAV_INLINE float drwav__bswap_f32(float n) +{ + union { + drwav_uint32 i; + float f; + } x; + x.f = n; + x.i = drwav__bswap32(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f32(float* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f32(pSamples[iSample]); + } +} + + +static DRWAV_INLINE double drwav__bswap_f64(double n) +{ + union { + drwav_uint64 i; + double f; + } x; + x.f = n; + x.i = drwav__bswap64(x.i); + + return x.f; +} + +static DRWAV_INLINE void drwav__bswap_samples_f64(double* pSamples, drwav_uint64 sampleCount) +{ + drwav_uint64 iSample; + for (iSample = 0; iSample < sampleCount; iSample += 1) { + pSamples[iSample] = drwav__bswap_f64(pSamples[iSample]); + } +} + + +static DRWAV_INLINE void drwav__bswap_samples_pcm(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + /* Assumes integer PCM. Floating point PCM is done in drwav__bswap_samples_ieee(). */ + switch (bytesPerSample) + { + case 2: /* s16, s12 (loosely packed) */ + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + case 3: /* s24 */ + { + drwav__bswap_samples_s24((drwav_uint8*)pSamples, sampleCount); + } break; + case 4: /* s32 */ + { + drwav__bswap_samples_s32((drwav_int32*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + +static DRWAV_INLINE void drwav__bswap_samples_ieee(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample) +{ + switch (bytesPerSample) + { + #if 0 /* Contributions welcome for f16 support. */ + case 2: /* f16 */ + { + drwav__bswap_samples_f16((drwav_float16*)pSamples, sampleCount); + } break; + #endif + case 4: /* f32 */ + { + drwav__bswap_samples_f32((float*)pSamples, sampleCount); + } break; + case 8: /* f64 */ + { + drwav__bswap_samples_f64((double*)pSamples, sampleCount); + } break; + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + +static DRWAV_INLINE void drwav__bswap_samples(void* pSamples, drwav_uint64 sampleCount, drwav_uint32 bytesPerSample, drwav_uint16 format) +{ + switch (format) + { + case DR_WAVE_FORMAT_PCM: + { + drwav__bswap_samples_pcm(pSamples, sampleCount, bytesPerSample); + } break; + + case DR_WAVE_FORMAT_IEEE_FLOAT: + { + drwav__bswap_samples_ieee(pSamples, sampleCount, bytesPerSample); + } break; + + case DR_WAVE_FORMAT_ALAW: + case DR_WAVE_FORMAT_MULAW: + { + drwav__bswap_samples_s16((drwav_int16*)pSamples, sampleCount); + } break; + + case DR_WAVE_FORMAT_ADPCM: + case DR_WAVE_FORMAT_DVI_ADPCM: + default: + { + /* Unsupported format. */ + DRWAV_ASSERT(DRWAV_FALSE); + } break; + } +} + + +static void* drwav__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_MALLOC(sz); +} + +static void* drwav__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRWAV_REALLOC(p, sz); +} + +static void drwav__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRWAV_FREE(p); +} + + +static void* drwav__malloc_from_callbacks(size_t sz, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } + + /* Try using realloc(). */ + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + + return NULL; +} + +static void* drwav__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); + } + + /* Try emulating realloc() in terms of malloc()/free(). */ + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + + if (p != NULL) { + DRWAV_COPY_MEMORY(p2, p, szOld); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drwav__free_from_callbacks(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +static drwav_allocation_callbacks drwav_copy_allocation_callbacks_or_defaults(const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + /* Copy. */ + return *pAllocationCallbacks; + } else { + /* Defaults. */ + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drwav__malloc_default; + allocationCallbacks.onRealloc = drwav__realloc_default; + allocationCallbacks.onFree = drwav__free_default; + return allocationCallbacks; + } +} + + +static DRWAV_INLINE drwav_bool32 drwav__is_compressed_format_tag(drwav_uint16 formatTag) +{ + return + formatTag == DR_WAVE_FORMAT_ADPCM || + formatTag == DR_WAVE_FORMAT_DVI_ADPCM; +} + +static unsigned int drwav__chunk_padding_size_riff(drwav_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 2); +} + +static unsigned int drwav__chunk_padding_size_w64(drwav_uint64 chunkSize) +{ + return (unsigned int)(chunkSize % 8); +} + +static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 samplesToRead, drwav_int16* pBufferOut); +static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount); + +static drwav_result drwav__read_chunk_header(drwav_read_proc onRead, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_chunk_header* pHeaderOut) +{ + if (container == drwav_container_riff || container == drwav_container_rf64) { + drwav_uint8 sizeInBytes[4]; + + if (onRead(pUserData, pHeaderOut->id.fourcc, 4) != 4) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 4) != 4) { + return DRWAV_INVALID_FILE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u32(sizeInBytes); + pHeaderOut->paddingSize = drwav__chunk_padding_size_riff(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 8; + } else { + drwav_uint8 sizeInBytes[8]; + + if (onRead(pUserData, pHeaderOut->id.guid, 16) != 16) { + return DRWAV_AT_END; + } + + if (onRead(pUserData, sizeInBytes, 8) != 8) { + return DRWAV_INVALID_FILE; + } + + pHeaderOut->sizeInBytes = drwav__bytes_to_u64(sizeInBytes) - 24; /* <-- Subtract 24 because w64 includes the size of the header. */ + pHeaderOut->paddingSize = drwav__chunk_padding_size_w64(pHeaderOut->sizeInBytes); + *pRunningBytesReadOut += 24; + } + + return DRWAV_SUCCESS; +} + +static drwav_bool32 drwav__seek_forward(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +{ + drwav_uint64 bytesRemainingToSeek = offset; + while (bytesRemainingToSeek > 0) { + if (bytesRemainingToSeek > 0x7FFFFFFF) { + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek -= 0x7FFFFFFF; + } else { + if (!onSeek(pUserData, (int)bytesRemainingToSeek, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + bytesRemainingToSeek = 0; + } + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav__seek_from_start(drwav_seek_proc onSeek, drwav_uint64 offset, void* pUserData) +{ + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_start); + } + + /* Larger than 32-bit seek. */ + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + + for (;;) { + if (offset <= 0x7FFFFFFF) { + return onSeek(pUserData, (int)offset, drwav_seek_origin_current); + } + + if (!onSeek(pUserData, 0x7FFFFFFF, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + offset -= 0x7FFFFFFF; + } + + /* Should never get here. */ + /*return DRWAV_TRUE; */ +} + + +static drwav_bool32 drwav__read_fmt(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, drwav_container container, drwav_uint64* pRunningBytesReadOut, drwav_fmt* fmtOut) +{ + drwav_chunk_header header; + drwav_uint8 fmt[16]; + + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + + /* Skip non-fmt chunks. */ + while (((container == drwav_container_riff || container == drwav_container_rf64) && !drwav__fourcc_equal(header.id.fourcc, "fmt ")) || (container == drwav_container_w64 && !drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT))) { + if (!drwav__seek_forward(onSeek, header.sizeInBytes + header.paddingSize, pUserData)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.sizeInBytes + header.paddingSize; + + /* Try the next header. */ + if (drwav__read_chunk_header(onRead, pUserData, container, pRunningBytesReadOut, &header) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + } + + + /* Validation. */ + if (container == drwav_container_riff || container == drwav_container_rf64) { + if (!drwav__fourcc_equal(header.id.fourcc, "fmt ")) { + return DRWAV_FALSE; + } + } else { + if (!drwav__guid_equal(header.id.guid, drwavGUID_W64_FMT)) { + return DRWAV_FALSE; + } + } + + + if (onRead(pUserData, fmt, sizeof(fmt)) != sizeof(fmt)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += sizeof(fmt); + + fmtOut->formatTag = drwav__bytes_to_u16(fmt + 0); + fmtOut->channels = drwav__bytes_to_u16(fmt + 2); + fmtOut->sampleRate = drwav__bytes_to_u32(fmt + 4); + fmtOut->avgBytesPerSec = drwav__bytes_to_u32(fmt + 8); + fmtOut->blockAlign = drwav__bytes_to_u16(fmt + 12); + fmtOut->bitsPerSample = drwav__bytes_to_u16(fmt + 14); + + fmtOut->extendedSize = 0; + fmtOut->validBitsPerSample = 0; + fmtOut->channelMask = 0; + memset(fmtOut->subFormat, 0, sizeof(fmtOut->subFormat)); + + if (header.sizeInBytes > 16) { + drwav_uint8 fmt_cbSize[2]; + int bytesReadSoFar = 0; + + if (onRead(pUserData, fmt_cbSize, sizeof(fmt_cbSize)) != sizeof(fmt_cbSize)) { + return DRWAV_FALSE; /* Expecting more data. */ + } + *pRunningBytesReadOut += sizeof(fmt_cbSize); + + bytesReadSoFar = 18; + + fmtOut->extendedSize = drwav__bytes_to_u16(fmt_cbSize); + if (fmtOut->extendedSize > 0) { + /* Simple validation. */ + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + if (fmtOut->extendedSize != 22) { + return DRWAV_FALSE; + } + } + + if (fmtOut->formatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + drwav_uint8 fmtext[22]; + if (onRead(pUserData, fmtext, fmtOut->extendedSize) != fmtOut->extendedSize) { + return DRWAV_FALSE; /* Expecting more data. */ + } + + fmtOut->validBitsPerSample = drwav__bytes_to_u16(fmtext + 0); + fmtOut->channelMask = drwav__bytes_to_u32(fmtext + 2); + drwav__bytes_to_guid(fmtext + 6, fmtOut->subFormat); + } else { + if (!onSeek(pUserData, fmtOut->extendedSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + } + *pRunningBytesReadOut += fmtOut->extendedSize; + + bytesReadSoFar += fmtOut->extendedSize; + } + + /* Seek past any leftover bytes. For w64 the leftover will be defined based on the chunk size. */ + if (!onSeek(pUserData, (int)(header.sizeInBytes - bytesReadSoFar), drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += (header.sizeInBytes - bytesReadSoFar); + } + + if (header.paddingSize > 0) { + if (!onSeek(pUserData, header.paddingSize, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + *pRunningBytesReadOut += header.paddingSize; + } + + return DRWAV_TRUE; +} + + +static size_t drwav__on_read(drwav_read_proc onRead, void* pUserData, void* pBufferOut, size_t bytesToRead, drwav_uint64* pCursor) +{ + size_t bytesRead; + + DRWAV_ASSERT(onRead != NULL); + DRWAV_ASSERT(pCursor != NULL); + + bytesRead = onRead(pUserData, pBufferOut, bytesToRead); + *pCursor += bytesRead; + return bytesRead; +} + +#if 0 +static drwav_bool32 drwav__on_seek(drwav_seek_proc onSeek, void* pUserData, int offset, drwav_seek_origin origin, drwav_uint64* pCursor) +{ + DRWAV_ASSERT(onSeek != NULL); + DRWAV_ASSERT(pCursor != NULL); + + if (!onSeek(pUserData, offset, origin)) { + return DRWAV_FALSE; + } + + if (origin == drwav_seek_origin_start) { + *pCursor = offset; + } else { + *pCursor += offset; + } + + return DRWAV_TRUE; +} +#endif + + + +static drwav_uint32 drwav_get_bytes_per_pcm_frame(drwav* pWav) +{ + /* + The bytes per frame is a bit ambiguous. It can be either be based on the bits per sample, or the block align. The way I'm doing it here + is that if the bits per sample is a multiple of 8, use floor(bitsPerSample*channels/8), otherwise fall back to the block align. + */ + if ((pWav->bitsPerSample & 0x7) == 0) { + /* Bits per sample is a multiple of 8. */ + return (pWav->bitsPerSample * pWav->fmt.channels) >> 3; + } else { + return pWav->fmt.blockAlign; + } +} + +DRWAV_API drwav_uint16 drwav_fmt_get_format(const drwav_fmt* pFMT) +{ + if (pFMT == NULL) { + return 0; + } + + if (pFMT->formatTag != DR_WAVE_FORMAT_EXTENSIBLE) { + return pFMT->formatTag; + } else { + return drwav__bytes_to_u16(pFMT->subFormat); /* Only the first two bytes are required. */ + } +} + +static drwav_bool32 drwav_preinit(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pReadSeekUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pWav == NULL || onRead == NULL || onSeek == NULL) { + return DRWAV_FALSE; + } + + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onRead = onRead; + pWav->onSeek = onSeek; + pWav->pUserData = pReadSeekUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init__internal(drwav* pWav, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags) +{ + /* This function assumes drwav_preinit() has been called beforehand. */ + + drwav_uint64 cursor; /* <-- Keeps track of the byte position so we can seek to specific locations. */ + drwav_bool32 sequential; + drwav_uint8 riff[4]; + drwav_fmt fmt; + unsigned short translatedFormatTag; + drwav_bool32 foundDataChunk; + drwav_uint64 dataChunkSize = 0; /* <-- Important! Don't explicitly set this to 0 anywhere else. Calculation of the size of the data chunk is performed in different paths depending on the container. */ + drwav_uint64 sampleCountFromFactChunk = 0; /* Same as dataChunkSize - make sure this is the only place this is initialized to 0. */ + drwav_uint64 chunkSize; + + cursor = 0; + sequential = (flags & DRWAV_SEQUENTIAL) != 0; + + /* The first 4 bytes should be the RIFF identifier. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff, sizeof(riff), &cursor) != sizeof(riff)) { + return DRWAV_FALSE; + } + + /* + The first 4 bytes can be used to identify the container. For RIFF files it will start with "RIFF" and for + w64 it will start with "riff". + */ + if (drwav__fourcc_equal(riff, "RIFF")) { + pWav->container = drwav_container_riff; + } else if (drwav__fourcc_equal(riff, "riff")) { + int i; + drwav_uint8 riff2[12]; + + pWav->container = drwav_container_w64; + + /* Check the rest of the GUID for validity. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, riff2, sizeof(riff2), &cursor) != sizeof(riff2)) { + return DRWAV_FALSE; + } + + for (i = 0; i < 12; ++i) { + if (riff2[i] != drwavGUID_W64_RIFF[i+4]) { + return DRWAV_FALSE; + } + } + } else if (drwav__fourcc_equal(riff, "RF64")) { + pWav->container = drwav_container_rf64; + } else { + return DRWAV_FALSE; /* Unknown or unsupported container. */ + } + + + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + drwav_uint8 chunkSizeBytes[4]; + drwav_uint8 wave[4]; + + /* RIFF/WAVE */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + if (pWav->container == drwav_container_riff) { + if (drwav__bytes_to_u32(chunkSizeBytes) < 36) { + return DRWAV_FALSE; /* Chunk size should always be at least 36 bytes. */ + } + } else { + if (drwav__bytes_to_u32(chunkSizeBytes) != 0xFFFFFFFF) { + return DRWAV_FALSE; /* Chunk size should always be set to -1/0xFFFFFFFF for RF64. The actual size is retrieved later. */ + } + } + + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__fourcc_equal(wave, "WAVE")) { + return DRWAV_FALSE; /* Expecting "WAVE". */ + } + } else { + drwav_uint8 chunkSizeBytes[8]; + drwav_uint8 wave[16]; + + /* W64 */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, chunkSizeBytes, sizeof(chunkSizeBytes), &cursor) != sizeof(chunkSizeBytes)) { + return DRWAV_FALSE; + } + + if (drwav__bytes_to_u64(chunkSizeBytes) < 80) { + return DRWAV_FALSE; + } + + if (drwav__on_read(pWav->onRead, pWav->pUserData, wave, sizeof(wave), &cursor) != sizeof(wave)) { + return DRWAV_FALSE; + } + + if (!drwav__guid_equal(wave, drwavGUID_W64_WAVE)) { + return DRWAV_FALSE; + } + } + + + /* For RF64, the "ds64" chunk must come next, before the "fmt " chunk. */ + if (pWav->container == drwav_container_rf64) { + drwav_uint8 sizeBytes[8]; + drwav_uint64 bytesRemainingInChunk; + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + if (!drwav__fourcc_equal(header.id.fourcc, "ds64")) { + return DRWAV_FALSE; /* Expecting "ds64". */ + } + + bytesRemainingInChunk = header.sizeInBytes + header.paddingSize; + + /* We don't care about the size of the RIFF chunk - skip it. */ + if (!drwav__seek_forward(pWav->onSeek, 8, pWav->pUserData)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + cursor += 8; + + + /* Next 8 bytes is the size of the "data" chunk. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + dataChunkSize = drwav__bytes_to_u64(sizeBytes); + + + /* Next 8 bytes is the same count which we would usually derived from the FACT chunk if it was available. */ + if (drwav__on_read(pWav->onRead, pWav->pUserData, sizeBytes, sizeof(sizeBytes), &cursor) != sizeof(sizeBytes)) { + return DRWAV_FALSE; + } + bytesRemainingInChunk -= 8; + sampleCountFromFactChunk = drwav__bytes_to_u64(sizeBytes); + + + /* Skip over everything else. */ + if (!drwav__seek_forward(pWav->onSeek, bytesRemainingInChunk, pWav->pUserData)) { + return DRWAV_FALSE; + } + cursor += bytesRemainingInChunk; + } + + + /* The next bytes should be the "fmt " chunk. */ + if (!drwav__read_fmt(pWav->onRead, pWav->onSeek, pWav->pUserData, pWav->container, &cursor, &fmt)) { + return DRWAV_FALSE; /* Failed to read the "fmt " chunk. */ + } + + /* Basic validation. */ + if ((fmt.sampleRate == 0 || fmt.sampleRate > DRWAV_MAX_SAMPLE_RATE) || + (fmt.channels == 0 || fmt.channels > DRWAV_MAX_CHANNELS) || + (fmt.bitsPerSample == 0 || fmt.bitsPerSample > DRWAV_MAX_BITS_PER_SAMPLE) || + fmt.blockAlign == 0) { + return DRWAV_FALSE; /* Probably an invalid WAV file. */ + } + + + /* Translate the internal format. */ + translatedFormatTag = fmt.formatTag; + if (translatedFormatTag == DR_WAVE_FORMAT_EXTENSIBLE) { + translatedFormatTag = drwav__bytes_to_u16(fmt.subFormat + 0); + } + + + /* + We need to enumerate over each chunk for two reasons: + 1) The "data" chunk may not be the next one + 2) We may want to report each chunk back to the client + + In order to correctly report each chunk back to the client we will need to keep looping until the end of the file. + */ + foundDataChunk = DRWAV_FALSE; + + /* The next chunk we care about is the "data" chunk. This is not necessarily the next chunk so we'll need to loop. */ + for (;;) + { + drwav_chunk_header header; + drwav_result result = drwav__read_chunk_header(pWav->onRead, pWav->pUserData, pWav->container, &cursor, &header); + if (result != DRWAV_SUCCESS) { + if (!foundDataChunk) { + return DRWAV_FALSE; + } else { + break; /* Probably at the end of the file. Get out of the loop. */ + } + } + + /* Tell the client about this chunk. */ + if (!sequential && onChunk != NULL) { + drwav_uint64 callbackBytesRead = onChunk(pChunkUserData, pWav->onRead, pWav->onSeek, pWav->pUserData, &header, pWav->container, &fmt); + + /* + dr_wav may need to read the contents of the chunk, so we now need to seek back to the position before + we called the callback. + */ + if (callbackBytesRead > 0) { + if (!drwav__seek_from_start(pWav->onSeek, cursor, pWav->pUserData)) { + return DRWAV_FALSE; + } + } + } + + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + + chunkSize = header.sizeInBytes; + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav__fourcc_equal(header.id.fourcc, "data")) { + foundDataChunk = DRWAV_TRUE; + if (pWav->container != drwav_container_rf64) { /* The data chunk size for RF64 will always be set to 0xFFFFFFFF here. It was set to it's true value earlier. */ + dataChunkSize = chunkSize; + } + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_DATA)) { + foundDataChunk = DRWAV_TRUE; + dataChunkSize = chunkSize; + } + } + + /* + If at this point we have found the data chunk and we're running in sequential mode, we need to break out of this loop. The reason for + this is that we would otherwise require a backwards seek which sequential mode forbids. + */ + if (foundDataChunk && sequential) { + break; + } + + /* Optional. Get the total sample count from the FACT chunk. This is useful for compressed formats. */ + if (pWav->container == drwav_container_riff) { + if (drwav__fourcc_equal(header.id.fourcc, "fact")) { + drwav_uint32 sampleCount; + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCount, 4, &cursor) != 4) { + return DRWAV_FALSE; + } + chunkSize -= 4; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + + /* + The sample count in the "fact" chunk is either unreliable, or I'm not understanding it properly. For now I am only enabling this + for Microsoft ADPCM formats. + */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + sampleCountFromFactChunk = sampleCount; + } else { + sampleCountFromFactChunk = 0; + } + } + } else if (pWav->container == drwav_container_w64) { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_FACT)) { + if (drwav__on_read(pWav->onRead, pWav->pUserData, &sampleCountFromFactChunk, 8, &cursor) != 8) { + return DRWAV_FALSE; + } + chunkSize -= 8; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + } + } else if (pWav->container == drwav_container_rf64) { + /* We retrieved the sample count from the ds64 chunk earlier so no need to do that here. */ + } + + /* "smpl" chunk. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + if (drwav__fourcc_equal(header.id.fourcc, "smpl")) { + drwav_uint8 smplHeaderData[36]; /* 36 = size of the smpl header section, not including the loop data. */ + if (chunkSize >= sizeof(smplHeaderData)) { + drwav_uint64 bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplHeaderData, sizeof(smplHeaderData), &cursor); + chunkSize -= bytesJustRead; + + if (bytesJustRead == sizeof(smplHeaderData)) { + drwav_uint32 iLoop; + + pWav->smpl.manufacturer = drwav__bytes_to_u32(smplHeaderData+0); + pWav->smpl.product = drwav__bytes_to_u32(smplHeaderData+4); + pWav->smpl.samplePeriod = drwav__bytes_to_u32(smplHeaderData+8); + pWav->smpl.midiUnityNotes = drwav__bytes_to_u32(smplHeaderData+12); + pWav->smpl.midiPitchFraction = drwav__bytes_to_u32(smplHeaderData+16); + pWav->smpl.smpteFormat = drwav__bytes_to_u32(smplHeaderData+20); + pWav->smpl.smpteOffset = drwav__bytes_to_u32(smplHeaderData+24); + pWav->smpl.numSampleLoops = drwav__bytes_to_u32(smplHeaderData+28); + pWav->smpl.samplerData = drwav__bytes_to_u32(smplHeaderData+32); + + for (iLoop = 0; iLoop < pWav->smpl.numSampleLoops && iLoop < drwav_countof(pWav->smpl.loops); ++iLoop) { + drwav_uint8 smplLoopData[24]; /* 24 = size of a loop section in the smpl chunk. */ + bytesJustRead = drwav__on_read(pWav->onRead, pWav->pUserData, smplLoopData, sizeof(smplLoopData), &cursor); + chunkSize -= bytesJustRead; + + if (bytesJustRead == sizeof(smplLoopData)) { + pWav->smpl.loops[iLoop].cuePointId = drwav__bytes_to_u32(smplLoopData+0); + pWav->smpl.loops[iLoop].type = drwav__bytes_to_u32(smplLoopData+4); + pWav->smpl.loops[iLoop].start = drwav__bytes_to_u32(smplLoopData+8); + pWav->smpl.loops[iLoop].end = drwav__bytes_to_u32(smplLoopData+12); + pWav->smpl.loops[iLoop].fraction = drwav__bytes_to_u32(smplLoopData+16); + pWav->smpl.loops[iLoop].playCount = drwav__bytes_to_u32(smplLoopData+20); + } else { + break; /* Break from the smpl loop for loop. */ + } + } + } + } else { + /* Looks like invalid data. Ignore the chunk. */ + } + } + } else { + if (drwav__guid_equal(header.id.guid, drwavGUID_W64_SMPL)) { + /* + This path will be hit when a W64 WAV file contains a smpl chunk. I don't have a sample file to test this path, so a contribution + is welcome to add support for this. + */ + } + } + + /* Make sure we seek past the padding. */ + chunkSize += header.paddingSize; + if (!drwav__seek_forward(pWav->onSeek, chunkSize, pWav->pUserData)) { + break; + } + cursor += chunkSize; + + if (!foundDataChunk) { + pWav->dataChunkDataPos = cursor; + } + } + + /* If we haven't found a data chunk, return an error. */ + if (!foundDataChunk) { + return DRWAV_FALSE; + } + + /* We may have moved passed the data chunk. If so we need to move back. If running in sequential mode we can assume we are already sitting on the data chunk. */ + if (!sequential) { + if (!drwav__seek_from_start(pWav->onSeek, pWav->dataChunkDataPos, pWav->pUserData)) { + return DRWAV_FALSE; + } + cursor = pWav->dataChunkDataPos; + } + + + /* At this point we should be sitting on the first byte of the raw audio data. */ + + pWav->fmt = fmt; + pWav->sampleRate = fmt.sampleRate; + pWav->channels = fmt.channels; + pWav->bitsPerSample = fmt.bitsPerSample; + pWav->bytesRemaining = dataChunkSize; + pWav->translatedFormatTag = translatedFormatTag; + pWav->dataChunkDataSize = dataChunkSize; + + if (sampleCountFromFactChunk != 0) { + pWav->totalPCMFrameCount = sampleCountFromFactChunk; + } else { + pWav->totalPCMFrameCount = dataChunkSize / drwav_get_bytes_per_pcm_frame(pWav); + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (6*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 totalBlockHeaderSizeInBytes; + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + + /* Make sure any trailing partial block is accounted for. */ + if ((blockCount * fmt.blockAlign) < dataChunkSize) { + blockCount += 1; + } + + /* We decode two samples per byte. There will be blockCount headers in the data chunk. This is enough to know how to calculate the total PCM frame count. */ + totalBlockHeaderSizeInBytes = blockCount * (4*fmt.channels); + pWav->totalPCMFrameCount = ((dataChunkSize - totalBlockHeaderSizeInBytes) * 2) / fmt.channels; + + /* The header includes a decoded sample for each channel which acts as the initial predictor sample. */ + pWav->totalPCMFrameCount += blockCount; + } + } + + /* Some formats only support a certain number of channels. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM || pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + if (pWav->channels > 2) { + return DRWAV_FALSE; + } + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + /* + I use libsndfile as a benchmark for testing, however in the version I'm using (from the Windows installer on the libsndfile website), + it appears the total sample count libsndfile uses for MS-ADPCM is incorrect. It would seem they are computing the total sample count + from the number of blocks, however this results in the inclusion of extra silent samples at the end of the last block. The correct + way to know the total sample count is to inspect the "fact" chunk, which should always be present for compressed formats, and should + always include the sample count. This little block of code below is only used to emulate the libsndfile logic so I can properly run my + correctness tests against libsndfile, and is disabled by default. + */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (6*pWav->channels))) * 2)) / fmt.channels; /* x2 because two samples per byte. */ + } + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + drwav_uint64 blockCount = dataChunkSize / fmt.blockAlign; + pWav->totalPCMFrameCount = (((blockCount * (fmt.blockAlign - (4*pWav->channels))) * 2) + (blockCount * pWav->channels)) / fmt.channels; + } +#endif + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_ex(pWav, onRead, onSeek, NULL, pUserData, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_ex(drwav* pWav, drwav_read_proc onRead, drwav_seek_proc onSeek, drwav_chunk_proc onChunk, void* pReadSeekUserData, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit(pWav, onRead, onSeek, pReadSeekUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); +} + + +static drwav_uint32 drwav__riff_chunk_size_riff(drwav_uint64 dataChunkSize) +{ + drwav_uint64 chunkSize = 4 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + + return (drwav_uint32)chunkSize; /* Safe cast due to the clamp above. */ +} + +static drwav_uint32 drwav__data_chunk_size_riff(drwav_uint64 dataChunkSize) +{ + if (dataChunkSize <= 0xFFFFFFFFUL) { + return (drwav_uint32)dataChunkSize; + } else { + return 0xFFFFFFFFUL; + } +} + +static drwav_uint64 drwav__riff_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 dataSubchunkPaddingSize = drwav__chunk_padding_size_w64(dataChunkSize); + + return 80 + 24 + dataChunkSize + dataSubchunkPaddingSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +static drwav_uint64 drwav__data_chunk_size_w64(drwav_uint64 dataChunkSize) +{ + return 24 + dataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ +} + +static drwav_uint64 drwav__riff_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + drwav_uint64 chunkSize = 4 + 36 + 24 + dataChunkSize + drwav__chunk_padding_size_riff(dataChunkSize); /* 4 = "WAVE". 36 = "ds64" chunk. 24 = "fmt " chunk. */ + if (chunkSize > 0xFFFFFFFFUL) { + chunkSize = 0xFFFFFFFFUL; + } + + return chunkSize; +} + +static drwav_uint64 drwav__data_chunk_size_rf64(drwav_uint64 dataChunkSize) +{ + return dataChunkSize; +} + + +static size_t drwav__write(drwav* pWav, const void* pData, size_t dataSize) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + /* Generic write. Assumes no byte reordering required. */ + return pWav->onWrite(pWav->pUserData, pData, dataSize); +} + +static size_t drwav__write_u16ne_to_le(drwav* pWav, drwav_uint16 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap16(value); + } + + return drwav__write(pWav, &value, 2); +} + +static size_t drwav__write_u32ne_to_le(drwav* pWav, drwav_uint32 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap32(value); + } + + return drwav__write(pWav, &value, 4); +} + +static size_t drwav__write_u64ne_to_le(drwav* pWav, drwav_uint64 value) +{ + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->onWrite != NULL); + + if (!drwav__is_little_endian()) { + value = drwav__bswap64(value); + } + + return drwav__write(pWav, &value, 8); +} + + +static drwav_bool32 drwav_preinit_write(drwav* pWav, const drwav_data_format* pFormat, drwav_bool32 isSequential, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pWav == NULL || onWrite == NULL) { + return DRWAV_FALSE; + } + + if (!isSequential && onSeek == NULL) { + return DRWAV_FALSE; /* <-- onSeek is required when in non-sequential mode. */ + } + + /* Not currently supporting compressed formats. Will need to add support for the "fact" chunk before we enable this. */ + if (pFormat->format == DR_WAVE_FORMAT_EXTENSIBLE) { + return DRWAV_FALSE; + } + if (pFormat->format == DR_WAVE_FORMAT_ADPCM || pFormat->format == DR_WAVE_FORMAT_DVI_ADPCM) { + return DRWAV_FALSE; + } + + DRWAV_ZERO_MEMORY(pWav, sizeof(*pWav)); + pWav->onWrite = onWrite; + pWav->onSeek = onSeek; + pWav->pUserData = pUserData; + pWav->allocationCallbacks = drwav_copy_allocation_callbacks_or_defaults(pAllocationCallbacks); + + if (pWav->allocationCallbacks.onFree == NULL || (pWav->allocationCallbacks.onMalloc == NULL && pWav->allocationCallbacks.onRealloc == NULL)) { + return DRWAV_FALSE; /* Invalid allocation callbacks. */ + } + + pWav->fmt.formatTag = (drwav_uint16)pFormat->format; + pWav->fmt.channels = (drwav_uint16)pFormat->channels; + pWav->fmt.sampleRate = pFormat->sampleRate; + pWav->fmt.avgBytesPerSec = (drwav_uint32)((pFormat->bitsPerSample * pFormat->sampleRate * pFormat->channels) / 8); + pWav->fmt.blockAlign = (drwav_uint16)((pFormat->channels * pFormat->bitsPerSample) / 8); + pWav->fmt.bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->fmt.extendedSize = 0; + pWav->isSequentialWrite = isSequential; + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init_write__internal(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) +{ + /* The function assumes drwav_preinit_write() was called beforehand. */ + + size_t runningPos = 0; + drwav_uint64 initialDataChunkSize = 0; + drwav_uint64 chunkSizeFMT; + + /* + The initial values for the "RIFF" and "data" chunks depends on whether or not we are initializing in sequential mode or not. In + sequential mode we set this to its final values straight away since they can be calculated from the total sample count. In non- + sequential mode we initialize it all to zero and fill it out in drwav_uninit() using a backwards seek. + */ + if (pWav->isSequentialWrite) { + initialDataChunkSize = (totalSampleCount * pWav->fmt.bitsPerSample) / 8; + + /* + The RIFF container has a limit on the number of samples. drwav is not allowing this. There's no practical limits for Wave64 + so for the sake of simplicity I'm not doing any validation for that. + */ + if (pFormat->container == drwav_container_riff) { + if (initialDataChunkSize > (0xFFFFFFFFUL - 36)) { + return DRWAV_FALSE; /* Not enough room to store every sample. */ + } + } + } + + pWav->dataChunkDataSizeTargetWrite = initialDataChunkSize; + + + /* "RIFF" chunk. */ + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeRIFF = 28 + (drwav_uint32)initialDataChunkSize; /* +28 = "WAVE" + [sizeof "fmt " chunk] */ + runningPos += drwav__write(pWav, "RIFF", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, "WAVE", 4); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeRIFF = 80 + 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ + runningPos += drwav__write(pWav, drwavGUID_W64_RIFF, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeRIFF); + runningPos += drwav__write(pWav, drwavGUID_W64_WAVE, 16); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "RF64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always 0xFFFFFFFF for RF64. Set to a proper value in the "ds64" chunk. */ + runningPos += drwav__write(pWav, "WAVE", 4); + } + + + /* "ds64" chunk (RF64 only). */ + if (pFormat->container == drwav_container_rf64) { + drwav_uint32 initialds64ChunkSize = 28; /* 28 = [Size of RIFF (8 bytes)] + [Size of DATA (8 bytes)] + [Sample Count (8 bytes)] + [Table Length (4 bytes)]. Table length always set to 0. */ + drwav_uint64 initialRiffChunkSize = 8 + initialds64ChunkSize + initialDataChunkSize; /* +8 for the ds64 header. */ + + runningPos += drwav__write(pWav, "ds64", 4); + runningPos += drwav__write_u32ne_to_le(pWav, initialds64ChunkSize); /* Size of ds64. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialRiffChunkSize); /* Size of RIFF. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, initialDataChunkSize); /* Size of DATA. Set to true value at the end. */ + runningPos += drwav__write_u64ne_to_le(pWav, totalSampleCount); /* Sample count. */ + runningPos += drwav__write_u32ne_to_le(pWav, 0); /* Table length. Always set to zero in our case since we're not doing any other chunks than "DATA". */ + } + + + /* "fmt " chunk. */ + if (pFormat->container == drwav_container_riff || pFormat->container == drwav_container_rf64) { + chunkSizeFMT = 16; + runningPos += drwav__write(pWav, "fmt ", 4); + runningPos += drwav__write_u32ne_to_le(pWav, (drwav_uint32)chunkSizeFMT); + } else if (pFormat->container == drwav_container_w64) { + chunkSizeFMT = 40; + runningPos += drwav__write(pWav, drwavGUID_W64_FMT, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeFMT); + } + + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.formatTag); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.channels); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.sampleRate); + runningPos += drwav__write_u32ne_to_le(pWav, pWav->fmt.avgBytesPerSec); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.blockAlign); + runningPos += drwav__write_u16ne_to_le(pWav, pWav->fmt.bitsPerSample); + + pWav->dataChunkDataPos = runningPos; + + /* "data" chunk. */ + if (pFormat->container == drwav_container_riff) { + drwav_uint32 chunkSizeDATA = (drwav_uint32)initialDataChunkSize; + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_w64) { + drwav_uint64 chunkSizeDATA = 24 + initialDataChunkSize; /* +24 because W64 includes the size of the GUID and size fields. */ + runningPos += drwav__write(pWav, drwavGUID_W64_DATA, 16); + runningPos += drwav__write_u64ne_to_le(pWav, chunkSizeDATA); + } else if (pFormat->container == drwav_container_rf64) { + runningPos += drwav__write(pWav, "data", 4); + runningPos += drwav__write_u32ne_to_le(pWav, 0xFFFFFFFF); /* Always set to 0xFFFFFFFF for RF64. The true size of the data chunk is specified in the ds64 chunk. */ + } + + /* + The runningPos variable is incremented in the section above but is left unused which is causing some static analysis tools to detect it + as a dead store. I'm leaving this as-is for safety just in case I want to expand this function later to include other tags and want to + keep track of the running position for whatever reason. The line below should silence the static analysis tools. + */ + (void)runningPos; + + /* Set some properties for the client's convenience. */ + pWav->container = pFormat->container; + pWav->channels = (drwav_uint16)pFormat->channels; + pWav->sampleRate = pFormat->sampleRate; + pWav->bitsPerSample = (drwav_uint16)pFormat->bitsPerSample; + pWav->translatedFormatTag = (drwav_uint16)pFormat->format; + + return DRWAV_TRUE; +} + + +DRWAV_API drwav_bool32 drwav_init_write(drwav* pWav, const drwav_data_format* pFormat, drwav_write_proc onWrite, drwav_seek_proc onSeek, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit_write(pWav, pFormat, DRWAV_FALSE, onWrite, onSeek, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, 0); /* DRWAV_FALSE = Not Sequential */ +} + +DRWAV_API drwav_bool32 drwav_init_write_sequential(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (!drwav_preinit_write(pWav, pFormat, DRWAV_TRUE, onWrite, NULL, pUserData, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); /* DRWAV_TRUE = Sequential */ +} + +DRWAV_API drwav_bool32 drwav_init_write_sequential_pcm_frames(drwav* pWav, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, drwav_write_proc onWrite, void* pUserData, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_write_sequential(pWav, pFormat, totalPCMFrameCount*pFormat->channels, onWrite, pUserData, pAllocationCallbacks); +} + +DRWAV_API drwav_uint64 drwav_target_write_size_bytes(const drwav_data_format* pFormat, drwav_uint64 totalSampleCount) +{ + /* Casting totalSampleCount to drwav_int64 for VC6 compatibility. No issues in practice because nobody is going to exhaust the whole 63 bits. */ + drwav_uint64 targetDataSizeBytes = (drwav_uint64)((drwav_int64)totalSampleCount * pFormat->channels * pFormat->bitsPerSample/8.0); + drwav_uint64 riffChunkSizeBytes; + drwav_uint64 fileSizeBytes = 0; + + if (pFormat->container == drwav_container_riff) { + riffChunkSizeBytes = drwav__riff_chunk_size_riff(targetDataSizeBytes); + fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ + } else if (pFormat->container == drwav_container_w64) { + riffChunkSizeBytes = drwav__riff_chunk_size_w64(targetDataSizeBytes); + fileSizeBytes = riffChunkSizeBytes; + } else if (pFormat->container == drwav_container_rf64) { + riffChunkSizeBytes = drwav__riff_chunk_size_rf64(targetDataSizeBytes); + fileSizeBytes = (8 + riffChunkSizeBytes); /* +8 because WAV doesn't include the size of the ChunkID and ChunkSize fields. */ + } + + return fileSizeBytes; +} + + +#ifndef DR_WAV_NO_STDIO + +/* drwav_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ +#include +static drwav_result drwav_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRWAV_SUCCESS; + #ifdef EPERM + case EPERM: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRWAV_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRWAV_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRWAV_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRWAV_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRWAV_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRWAV_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRWAV_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRWAV_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRWAV_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRWAV_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRWAV_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRWAV_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRWAV_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRWAV_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRWAV_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRWAV_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRWAV_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRWAV_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRWAV_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRWAV_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRWAV_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRWAV_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRWAV_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRWAV_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRWAV_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRWAV_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRWAV_NOT_IMPLEMENTED; + #endif + #ifdef ENOTEMPTY + case ENOTEMPTY: return DRWAV_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRWAV_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRWAV_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRWAV_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRWAV_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRWAV_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRWAV_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRWAV_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRWAV_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRWAV_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRWAV_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRWAV_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRWAV_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRWAV_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRWAV_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRWAV_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRWAV_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRWAV_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRWAV_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRWAV_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRWAV_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRWAV_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRWAV_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRWAV_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRWAV_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRWAV_ERROR; + #endif + #ifdef EADV + case EADV: return DRWAV_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRWAV_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRWAV_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRWAV_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRWAV_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRWAV_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRWAV_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRWAV_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRWAV_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRWAV_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRWAV_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRWAV_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRWAV_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRWAV_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRWAV_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRWAV_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRWAV_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRWAV_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRWAV_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRWAV_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRWAV_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRWAV_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRWAV_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRWAV_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRWAV_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRWAV_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRWAV_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRWAV_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRWAV_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRWAV_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRWAV_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRWAV_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRWAV_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRWAV_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRWAV_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRWAV_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRWAV_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRWAV_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRWAV_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRWAV_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRWAV_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRWAV_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRWAV_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRWAV_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRWAV_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRWAV_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRWAV_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRWAV_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRWAV_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRWAV_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRWAV_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRWAV_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRWAV_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRWAV_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRWAV_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRWAV_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRWAV_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRWAV_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRWAV_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRWAV_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRWAV_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRWAV_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRWAV_ERROR; + #endif + default: return DRWAV_ERROR; + } +} + +static drwav_result drwav_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if _MSC_VER && _MSC_VER >= 1400 + errno_t err; +#endif + + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } + +#if _MSC_VER && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drwav_result result = drwav_result_from_errno(errno); + if (result == DRWAV_SUCCESS) { + result = DRWAV_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRWAV_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRWAV_HAS_WFOPEN + #endif +#endif + +static drwav_result drwav_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRWAV_INVALID_ARGS; + } + +#if defined(DRWAV_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drwav_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drwav_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can + think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility. + */ + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + DRWAV_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drwav_result_from_errno(errno); + } + + pFilePathMB = (char*)drwav__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRWAV_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + DRWAV_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + + *ppFile = fopen(pFilePathMB, pOpenModeMB); + + drwav__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + + if (*ppFile == NULL) { + return DRWAV_ERROR; + } +#endif + + return DRWAV_SUCCESS; +} + + +static size_t drwav__on_read_stdio(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + return fread(pBufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +static size_t drwav__on_write_stdio(void* pUserData, const void* pData, size_t bytesToWrite) +{ + return fwrite(pData, 1, bytesToWrite, (FILE*)pUserData); +} + +static drwav_bool32 drwav__on_seek_stdio(void* pUserData, int offset, drwav_seek_origin origin) +{ + return fseek((FILE*)pUserData, offset, (origin == drwav_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0; +} + +DRWAV_API drwav_bool32 drwav_init_file(drwav* pWav, const char* filename, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_ex(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); +} + + +static drwav_bool32 drwav_init_file__internal_FILE(drwav* pWav, FILE* pFile, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav_bool32 result; + + result = drwav_preinit(pWav, drwav__on_read_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + result = drwav_init__internal(pWav, onChunk, pChunkUserData, flags); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init_file_ex(drwav* pWav, const char* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_fopen(&pFile, filename, "rb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_w(drwav* pWav, const wchar_t* filename, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_ex_w(pWav, filename, NULL, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_ex_w(drwav* pWav, const wchar_t* filename, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_wfopen(&pFile, filename, L"rb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file__internal_FILE(pWav, pFile, onChunk, pChunkUserData, flags, pAllocationCallbacks); +} + + +static drwav_bool32 drwav_init_file_write__internal_FILE(drwav* pWav, FILE* pFile, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav_bool32 result; + + result = drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_stdio, drwav__on_seek_stdio, (void*)pFile, pAllocationCallbacks); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + result = drwav_init_write__internal(pWav, pFormat, totalSampleCount); + if (result != DRWAV_TRUE) { + fclose(pFile); + return result; + } + + return DRWAV_TRUE; +} + +static drwav_bool32 drwav_init_file_write__internal(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_fopen(&pFile, filename, "wb") != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); +} + +static drwav_bool32 drwav_init_file_write_w__internal(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + FILE* pFile; + if (drwav_wfopen(&pFile, filename, L"wb", pAllocationCallbacks) != DRWAV_SUCCESS) { + return DRWAV_FALSE; + } + + /* This takes ownership of the FILE* object. */ + return drwav_init_file_write__internal_FILE(pWav, pFile, pFormat, totalSampleCount, isSequential, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write(drwav* pWav, const char* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames(drwav* pWav, const char* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_file_write_sequential(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write_w__internal(pWav, filename, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_file_write_w__internal(pWav, filename, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_file_write_sequential_pcm_frames_w(drwav* pWav, const wchar_t* filename, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_file_write_sequential_w(pWav, filename, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} +#endif /* DR_WAV_NO_STDIO */ + + +static size_t drwav__on_read_memory(void* pUserData, void* pBufferOut, size_t bytesToRead) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStream.dataSize >= pWav->memoryStream.currentReadPos); + + bytesRemaining = pWav->memoryStream.dataSize - pWav->memoryStream.currentReadPos; + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (bytesToRead > 0) { + DRWAV_COPY_MEMORY(pBufferOut, pWav->memoryStream.data + pWav->memoryStream.currentReadPos, bytesToRead); + pWav->memoryStream.currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +static drwav_bool32 drwav__on_seek_memory(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStream.currentReadPos + offset > pWav->memoryStream.dataSize) { + return DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStream.currentReadPos < (size_t)-offset) { + return DRWAV_FALSE; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStream.currentReadPos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStream.dataSize) { + pWav->memoryStream.currentReadPos = offset; + } else { + return DRWAV_FALSE; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +static size_t drwav__on_write_memory(void* pUserData, const void* pDataIn, size_t bytesToWrite) +{ + drwav* pWav = (drwav*)pUserData; + size_t bytesRemaining; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(pWav->memoryStreamWrite.dataCapacity >= pWav->memoryStreamWrite.currentWritePos); + + bytesRemaining = pWav->memoryStreamWrite.dataCapacity - pWav->memoryStreamWrite.currentWritePos; + if (bytesRemaining < bytesToWrite) { + /* Need to reallocate. */ + void* pNewData; + size_t newDataCapacity = (pWav->memoryStreamWrite.dataCapacity == 0) ? 256 : pWav->memoryStreamWrite.dataCapacity * 2; + + /* If doubling wasn't enough, just make it the minimum required size to write the data. */ + if ((newDataCapacity - pWav->memoryStreamWrite.currentWritePos) < bytesToWrite) { + newDataCapacity = pWav->memoryStreamWrite.currentWritePos + bytesToWrite; + } + + pNewData = drwav__realloc_from_callbacks(*pWav->memoryStreamWrite.ppData, newDataCapacity, pWav->memoryStreamWrite.dataCapacity, &pWav->allocationCallbacks); + if (pNewData == NULL) { + return 0; + } + + *pWav->memoryStreamWrite.ppData = pNewData; + pWav->memoryStreamWrite.dataCapacity = newDataCapacity; + } + + DRWAV_COPY_MEMORY(((drwav_uint8*)(*pWav->memoryStreamWrite.ppData)) + pWav->memoryStreamWrite.currentWritePos, pDataIn, bytesToWrite); + + pWav->memoryStreamWrite.currentWritePos += bytesToWrite; + if (pWav->memoryStreamWrite.dataSize < pWav->memoryStreamWrite.currentWritePos) { + pWav->memoryStreamWrite.dataSize = pWav->memoryStreamWrite.currentWritePos; + } + + *pWav->memoryStreamWrite.pDataSize = pWav->memoryStreamWrite.dataSize; + + return bytesToWrite; +} + +static drwav_bool32 drwav__on_seek_memory_write(void* pUserData, int offset, drwav_seek_origin origin) +{ + drwav* pWav = (drwav*)pUserData; + DRWAV_ASSERT(pWav != NULL); + + if (origin == drwav_seek_origin_current) { + if (offset > 0) { + if (pWav->memoryStreamWrite.currentWritePos + offset > pWav->memoryStreamWrite.dataSize) { + offset = (int)(pWav->memoryStreamWrite.dataSize - pWav->memoryStreamWrite.currentWritePos); /* Trying to seek too far forward. */ + } + } else { + if (pWav->memoryStreamWrite.currentWritePos < (size_t)-offset) { + offset = -(int)pWav->memoryStreamWrite.currentWritePos; /* Trying to seek too far backwards. */ + } + } + + /* This will never underflow thanks to the clamps above. */ + pWav->memoryStreamWrite.currentWritePos += offset; + } else { + if ((drwav_uint32)offset <= pWav->memoryStreamWrite.dataSize) { + pWav->memoryStreamWrite.currentWritePos = offset; + } else { + pWav->memoryStreamWrite.currentWritePos = pWav->memoryStreamWrite.dataSize; /* Trying to seek too far forward. */ + } + } + + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_init_memory(drwav* pWav, const void* data, size_t dataSize, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_ex(pWav, data, dataSize, NULL, NULL, 0, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_ex(drwav* pWav, const void* data, size_t dataSize, drwav_chunk_proc onChunk, void* pChunkUserData, drwav_uint32 flags, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (data == NULL || dataSize == 0) { + return DRWAV_FALSE; + } + + if (!drwav_preinit(pWav, drwav__on_read_memory, drwav__on_seek_memory, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + pWav->memoryStream.data = (const drwav_uint8*)data; + pWav->memoryStream.dataSize = dataSize; + pWav->memoryStream.currentReadPos = 0; + + return drwav_init__internal(pWav, onChunk, pChunkUserData, flags); +} + + +static drwav_bool32 drwav_init_memory_write__internal(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, drwav_bool32 isSequential, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (ppData == NULL || pDataSize == NULL) { + return DRWAV_FALSE; + } + + *ppData = NULL; /* Important because we're using realloc()! */ + *pDataSize = 0; + + if (!drwav_preinit_write(pWav, pFormat, isSequential, drwav__on_write_memory, drwav__on_seek_memory_write, pWav, pAllocationCallbacks)) { + return DRWAV_FALSE; + } + + pWav->memoryStreamWrite.ppData = ppData; + pWav->memoryStreamWrite.pDataSize = pDataSize; + pWav->memoryStreamWrite.dataSize = 0; + pWav->memoryStreamWrite.dataCapacity = 0; + pWav->memoryStreamWrite.currentWritePos = 0; + + return drwav_init_write__internal(pWav, pFormat, totalSampleCount); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, 0, DRWAV_FALSE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalSampleCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + return drwav_init_memory_write__internal(pWav, ppData, pDataSize, pFormat, totalSampleCount, DRWAV_TRUE, pAllocationCallbacks); +} + +DRWAV_API drwav_bool32 drwav_init_memory_write_sequential_pcm_frames(drwav* pWav, void** ppData, size_t* pDataSize, const drwav_data_format* pFormat, drwav_uint64 totalPCMFrameCount, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pFormat == NULL) { + return DRWAV_FALSE; + } + + return drwav_init_memory_write_sequential(pWav, ppData, pDataSize, pFormat, totalPCMFrameCount*pFormat->channels, pAllocationCallbacks); +} + + + +DRWAV_API drwav_result drwav_uninit(drwav* pWav) +{ + drwav_result result = DRWAV_SUCCESS; + + if (pWav == NULL) { + return DRWAV_INVALID_ARGS; + } + + /* + If the drwav object was opened in write mode we'll need to finalize a few things: + - Make sure the "data" chunk is aligned to 16-bits for RIFF containers, or 64 bits for W64 containers. + - Set the size of the "data" chunk. + */ + if (pWav->onWrite != NULL) { + drwav_uint32 paddingSize = 0; + + /* Padding. Do not adjust pWav->dataChunkDataSize - this should not include the padding. */ + if (pWav->container == drwav_container_riff || pWav->container == drwav_container_rf64) { + paddingSize = drwav__chunk_padding_size_riff(pWav->dataChunkDataSize); + } else { + paddingSize = drwav__chunk_padding_size_w64(pWav->dataChunkDataSize); + } + + if (paddingSize > 0) { + drwav_uint64 paddingData = 0; + drwav__write(pWav, &paddingData, paddingSize); /* Byte order does not matter for this. */ + } + + /* + Chunk sizes. When using sequential mode, these will have been filled in at initialization time. We only need + to do this when using non-sequential mode. + */ + if (pWav->onSeek && !pWav->isSequentialWrite) { + if (pWav->container == drwav_container_riff) { + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, 4, drwav_seek_origin_start)) { + drwav_uint32 riffChunkSize = drwav__riff_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, riffChunkSize); + } + + /* the "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 4, drwav_seek_origin_start)) { + drwav_uint32 dataChunkSize = drwav__data_chunk_size_riff(pWav->dataChunkDataSize); + drwav__write_u32ne_to_le(pWav, dataChunkSize); + } + } else if (pWav->container == drwav_container_w64) { + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, 16, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos + 16, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_w64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); + } + } else if (pWav->container == drwav_container_rf64) { + /* We only need to update the ds64 chunk. The "RIFF" and "data" chunks always have their sizes set to 0xFFFFFFFF for RF64. */ + int ds64BodyPos = 12 + 8; + + /* The "RIFF" chunk size. */ + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 0, drwav_seek_origin_start)) { + drwav_uint64 riffChunkSize = drwav__riff_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, riffChunkSize); + } + + /* The "data" chunk size. */ + if (pWav->onSeek(pWav->pUserData, ds64BodyPos + 8, drwav_seek_origin_start)) { + drwav_uint64 dataChunkSize = drwav__data_chunk_size_rf64(pWav->dataChunkDataSize); + drwav__write_u64ne_to_le(pWav, dataChunkSize); + } + } + } + + /* Validation for sequential mode. */ + if (pWav->isSequentialWrite) { + if (pWav->dataChunkDataSize != pWav->dataChunkDataSizeTargetWrite) { + result = DRWAV_INVALID_FILE; + } + } + } + +#ifndef DR_WAV_NO_STDIO + /* + If we opened the file with drwav_open_file() we will want to close the file handle. We can know whether or not drwav_open_file() + was used by looking at the onRead and onSeek callbacks. + */ + if (pWav->onRead == drwav__on_read_stdio || pWav->onWrite == drwav__on_write_stdio) { + fclose((FILE*)pWav->pUserData); + } +#endif + + return result; +} + + + +DRWAV_API size_t drwav_read_raw(drwav* pWav, size_t bytesToRead, void* pBufferOut) +{ + size_t bytesRead; + + if (pWav == NULL || bytesToRead == 0) { + return 0; + } + + if (bytesToRead > pWav->bytesRemaining) { + bytesToRead = (size_t)pWav->bytesRemaining; + } + + if (pBufferOut != NULL) { + bytesRead = pWav->onRead(pWav->pUserData, pBufferOut, bytesToRead); + } else { + /* We need to seek. If we fail, we need to read-and-discard to make sure we get a good byte count. */ + bytesRead = 0; + while (bytesRead < bytesToRead) { + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > 0x7FFFFFFF) { + bytesToSeek = 0x7FFFFFFF; + } + + if (pWav->onSeek(pWav->pUserData, (int)bytesToSeek, drwav_seek_origin_current) == DRWAV_FALSE) { + break; + } + + bytesRead += bytesToSeek; + } + + /* When we get here we may need to read-and-discard some data. */ + while (bytesRead < bytesToRead) { + drwav_uint8 buffer[4096]; + size_t bytesSeeked; + size_t bytesToSeek = (bytesToRead - bytesRead); + if (bytesToSeek > sizeof(buffer)) { + bytesToSeek = sizeof(buffer); + } + + bytesSeeked = pWav->onRead(pWav->pUserData, buffer, bytesToSeek); + bytesRead += bytesSeeked; + + if (bytesSeeked < bytesToSeek) { + break; /* Reached the end. */ + } + } + } + + pWav->bytesRemaining -= bytesRead; + return bytesRead; +} + + + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_le(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + drwav_uint32 bytesPerFrame; + drwav_uint64 bytesToRead; /* Intentionally uint64 instead of size_t so we can do a check that we're not reading too much on 32-bit builds. */ + + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + /* Cannot use this function for compressed formats. */ + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + return 0; + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + bytesToRead = framesToRead * bytesPerFrame; + if (bytesToRead > DRWAV_SIZE_MAX) { + bytesToRead = (DRWAV_SIZE_MAX / bytesPerFrame) * bytesPerFrame; /* Round the number of bytes to read to a clean frame boundary. */ + } + + /* + Doing an explicit check here just to make it clear that we don't want to be attempt to read anything if there's no bytes to read. There + *could* be a time where it evaluates to 0 due to overflowing. + */ + if (bytesToRead == 0) { + return 0; + } + + return drwav_read_raw(pWav, (size_t)bytesToRead, pBufferOut) / bytesPerFrame; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_be(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + + if (pBufferOut != NULL) { + drwav__bswap_samples(pBufferOut, framesRead*pWav->channels, drwav_get_bytes_per_pcm_frame(pWav)/pWav->channels, pWav->translatedFormatTag); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames(drwav* pWav, drwav_uint64 framesToRead, void* pBufferOut) +{ + if (drwav__is_little_endian()) { + return drwav_read_pcm_frames_le(pWav, framesToRead, pBufferOut); + } else { + return drwav_read_pcm_frames_be(pWav, framesToRead, pBufferOut); + } +} + + + +DRWAV_API drwav_bool32 drwav_seek_to_first_pcm_frame(drwav* pWav) +{ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; /* No seeking in write mode. */ + } + + if (!pWav->onSeek(pWav->pUserData, (int)pWav->dataChunkDataPos, drwav_seek_origin_start)) { + return DRWAV_FALSE; + } + + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + pWav->compressed.iCurrentPCMFrame = 0; + + /* Cached data needs to be cleared for compressed formats. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->msadpcm); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + DRWAV_ZERO_OBJECT(&pWav->ima); + } else { + DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ + } + } + + pWav->bytesRemaining = pWav->dataChunkDataSize; + return DRWAV_TRUE; +} + +DRWAV_API drwav_bool32 drwav_seek_to_pcm_frame(drwav* pWav, drwav_uint64 targetFrameIndex) +{ + /* Seeking should be compatible with wave files > 2GB. */ + + if (pWav == NULL || pWav->onSeek == NULL) { + return DRWAV_FALSE; + } + + /* No seeking in write mode. */ + if (pWav->onWrite != NULL) { + return DRWAV_FALSE; + } + + /* If there are no samples, just return DRWAV_TRUE without doing anything. */ + if (pWav->totalPCMFrameCount == 0) { + return DRWAV_TRUE; + } + + /* Make sure the sample is clamped. */ + if (targetFrameIndex >= pWav->totalPCMFrameCount) { + targetFrameIndex = pWav->totalPCMFrameCount - 1; + } + + /* + For compressed formats we just use a slow generic seek. If we are seeking forward we just seek forward. If we are going backwards we need + to seek back to the start. + */ + if (drwav__is_compressed_format_tag(pWav->translatedFormatTag)) { + /* TODO: This can be optimized. */ + + /* + If we're seeking forward it's simple - just keep reading samples until we hit the sample we're requesting. If we're seeking backwards, + we first need to seek back to the start and then just do the same thing as a forward seek. + */ + if (targetFrameIndex < pWav->compressed.iCurrentPCMFrame) { + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; + } + } + + if (targetFrameIndex > pWav->compressed.iCurrentPCMFrame) { + drwav_uint64 offsetInFrames = targetFrameIndex - pWav->compressed.iCurrentPCMFrame; + + drwav_int16 devnull[2048]; + while (offsetInFrames > 0) { + drwav_uint64 framesRead = 0; + drwav_uint64 framesToRead = offsetInFrames; + if (framesToRead > drwav_countof(devnull)/pWav->channels) { + framesToRead = drwav_countof(devnull)/pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, devnull); + } else if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + framesRead = drwav_read_pcm_frames_s16__ima(pWav, framesToRead, devnull); + } else { + DRWAV_ASSERT(DRWAV_FALSE); /* If this assertion is triggered it means I've implemented a new compressed format but forgot to add a branch for it here. */ + } + + if (framesRead != framesToRead) { + return DRWAV_FALSE; + } + + offsetInFrames -= framesRead; + } + } + } else { + drwav_uint64 totalSizeInBytes; + drwav_uint64 currentBytePos; + drwav_uint64 targetBytePos; + drwav_uint64 offset; + + totalSizeInBytes = pWav->totalPCMFrameCount * drwav_get_bytes_per_pcm_frame(pWav); + DRWAV_ASSERT(totalSizeInBytes >= pWav->bytesRemaining); + + currentBytePos = totalSizeInBytes - pWav->bytesRemaining; + targetBytePos = targetFrameIndex * drwav_get_bytes_per_pcm_frame(pWav); + + if (currentBytePos < targetBytePos) { + /* Offset forwards. */ + offset = (targetBytePos - currentBytePos); + } else { + /* Offset backwards. */ + if (!drwav_seek_to_first_pcm_frame(pWav)) { + return DRWAV_FALSE; + } + offset = targetBytePos; + } + + while (offset > 0) { + int offset32 = ((offset > INT_MAX) ? INT_MAX : (int)offset); + if (!pWav->onSeek(pWav->pUserData, offset32, drwav_seek_origin_current)) { + return DRWAV_FALSE; + } + + pWav->bytesRemaining -= offset32; + offset -= offset32; + } + } + + return DRWAV_TRUE; +} + + +DRWAV_API size_t drwav_write_raw(drwav* pWav, size_t bytesToWrite, const void* pData) +{ + size_t bytesWritten; + + if (pWav == NULL || bytesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesWritten = pWav->onWrite(pWav->pUserData, pData, bytesToWrite); + pWav->dataChunkDataSize += bytesWritten; + + return bytesWritten; +} + + +DRWAV_API drwav_uint64 drwav_write_pcm_frames_le(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + const drwav_uint8* pRunningData; + + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { + return 0; + } + + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; + + while (bytesToWrite > 0) { + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; + + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ + + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, pRunningData); + if (bytesJustWritten == 0) { + break; + } + + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; +} + +DRWAV_API drwav_uint64 drwav_write_pcm_frames_be(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + drwav_uint64 bytesToWrite; + drwav_uint64 bytesWritten; + drwav_uint32 bytesPerSample; + const drwav_uint8* pRunningData; + + if (pWav == NULL || framesToWrite == 0 || pData == NULL) { + return 0; + } + + bytesToWrite = ((framesToWrite * pWav->channels * pWav->bitsPerSample) / 8); + if (bytesToWrite > DRWAV_SIZE_MAX) { + return 0; + } + + bytesWritten = 0; + pRunningData = (const drwav_uint8*)pData; + + bytesPerSample = drwav_get_bytes_per_pcm_frame(pWav) / pWav->channels; + + while (bytesToWrite > 0) { + drwav_uint8 temp[4096]; + drwav_uint32 sampleCount; + size_t bytesJustWritten; + drwav_uint64 bytesToWriteThisIteration; + + bytesToWriteThisIteration = bytesToWrite; + DRWAV_ASSERT(bytesToWriteThisIteration <= DRWAV_SIZE_MAX); /* <-- This is checked above. */ + + /* + WAV files are always little-endian. We need to byte swap on big-endian architectures. Since our input buffer is read-only we need + to use an intermediary buffer for the conversion. + */ + sampleCount = sizeof(temp)/bytesPerSample; + + if (bytesToWriteThisIteration > ((drwav_uint64)sampleCount)*bytesPerSample) { + bytesToWriteThisIteration = ((drwav_uint64)sampleCount)*bytesPerSample; + } + + DRWAV_COPY_MEMORY(temp, pRunningData, (size_t)bytesToWriteThisIteration); + drwav__bswap_samples(temp, sampleCount, bytesPerSample, pWav->translatedFormatTag); + + bytesJustWritten = drwav_write_raw(pWav, (size_t)bytesToWriteThisIteration, temp); + if (bytesJustWritten == 0) { + break; + } + + bytesToWrite -= bytesJustWritten; + bytesWritten += bytesJustWritten; + pRunningData += bytesJustWritten; + } + + return (bytesWritten * 8) / pWav->bitsPerSample / pWav->channels; +} + +DRWAV_API drwav_uint64 drwav_write_pcm_frames(drwav* pWav, drwav_uint64 framesToWrite, const void* pData) +{ + if (drwav__is_little_endian()) { + return drwav_write_pcm_frames_le(pWav, framesToWrite, pData); + } else { + return drwav_write_pcm_frames_be(pWav, framesToWrite, pData); + } +} + + +static drwav_uint64 drwav_read_pcm_frames_s16__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead = 0; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + /* If there are no cached frames we need to load a new block. */ + if (pWav->msadpcm.cachedFrameCount == 0 && pWav->msadpcm.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + /* Mono. */ + drwav_uint8 header[7]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 1); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 3); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 5); + pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][0]; + pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.cachedFrameCount = 2; + } else { + /* Stereo. */ + drwav_uint8 header[14]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + pWav->msadpcm.predictor[0] = header[0]; + pWav->msadpcm.predictor[1] = header[1]; + pWav->msadpcm.delta[0] = drwav__bytes_to_s16(header + 2); + pWav->msadpcm.delta[1] = drwav__bytes_to_s16(header + 4); + pWav->msadpcm.prevFrames[0][1] = (drwav_int32)drwav__bytes_to_s16(header + 6); + pWav->msadpcm.prevFrames[1][1] = (drwav_int32)drwav__bytes_to_s16(header + 8); + pWav->msadpcm.prevFrames[0][0] = (drwav_int32)drwav__bytes_to_s16(header + 10); + pWav->msadpcm.prevFrames[1][0] = (drwav_int32)drwav__bytes_to_s16(header + 12); + + pWav->msadpcm.cachedFrames[0] = pWav->msadpcm.prevFrames[0][0]; + pWav->msadpcm.cachedFrames[1] = pWav->msadpcm.prevFrames[1][0]; + pWav->msadpcm.cachedFrames[2] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.cachedFrames[3] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.cachedFrameCount = 2; + } + } + + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->msadpcm.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample = 0; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->msadpcm.cachedFrames[(drwav_countof(pWav->msadpcm.cachedFrames) - (pWav->msadpcm.cachedFrameCount*pWav->channels)) + iSample]; + } + + pBufferOut += pWav->channels; + } + + framesToRead -= 1; + totalFramesRead += 1; + pWav->compressed.iCurrentPCMFrame += 1; + pWav->msadpcm.cachedFrameCount -= 1; + } + + if (framesToRead == 0) { + return totalFramesRead; + } + + + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->msadpcm.cachedFrameCount == 0) { + if (pWav->msadpcm.bytesRemainingInBlock == 0) { + continue; + } else { + static drwav_int32 adaptationTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 + }; + static drwav_int32 coeff1Table[] = { 256, 512, 0, 192, 240, 460, 392 }; + static drwav_int32 coeff2Table[] = { 0, -256, 0, 64, 0, -208, -232 }; + + drwav_uint8 nibbles; + drwav_int32 nibble0; + drwav_int32 nibble1; + + if (pWav->onRead(pWav->pUserData, &nibbles, 1) != 1) { + return totalFramesRead; + } + pWav->msadpcm.bytesRemainingInBlock -= 1; + + /* TODO: Optimize away these if statements. */ + nibble0 = ((nibbles & 0xF0) >> 4); if ((nibbles & 0x80)) { nibble0 |= 0xFFFFFFF0UL; } + nibble1 = ((nibbles & 0x0F) >> 0); if ((nibbles & 0x08)) { nibble1 |= 0xFFFFFFF0UL; } + + if (pWav->channels == 1) { + /* Mono. */ + drwav_int32 newSample0; + drwav_int32 newSample1; + + newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; + + + newSample1 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[0]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample1; + + + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 2; + } else { + /* Stereo. */ + drwav_int32 newSample0; + drwav_int32 newSample1; + + /* Left. */ + newSample0 = ((pWav->msadpcm.prevFrames[0][1] * coeff1Table[pWav->msadpcm.predictor[0]]) + (pWav->msadpcm.prevFrames[0][0] * coeff2Table[pWav->msadpcm.predictor[0]])) >> 8; + newSample0 += nibble0 * pWav->msadpcm.delta[0]; + newSample0 = drwav_clamp(newSample0, -32768, 32767); + + pWav->msadpcm.delta[0] = (adaptationTable[((nibbles & 0xF0) >> 4)] * pWav->msadpcm.delta[0]) >> 8; + if (pWav->msadpcm.delta[0] < 16) { + pWav->msadpcm.delta[0] = 16; + } + + pWav->msadpcm.prevFrames[0][0] = pWav->msadpcm.prevFrames[0][1]; + pWav->msadpcm.prevFrames[0][1] = newSample0; + + + /* Right. */ + newSample1 = ((pWav->msadpcm.prevFrames[1][1] * coeff1Table[pWav->msadpcm.predictor[1]]) + (pWav->msadpcm.prevFrames[1][0] * coeff2Table[pWav->msadpcm.predictor[1]])) >> 8; + newSample1 += nibble1 * pWav->msadpcm.delta[1]; + newSample1 = drwav_clamp(newSample1, -32768, 32767); + + pWav->msadpcm.delta[1] = (adaptationTable[((nibbles & 0x0F) >> 0)] * pWav->msadpcm.delta[1]) >> 8; + if (pWav->msadpcm.delta[1] < 16) { + pWav->msadpcm.delta[1] = 16; + } + + pWav->msadpcm.prevFrames[1][0] = pWav->msadpcm.prevFrames[1][1]; + pWav->msadpcm.prevFrames[1][1] = newSample1; + + pWav->msadpcm.cachedFrames[2] = newSample0; + pWav->msadpcm.cachedFrames[3] = newSample1; + pWav->msadpcm.cachedFrameCount = 1; + } + } + } + } + + return totalFramesRead; +} + + +static drwav_uint64 drwav_read_pcm_frames_s16__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead = 0; + drwav_uint32 iChannel; + + static drwav_int32 indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8 + }; + + static drwav_int32 stepTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + }; + + DRWAV_ASSERT(pWav != NULL); + DRWAV_ASSERT(framesToRead > 0); + + /* TODO: Lots of room for optimization here. */ + + while (framesToRead > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + /* If there are no cached samples we need to load a new block. */ + if (pWav->ima.cachedFrameCount == 0 && pWav->ima.bytesRemainingInBlock == 0) { + if (pWav->channels == 1) { + /* Mono. */ + drwav_uint8 header[4]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + if (header[2] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); + pWav->ima.bytesRemainingInBlock = 0; + return totalFramesRead; /* Invalid data. */ + } + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[0]; + pWav->ima.cachedFrameCount = 1; + } else { + /* Stereo. */ + drwav_uint8 header[8]; + if (pWav->onRead(pWav->pUserData, header, sizeof(header)) != sizeof(header)) { + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock = pWav->fmt.blockAlign - sizeof(header); + + if (header[2] >= drwav_countof(stepTable) || header[6] >= drwav_countof(stepTable)) { + pWav->onSeek(pWav->pUserData, pWav->ima.bytesRemainingInBlock, drwav_seek_origin_current); + pWav->ima.bytesRemainingInBlock = 0; + return totalFramesRead; /* Invalid data. */ + } + + pWav->ima.predictor[0] = drwav__bytes_to_s16(header + 0); + pWav->ima.stepIndex[0] = header[2]; + pWav->ima.predictor[1] = drwav__bytes_to_s16(header + 4); + pWav->ima.stepIndex[1] = header[6]; + + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 2] = pWav->ima.predictor[0]; + pWav->ima.cachedFrames[drwav_countof(pWav->ima.cachedFrames) - 1] = pWav->ima.predictor[1]; + pWav->ima.cachedFrameCount = 1; + } + } + + /* Output anything that's cached. */ + while (framesToRead > 0 && pWav->ima.cachedFrameCount > 0 && pWav->compressed.iCurrentPCMFrame < pWav->totalPCMFrameCount) { + if (pBufferOut != NULL) { + drwav_uint32 iSample; + for (iSample = 0; iSample < pWav->channels; iSample += 1) { + pBufferOut[iSample] = (drwav_int16)pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + iSample]; + } + pBufferOut += pWav->channels; + } + + framesToRead -= 1; + totalFramesRead += 1; + pWav->compressed.iCurrentPCMFrame += 1; + pWav->ima.cachedFrameCount -= 1; + } + + if (framesToRead == 0) { + return totalFramesRead; + } + + /* + If there's nothing left in the cache, just go ahead and load more. If there's nothing left to load in the current block we just continue to the next + loop iteration which will trigger the loading of a new block. + */ + if (pWav->ima.cachedFrameCount == 0) { + if (pWav->ima.bytesRemainingInBlock == 0) { + continue; + } else { + /* + From what I can tell with stereo streams, it looks like every 4 bytes (8 samples) is for one channel. So it goes 4 bytes for the + left channel, 4 bytes for the right channel. + */ + pWav->ima.cachedFrameCount = 8; + for (iChannel = 0; iChannel < pWav->channels; ++iChannel) { + drwav_uint32 iByte; + drwav_uint8 nibbles[4]; + if (pWav->onRead(pWav->pUserData, &nibbles, 4) != 4) { + pWav->ima.cachedFrameCount = 0; + return totalFramesRead; + } + pWav->ima.bytesRemainingInBlock -= 4; + + for (iByte = 0; iByte < 4; ++iByte) { + drwav_uint8 nibble0 = ((nibbles[iByte] & 0x0F) >> 0); + drwav_uint8 nibble1 = ((nibbles[iByte] & 0xF0) >> 4); + + drwav_int32 step = stepTable[pWav->ima.stepIndex[iChannel]]; + drwav_int32 predictor = pWav->ima.predictor[iChannel]; + + drwav_int32 diff = step >> 3; + if (nibble0 & 1) diff += step >> 2; + if (nibble0 & 2) diff += step >> 1; + if (nibble0 & 4) diff += step; + if (nibble0 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble0], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+0)*pWav->channels + iChannel] = predictor; + + + step = stepTable[pWav->ima.stepIndex[iChannel]]; + predictor = pWav->ima.predictor[iChannel]; + + diff = step >> 3; + if (nibble1 & 1) diff += step >> 2; + if (nibble1 & 2) diff += step >> 1; + if (nibble1 & 4) diff += step; + if (nibble1 & 8) diff = -diff; + + predictor = drwav_clamp(predictor + diff, -32768, 32767); + pWav->ima.predictor[iChannel] = predictor; + pWav->ima.stepIndex[iChannel] = drwav_clamp(pWav->ima.stepIndex[iChannel] + indexTable[nibble1], 0, (drwav_int32)drwav_countof(stepTable)-1); + pWav->ima.cachedFrames[(drwav_countof(pWav->ima.cachedFrames) - (pWav->ima.cachedFrameCount*pWav->channels)) + (iByte*2+1)*pWav->channels + iChannel] = predictor; + } + } + } + } + } + + return totalFramesRead; +} + + +#ifndef DR_WAV_NO_CONVERSION_API +static unsigned short g_drwavAlawTable[256] = { + 0xEA80, 0xEB80, 0xE880, 0xE980, 0xEE80, 0xEF80, 0xEC80, 0xED80, 0xE280, 0xE380, 0xE080, 0xE180, 0xE680, 0xE780, 0xE480, 0xE580, + 0xF540, 0xF5C0, 0xF440, 0xF4C0, 0xF740, 0xF7C0, 0xF640, 0xF6C0, 0xF140, 0xF1C0, 0xF040, 0xF0C0, 0xF340, 0xF3C0, 0xF240, 0xF2C0, + 0xAA00, 0xAE00, 0xA200, 0xA600, 0xBA00, 0xBE00, 0xB200, 0xB600, 0x8A00, 0x8E00, 0x8200, 0x8600, 0x9A00, 0x9E00, 0x9200, 0x9600, + 0xD500, 0xD700, 0xD100, 0xD300, 0xDD00, 0xDF00, 0xD900, 0xDB00, 0xC500, 0xC700, 0xC100, 0xC300, 0xCD00, 0xCF00, 0xC900, 0xCB00, + 0xFEA8, 0xFEB8, 0xFE88, 0xFE98, 0xFEE8, 0xFEF8, 0xFEC8, 0xFED8, 0xFE28, 0xFE38, 0xFE08, 0xFE18, 0xFE68, 0xFE78, 0xFE48, 0xFE58, + 0xFFA8, 0xFFB8, 0xFF88, 0xFF98, 0xFFE8, 0xFFF8, 0xFFC8, 0xFFD8, 0xFF28, 0xFF38, 0xFF08, 0xFF18, 0xFF68, 0xFF78, 0xFF48, 0xFF58, + 0xFAA0, 0xFAE0, 0xFA20, 0xFA60, 0xFBA0, 0xFBE0, 0xFB20, 0xFB60, 0xF8A0, 0xF8E0, 0xF820, 0xF860, 0xF9A0, 0xF9E0, 0xF920, 0xF960, + 0xFD50, 0xFD70, 0xFD10, 0xFD30, 0xFDD0, 0xFDF0, 0xFD90, 0xFDB0, 0xFC50, 0xFC70, 0xFC10, 0xFC30, 0xFCD0, 0xFCF0, 0xFC90, 0xFCB0, + 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1D80, 0x1C80, 0x1F80, 0x1E80, 0x1980, 0x1880, 0x1B80, 0x1A80, + 0x0AC0, 0x0A40, 0x0BC0, 0x0B40, 0x08C0, 0x0840, 0x09C0, 0x0940, 0x0EC0, 0x0E40, 0x0FC0, 0x0F40, 0x0CC0, 0x0C40, 0x0DC0, 0x0D40, + 0x5600, 0x5200, 0x5E00, 0x5A00, 0x4600, 0x4200, 0x4E00, 0x4A00, 0x7600, 0x7200, 0x7E00, 0x7A00, 0x6600, 0x6200, 0x6E00, 0x6A00, + 0x2B00, 0x2900, 0x2F00, 0x2D00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3B00, 0x3900, 0x3F00, 0x3D00, 0x3300, 0x3100, 0x3700, 0x3500, + 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01D8, 0x01C8, 0x01F8, 0x01E8, 0x0198, 0x0188, 0x01B8, 0x01A8, + 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00D8, 0x00C8, 0x00F8, 0x00E8, 0x0098, 0x0088, 0x00B8, 0x00A8, + 0x0560, 0x0520, 0x05E0, 0x05A0, 0x0460, 0x0420, 0x04E0, 0x04A0, 0x0760, 0x0720, 0x07E0, 0x07A0, 0x0660, 0x0620, 0x06E0, 0x06A0, + 0x02B0, 0x0290, 0x02F0, 0x02D0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03B0, 0x0390, 0x03F0, 0x03D0, 0x0330, 0x0310, 0x0370, 0x0350 +}; + +static unsigned short g_drwavMulawTable[256] = { + 0x8284, 0x8684, 0x8A84, 0x8E84, 0x9284, 0x9684, 0x9A84, 0x9E84, 0xA284, 0xA684, 0xAA84, 0xAE84, 0xB284, 0xB684, 0xBA84, 0xBE84, + 0xC184, 0xC384, 0xC584, 0xC784, 0xC984, 0xCB84, 0xCD84, 0xCF84, 0xD184, 0xD384, 0xD584, 0xD784, 0xD984, 0xDB84, 0xDD84, 0xDF84, + 0xE104, 0xE204, 0xE304, 0xE404, 0xE504, 0xE604, 0xE704, 0xE804, 0xE904, 0xEA04, 0xEB04, 0xEC04, 0xED04, 0xEE04, 0xEF04, 0xF004, + 0xF0C4, 0xF144, 0xF1C4, 0xF244, 0xF2C4, 0xF344, 0xF3C4, 0xF444, 0xF4C4, 0xF544, 0xF5C4, 0xF644, 0xF6C4, 0xF744, 0xF7C4, 0xF844, + 0xF8A4, 0xF8E4, 0xF924, 0xF964, 0xF9A4, 0xF9E4, 0xFA24, 0xFA64, 0xFAA4, 0xFAE4, 0xFB24, 0xFB64, 0xFBA4, 0xFBE4, 0xFC24, 0xFC64, + 0xFC94, 0xFCB4, 0xFCD4, 0xFCF4, 0xFD14, 0xFD34, 0xFD54, 0xFD74, 0xFD94, 0xFDB4, 0xFDD4, 0xFDF4, 0xFE14, 0xFE34, 0xFE54, 0xFE74, + 0xFE8C, 0xFE9C, 0xFEAC, 0xFEBC, 0xFECC, 0xFEDC, 0xFEEC, 0xFEFC, 0xFF0C, 0xFF1C, 0xFF2C, 0xFF3C, 0xFF4C, 0xFF5C, 0xFF6C, 0xFF7C, + 0xFF88, 0xFF90, 0xFF98, 0xFFA0, 0xFFA8, 0xFFB0, 0xFFB8, 0xFFC0, 0xFFC8, 0xFFD0, 0xFFD8, 0xFFE0, 0xFFE8, 0xFFF0, 0xFFF8, 0x0000, + 0x7D7C, 0x797C, 0x757C, 0x717C, 0x6D7C, 0x697C, 0x657C, 0x617C, 0x5D7C, 0x597C, 0x557C, 0x517C, 0x4D7C, 0x497C, 0x457C, 0x417C, + 0x3E7C, 0x3C7C, 0x3A7C, 0x387C, 0x367C, 0x347C, 0x327C, 0x307C, 0x2E7C, 0x2C7C, 0x2A7C, 0x287C, 0x267C, 0x247C, 0x227C, 0x207C, + 0x1EFC, 0x1DFC, 0x1CFC, 0x1BFC, 0x1AFC, 0x19FC, 0x18FC, 0x17FC, 0x16FC, 0x15FC, 0x14FC, 0x13FC, 0x12FC, 0x11FC, 0x10FC, 0x0FFC, + 0x0F3C, 0x0EBC, 0x0E3C, 0x0DBC, 0x0D3C, 0x0CBC, 0x0C3C, 0x0BBC, 0x0B3C, 0x0ABC, 0x0A3C, 0x09BC, 0x093C, 0x08BC, 0x083C, 0x07BC, + 0x075C, 0x071C, 0x06DC, 0x069C, 0x065C, 0x061C, 0x05DC, 0x059C, 0x055C, 0x051C, 0x04DC, 0x049C, 0x045C, 0x041C, 0x03DC, 0x039C, + 0x036C, 0x034C, 0x032C, 0x030C, 0x02EC, 0x02CC, 0x02AC, 0x028C, 0x026C, 0x024C, 0x022C, 0x020C, 0x01EC, 0x01CC, 0x01AC, 0x018C, + 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, 0x00F4, 0x00E4, 0x00D4, 0x00C4, 0x00B4, 0x00A4, 0x0094, 0x0084, + 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 +}; + +static DRWAV_INLINE drwav_int16 drwav__alaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavAlawTable[sampleIn]; +} + +static DRWAV_INLINE drwav_int16 drwav__mulaw_to_s16(drwav_uint8 sampleIn) +{ + return (short)g_drwavMulawTable[sampleIn]; +} + + + +static void drwav__pcm_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_s16(pOut, pIn, totalSampleCount); + return; + } + + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int16*)pIn)[i]; + } + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s16(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_s16(pOut, (const drwav_int32*)pIn, totalSampleCount); + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int16)((drwav_int64)sample >> 48); + } +} + +static void drwav__ieee_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s16(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s16(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + +static drwav_uint64 drwav_read_pcm_frames_s16__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint32 bytesPerFrame; + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + /* Fast path. */ + if ((pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 16) || pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s16__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_s16(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int16) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int16) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s16__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s16__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s16__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s16__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s16__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s16__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16le(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s16be(drwav* pWav, drwav_uint64 framesToRead, drwav_int16* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s16(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x << 8; + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_s24_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = ((int)(((unsigned int)(((const drwav_uint8*)pIn)[i*3+0]) << 8) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+1]) << 16) | ((unsigned int)(((const drwav_uint8*)pIn)[i*3+2])) << 24)) >> 8; + r = x >> 8; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_s32_to_s16(drwav_int16* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + int x = pIn[i]; + r = x >> 16; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_f32_to_s16(drwav_int16* pOut, const float* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + float c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5f); + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_f64_to_s16(drwav_int16* pOut, const double* pIn, size_t sampleCount) +{ + int r; + size_t i; + for (i = 0; i < sampleCount; ++i) { + double x = pIn[i]; + double c; + c = ((x < -1) ? -1 : ((x > 1) ? 1 : x)); + c = c + 1; + r = (int)(c * 32767.5); + r = r - 32768; + pOut[i] = (short)r; + } +} + +DRWAV_API void drwav_alaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__alaw_to_s16(pIn[i]); + } +} + +DRWAV_API void drwav_mulaw_to_s16(drwav_int16* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + for (i = 0; i < sampleCount; ++i) { + pOut[i] = drwav__mulaw_to_s16(pIn[i]); + } +} + + + +static void drwav__pcm_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_f32(pOut, pIn, sampleCount); + return; + } + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + drwav_s16_to_f32(pOut, (const drwav_int16*)pIn, sampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_f32(pOut, pIn, sampleCount); + return; + } + if (bytesPerSample == 4) { + drwav_s32_to_f32(pOut, (const drwav_int32*)pIn, sampleCount); + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < sampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (float)((drwav_int64)sample / 9223372036854775807.0); + } +} + +static void drwav__ieee_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + unsigned int i; + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((const float*)pIn)[i]; + } + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_f32(pOut, (const double*)pIn, sampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, sampleCount * sizeof(*pOut)); + return; + } +} + + +static drwav_uint64 drwav_read_pcm_frames_f32__pcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_f32(pBufferOut, sampleData, (size_t)framesRead*pWav->channels, bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__ima(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_f32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__ieee(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + /* Fast path. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__alaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_f32__mulaw(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_f32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(float) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(float) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_f32__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_f32__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_f32__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_f32__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_f32__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_f32__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32le(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_f32be(drwav* pWav, drwav_uint64 framesToRead, float* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_f32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_f32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + +#ifdef DR_WAV_LIBSNDFILE_COMPAT + /* + It appears libsndfile uses slightly different logic for the u8 -> f32 conversion to dr_wav, which in my opinion is incorrect. It appears + libsndfile performs the conversion something like "f32 = (u8 / 256) * 2 - 1", however I think it should be "f32 = (u8 / 255) * 2 - 1" (note + the divisor of 256 vs 255). I use libsndfile as a benchmark for testing, so I'm therefore leaving this block here just for my automated + correctness testing. This is disabled by default. + */ + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (pIn[i] / 256.0f) * 2 - 1; + } +#else + for (i = 0; i < sampleCount; ++i) { + float x = pIn[i]; + x = x * 0.00784313725490196078f; /* 0..255 to 0..2 */ + x = x - 1; /* 0..2 to -1..1 */ + + *pOut++ = x; + } +#endif +} + +DRWAV_API void drwav_s16_to_f32(float* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] * 0.000030517578125f; + } +} + +DRWAV_API void drwav_s24_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + double x; + drwav_uint32 a = ((drwav_uint32)(pIn[i*3+0]) << 8); + drwav_uint32 b = ((drwav_uint32)(pIn[i*3+1]) << 16); + drwav_uint32 c = ((drwav_uint32)(pIn[i*3+2]) << 24); + + x = (double)((drwav_int32)(a | b | c) >> 8); + *pOut++ = (float)(x * 0.00000011920928955078125); + } +} + +DRWAV_API void drwav_s32_to_f32(float* pOut, const drwav_int32* pIn, size_t sampleCount) +{ + size_t i; + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)(pIn[i] / 2147483648.0); + } +} + +DRWAV_API void drwav_f64_to_f32(float* pOut, const double* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (float)pIn[i]; + } +} + +DRWAV_API void drwav_alaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__alaw_to_s16(pIn[i]) / 32768.0f; + } +} + +DRWAV_API void drwav_mulaw_to_f32(float* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = drwav__mulaw_to_s16(pIn[i]) / 32768.0f; + } +} + + + +static void drwav__pcm_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + unsigned int i; + + /* Special case for 8-bit sample data because it's treated as unsigned. */ + if (bytesPerSample == 1) { + drwav_u8_to_s32(pOut, pIn, totalSampleCount); + return; + } + + /* Slightly more optimal implementation for common formats. */ + if (bytesPerSample == 2) { + drwav_s16_to_s32(pOut, (const drwav_int16*)pIn, totalSampleCount); + return; + } + if (bytesPerSample == 3) { + drwav_s24_to_s32(pOut, pIn, totalSampleCount); + return; + } + if (bytesPerSample == 4) { + for (i = 0; i < totalSampleCount; ++i) { + *pOut++ = ((const drwav_int32*)pIn)[i]; + } + return; + } + + + /* Anything more than 64 bits per sample is not supported. */ + if (bytesPerSample > 8) { + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } + + + /* Generic, slow converter. */ + for (i = 0; i < totalSampleCount; ++i) { + drwav_uint64 sample = 0; + unsigned int shift = (8 - bytesPerSample) * 8; + + unsigned int j; + for (j = 0; j < bytesPerSample; j += 1) { + DRWAV_ASSERT(j < 8); + sample |= (drwav_uint64)(pIn[j]) << shift; + shift += 8; + } + + pIn += j; + *pOut++ = (drwav_int32)((drwav_int64)sample >> 32); + } +} + +static void drwav__ieee_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t totalSampleCount, unsigned int bytesPerSample) +{ + if (bytesPerSample == 4) { + drwav_f32_to_s32(pOut, (const float*)pIn, totalSampleCount); + return; + } else if (bytesPerSample == 8) { + drwav_f64_to_s32(pOut, (const double*)pIn, totalSampleCount); + return; + } else { + /* Only supporting 32- and 64-bit float. Output silence in all other cases. Contributions welcome for 16-bit float. */ + DRWAV_ZERO_MEMORY(pOut, totalSampleCount * sizeof(*pOut)); + return; + } +} + + +static drwav_uint64 drwav_read_pcm_frames_s32__pcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + drwav_uint32 bytesPerFrame; + + /* Fast path. */ + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM && pWav->bitsPerSample == 32) { + return drwav_read_pcm_frames(pWav, framesToRead, pBufferOut); + } + + bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__pcm_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__msadpcm(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__ima(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + /* + We're just going to borrow the implementation from the drwav_read_s16() since IMA-ADPCM is a little bit more complicated than other formats and I don't + want to duplicate that code. + */ + drwav_uint64 totalFramesRead = 0; + drwav_int16 samples16[2048]; + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames_s16(pWav, drwav_min(framesToRead, drwav_countof(samples16)/pWav->channels), samples16); + if (framesRead == 0) { + break; + } + + drwav_s16_to_s32(pBufferOut, samples16, (size_t)(framesRead*pWav->channels)); /* <-- Safe cast because we're clamping to 2048. */ + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__ieee(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav__ieee_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels), bytesPerFrame/pWav->channels); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__alaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_alaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +static drwav_uint64 drwav_read_pcm_frames_s32__mulaw(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 totalFramesRead; + drwav_uint8 sampleData[4096]; + + drwav_uint32 bytesPerFrame = drwav_get_bytes_per_pcm_frame(pWav); + if (bytesPerFrame == 0) { + return 0; + } + + totalFramesRead = 0; + + while (framesToRead > 0) { + drwav_uint64 framesRead = drwav_read_pcm_frames(pWav, drwav_min(framesToRead, sizeof(sampleData)/bytesPerFrame), sampleData); + if (framesRead == 0) { + break; + } + + drwav_mulaw_to_s32(pBufferOut, sampleData, (size_t)(framesRead*pWav->channels)); + + pBufferOut += framesRead*pWav->channels; + framesToRead -= framesRead; + totalFramesRead += framesRead; + } + + return totalFramesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + if (pWav == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drwav_read_pcm_frames(pWav, framesToRead, NULL); + } + + /* Don't try to read more samples than can potentially fit in the output buffer. */ + if (framesToRead * pWav->channels * sizeof(drwav_int32) > DRWAV_SIZE_MAX) { + framesToRead = DRWAV_SIZE_MAX / sizeof(drwav_int32) / pWav->channels; + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_PCM) { + return drwav_read_pcm_frames_s32__pcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ADPCM) { + return drwav_read_pcm_frames_s32__msadpcm(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_IEEE_FLOAT) { + return drwav_read_pcm_frames_s32__ieee(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_ALAW) { + return drwav_read_pcm_frames_s32__alaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_MULAW) { + return drwav_read_pcm_frames_s32__mulaw(pWav, framesToRead, pBufferOut); + } + + if (pWav->translatedFormatTag == DR_WAVE_FORMAT_DVI_ADPCM) { + return drwav_read_pcm_frames_s32__ima(pWav, framesToRead, pBufferOut); + } + + return 0; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32le(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_FALSE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + +DRWAV_API drwav_uint64 drwav_read_pcm_frames_s32be(drwav* pWav, drwav_uint64 framesToRead, drwav_int32* pBufferOut) +{ + drwav_uint64 framesRead = drwav_read_pcm_frames_s32(pWav, framesToRead, pBufferOut); + if (pBufferOut != NULL && drwav__is_little_endian() == DRWAV_TRUE) { + drwav__bswap_samples_s32(pBufferOut, framesRead*pWav->channels); + } + + return framesRead; +} + + +DRWAV_API void drwav_u8_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((int)pIn[i] - 128) << 24; + } +} + +DRWAV_API void drwav_s16_to_s32(drwav_int32* pOut, const drwav_int16* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = pIn[i] << 16; + } +} + +DRWAV_API void drwav_s24_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + unsigned int s0 = pIn[i*3 + 0]; + unsigned int s1 = pIn[i*3 + 1]; + unsigned int s2 = pIn[i*3 + 2]; + + drwav_int32 sample32 = (drwav_int32)((s0 << 8) | (s1 << 16) | (s2 << 24)); + *pOut++ = sample32; + } +} + +DRWAV_API void drwav_f32_to_s32(drwav_int32* pOut, const float* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +DRWAV_API void drwav_f64_to_s32(drwav_int32* pOut, const double* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = (drwav_int32)(2147483648.0 * pIn[i]); + } +} + +DRWAV_API void drwav_alaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i = 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__alaw_to_s16(pIn[i])) << 16; + } +} + +DRWAV_API void drwav_mulaw_to_s32(drwav_int32* pOut, const drwav_uint8* pIn, size_t sampleCount) +{ + size_t i; + + if (pOut == NULL || pIn == NULL) { + return; + } + + for (i= 0; i < sampleCount; ++i) { + *pOut++ = ((drwav_int32)drwav__mulaw_to_s16(pIn[i])) << 16; + } +} + + + +static drwav_int16* drwav__read_pcm_frames_and_close_s16(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + drwav_int16* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int16); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (drwav_int16*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_s16(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + +static float* drwav__read_pcm_frames_and_close_f32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + float* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(float); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (float*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_f32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + +static drwav_int32* drwav__read_pcm_frames_and_close_s32(drwav* pWav, unsigned int* channels, unsigned int* sampleRate, drwav_uint64* totalFrameCount) +{ + drwav_uint64 sampleDataSize; + drwav_int32* pSampleData; + drwav_uint64 framesRead; + + DRWAV_ASSERT(pWav != NULL); + + sampleDataSize = pWav->totalPCMFrameCount * pWav->channels * sizeof(drwav_int32); + if (sampleDataSize > DRWAV_SIZE_MAX) { + drwav_uninit(pWav); + return NULL; /* File's too big. */ + } + + pSampleData = (drwav_int32*)drwav__malloc_from_callbacks((size_t)sampleDataSize, &pWav->allocationCallbacks); /* <-- Safe cast due to the check above. */ + if (pSampleData == NULL) { + drwav_uninit(pWav); + return NULL; /* Failed to allocate memory. */ + } + + framesRead = drwav_read_pcm_frames_s32(pWav, (size_t)pWav->totalPCMFrameCount, pSampleData); + if (framesRead != pWav->totalPCMFrameCount) { + drwav__free_from_callbacks(pSampleData, &pWav->allocationCallbacks); + drwav_uninit(pWav); + return NULL; /* There was an error reading the samples. */ + } + + drwav_uninit(pWav); + + if (sampleRate) { + *sampleRate = pWav->sampleRate; + } + if (channels) { + *channels = pWav->channels; + } + if (totalFrameCount) { + *totalFrameCount = pWav->totalPCMFrameCount; + } + + return pSampleData; +} + + + +DRWAV_API drwav_int16* drwav_open_and_read_pcm_frames_s16(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_and_read_pcm_frames_f32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_and_read_pcm_frames_s32(drwav_read_proc onRead, drwav_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init(&wav, onRead, onSeek, pUserData, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +#ifndef DR_WAV_NO_STDIO +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + + +DRWAV_API drwav_int16* drwav_open_file_and_read_pcm_frames_s16_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_file_and_read_pcm_frames_f32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_file_and_read_pcm_frames_s32_w(const wchar_t* filename, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (channelsOut) { + *channelsOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_file_w(&wav, filename, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif + +DRWAV_API drwav_int16* drwav_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s16(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API float* drwav_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_f32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} + +DRWAV_API drwav_int32* drwav_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channelsOut, unsigned int* sampleRateOut, drwav_uint64* totalFrameCountOut, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + drwav wav; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalFrameCountOut) { + *totalFrameCountOut = 0; + } + + if (!drwav_init_memory(&wav, data, dataSize, pAllocationCallbacks)) { + return NULL; + } + + return drwav__read_pcm_frames_and_close_s32(&wav, channelsOut, sampleRateOut, totalFrameCountOut); +} +#endif /* DR_WAV_NO_CONVERSION_API */ + + +DRWAV_API void drwav_free(void* p, const drwav_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drwav__free_from_callbacks(p, pAllocationCallbacks); + } else { + drwav__free_default(p, NULL); + } +} + +DRWAV_API drwav_uint16 drwav_bytes_to_u16(const drwav_uint8* data) +{ + return drwav__bytes_to_u16(data); +} + +DRWAV_API drwav_int16 drwav_bytes_to_s16(const drwav_uint8* data) +{ + return drwav__bytes_to_s16(data); +} + +DRWAV_API drwav_uint32 drwav_bytes_to_u32(const drwav_uint8* data) +{ + return drwav__bytes_to_u32(data); +} + +DRWAV_API drwav_int32 drwav_bytes_to_s32(const drwav_uint8* data) +{ + return drwav__bytes_to_s32(data); +} + +DRWAV_API drwav_uint64 drwav_bytes_to_u64(const drwav_uint8* data) +{ + return drwav__bytes_to_u64(data); +} + +DRWAV_API drwav_int64 drwav_bytes_to_s64(const drwav_uint8* data) +{ + return drwav__bytes_to_s64(data); +} + + +DRWAV_API drwav_bool32 drwav_guid_equal(const drwav_uint8 a[16], const drwav_uint8 b[16]) +{ + return drwav__guid_equal(a, b); +} + +DRWAV_API drwav_bool32 drwav_fourcc_equal(const drwav_uint8* a, const char* b) +{ + return drwav__fourcc_equal(a, b); +} + +#endif /* dr_wav_c */ +#endif /* DR_WAV_IMPLEMENTATION */ + +/* +RELEASE NOTES - v0.11.0 +======================= +Version 0.11.0 has breaking API changes. + +Improved Client-Defined Memory Allocation +----------------------------------------- +The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The +existing system of DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE are still in place and will be used by default when no custom +allocation callbacks are specified. + +To use the new system, you pass in a pointer to a drwav_allocation_callbacks object to drwav_init() and family, like this: + + void* my_malloc(size_t sz, void* pUserData) + { + return malloc(sz); + } + void* my_realloc(void* p, size_t sz, void* pUserData) + { + return realloc(p, sz); + } + void my_free(void* p, void* pUserData) + { + free(p); + } + + ... + + drwav_allocation_callbacks allocationCallbacks; + allocationCallbacks.pUserData = &myData; + allocationCallbacks.onMalloc = my_malloc; + allocationCallbacks.onRealloc = my_realloc; + allocationCallbacks.onFree = my_free; + drwav_init_file(&wav, "my_file.wav", &allocationCallbacks); + +The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines. + +Passing in null for the allocation callbacks object will cause dr_wav to use defaults which is the same as DRWAV_MALLOC, +DRWAV_REALLOC and DRWAV_FREE and the equivalent of how it worked in previous versions. + +Every API that opens a drwav object now takes this extra parameter. These include the following: + + drwav_init() + drwav_init_ex() + drwav_init_file() + drwav_init_file_ex() + drwav_init_file_w() + drwav_init_file_w_ex() + drwav_init_memory() + drwav_init_memory_ex() + drwav_init_write() + drwav_init_write_sequential() + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write() + drwav_init_file_write_sequential() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write() + drwav_init_memory_write_sequential() + drwav_init_memory_write_sequential_pcm_frames() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_pcm_frames_s32() + +Endian Improvements +------------------- +Previously, the following APIs returned little-endian audio data. These now return native-endian data. This improves compatibility +on big-endian architectures. + + drwav_read_pcm_frames() + drwav_read_pcm_frames_s16() + drwav_read_pcm_frames_s32() + drwav_read_pcm_frames_f32() + drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_pcm_frames_s32() + drwav_open_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_pcm_frames_s32() + drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_pcm_frames_s16_w() + drwav_open_file_and_read_pcm_frames_s32_w() + drwav_open_file_and_read_pcm_frames_f32_w() + drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_pcm_frames_s32() + drwav_open_memory_and_read_pcm_frames_f32() + +APIs have been added to give you explicit control over whether or not audio data is read or written in big- or little-endian byte +order: + + drwav_read_pcm_frames_le() + drwav_read_pcm_frames_be() + drwav_read_pcm_frames_s16le() + drwav_read_pcm_frames_s16be() + drwav_read_pcm_frames_f32le() + drwav_read_pcm_frames_f32be() + drwav_read_pcm_frames_s32le() + drwav_read_pcm_frames_s32be() + drwav_write_pcm_frames_le() + drwav_write_pcm_frames_be() + +Removed APIs +------------ +The following APIs were deprecated in version 0.10.0 and have now been removed: + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + + + +RELEASE NOTES - v0.10.0 +======================= +Version 0.10.0 has breaking API changes. There are no significant bug fixes in this release, so if you are affected you do +not need to upgrade. + +Removed APIs +------------ +The following APIs were deprecated in version 0.9.0 and have been completely removed in version 0.10.0: + + drwav_read() + drwav_read_s16() + drwav_read_f32() + drwav_read_s32() + drwav_seek_to_sample() + drwav_write() + drwav_open_and_read_s16() + drwav_open_and_read_f32() + drwav_open_and_read_s32() + drwav_open_file_and_read_s16() + drwav_open_file_and_read_f32() + drwav_open_file_and_read_s32() + drwav_open_memory_and_read_s16() + drwav_open_memory_and_read_f32() + drwav_open_memory_and_read_s32() + drwav::totalSampleCount + +See release notes for version 0.9.0 at the bottom of this file for replacement APIs. + +Deprecated APIs +--------------- +The following APIs have been deprecated. There is a confusing and completely arbitrary difference between drwav_init*() and +drwav_open*(), where drwav_init*() initializes a pre-allocated drwav object, whereas drwav_open*() will first allocated a +drwav object on the heap and then initialize it. drwav_open*() has been deprecated which means you must now use a pre- +allocated drwav object with drwav_init*(). If you need the previous functionality, you can just do a malloc() followed by +a called to one of the drwav_init*() APIs. + + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + +These APIs will be removed completely in a future version. The rationale for this change is to remove confusion between the +two different ways to initialize a drwav object. +*/ + +/* +REVISION HISTORY +================ +v0.12.16 - 2020-12-02 + - Fix a bug when trying to read more bytes than can fit in a size_t. + +v0.12.15 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.14 - 2020-11-13 + - Minor code clean up. + +v0.12.13 - 2020-11-01 + - Improve compiler support for older versions of GCC. + +v0.12.12 - 2020-09-28 + - Add support for RF64. + - Fix a bug in writing mode where the size of the RIFF chunk incorrectly includes the header section. + +v0.12.11 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.10 - 2020-08-24 + - Fix a bug when seeking with ADPCM formats. + +v0.12.9 - 2020-08-02 + - Simplify sized types. + +v0.12.8 - 2020-07-25 + - Fix a compilation warning. + +v0.12.7 - 2020-07-15 + - Fix some bugs on big-endian architectures. + - Fix an error in s24 to f32 conversion. + +v0.12.6 - 2020-06-23 + - Change drwav_read_*() to allow NULL to be passed in as the output buffer which is equivalent to a forward seek. + - Fix a buffer overflow when trying to decode invalid IMA-ADPCM files. + - Add include guard for the implementation section. + +v0.12.5 - 2020-05-27 + - Minor documentation fix. + +v0.12.4 - 2020-05-16 + - Replace assert() with DRWAV_ASSERT(). + - Add compile-time and run-time version querying. + - DRWAV_VERSION_MINOR + - DRWAV_VERSION_MAJOR + - DRWAV_VERSION_REVISION + - DRWAV_VERSION_STRING + - drwav_version() + - drwav_version_string() + +v0.12.3 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.2 - 2020-04-21 + - Fix a bug where drwav_init_file() does not close the file handle after attempting to load an erroneous file. + +v0.12.1 - 2020-04-13 + - Fix some pedantic warnings. + +v0.12.0 - 2020-04-04 + - API CHANGE: Add container and format parameters to the chunk callback. + - Minor documentation updates. + +v0.11.5 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.11.4 - 2020-01-29 + - Fix some static analysis warnings. + - Fix a bug when reading f32 samples from an A-law encoded stream. + +v0.11.3 - 2020-01-12 + - Minor changes to some f32 format conversion routines. + - Minor bug fix for ADPCM conversion when end of file is reached. + +v0.11.2 - 2019-12-02 + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix an integer overflow bug. + - Fix a null pointer dereference bug. + - Add limits to sample rate, channels and bits per sample to tighten up some validation. + +v0.11.1 - 2019-10-07 + - Internal code clean up. + +v0.11.0 - 2019-10-06 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drwav_init() + - drwav_init_ex() + - drwav_init_file() + - drwav_init_file_ex() + - drwav_init_file_w() + - drwav_init_file_w_ex() + - drwav_init_memory() + - drwav_init_memory_ex() + - drwav_init_write() + - drwav_init_write_sequential() + - drwav_init_write_sequential_pcm_frames() + - drwav_init_file_write() + - drwav_init_file_write_sequential() + - drwav_init_file_write_sequential_pcm_frames() + - drwav_init_file_write_w() + - drwav_init_file_write_sequential_w() + - drwav_init_file_write_sequential_pcm_frames_w() + - drwav_init_memory_write() + - drwav_init_memory_write_sequential() + - drwav_init_memory_write_sequential_pcm_frames() + - drwav_open_and_read_pcm_frames_s16() + - drwav_open_and_read_pcm_frames_f32() + - drwav_open_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_s16() + - drwav_open_file_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_s16_w() + - drwav_open_file_and_read_pcm_frames_f32_w() + - drwav_open_file_and_read_pcm_frames_s32_w() + - drwav_open_memory_and_read_pcm_frames_s16() + - drwav_open_memory_and_read_pcm_frames_f32() + - drwav_open_memory_and_read_pcm_frames_s32() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRWAV_MALLOC, DRWAV_REALLOC and DRWAV_FREE. + - Add support for reading and writing PCM frames in an explicit endianness. New APIs: + - drwav_read_pcm_frames_le() + - drwav_read_pcm_frames_be() + - drwav_read_pcm_frames_s16le() + - drwav_read_pcm_frames_s16be() + - drwav_read_pcm_frames_f32le() + - drwav_read_pcm_frames_f32be() + - drwav_read_pcm_frames_s32le() + - drwav_read_pcm_frames_s32be() + - drwav_write_pcm_frames_le() + - drwav_write_pcm_frames_be() + - Remove deprecated APIs. + - API CHANGE: The following APIs now return native-endian data. Previously they returned little-endian data. + - drwav_read_pcm_frames() + - drwav_read_pcm_frames_s16() + - drwav_read_pcm_frames_s32() + - drwav_read_pcm_frames_f32() + - drwav_open_and_read_pcm_frames_s16() + - drwav_open_and_read_pcm_frames_s32() + - drwav_open_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s16() + - drwav_open_file_and_read_pcm_frames_s32() + - drwav_open_file_and_read_pcm_frames_f32() + - drwav_open_file_and_read_pcm_frames_s16_w() + - drwav_open_file_and_read_pcm_frames_s32_w() + - drwav_open_file_and_read_pcm_frames_f32_w() + - drwav_open_memory_and_read_pcm_frames_s16() + - drwav_open_memory_and_read_pcm_frames_s32() + - drwav_open_memory_and_read_pcm_frames_f32() + +v0.10.1 - 2019-08-31 + - Correctly handle partial trailing ADPCM blocks. + +v0.10.0 - 2019-08-04 + - Remove deprecated APIs. + - Add wchar_t variants for file loading APIs: + drwav_init_file_w() + drwav_init_file_ex_w() + drwav_init_file_write_w() + drwav_init_file_write_sequential_w() + - Add drwav_target_write_size_bytes() which calculates the total size in bytes of a WAV file given a format and sample count. + - Add APIs for specifying the PCM frame count instead of the sample count when opening in sequential write mode: + drwav_init_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames() + drwav_init_file_write_sequential_pcm_frames_w() + drwav_init_memory_write_sequential_pcm_frames() + - Deprecate drwav_open*() and drwav_close(): + drwav_open() + drwav_open_ex() + drwav_open_write() + drwav_open_write_sequential() + drwav_open_file() + drwav_open_file_ex() + drwav_open_file_write() + drwav_open_file_write_sequential() + drwav_open_memory() + drwav_open_memory_ex() + drwav_open_memory_write() + drwav_open_memory_write_sequential() + drwav_close() + - Minor documentation updates. + +v0.9.2 - 2019-05-21 + - Fix warnings. + +v0.9.1 - 2019-05-05 + - Add support for C89. + - Change license to choice of public domain or MIT-0. + +v0.9.0 - 2018-12-16 + - API CHANGE: Add new reading APIs for reading by PCM frames instead of samples. Old APIs have been deprecated and + will be removed in v0.10.0. Deprecated APIs and their replacements: + drwav_read() -> drwav_read_pcm_frames() + drwav_read_s16() -> drwav_read_pcm_frames_s16() + drwav_read_f32() -> drwav_read_pcm_frames_f32() + drwav_read_s32() -> drwav_read_pcm_frames_s32() + drwav_seek_to_sample() -> drwav_seek_to_pcm_frame() + drwav_write() -> drwav_write_pcm_frames() + drwav_open_and_read_s16() -> drwav_open_and_read_pcm_frames_s16() + drwav_open_and_read_f32() -> drwav_open_and_read_pcm_frames_f32() + drwav_open_and_read_s32() -> drwav_open_and_read_pcm_frames_s32() + drwav_open_file_and_read_s16() -> drwav_open_file_and_read_pcm_frames_s16() + drwav_open_file_and_read_f32() -> drwav_open_file_and_read_pcm_frames_f32() + drwav_open_file_and_read_s32() -> drwav_open_file_and_read_pcm_frames_s32() + drwav_open_memory_and_read_s16() -> drwav_open_memory_and_read_pcm_frames_s16() + drwav_open_memory_and_read_f32() -> drwav_open_memory_and_read_pcm_frames_f32() + drwav_open_memory_and_read_s32() -> drwav_open_memory_and_read_pcm_frames_s32() + drwav::totalSampleCount -> drwav::totalPCMFrameCount + - API CHANGE: Rename drwav_open_and_read_file_*() to drwav_open_file_and_read_*(). + - API CHANGE: Rename drwav_open_and_read_memory_*() to drwav_open_memory_and_read_*(). + - Add built-in support for smpl chunks. + - Add support for firing a callback for each chunk in the file at initialization time. + - This is enabled through the drwav_init_ex(), etc. family of APIs. + - Handle invalid FMT chunks more robustly. + +v0.8.5 - 2018-09-11 + - Const correctness. + - Fix a potential stack overflow. + +v0.8.4 - 2018-08-07 + - Improve 64-bit detection. + +v0.8.3 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.8.2 - 2018-08-02 + - Fix some big-endian bugs. + +v0.8.1 - 2018-06-29 + - Add support for sequential writing APIs. + - Disable seeking in write mode. + - Fix bugs with Wave64. + - Fix typos. + +v0.8 - 2018-04-27 + - Bug fix. + - Start using major.minor.revision versioning. + +v0.7f - 2018-02-05 + - Restrict ADPCM formats to a maximum of 2 channels. + +v0.7e - 2018-02-02 + - Fix a crash. + +v0.7d - 2018-02-01 + - Fix a crash. + +v0.7c - 2018-02-01 + - Set drwav.bytesPerSample to 0 for all compressed formats. + - Fix a crash when reading 16-bit floating point WAV files. In this case dr_wav will output silence for + all format conversion reading APIs (*_s16, *_s32, *_f32 APIs). + - Fix some divide-by-zero errors. + +v0.7b - 2018-01-22 + - Fix errors with seeking of compressed formats. + - Fix compilation error when DR_WAV_NO_CONVERSION_API + +v0.7a - 2017-11-17 + - Fix some GCC warnings. + +v0.7 - 2017-11-04 + - Add writing APIs. + +v0.6 - 2017-08-16 + - API CHANGE: Rename dr_* types to drwav_*. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add support for Microsoft ADPCM. + - Add support for IMA ADPCM (DVI, format code 0x11). + - Optimizations to drwav_read_s16(). + - Bug fixes. + +v0.5g - 2017-07-16 + - Change underlying type for booleans to unsigned. + +v0.5f - 2017-04-04 + - Fix a minor bug with drwav_open_and_read_s16() and family. + +v0.5e - 2016-12-29 + - Added support for reading samples as signed 16-bit integers. Use the _s16() family of APIs for this. + - Minor fixes to documentation. + +v0.5d - 2016-12-28 + - Use drwav_int* and drwav_uint* sized types to improve compiler support. + +v0.5c - 2016-11-11 + - Properly handle JUNK chunks that come before the FMT chunk. + +v0.5b - 2016-10-23 + - A minor change to drwav_bool8 and drwav_bool32 types. + +v0.5a - 2016-10-11 + - Fixed a bug with drwav_open_and_read() and family due to incorrect argument ordering. + - Improve A-law and mu-law efficiency. + +v0.5 - 2016-09-29 + - API CHANGE. Swap the order of "channels" and "sampleRate" parameters in drwav_open_and_read*(). Rationale for this is to + keep it consistent with dr_audio and dr_flac. + +v0.4b - 2016-09-18 + - Fixed a typo in documentation. + +v0.4a - 2016-09-18 + - Fixed a typo. + - Change date format to ISO 8601 (YYYY-MM-DD) + +v0.4 - 2016-07-13 + - API CHANGE. Make onSeek consistent with dr_flac. + - API CHANGE. Rename drwav_seek() to drwav_seek_to_sample() for clarity and consistency with dr_flac. + - Added support for Sony Wave64. + +v0.3a - 2016-05-28 + - API CHANGE. Return drwav_bool32 instead of int in onSeek callback. + - Fixed a memory leak. + +v0.3 - 2016-05-22 + - Lots of API changes for consistency. + +v0.2a - 2016-05-16 + - Fixed Linux/GCC build. + +v0.2 - 2016-05-11 + - Added support for reading data as signed 32-bit PCM for consistency with dr_flac. + +v0.1a - 2016-05-07 + - Fixed a bug in drwav_open_file() where the file handle would not be closed if the loader failed to initialize. + +v0.1 - 2016-05-04 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== +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 + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2020 David Reid + +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. + +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/whisper.cpp-1.5.2/examples/generate-karaoke.sh b/whisper.cpp-1.5.2/examples/generate-karaoke.sh new file mode 100755 index 0000000..7062c9a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/generate-karaoke.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Simple tool to record audio from the microphone and generate a karaoke video +# Usage: +# +# cd whisper.cpp +# make +# +# ./examples/generate-karaoke.sh [model] [step_ms] +# +# Press Ctrl+C to stop recording +# + +executable="./main" +model="base.en" +model_path="models/ggml-$model.bin" + +# require sox and ffmpeg to be installed +if ! command -v sox &> /dev/null +then + echo "sox could not be found" + exit 1 +fi + +if ! command -v ffmpeg &> /dev/null +then + echo "ffmpeg could not be found" + exit 2 +fi + +if [ ! -f "$executable" ]; then + echo "'$executable' does not exist. Please build it first." + exit 3 +fi + +if [ ! -f "$model_path" ]; then + echo "'$model_path' does not exist. Please download it first." + exit 4 +fi + +# record some raw audio +sox -d rec.wav + +# resample to 16kHz +ffmpeg -y -i ./rec.wav -ar 16000 -ac 1 -c:a pcm_s16le ./rec16.wav > /dev/null 2>&1 + +# run Whisper +echo "Processing ..." +./main -m models/ggml-base.en.bin rec16.wav -owts > /dev/null 2>&1 + +# generate Karaoke video +echo "Generating video ..." +source rec16.wav.wts > /dev/null 2>&1 + +# play the video +echo "Playing ./rec16.wav.mp4 ..." +ffplay -loglevel 0 -autoexit ./rec16.wav.mp4 + +echo "Done" +exit 0 diff --git a/whisper.cpp-1.5.2/examples/grammar-parser.cpp b/whisper.cpp-1.5.2/examples/grammar-parser.cpp new file mode 100644 index 0000000..2daaaef --- /dev/null +++ b/whisper.cpp-1.5.2/examples/grammar-parser.cpp @@ -0,0 +1,423 @@ +#include "grammar-parser.h" +#include +#include +#include +#include +#include +#include + +namespace grammar_parser { + // NOTE: assumes valid utf8 (but checks for overrun) + // copied from whisper.cpp + std::pair decode_utf8(const char * src) { + static const int lookup[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 4 }; + uint8_t first_byte = static_cast(*src); + uint8_t highbits = first_byte >> 4; + int len = lookup[highbits]; + uint8_t mask = (1 << (8 - len)) - 1; + uint32_t value = first_byte & mask; + const char * end = src + len; // may overrun! + const char * pos = src + 1; + for ( ; pos < end && *pos; pos++) { + value = (value << 6) + (static_cast(*pos) & 0x3F); + } + return std::make_pair(value, pos); + } + + uint32_t get_symbol_id(parse_state & state, const char * src, size_t len) { + uint32_t next_id = static_cast(state.symbol_ids.size()); + auto result = state.symbol_ids.insert(std::make_pair(std::string(src, len), next_id)); + return result.first->second; + } + + uint32_t generate_symbol_id(parse_state & state, const std::string & base_name) { + uint32_t next_id = static_cast(state.symbol_ids.size()); + state.symbol_ids[base_name + '_' + std::to_string(next_id)] = next_id; + return next_id; + } + + void add_rule( + parse_state & state, + uint32_t rule_id, + const std::vector & rule) { + if (state.rules.size() <= rule_id) { + state.rules.resize(rule_id + 1); + } + state.rules[rule_id] = rule; + } + + bool is_word_char(char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '-' || ('0' <= c && c <= '9'); + } + + std::pair parse_hex(const char * src, int size) { + const char * pos = src; + const char * end = src + size; + uint32_t value = 0; + for ( ; pos < end && *pos; pos++) { + value <<= 4; + char c = *pos; + if ('a' <= c && c <= 'f') { + value += c - 'a' + 10; + } else if ('A' <= c && c <= 'F') { + value += c - 'A' + 10; + } else if ('0' <= c && c <= '9') { + value += c - '0'; + } else { + break; + } + } + if (pos != end) { + throw std::runtime_error("expecting " + std::to_string(size) + " hex chars at " + src); + } + return std::make_pair(value, pos); + } + + const char * parse_space(const char * src, bool newline_ok) { + const char * pos = src; + while (*pos == ' ' || *pos == '\t' || *pos == '#' || + (newline_ok && (*pos == '\r' || *pos == '\n'))) { + if (*pos == '#') { + while (*pos && *pos != '\r' && *pos != '\n') { + pos++; + } + } else { + pos++; + } + } + return pos; + } + + const char * parse_name(const char * src) { + const char * pos = src; + while (is_word_char(*pos)) { + pos++; + } + if (pos == src) { + throw std::runtime_error(std::string("expecting name at ") + src); + } + return pos; + } + + std::pair parse_char(const char * src) { + if (*src == '\\') { + switch (src[1]) { + case 'x': return parse_hex(src + 2, 2); + case 'u': return parse_hex(src + 2, 4); + case 'U': return parse_hex(src + 2, 8); + case 't': return std::make_pair('\t', src + 2); + case 'r': return std::make_pair('\r', src + 2); + case 'n': return std::make_pair('\n', src + 2); + case '\\': + case '"': + case '[': + case ']': + return std::make_pair(src[1], src + 2); + default: + throw std::runtime_error(std::string("unknown escape at ") + src); + } + } else if (*src) { + return decode_utf8(src); + } + throw std::runtime_error("unexpected end of input"); + } + + const char * parse_alternates( + parse_state & state, + const char * src, + const std::string & rule_name, + uint32_t rule_id, + bool is_nested); + + const char * parse_sequence( + parse_state & state, + const char * src, + const std::string & rule_name, + std::vector & out_elements, + bool is_nested) { + size_t last_sym_start = out_elements.size(); + const char * pos = src; + while (*pos) { + if (*pos == '"') { // literal string + pos++; + last_sym_start = out_elements.size(); + while (*pos != '"') { + auto char_pair = parse_char(pos); + pos = char_pair.second; + out_elements.push_back({WHISPER_GRETYPE_CHAR, char_pair.first}); + } + pos = parse_space(pos + 1, is_nested); + } else if (*pos == '[') { // char range(s) + pos++; + enum whisper_gretype start_type = WHISPER_GRETYPE_CHAR; + if (*pos == '^') { + pos++; + start_type = WHISPER_GRETYPE_CHAR_NOT; + } + last_sym_start = out_elements.size(); + while (*pos != ']') { + auto char_pair = parse_char(pos); + pos = char_pair.second; + enum whisper_gretype type = last_sym_start < out_elements.size() + ? WHISPER_GRETYPE_CHAR_ALT + : start_type; + + out_elements.push_back({type, char_pair.first}); + if (pos[0] == '-' && pos[1] != ']') { + auto endchar_pair = parse_char(pos + 1); + pos = endchar_pair.second; + out_elements.push_back({WHISPER_GRETYPE_CHAR_RNG_UPPER, endchar_pair.first}); + } + } + pos = parse_space(pos + 1, is_nested); + } else if (is_word_char(*pos)) { // rule reference + const char * name_end = parse_name(pos); + uint32_t ref_rule_id = get_symbol_id(state, pos, name_end - pos); + pos = parse_space(name_end, is_nested); + last_sym_start = out_elements.size(); + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, ref_rule_id}); + } else if (*pos == '(') { // grouping + // parse nested alternates into synthesized rule + pos = parse_space(pos + 1, true); + uint32_t sub_rule_id = generate_symbol_id(state, rule_name); + pos = parse_alternates(state, pos, rule_name, sub_rule_id, true); + last_sym_start = out_elements.size(); + // output reference to synthesized rule + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + if (*pos != ')') { + throw std::runtime_error(std::string("expecting ')' at ") + pos); + } + pos = parse_space(pos + 1, is_nested); + } else if (*pos == '*' || *pos == '+' || *pos == '?') { // repetition operator + if (last_sym_start == out_elements.size()) { + throw std::runtime_error(std::string("expecting preceeding item to */+/? at ") + pos); + } + + // apply transformation to previous symbol (last_sym_start to end) according to + // rewrite rules: + // S* --> S' ::= S S' | + // S+ --> S' ::= S S' | S + // S? --> S' ::= S | + uint32_t sub_rule_id = generate_symbol_id(state, rule_name); + std::vector sub_rule; + // add preceding symbol to generated rule + sub_rule.insert( + sub_rule.end(), out_elements.begin() + last_sym_start, out_elements.end()); + if (*pos == '*' || *pos == '+') { + // cause generated rule to recurse + sub_rule.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + } + // mark start of alternate def + sub_rule.push_back({WHISPER_GRETYPE_ALT, 0}); + if (*pos == '+') { + // add preceding symbol as alternate only for '+' (otherwise empty) + sub_rule.insert( + sub_rule.end(), out_elements.begin() + last_sym_start, out_elements.end()); + } + sub_rule.push_back({WHISPER_GRETYPE_END, 0}); + add_rule(state, sub_rule_id, sub_rule); + + // in original rule, replace previous symbol with reference to generated rule + out_elements.resize(last_sym_start); + out_elements.push_back({WHISPER_GRETYPE_RULE_REF, sub_rule_id}); + + pos = parse_space(pos + 1, is_nested); + } else { + break; + } + } + return pos; + } + + const char * parse_alternates( + parse_state & state, + const char * src, + const std::string & rule_name, + uint32_t rule_id, + bool is_nested) { + std::vector rule; + const char * pos = parse_sequence(state, src, rule_name, rule, is_nested); + while (*pos == '|') { + rule.push_back({WHISPER_GRETYPE_ALT, 0}); + pos = parse_space(pos + 1, true); + pos = parse_sequence(state, pos, rule_name, rule, is_nested); + } + rule.push_back({WHISPER_GRETYPE_END, 0}); + add_rule(state, rule_id, rule); + return pos; + } + + const char * parse_rule(parse_state & state, const char * src) { + const char * name_end = parse_name(src); + const char * pos = parse_space(name_end, false); + size_t name_len = name_end - src; + uint32_t rule_id = get_symbol_id(state, src, name_len); + const std::string name(src, name_len); + + if (!(pos[0] == ':' && pos[1] == ':' && pos[2] == '=')) { + throw std::runtime_error(std::string("expecting ::= at ") + pos); + } + pos = parse_space(pos + 3, true); + + pos = parse_alternates(state, pos, name, rule_id, false); + + if (*pos == '\r') { + pos += pos[1] == '\n' ? 2 : 1; + } else if (*pos == '\n') { + pos++; + } else if (*pos) { + throw std::runtime_error(std::string("expecting newline or end at ") + pos); + } + return parse_space(pos, true); + } + + parse_state parse(const char * src) { + try { + parse_state state; + const char * pos = parse_space(src, true); + while (*pos) { + pos = parse_rule(state, pos); + } + return state; + } catch (const std::exception & err) { + fprintf(stderr, "%s: error parsing grammar: %s\n", __func__, err.what()); + return parse_state(); + } + } + + void print_grammar_char(FILE * file, uint32_t c) { + if (0x20 <= c && c <= 0x7f) { + fprintf(file, "%c", static_cast(c)); + } else { + // cop out of encoding UTF-8 + fprintf(file, "", c); + } + } + + bool is_char_element(whisper_grammar_element elem) { + switch (elem.type) { + case WHISPER_GRETYPE_CHAR: return true; + case WHISPER_GRETYPE_CHAR_NOT: return true; + case WHISPER_GRETYPE_CHAR_ALT: return true; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: return true; + default: return false; + } + } + + void print_rule_binary(FILE * file, const std::vector & rule) { + for (auto elem : rule) { + switch (elem.type) { + case WHISPER_GRETYPE_END: fprintf(file, "END"); break; + case WHISPER_GRETYPE_ALT: fprintf(file, "ALT"); break; + case WHISPER_GRETYPE_RULE_REF: fprintf(file, "RULE_REF"); break; + case WHISPER_GRETYPE_CHAR: fprintf(file, "CHAR"); break; + case WHISPER_GRETYPE_CHAR_NOT: fprintf(file, "CHAR_NOT"); break; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: fprintf(file, "CHAR_RNG_UPPER"); break; + case WHISPER_GRETYPE_CHAR_ALT: fprintf(file, "CHAR_ALT"); break; + } + switch (elem.type) { + case WHISPER_GRETYPE_END: + case WHISPER_GRETYPE_ALT: + case WHISPER_GRETYPE_RULE_REF: + fprintf(file, "(%u) ", elem.value); + break; + case WHISPER_GRETYPE_CHAR: + case WHISPER_GRETYPE_CHAR_NOT: + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + case WHISPER_GRETYPE_CHAR_ALT: + fprintf(file, "(\""); + print_grammar_char(file, elem.value); + fprintf(file, "\") "); + break; + } + } + fprintf(file, "\n"); + } + + void print_rule( + FILE * file, + uint32_t rule_id, + const std::vector & rule, + const std::map & symbol_id_names) { + if (rule.empty() || rule.back().type != WHISPER_GRETYPE_END) { + throw std::runtime_error( + "malformed rule, does not end with WHISPER_GRETYPE_END: " + std::to_string(rule_id)); + } + fprintf(file, "%s ::= ", symbol_id_names.at(rule_id).c_str()); + for (size_t i = 0, end = rule.size() - 1; i < end; i++) { + whisper_grammar_element elem = rule[i]; + switch (elem.type) { + case WHISPER_GRETYPE_END: + throw std::runtime_error( + "unexpected end of rule: " + std::to_string(rule_id) + "," + + std::to_string(i)); + case WHISPER_GRETYPE_ALT: + fprintf(file, "| "); + break; + case WHISPER_GRETYPE_RULE_REF: + fprintf(file, "%s ", symbol_id_names.at(elem.value).c_str()); + break; + case WHISPER_GRETYPE_CHAR: + fprintf(file, "["); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_NOT: + fprintf(file, "[^"); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + if (i == 0 || !is_char_element(rule[i - 1])) { + throw std::runtime_error( + "WHISPER_GRETYPE_CHAR_RNG_UPPER without preceding char: " + + std::to_string(rule_id) + "," + std::to_string(i)); + } + fprintf(file, "-"); + print_grammar_char(file, elem.value); + break; + case WHISPER_GRETYPE_CHAR_ALT: + if (i == 0 || !is_char_element(rule[i - 1])) { + throw std::runtime_error( + "WHISPER_GRETYPE_CHAR_ALT without preceding char: " + + std::to_string(rule_id) + "," + std::to_string(i)); + } + print_grammar_char(file, elem.value); + break; + } + if (is_char_element(elem)) { + switch (rule[i + 1].type) { + case WHISPER_GRETYPE_CHAR_ALT: + case WHISPER_GRETYPE_CHAR_RNG_UPPER: + break; + default: + fprintf(file, "] "); + } + } + } + fprintf(file, "\n"); + } + + void print_grammar(FILE * file, const parse_state & state) { + try { + std::map symbol_id_names; + for (auto kv : state.symbol_ids) { + symbol_id_names[kv.second] = kv.first; + } + for (size_t i = 0, end = state.rules.size(); i < end; i++) { + // fprintf(file, "%zu: ", i); + // print_rule_binary(file, state.rules[i]); + print_rule(file, uint32_t(i), state.rules[i], symbol_id_names); + // fprintf(file, "\n"); + } + } catch (const std::exception & err) { + fprintf(stderr, "\n%s: error printing grammar: %s\n", __func__, err.what()); + } + } + + std::vector parse_state::c_rules() const{ + std::vector ret; + for (const auto & rule : rules) { + ret.push_back(rule.data()); + } + return ret; + } +} diff --git a/whisper.cpp-1.5.2/examples/grammar-parser.h b/whisper.cpp-1.5.2/examples/grammar-parser.h new file mode 100644 index 0000000..47d019c --- /dev/null +++ b/whisper.cpp-1.5.2/examples/grammar-parser.h @@ -0,0 +1,29 @@ +// Implements a parser for an extended Backus-Naur form (BNF), producing the +// binary context-free grammar format specified by whisper.h. Supports character +// ranges, grouping, and repetition operators. As an example, a grammar for +// arithmetic might look like: +// +// root ::= expr +// expr ::= term ([-+*/] term)* +// term ::= num | "(" space expr ")" space +// num ::= [0-9]+ space +// space ::= [ \t\n]* + +#pragma once +#include "whisper.h" +#include +#include +#include +#include + +namespace grammar_parser { + struct parse_state { + std::map symbol_ids; + std::vector> rules; + + std::vector c_rules() const; + }; + + parse_state parse(const char * src); + void print_grammar(FILE * file, const parse_state & state); +} diff --git a/whisper.cpp-1.5.2/examples/helpers.js b/whisper.cpp-1.5.2/examples/helpers.js new file mode 100644 index 0000000..23f18ab --- /dev/null +++ b/whisper.cpp-1.5.2/examples/helpers.js @@ -0,0 +1,194 @@ +// Common Javascript functions used by the examples + +function convertTypedArray(src, type) { + var buffer = new ArrayBuffer(src.byteLength); + var baseView = new src.constructor(buffer).set(src); + return new type(buffer); +} + +var printTextarea = (function() { + var element = document.getElementById('output'); + if (element) element.value = ''; // clear browser cache + return function(text) { + if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' '); + console.log(text); + if (element) { + element.value += text + "\n"; + element.scrollTop = element.scrollHeight; // focus on bottom + } + }; +})(); + +async function clearCache() { + if (confirm('Are you sure you want to clear the cache?\nAll the models will be downloaded again.')) { + indexedDB.deleteDatabase(dbName); + location.reload(); + } +} + +// fetch a remote file from remote URL using the Fetch API +async function fetchRemote(url, cbProgress, cbPrint) { + cbPrint('fetchRemote: downloading with fetch()...'); + + const response = await fetch( + url, + { + method: 'GET', + headers: { + 'Content-Type': 'application/octet-stream', + }, + } + ); + + if (!response.ok) { + cbPrint('fetchRemote: failed to fetch ' + url); + return; + } + + const contentLength = response.headers.get('content-length'); + const total = parseInt(contentLength, 10); + const reader = response.body.getReader(); + + var chunks = []; + var receivedLength = 0; + var progressLast = -1; + + while (true) { + const { done, value } = await reader.read(); + + if (done) { + break; + } + + chunks.push(value); + receivedLength += value.length; + + if (contentLength) { + cbProgress(receivedLength/total); + + var progressCur = Math.round((receivedLength / total) * 10); + if (progressCur != progressLast) { + cbPrint('fetchRemote: fetching ' + 10*progressCur + '% ...'); + progressLast = progressCur; + } + } + } + + var position = 0; + var chunksAll = new Uint8Array(receivedLength); + + for (var chunk of chunks) { + chunksAll.set(chunk, position); + position += chunk.length; + } + + return chunksAll; +} + +// load remote data +// - check if the data is already in the IndexedDB +// - if not, fetch it from the remote URL and store it in the IndexedDB +function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) { + if (!navigator.storage || !navigator.storage.estimate) { + cbPrint('loadRemote: navigator.storage.estimate() is not supported'); + } else { + // query the storage quota and print it + navigator.storage.estimate().then(function (estimate) { + cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes'); + cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes'); + }); + } + + // check if the data is already in the IndexedDB + var rq = indexedDB.open(dbName, dbVersion); + + rq.onupgradeneeded = function (event) { + var db = event.target.result; + if (db.version == 1) { + var os = db.createObjectStore('models', { autoIncrement: false }); + cbPrint('loadRemote: created IndexedDB ' + db.name + ' version ' + db.version); + } else { + // clear the database + var os = event.currentTarget.transaction.objectStore('models'); + os.clear(); + cbPrint('loadRemote: cleared IndexedDB ' + db.name + ' version ' + db.version); + } + }; + + rq.onsuccess = function (event) { + var db = event.target.result; + var tx = db.transaction(['models'], 'readonly'); + var os = tx.objectStore('models'); + var rq = os.get(url); + + rq.onsuccess = function (event) { + if (rq.result) { + cbPrint('loadRemote: "' + url + '" is already in the IndexedDB'); + cbReady(dst, rq.result); + } else { + // data is not in the IndexedDB + cbPrint('loadRemote: "' + url + '" is not in the IndexedDB'); + + // alert and ask the user to confirm + if (!confirm( + 'You are about to download ' + size_mb + ' MB of data.\n' + + 'The model data will be cached in the browser for future use.\n\n' + + 'Press OK to continue.')) { + cbCancel(); + return; + } + + fetchRemote(url, cbProgress, cbPrint).then(function (data) { + if (data) { + // store the data in the IndexedDB + var rq = indexedDB.open(dbName, dbVersion); + rq.onsuccess = function (event) { + var db = event.target.result; + var tx = db.transaction(['models'], 'readwrite'); + var os = tx.objectStore('models'); + + var rq = null; + try { + var rq = os.put(data, url); + } catch (e) { + cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB: \n' + e); + cbCancel(); + return; + } + + rq.onsuccess = function (event) { + cbPrint('loadRemote: "' + url + '" stored in the IndexedDB'); + cbReady(dst, data); + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB'); + cbCancel(); + }; + }; + } + }); + } + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to get data from the IndexedDB'); + cbCancel(); + }; + }; + + rq.onerror = function (event) { + cbPrint('loadRemote: failed to open IndexedDB'); + cbCancel(); + }; + + rq.onblocked = function (event) { + cbPrint('loadRemote: failed to open IndexedDB: blocked'); + cbCancel(); + }; + + rq.onabort = function (event) { + cbPrint('loadRemote: failed to open IndexedDB: abort'); + cbCancel(); + }; +} diff --git a/whisper.cpp-1.5.2/examples/livestream.sh b/whisper.cpp-1.5.2/examples/livestream.sh new file mode 100755 index 0000000..fbeb6db --- /dev/null +++ b/whisper.cpp-1.5.2/examples/livestream.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# +# Transcribe audio livestream by feeding ffmpeg output to whisper.cpp at regular intervals +# Idea by @semiformal-net +# ref: https://github.com/ggerganov/whisper.cpp/issues/185 +# + +set -eo pipefail + +url="http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_low/ak/bbc_world_service.m3u8" +fmt=aac # the audio format extension of the stream (TODO: auto detect) +step_s=30 +model="base.en" + +check_requirements() +{ + if ! command -v ./main &>/dev/null; then + echo "whisper.cpp main executable is required (make)" + exit 1 + fi + + if ! command -v ffmpeg &>/dev/null; then + echo "ffmpeg is required (https://ffmpeg.org)" + exit 1 + fi +} + +check_requirements + + +if [ -z "$1" ]; then + echo "Usage: $0 stream_url [step_s] [model]" + echo "" + echo " Example:" + echo " $0 $url $step_s $model" + echo "" + echo "No url specified, using default: $url" +else + url="$1" +fi + +if [ -n "$2" ]; then + step_s="$2" +fi + +if [ -n "$3" ]; then + model="$3" +fi + +# Whisper models +models=( "tiny.en" "tiny" "base.en" "base" "small.en" "small" "medium.en" "medium" "large-v1" "large-v2" "large-v3" ) + +# list available models +function list_models { + printf "\n" + printf " Available models:" + for model in "${models[@]}"; do + printf " $model" + done + printf "\n\n" +} + +if [[ ! " ${models[@]} " =~ " ${model} " ]]; then + printf "Invalid model: $model\n" + list_models + + exit 1 +fi + +running=1 + +trap "running=0" SIGINT SIGTERM + +printf "[+] Transcribing stream with model '$model', step_s $step_s (press Ctrl+C to stop):\n\n" + +# continuous stream in native fmt (this file will grow forever!) +ffmpeg -loglevel quiet -y -re -probesize 32 -i $url -c copy /tmp/whisper-live0.${fmt} & +if [ $? -ne 0 ]; then + printf "Error: ffmpeg failed to capture audio stream\n" + exit 1 +fi + +printf "Buffering audio. Please wait...\n\n" +sleep $(($step_s)) + +# do not stop script on error +set +e + +i=0 +SECONDS=0 +while [ $running -eq 1 ]; do + # extract the next piece from the main file above and transcode to wav. -ss sets start time and nudges it by -0.5s to catch missing words (??) + err=1 + while [ $err -ne 0 ]; do + if [ $i -gt 0 ]; then + ffmpeg -loglevel quiet -v error -noaccurate_seek -i /tmp/whisper-live0.${fmt} -y -ar 16000 -ac 1 -c:a pcm_s16le -ss $(($i*$step_s-1)).5 -t $step_s /tmp/whisper-live.wav 2> /tmp/whisper-live.err + else + ffmpeg -loglevel quiet -v error -noaccurate_seek -i /tmp/whisper-live0.${fmt} -y -ar 16000 -ac 1 -c:a pcm_s16le -ss $(($i*$step_s)) -t $step_s /tmp/whisper-live.wav 2> /tmp/whisper-live.err + fi + err=$(cat /tmp/whisper-live.err | wc -l) + done + + ./main -t 8 -m ./models/ggml-${model}.bin -f /tmp/whisper-live.wav --no-timestamps -otxt 2> /tmp/whispererr | tail -n 1 + + while [ $SECONDS -lt $((($i+1)*$step_s)) ]; do + sleep 1 + done + ((i=i+1)) +done + +killall -v ffmpeg +killall -v main diff --git a/whisper.cpp-1.5.2/examples/lsp/CMakeLists.txt b/whisper.cpp-1.5.2/examples/lsp/CMakeLists.txt new file mode 100644 index 0000000..e7ac251 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/lsp/CMakeLists.txt @@ -0,0 +1,9 @@ +if (WHISPER_SDL2) + # stream + set(TARGET lsp) + add_executable(${TARGET} lsp.cpp) + + include(DefaultTargetOptions) + + target_link_libraries(${TARGET} PRIVATE common common-sdl whisper ${CMAKE_THREAD_LIBS_INIT}) +endif () diff --git a/whisper.cpp-1.5.2/examples/lsp/README.md b/whisper.cpp-1.5.2/examples/lsp/README.md new file mode 100644 index 0000000..b9afb11 --- /dev/null +++ b/whisper.cpp-1.5.2/examples/lsp/README.md @@ -0,0 +1,104 @@ +# Language Server + +This example consists of a simple language server to expose both unguided +and guided (command) transcriptions by sending json messages over stdout/stdin +as well as a rather robust vim plugin that makes use of the language server. + +## Vim plugin quick start + +Compile the language server with + +```bash +make lsp +``` +Install the plugin itself by copying or symlinking whisper.vim into ~/.vim/autoload/ + +In your vimrc, set the path of your whisper.cpp directory and optionally add some keybinds. + +```vim +let g:whisper_dir = "~/whisper.cpp" +" Start listening for commands when Ctrl - g is pressed in normal mode +nnoremap call whisper#requestCommands() +" Start unguided transcription when Ctrl - g is pressed in insert mode +inoremap call whisper#doTranscription() +``` + +## Vim plugin usage + +The vim plugin was designed to closely follow the mnemonics of vim + +`s:spoken_dict` is used to translate keys to their spoken form. + + +Keys corresponding to a string use that spoken value normally and when a motion is expected, but use the key itself when a character is expected. +Keys corresponding to a dict, like `i`, can have manual difinitions given to each possible commandset. + +0 is normal (insert), 1 is motion (inside), 2 is it's usage as a single key ([till] i), and 3 is it's usage in an area selection (s -> [around] sentence) + +Some punctuation items, like `-` are explicitly given pronunciations to prevent them from being picked as punctuation instead of an actual command word. + +Not all commands will tokenize to a single token and this can interfere with interpretation. "yank" as an example, takes multiple tokens and correspondingly, will give more accurate detection when only the first "ya" is used. While it could be changed to something else that is a single token (copy), value was placed on maintaining vim mnemonics. + +Commands that would normally move the editor into insert mode (insert, append, open, change) will begin unguided transcription. +Unguided transcription will end when a speech segment ends in exit. +Presence of punctuation can be designated by whether or not you add a pause between the previous speech segment and exit. +Exiting only occurs if exit is the last word, so "Take the first exit on your right" would not cause transcription to end. + +After a command is evaluated, the plugin will continue listening for the next command. + +While in command mode, "Exit" will end listening. + +A best effort approach is taken to keep track of audio that is recorded while a previous chunk is still processing and immediately interpret it afterwards, but the current voice detection still needs a fairly sizable gap to determine when a command has been spoken. + +Log information is sent to a special `whisper_log` buffer and can be accessed with +```vim +:e whisper_log +``` + +## Vim plugin configuration + +`g:whisper_dir` +A full path to the whisper.cpp repo. It can be expanded in the definition like so: +```vim +let g:whisper_dir = expand("~/whisper.cpp/") +``` +(The WHISPER_CPP_HOME environment variable is also checked for users of the existing whisper.nvim script) + +`g:whisper_lsp_path` +Can be used to manually set the path to the language server. +If not defined, it will be inferred from the above whisper_dir + +`g:whisper_model_path` +A full path to the model to load. If not defined, it will default to ggml-base.en.bin + +`g:whisper_user_commands` +A dictionary of spoken commands that correspond to either strings or funcrefs. +This can be used to create connections with other user plugins, for example +```vim +let g:whisper_user_commands = {"gen": "llama#doLlamaGen"} +``` +will trigger the llama.cpp plugin to begin generation when "gen" is spoken + +## Language server methods + +`registerCommandset` +`params` is a list of strings that should be checked for with this commandset. The server prepends a space to these strings before tokenizing. +Responds with +`result.index` an integer index for the commandset registered, which should be included when initiating a guided transcription to select this commandset. +Will return an error if any of the commands in the commandset have duplicate tokenizations + +`guided` +`params.commandset_index` An index returned by a corresponding commandset registration. If not set, the most recently registered commandset is used. +`params.timestamp` A positive unsigned integer which designates a point in time which audio should begin processing from. If left blank, the start point of audio processing will be the moment the message is recieved. This should be left blank unless you have a timestamp from a previous response. +Responds with +`result.command_index` The numerical index (starting from 0) of the detected command in the selected commandset +`result.command_text` A string containing the command as provided in the commandset +`result.timestamp` A positive unsigned integer that designates the point in time which audio stopped being processed at. Pass this timestamp back in a subsequent message to mask the latency of transcription. + +`unguided` +`params.no_context` Sets the corresponding whisper `no_context` param. Defaults to true. Might provide more accurate results for consecutive unguided transcriptions if those after the first are set to false. +`params.prompt` If provided, sets the initial prompt used during transcription. +`params.timestamp` A positive unsigned integer which designates a point in time which audio should begin processing from. If left blank, the start point of audio processing will be the moment the message is recieved. This should be left blank unless you have a timestamp from a previous response. +Responds with +`result.transcription` A string containing the transcribed text. N.B. This will almost always start with a space due to how text is tokenized. +`result.timestamp` A positive unsigned integer that designates the point in time which audio stopped being processed at. Pass this timestamp back in a subsequent message to mask the latency of transcription. diff --git a/whisper.cpp-1.5.2/examples/lsp/json.hpp b/whisper.cpp-1.5.2/examples/lsp/json.hpp new file mode 100644 index 0000000..4d1a37a --- /dev/null +++ b/whisper.cpp-1.5.2/examples/lsp/json.hpp @@ -0,0 +1,24596 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 2 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 2 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { Type nlohmann_json_default_obj; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.2 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template