From 65f1c0fab20157eb03af97a89f673d5a384c5902 Mon Sep 17 00:00:00 2001 From: Fangjun Kuang Date: Sun, 11 Aug 2024 22:43:42 +0800 Subject: [PATCH] Add Pascal API for reading wave files (#1243) --- .github/workflows/pascal.yaml | 112 ++++++++++++++++++++++++ .gitignore | 2 + README.md | 6 +- pascal-api-examples/read-wav/.gitignore | 1 + pascal-api-examples/read-wav/main.pas | 21 +++++ pascal-api-examples/read-wav/run.sh | 38 ++++++++ sherpa-onnx/pascal-api/README.md | 7 ++ sherpa-onnx/pascal-api/sherpa_onnx.pas | 77 ++++++++++++++++ 8 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/pascal.yaml create mode 100644 pascal-api-examples/read-wav/.gitignore create mode 100644 pascal-api-examples/read-wav/main.pas create mode 100755 pascal-api-examples/read-wav/run.sh create mode 100644 sherpa-onnx/pascal-api/README.md create mode 100644 sherpa-onnx/pascal-api/sherpa_onnx.pas diff --git a/.github/workflows/pascal.yaml b/.github/workflows/pascal.yaml new file mode 100644 index 00000000..55285c3f --- /dev/null +++ b/.github/workflows/pascal.yaml @@ -0,0 +1,112 @@ +name: pascal + +on: + push: + branches: + - master + paths: + - '.github/workflows/pascal.yaml' + - 'CMakeLists.txt' + - 'cmake/**' + - 'pascal-api-examples/**' + - 'sherpa-onnx/csrc/*' + - 'sherpa-onnx/c-api/*' + - 'sherpa-onnx/pascal-api/*' + pull_request: + branches: + - master + paths: + - '.github/workflows/pascal.yaml' + - 'CMakeLists.txt' + - 'cmake/**' + - 'pascal-api-examples/**' + - 'sherpa-onnx/csrc/*' + - 'sherpa-onnx/c-api/*' + - 'sherpa-onnx/pascal-api/*' + + workflow_dispatch: + +concurrency: + group: pascal-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + pascal: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, macos-13] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ matrix.os }} + + - name: Install Free pascal compiler (ubuntu) + if: matrix.os == 'ubuntu-latest' + shell: bash + run: | + sudo apt-get update + sudo apt-get install -q -y fpc + + - name: Install Free pascal compiler (macos) + if: matrix.os == 'macos-latest' || matrix.os == 'macos-13' + shell: bash + run: | + brew install fpc + # brew install --cask lazarus + + - name: FPC info + shell: bash + run: | + which fpc + fpc -i + + - name: OS info + shell: bash + run: | + uname -a + + - name: Configure CMake + shell: bash + run: | + export CMAKE_CXX_COMPILER_LAUNCHER=ccache + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + cmake --version + + mkdir build + cd build + + cmake \ + -D BUILD_SHARED_LIBS=ON \ + -D SHERPA_ONNX_ENABLE_BINARY=OFF \ + -D CMAKE_BUILD_TYPE=Release \ + .. + + - name: Build sherpa-onnx + shell: bash + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + + cd build + make -j2 sherpa-onnx-c-api + + - name: Run Pascal test + shell: bash + run: | + cd ./pascal-api-examples + + echo "----read-wav test-----" + pushd read-wav + ./run.sh + ls -lh + popd diff --git a/.gitignore b/.gitignore index 8c4c5c5a..6ed4a1b1 100644 --- a/.gitignore +++ b/.gitignore @@ -114,3 +114,5 @@ lib*.a sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17 *.bak vits-melo-tts-zh_en +*.o +*.ppu diff --git a/README.md b/README.md index e411e535..6c281d3e 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ |--------|-------|-----------|-------|---------|---------------| | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | -| 7. Kotlin | 8. Swift | 9. Go | 10. Dart | 11. Rust | -|-----------|----------|-------|----------|----------| -| ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | +| 7. Kotlin | 8. Swift | 9. Go | 10. Dart | 11. Rust | 12. Pascal | +|-----------|----------|-------|----------|----------|------------| +| ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | ✔️ | For Rust support, please see https://github.com/thewh1teagle/sherpa-rs diff --git a/pascal-api-examples/read-wav/.gitignore b/pascal-api-examples/read-wav/.gitignore new file mode 100644 index 00000000..ba2906d0 --- /dev/null +++ b/pascal-api-examples/read-wav/.gitignore @@ -0,0 +1 @@ +main diff --git a/pascal-api-examples/read-wav/main.pas b/pascal-api-examples/read-wav/main.pas new file mode 100644 index 00000000..899127bd --- /dev/null +++ b/pascal-api-examples/read-wav/main.pas @@ -0,0 +1,21 @@ +{ Copyright (c) 2024 Xiaomi Corporation } +program main; + +{$mode objfpc} + +uses + sherpa_onnx; + +var + Wave: TSherpaOnnxWave; + S: Single; + I: Integer; +begin + Wave := SherpaOnnxReadWave('./lei-jun-test.wav'); + WriteLn('info ', Wave.SampleRate, ' ', Length(Wave.Samples)); + S := 0; + for i := Low(Wave.Samples) to High(Wave.Samples) do + S += Wave.Samples[i]; + + WriteLn('sum is ', S); +end. diff --git a/pascal-api-examples/read-wav/run.sh b/pascal-api-examples/read-wav/run.sh new file mode 100755 index 00000000..60bb803c --- /dev/null +++ b/pascal-api-examples/read-wav/run.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +set -ex + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +SHERPA_ONNX_DIR=$(cd $SCRIPT_DIR/../.. && pwd) + +echo "SHERPA_ONNX_DIR: $SHERPA_ONNX_DIR" + +if [[ ! -f ../../build/lib/libsherpa-onnx-c-api.dylib && ! -f ../../build/lib/libsherpa-onnx-c-api.so ]]; then + mkdir -p ../../build + pushd ../../build + cmake \ + -DSHERPA_ONNX_ENABLE_PYTHON=OFF \ + -DSHERPA_ONNX_ENABLE_TESTS=OFF \ + -DSHERPA_ONNX_ENABLE_CHECK=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \ + .. + + make -j4 sherpa-onnx-c-api + ls -lh lib + popd +fi + +if [ ! -f ./lei-jun-test.wav ]; then + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/lei-jun-test.wav +fi + +fpc \ + -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ + -Fl$SHERPA_ONNX_DIR/build/lib \ + ./main.pas + +export LD_LIBRARY_PATH=$SHERPA_ONNX_DIR/build/lib:$LD_LIBRARY_PATH +export DYLD_LIBRARY_PATH=$SHERPA_ONNX_DIR/build/lib:$DYLD_LIBRARY_PATH + +./main diff --git a/sherpa-onnx/pascal-api/README.md b/sherpa-onnx/pascal-api/README.md new file mode 100644 index 00000000..9be45649 --- /dev/null +++ b/sherpa-onnx/pascal-api/README.md @@ -0,0 +1,7 @@ +# Introduction + +This directory contains APIs for [Object Pascal](https://en.wikipedia.org/wiki/Object_Pascal). + +Please see +https://github.com/k2-fsa/sherpa-onnx/tree/master/pascal-api-examples +for usages. diff --git a/sherpa-onnx/pascal-api/sherpa_onnx.pas b/sherpa-onnx/pascal-api/sherpa_onnx.pas new file mode 100644 index 00000000..62b1c3a8 --- /dev/null +++ b/sherpa-onnx/pascal-api/sherpa_onnx.pas @@ -0,0 +1,77 @@ +{ Copyright (c) 2024 Xiaomi Corporation } + +unit sherpa_onnx; + +{$mode objfpc} + +interface + +type + TSherpaOnnxWave = record + Samples: array of Single; { normalized to the range [-1, 1] } + SampleRate: Integer; + end; + +{ It supports reading a single channel wave with 16-bit encoded samples. + Samples are normalized to the range [-1, 1]. +} +function SherpaOnnxReadWave(Filename: string): TSherpaOnnxWave; + +implementation + +uses + ctypes; + +const + {See https://www.freepascal.org/docs-html/prog/progap7.html} + + {$IFDEF WINDOWS} + SherpaOnnxLibName = 'sherpa-onnx-c-api.dll'; + {$ENDIF} + + {$IFDEF DARWIN} + SherpaOnnxLibName = 'sherpa-onnx-c-api'; + {$linklib sherpa-onnx-c-api} + {$ENDIF} + + {$IFDEF LINUX} + SherpaOnnxLibName = 'libsherpa-onnx-c-api.so'; + {$ENDIF} + +type + SherpaOnnxWave = record + Samples: pcfloat; + SampleRate: cint32; + NumSamples: cint32; + end; + + PSherpaOnnxWave = ^SherpaOnnxWave; + +function SherpaOnnxReadWaveWrapper(Filename: PAnsiChar): PSherpaOnnxWave; cdecl; + external SherpaOnnxLibName name 'SherpaOnnxReadWave'; + +procedure SherpaOnnxFreeWaveWrapper(P: PSherpaOnnxWave); cdecl; + external SherpaOnnxLibName name 'SherpaOnnxFreeWave'; + +function SherpaOnnxReadWave(Filename: string): TSherpaOnnxWave; +var + AnsiFilename: AnsiString; + PFilename: PAnsiChar; + PWave: PSherpaOnnxWave; + I: Integer; +begin + AnsiFilename := Filename; + PFilename := PAnsiChar(AnsiFilename); + PWave := SherpaOnnxReadWaveWrapper(PFilename); + + SetLength(Result.Samples, PWave^.NumSamples); + + Result.SampleRate := PWave^.SampleRate; + + for I := Low(Result.Samples) to High(Result.Samples) do + Result.Samples[i] := PWave^.Samples[i]; + + SherpaOnnxFreeWaveWrapper(PWave); +end; + +end.