Fangjun Kuang
Committed by GitHub

Add Lazarus example for generating subtitles using Silero VAD with non-streaming ASR (#1251)

正在显示 32 个修改的文件 包含 1699 行增加16 行删除
  1 +name: lazarus
  2 +
  3 +on:
  4 + push:
  5 + branches:
  6 + - master
  7 + paths:
  8 + - '.github/workflows/lazarus.yaml'
  9 + - 'CMakeLists.txt'
  10 + - 'cmake/**'
  11 + - 'lazarus-examples/**'
  12 + - 'sherpa-onnx/csrc/*'
  13 + - 'sherpa-onnx/c-api/*'
  14 + - 'sherpa-onnx/pascal-api/*'
  15 + pull_request:
  16 + branches:
  17 + - master
  18 + paths:
  19 + - '.github/workflows/lazarus.yaml'
  20 + - 'CMakeLists.txt'
  21 + - 'cmake/**'
  22 + - 'lazarus-examples/**'
  23 + - 'sherpa-onnx/csrc/*'
  24 + - 'sherpa-onnx/c-api/*'
  25 + - 'sherpa-onnx/pascal-api/*'
  26 +
  27 + workflow_dispatch:
  28 +
  29 +concurrency:
  30 + group: lazarus-${{ github.ref }}
  31 + cancel-in-progress: true
  32 +
  33 +permissions:
  34 + contents: read
  35 +
  36 +jobs:
  37 + build:
  38 + name: ${{ matrix.os }}
  39 + runs-on: ${{ matrix.os }}
  40 + strategy:
  41 + fail-fast: false
  42 + matrix:
  43 + os: [ubuntu-20.04, macos-latest, macos-13, windows-latest]
  44 +
  45 + steps:
  46 + - uses: actions/checkout@v4
  47 + with:
  48 + fetch-depth: 0
  49 +
  50 + - name: ccache
  51 + uses: hendrikmuhs/ccache-action@v1.2
  52 + with:
  53 + key: ${{ matrix.os }}
  54 +
  55 + # See https://github.com/gcarreno/setup-lazarus
  56 + - uses: gcarreno/setup-lazarus@v3
  57 + with:
  58 + lazarus-version: "stable"
  59 + with-cache: true
  60 +
  61 + - name: Lazarus info
  62 + shell: bash
  63 + run: |
  64 + which lazbuild
  65 + lazbuild --help
  66 +
  67 + - name: FPC info
  68 + shell: bash
  69 + run: |
  70 + which fpc
  71 + fpc -i
  72 +
  73 + - name: OS info
  74 + shell: bash
  75 + run: |
  76 + uname -a
  77 +
  78 + - name: Install patchelf for ubuntu
  79 + if: matrix.os == 'ubuntu-20.04'
  80 + shell: bash
  81 + run: |
  82 + sudo apt-get update -q
  83 + sudo apt-get install -q -y patchelf
  84 +
  85 + - name: Show Patchelf version (ubuntu)
  86 + if: matrix.os == 'ubuntu-20.04'
  87 + shell: bash
  88 + run: |
  89 + patchelf --version
  90 + patchelf --help
  91 + which patchelf
  92 +
  93 + - name: Configure CMake
  94 + shell: bash
  95 + run: |
  96 + export CMAKE_CXX_COMPILER_LAUNCHER=ccache
  97 + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
  98 + cmake --version
  99 +
  100 + mkdir build
  101 + cd build
  102 + os=${{ matrix.os }}
  103 +
  104 + if [[ $os == 'windows-latest' || $os == 'ubuntu-20.04' ]]; then
  105 + BUILD_SHARED_LIBS=ON
  106 + else
  107 + BUILD_SHARED_LIBS=OFF
  108 + fi
  109 +
  110 + cmake \
  111 + -DCMAKE_INSTALL_PREFIX=./install \
  112 + -D BUILD_SHARED_LIBS=$BUILD_SHARED_LIBS \
  113 + -D SHERPA_ONNX_ENABLE_BINARY=OFF \
  114 + -D CMAKE_BUILD_TYPE=Release \
  115 + ..
  116 +
  117 + - name: Build sherpa-onnx
  118 + shell: bash
  119 + run: |
  120 + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
  121 +
  122 + cd build
  123 + cmake --build . --target install --config Release -j 2
  124 +
  125 + ls -lh install/lib/
  126 +
  127 + cp -v install/lib/*.dll ../lazarus-examples/generate_subtitles/ || true
  128 + cp -v install/lib/*.so* ../lazarus-examples/generate_subtitles/ || true
  129 +
  130 + - name: Build generating subtitles
  131 + shell: bash
  132 + run: |
  133 + cd lazarus-examples/generate_subtitles
  134 + os=${{ matrix.os }}
  135 + if [[ $os == macos-13 ]]; then
  136 + lazbuild --verbose --build-mode=Release --widgetset=cocoa ./generate_subtitles.lpi
  137 + elif [[ $os == macos-latest ]]; then
  138 + lazbuild --verbose --build-mode=Release --widgetset=cocoa --cpu=aarch64 ./generate_subtitles.lpi
  139 + elif [[ $os == 'ubuntu-20.04' ]]; then
  140 + lazbuild --verbose --build-mode=Release-Linux ./generate_subtitles.lpi
  141 + else
  142 + lazbuild --verbose --build-mode=Release ./generate_subtitles.lpi
  143 + fi
  144 +
  145 + - name: Display generating subtitles
  146 + shell: bash
  147 + run: |
  148 + cd lazarus-examples/generate_subtitles
  149 + ls -lh
  150 +
  151 + - name: Collect generating subtitles (Ubuntu)
  152 + if: matrix.os == 'ubuntu-20.04'
  153 + shell: bash
  154 + run: |
  155 + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  156 + cd lazarus-examples/generate_subtitles
  157 + ls -lh
  158 + readelf -d ./generate_subtitles
  159 + echo '----------'
  160 + ldd ./generate_subtitles
  161 +
  162 + d=generate_subtitles-linux-x64-$SHERPA_ONNX_VERSION
  163 + echo "---before running patchelf---"
  164 + readelf -d ./generate_subtitles
  165 +
  166 + patchelf --set-rpath '$ORIGIN' ./generate_subtitles
  167 +
  168 + echo "---after running patchelf---"
  169 + readelf -d ./generate_subtitles
  170 +
  171 + mkdir -p $d
  172 + cp -v ./generate_subtitles $d/
  173 + cp -v *.so $d/
  174 +
  175 + mv -v $d /tmp/linux-x64
  176 +
  177 + ls -lh /tmp/linux-x64
  178 +
  179 + - name: Collect generating subtitles (windows)
  180 + if: matrix.os == 'windows-latest'
  181 + shell: bash
  182 + run: |
  183 + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  184 + cd lazarus-examples/generate_subtitles
  185 + ls -lh
  186 +
  187 + d=generate-subtitles-windows-x64-$SHERPA_ONNX_VERSION
  188 + mkdir -p $d
  189 + cp -v ./generate_subtitles.exe $d/
  190 + cp -v onnxruntime.dll $d/
  191 + cp -v sherpa-onnx-c-api.dll $d/
  192 + mv $d ../../windows-x64
  193 + cd ../..
  194 +
  195 + ls -lh windows-x64
  196 +
  197 + - name: Collect generating subtitles (macos)
  198 + if: matrix.os == 'macos-13' || matrix.os == 'macos-latest'
  199 + shell: bash
  200 + run: |
  201 + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  202 + cd lazarus-examples/generate_subtitles
  203 + ls -lh
  204 + file ./generate_subtitles
  205 + echo '----------'
  206 + otool -L ./generate_subtitles
  207 + rm -v generate_subtitles.app/Contents/MacOS/generate_subtitles
  208 + cp -v ./generate_subtitles generate_subtitles.app/Contents/MacOS/generate_subtitles
  209 + chmod +x generate_subtitles.app/Contents/MacOS/generate_subtitles
  210 +
  211 + if [[ ${{ matrix.os }} == 'macos-latest' ]]; then
  212 + mv generate_subtitles.app /tmp/macos-arm64
  213 + else
  214 + mv generate_subtitles.app /tmp/macos-x64
  215 + d=generate-subtitles-macos-x64-$SHERPA_ONNX_VERSION.app
  216 + fi
  217 +
  218 + ls -lh /tmp
  219 + echo "---"
  220 + ls -lh /tmp/macos-*
  221 +
  222 + - uses: actions/upload-artifact@v4
  223 + if: matrix.os == 'ubuntu-20.04'
  224 + with:
  225 + name: linux-x64
  226 + path: /tmp/linux-x64
  227 +
  228 + - uses: actions/upload-artifact@v4
  229 + if: matrix.os == 'macos-latest'
  230 + with:
  231 + name: macos-arm64
  232 + path: /tmp/macos-arm64
  233 +
  234 + - uses: actions/upload-artifact@v4
  235 + if: matrix.os == 'macos-13'
  236 + with:
  237 + name: macos-x64
  238 + path: /tmp/macos-x64
  239 +
  240 + - uses: actions/upload-artifact@v4
  241 + if: matrix.os == 'windows-latest'
  242 + with:
  243 + name: windows-x64
  244 + path: ./windows-x64
  245 +
  246 + release:
  247 + runs-on: ${{ matrix.os }}
  248 + needs: [build]
  249 + strategy:
  250 + fail-fast: false
  251 + matrix:
  252 + os: [ubuntu-latest]
  253 + total: ["2"]
  254 + index: ["0", "1"]
  255 +
  256 + steps:
  257 + - uses: actions/checkout@v4
  258 + with:
  259 + fetch-depth: 0
  260 +
  261 + - name: Retrieve artifact from windows x64
  262 + uses: actions/download-artifact@v4
  263 + with:
  264 + name: windows-x64
  265 + path: /tmp/windows-x64
  266 +
  267 + - name: Retrieve artifact from linux x64
  268 + uses: actions/download-artifact@v4
  269 + with:
  270 + name: linux-x64
  271 + path: /tmp/linux-x64
  272 +
  273 + - name: Retrieve artifact from macos x64
  274 + uses: actions/download-artifact@v4
  275 + with:
  276 + name: macos-x64
  277 + path: /tmp/macos-x64
  278 +
  279 + - name: Retrieve artifact from macos arm64
  280 + uses: actions/download-artifact@v4
  281 + with:
  282 + name: macos-arm64
  283 + path: /tmp/macos-arm64
  284 +
  285 + - name: Display build files
  286 + shell: bash
  287 + run: |
  288 + ls -lh /tmp
  289 + echo "---linux-x64---"
  290 + ls -lh /tmp/linux-x64/
  291 + readelf -d /tmp/linux-x64/generate_subtitles
  292 + echo "---"
  293 + ldd /tmp/linux-x64/generate_subtitles
  294 +
  295 + echo "---macos-x64---"
  296 + ls -lh /tmp/macos-x64/
  297 + mkdir -p /tmp/macos-x64/Contents/Resources
  298 + chmod +x /tmp/macos-x64/Contents/MacOS/generate_subtitles
  299 +
  300 + echo "---macos-arm64---"
  301 + ls -lh /tmp/macos-arm64/
  302 + mkdir -p /tmp/macos-arm64/Contents/Resources
  303 + chmod +x /tmp/macos-arm64/Contents/MacOS/generate_subtitles
  304 +
  305 + echo "---windows-x64---"
  306 + ls -lh /tmp/windows-x64/
  307 +
  308 + - name: Install Python dependencies
  309 + shell: bash
  310 + run: |
  311 + python3 -m pip install --upgrade pip jinja2
  312 +
  313 + - name: Generate build script
  314 + shell: bash
  315 + run: |
  316 + cd scripts/lazarus
  317 +
  318 + total=${{ matrix.total }}
  319 + index=${{ matrix.index }}
  320 +
  321 + ./generate-subtitles.py --total $total --index $index
  322 +
  323 + chmod +x build-generate-subtitles.sh
  324 + mv -v ./build-generate-subtitles.sh ../..
  325 +
  326 + - name: Generate tar files
  327 + shell: bash
  328 + run: |
  329 + ./build-generate-subtitles.sh
  330 +
  331 + - name: Display tar files
  332 + shell: bash
  333 + run: |
  334 + ls -lh /tmp/out
  335 +
  336 + - name: Publish to huggingface
  337 + env:
  338 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  339 + uses: nick-fields/retry@v3
  340 + with:
  341 + max_attempts: 20
  342 + timeout_seconds: 200
  343 + shell: bash
  344 + command: |
  345 + git config --global user.email "csukuangfj@gmail.com"
  346 + git config --global user.name "Fangjun Kuang"
  347 +
  348 + rm -rf huggingface
  349 + export GIT_LFS_SKIP_SMUDGE=1
  350 + export GIT_CLONE_PROTECTION_ACTIVE=false
  351 +
  352 + SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  353 + echo "SHERPA_ONNX_VERSION $SHERPA_ONNX_VERSION"
  354 +
  355 + git clone https://huggingface.co/csukuangfj/sherpa-onnx-bin huggingface
  356 + cd huggingface
  357 + git fetch
  358 + git pull
  359 + git merge -m "merge remote" --ff origin main
  360 +
  361 + d=generate-subtitles/$SHERPA_ONNX_VERSION
  362 + mkdir -p $d
  363 +
  364 + cp -v /tmp/out/*.tar.bz2 $d/
  365 + git status
  366 + git lfs track "*.tar.bz2"
  367 + git add .
  368 + git commit -m "add more files"
  369 + git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-bin main
  1 +# Lazarus compiler-generated binaries (safe to delete)
  2 +*.exe
  3 +*.dll
  4 +*.so
  5 +*.dylib
  6 +*.lrs
  7 +*.res
  8 +*.compiled
  9 +*.dbg
  10 +*.ppu
  11 +*.o
  12 +*.or
  13 +*.a
  14 +
  15 +# Lazarus autogenerated files (duplicated info)
  16 +*.rst
  17 +*.rsj
  18 +*.lrt
  19 +
  20 +# Lazarus local files (user-specific info)
  21 +*.lps
  22 +
  23 +# Lazarus backups and unit output folders.
  24 +# These can be changed by user in Lazarus/project options.
  25 +backup/
  26 +*.bak
  27 +lib/
  28 +
  29 +# Application bundle for Mac OS
  30 +*.app/
  1 +generate_subtitles.app
  2 +generate_subtitles
  3 +generate_subtitles.dSYM
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<CONFIG>
  3 + <ProjectOptions>
  4 + <Version Value="12"/>
  5 + <PathDelim Value="\"/>
  6 + <General>
  7 + <SessionStorage Value="InProjectDir"/>
  8 + <Title Value="generate_subtitles"/>
  9 + <Scaled Value="True"/>
  10 + <ResourceType Value="res"/>
  11 + <UseXPManifest Value="True"/>
  12 + <XPManifest>
  13 + <DpiAware Value="True"/>
  14 + </XPManifest>
  15 + <Icon Value="0"/>
  16 + </General>
  17 + <BuildModes>
  18 + <Item Name="Default" Default="True"/>
  19 + <Item Name="Debug">
  20 + <CompilerOptions>
  21 + <Version Value="11"/>
  22 + <PathDelim Value="\"/>
  23 + <Target>
  24 + <Filename Value="generate_subtitles"/>
  25 + </Target>
  26 + <SearchPaths>
  27 + <IncludeFiles Value="$(ProjOutDir)"/>
  28 + <Libraries Value="..\..\build-static\install\lib;..\..\build\install\lib"/>
  29 + <OtherUnitFiles Value="..\..\sherpa-onnx\pascal-api"/>
  30 + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
  31 + </SearchPaths>
  32 + <Parsing>
  33 + <SyntaxOptions>
  34 + <IncludeAssertionCode Value="True"/>
  35 + </SyntaxOptions>
  36 + </Parsing>
  37 + <CodeGeneration>
  38 + <Checks>
  39 + <IOChecks Value="True"/>
  40 + <RangeChecks Value="True"/>
  41 + <OverflowChecks Value="True"/>
  42 + <StackChecks Value="True"/>
  43 + </Checks>
  44 + <VerifyObjMethodCallValidity Value="True"/>
  45 + </CodeGeneration>
  46 + <Linking>
  47 + <Debugging>
  48 + <DebugInfoType Value="dsDwarf3"/>
  49 + <UseHeaptrc Value="True"/>
  50 + <TrashVariables Value="True"/>
  51 + <StripSymbols Value="True"/>
  52 + <UseExternalDbgSyms Value="True"/>
  53 + </Debugging>
  54 + <Options>
  55 + <Win32>
  56 + <GraphicApplication Value="True"/>
  57 + </Win32>
  58 + </Options>
  59 + </Linking>
  60 + </CompilerOptions>
  61 + </Item>
  62 + <Item Name="Release">
  63 + <CompilerOptions>
  64 + <Version Value="11"/>
  65 + <PathDelim Value="\"/>
  66 + <Target>
  67 + <Filename Value="generate_subtitles"/>
  68 + </Target>
  69 + <SearchPaths>
  70 + <IncludeFiles Value="$(ProjOutDir)"/>
  71 + <Libraries Value="..\..\build-static\install\lib;..\..\build\install\lib"/>
  72 + <OtherUnitFiles Value="..\..\sherpa-onnx\pascal-api"/>
  73 + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
  74 + </SearchPaths>
  75 + <CodeGeneration>
  76 + <SmartLinkUnit Value="True"/>
  77 + <Optimizations>
  78 + <OptimizationLevel Value="3"/>
  79 + </Optimizations>
  80 + </CodeGeneration>
  81 + <Linking>
  82 + <Debugging>
  83 + <GenerateDebugInfo Value="False"/>
  84 + <RunWithoutDebug Value="True"/>
  85 + <StripSymbols Value="True"/>
  86 + </Debugging>
  87 + <LinkSmart Value="True"/>
  88 + <Options>
  89 + <Win32>
  90 + <GraphicApplication Value="True"/>
  91 + </Win32>
  92 + </Options>
  93 + </Linking>
  94 + </CompilerOptions>
  95 + </Item>
  96 + <Item Name="Release-Linux">
  97 + <CompilerOptions>
  98 + <Version Value="11"/>
  99 + <PathDelim Value="\"/>
  100 + <Target>
  101 + <Filename Value="generate_subtitles"/>
  102 + </Target>
  103 + <SearchPaths>
  104 + <IncludeFiles Value="$(ProjOutDir)"/>
  105 + <Libraries Value="..\..\build-static\install\lib;..\..\build\install\lib"/>
  106 + <OtherUnitFiles Value="..\..\sherpa-onnx\pascal-api"/>
  107 + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
  108 + </SearchPaths>
  109 + <CodeGeneration>
  110 + <SmartLinkUnit Value="True"/>
  111 + <Optimizations>
  112 + <OptimizationLevel Value="3"/>
  113 + </Optimizations>
  114 + </CodeGeneration>
  115 + <Linking>
  116 + <Debugging>
  117 + <GenerateDebugInfo Value="False"/>
  118 + <RunWithoutDebug Value="True"/>
  119 + <StripSymbols Value="True"/>
  120 + </Debugging>
  121 + <LinkSmart Value="True"/>
  122 + <Options>
  123 + <Win32>
  124 + <GraphicApplication Value="True"/>
  125 + </Win32>
  126 + </Options>
  127 + </Linking>
  128 + <Other>
  129 + <CustomOptions Value="-dSHERPA_ONNX_USE_SHARED_LIBS"/>
  130 + </Other>
  131 + </CompilerOptions>
  132 + </Item>
  133 + </BuildModes>
  134 + <PublishOptions>
  135 + <Version Value="2"/>
  136 + <UseFileFilters Value="True"/>
  137 + </PublishOptions>
  138 + <RunParams>
  139 + <FormatVersion Value="2"/>
  140 + </RunParams>
  141 + <RequiredPackages>
  142 + <Item>
  143 + <PackageName Value="LCL"/>
  144 + </Item>
  145 + </RequiredPackages>
  146 + <Units>
  147 + <Unit>
  148 + <Filename Value="generate_subtitles.lpr"/>
  149 + <IsPartOfProject Value="True"/>
  150 + </Unit>
  151 + <Unit>
  152 + <Filename Value="unit1.pas"/>
  153 + <IsPartOfProject Value="True"/>
  154 + <ComponentName Value="Form1"/>
  155 + <HasResources Value="True"/>
  156 + <ResourceBaseClass Value="Form"/>
  157 + <UnitName Value="Unit1"/>
  158 + </Unit>
  159 + <Unit>
  160 + <Filename Value="my_worker.pas"/>
  161 + <IsPartOfProject Value="True"/>
  162 + </Unit>
  163 + </Units>
  164 + </ProjectOptions>
  165 + <CompilerOptions>
  166 + <Version Value="11"/>
  167 + <PathDelim Value="\"/>
  168 + <Target>
  169 + <Filename Value="generate_subtitles"/>
  170 + </Target>
  171 + <SearchPaths>
  172 + <IncludeFiles Value="$(ProjOutDir)"/>
  173 + <Libraries Value="..\..\build-static\install\lib;..\..\build\install\lib"/>
  174 + <OtherUnitFiles Value="..\..\sherpa-onnx\pascal-api"/>
  175 + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
  176 + </SearchPaths>
  177 + <CodeGeneration>
  178 + <Optimizations>
  179 + <OptimizationLevel Value="2"/>
  180 + </Optimizations>
  181 + </CodeGeneration>
  182 + <Linking>
  183 + <Debugging>
  184 + <GenerateDebugInfo Value="False"/>
  185 + <DebugInfoType Value="dsDwarf3"/>
  186 + <StripSymbols Value="True"/>
  187 + </Debugging>
  188 + <Options>
  189 + <Win32>
  190 + <GraphicApplication Value="True"/>
  191 + </Win32>
  192 + </Options>
  193 + </Linking>
  194 + </CompilerOptions>
  195 + <Debugging>
  196 + <Exceptions>
  197 + <Item>
  198 + <Name Value="EAbort"/>
  199 + </Item>
  200 + <Item>
  201 + <Name Value="ECodetoolError"/>
  202 + </Item>
  203 + <Item>
  204 + <Name Value="EFOpenError"/>
  205 + </Item>
  206 + </Exceptions>
  207 + </Debugging>
  208 +</CONFIG>
  1 +program generate_subtitles;
  2 +
  3 +{$mode objfpc}{$H+}
  4 +
  5 +uses
  6 + {$IFDEF UNIX}
  7 + cthreads,
  8 + cmem,
  9 + {$ENDIF}
  10 + {$IFDEF HASAMIGA}
  11 + athreads,
  12 + {$ENDIF}
  13 + Interfaces, // this includes the LCL widgetset
  14 + Forms, unit1, my_worker
  15 + { you can add units after this };
  16 +
  17 +{$R *.res}
  18 +
  19 +begin
  20 + RequireDerivedFormResource:=True;
  21 + Application.Scaled:=True;
  22 + Application.Initialize;
  23 + Application.CreateForm(TForm1, Form1);
  24 + Application.Run;
  25 +end.
  26 +
  1 +unit my_worker;
  2 +
  3 +{$mode ObjFPC}{$H+}
  4 +
  5 +{
  6 +See
  7 +https://wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial
  8 +
  9 +https://www.freepascal.org/docs-html/rtl/classes/tthread.html
  10 +}
  11 +
  12 +interface
  13 +
  14 +uses
  15 + {$IFDEF UNIX}
  16 + cthreads,
  17 + cmem,
  18 + {$ENDIF}
  19 + {$IFDEF HASAMIGA}
  20 + athreads,
  21 + {$ENDIF}
  22 + Classes, SysUtils;
  23 +
  24 +type
  25 + TMyWorkerThread = class(TThread)
  26 + private
  27 + Status: AnsiString;
  28 + StartTime: Single;
  29 + StopTime: Single;
  30 + TotalDuration: Single;
  31 + procedure ShowStatus;
  32 + procedure ShowProgress;
  33 + protected
  34 + procedure Execute; override;
  35 + public
  36 + WaveFilename: AnsiString;
  37 + Constructor Create(CreateSuspended : boolean; Filename: AnsiString);
  38 + end;
  39 +
  40 +var
  41 + MyWorkerThread: TMyWorkerThread;
  42 +
  43 +implementation
  44 +
  45 +uses
  46 + unit1, sherpa_onnx;
  47 +
  48 +constructor TMyWorkerThread.Create(CreateSuspended : boolean; Filename: AnsiString);
  49 +begin
  50 + inherited Create(CreateSuspended);
  51 + WaveFilename := Filename;
  52 + FreeOnTerminate := True;
  53 +end;
  54 +
  55 +procedure TMyWorkerThread.ShowStatus;
  56 +begin
  57 + Form1.UpdateResult(Status, StartTime, StopTime, TotalDuration);
  58 +end;
  59 +
  60 +procedure TMyWorkerThread.ShowProgress;
  61 +begin
  62 + Form1.UpdateProgress(StopTime, TotalDuration);
  63 +end;
  64 +
  65 +procedure TMyWorkerThread.Execute;
  66 +var
  67 + Wave: TSherpaOnnxWave;
  68 + WindowSize: Integer;
  69 + Offset: Integer;
  70 + SpeechSegment: TSherpaOnnxSpeechSegment;
  71 +
  72 + Duration: Single;
  73 +
  74 +
  75 + Stream: TSherpaOnnxOfflineStream;
  76 + RecognitionResult: TSherpaOnnxOfflineRecognizerResult;
  77 +begin
  78 + Wave := SherpaOnnxReadWave(WaveFilename);
  79 + TotalDuration := 0;
  80 + StartTime := 0;
  81 + StopTime := 0;
  82 + if (Wave.Samples = nil) or (Length(Wave.Samples) = 0) then
  83 + begin
  84 + Status := Format('Failed to read %s. We only support 1 channel, 16000Hz, 16-bit encoded wave files',
  85 + [Wavefilename]);
  86 + Synchronize(@ShowStatus);
  87 +
  88 + Exit;
  89 + end;
  90 + if Wave.SampleRate <> 16000 then
  91 + begin
  92 + Status := Format('Expected sample rate 16000. Given %d. Please select a new file', [Wave.SampleRate]);
  93 + Synchronize(@ShowStatus);
  94 + Exit;
  95 + end;
  96 + TotalDuration := Length(Wave.Samples) / Wave.SampleRate;
  97 + WindowSize := Form1.Vad.Config.SileroVad.WindowSize;
  98 +
  99 + Offset := 0;
  100 + Form1.Vad.Reset;
  101 +
  102 + while not Terminated and (Offset + WindowSize <= Length(Wave.Samples)) do
  103 + begin
  104 + Form1.Vad.AcceptWaveform(Wave.Samples, Offset, WindowSize);
  105 + Offset += WindowSize;
  106 + StopTime := Offset / Wave.SampleRate;
  107 +
  108 + if (Offset mod 20480) = 0 then
  109 + Synchronize(@ShowProgress);
  110 +
  111 + while not Terminated and not Form1.Vad.IsEmpty do
  112 + begin
  113 + SpeechSegment := Form1.Vad.Front;
  114 + Form1.Vad.Pop;
  115 + Stream := Form1.OfflineRecognizer.CreateStream;
  116 +
  117 + Stream.AcceptWaveform(SpeechSegment.Samples, Wave.SampleRate);
  118 + Form1.OfflineRecognizer.Decode(Stream);
  119 + RecognitionResult := Form1.OfflineRecognizer.GetResult(Stream);
  120 +
  121 + StartTime := SpeechSegment.Start / Wave.SampleRate;
  122 + Duration := Length(SpeechSegment.Samples) / Wave.SampleRate;
  123 + StopTime := StartTime + Duration;
  124 + Status := RecognitionResult.Text;
  125 +
  126 + Synchronize(@ShowStatus);
  127 + FreeAndNil(Stream);
  128 + end;
  129 + end;
  130 +
  131 + Form1.Vad.Flush;
  132 + while not Terminated and not Form1.Vad.IsEmpty do
  133 + begin
  134 + SpeechSegment := Form1.Vad.Front;
  135 + Form1.Vad.Pop;
  136 + Stream := Form1.OfflineRecognizer.CreateStream;
  137 +
  138 + Stream.AcceptWaveform(SpeechSegment.Samples, Wave.SampleRate);
  139 + Form1.OfflineRecognizer.Decode(Stream);
  140 + RecognitionResult := Form1.OfflineRecognizer.GetResult(Stream);
  141 +
  142 + StartTime := SpeechSegment.Start / Wave.SampleRate;
  143 + Duration := Length(SpeechSegment.Samples) / Wave.SampleRate;
  144 + StopTime := StartTime + Duration;
  145 + Status := RecognitionResult.Text;
  146 +
  147 + Synchronize(@ShowStatus);
  148 + FreeAndNil(Stream);
  149 + end;
  150 +
  151 + if Terminated then
  152 + Status := 'Cancelled!'
  153 + else
  154 + Status := 'DONE!';
  155 +
  156 + Synchronize(@ShowStatus);
  157 +end;
  158 +
  159 +end.
  160 +
  1 +object Form1: TForm1
  2 + Left = 366
  3 + Height = 623
  4 + Top = 117
  5 + Width = 852
  6 + Caption = 'Next-gen Kaldi: Generate Subtitles'
  7 + ClientHeight = 623
  8 + ClientWidth = 852
  9 + OnClose = FormClose
  10 + OnCreate = FormCreate
  11 + LCLVersion = '3.4.0.0'
  12 + object FileNameEdt: TEdit
  13 + Left = 200
  14 + Height = 22
  15 + Top = 40
  16 + Width = 440
  17 + TabOrder = 0
  18 + OnChange = FileNameEdtChange
  19 + end
  20 + object SelectFileBtn: TButton
  21 + Left = 96
  22 + Height = 25
  23 + Top = 40
  24 + Width = 97
  25 + Caption = 'Select a file...'
  26 + TabOrder = 1
  27 + OnClick = SelectFileBtnClick
  28 + end
  29 + object StartBtn: TButton
  30 + Left = 656
  31 + Height = 25
  32 + Top = 37
  33 + Width = 75
  34 + Caption = 'Start'
  35 + TabOrder = 2
  36 + OnClick = StartBtnClick
  37 + end
  38 + object InitBtn: TButton
  39 + Left = 280
  40 + Height = 25
  41 + Top = 8
  42 + Width = 280
  43 + Caption = 'Click me to intialize models before you start'
  44 + TabOrder = 3
  45 + OnClick = InitBtnClick
  46 + end
  47 + object ResultMemo: TMemo
  48 + Left = 24
  49 + Height = 488
  50 + Top = 72
  51 + Width = 800
  52 + ScrollBars = ssAutoBoth
  53 + TabOrder = 4
  54 + end
  55 + object ProgressBar: TProgressBar
  56 + Left = 32
  57 + Height = 16
  58 + Top = 592
  59 + Width = 792
  60 + TabOrder = 5
  61 + end
  62 + object ProgressLabel: TLabel
  63 + Left = 770
  64 + Height = 16
  65 + Top = 568
  66 + Width = 8
  67 + Caption = '0'
  68 + end
  69 + object SelectFileDlg: TOpenDialog
  70 + Title = 'Open a wave file'
  71 + Left = 600
  72 + Top = 488
  73 + end
  74 +end
  1 +unit Unit1;
  2 +
  3 +{$mode objfpc}{$H+}
  4 +
  5 +{$IFDEF DARWIN}
  6 +{$modeswitch objectivec1} {For getting resource directory}
  7 +{$ENDIF}
  8 +
  9 +interface
  10 +
  11 +uses
  12 + Classes, SysUtils, StrUtils, Forms, Controls,
  13 + Graphics, Dialogs, StdCtrls,
  14 + sherpa_onnx, ComCtrls;
  15 +
  16 +type
  17 +
  18 + { TForm1 }
  19 +
  20 + TForm1 = class(TForm)
  21 + InitBtn: TButton;
  22 + ProgressBar: TProgressBar;
  23 + ResultMemo: TMemo;
  24 + StartBtn: TButton;
  25 + SelectFileDlg: TOpenDialog;
  26 + SelectFileBtn: TButton;
  27 + FileNameEdt: TEdit;
  28 + ProgressLabel: TLabel;
  29 + procedure FileNameEdtChange(Sender: TObject);
  30 + procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  31 + procedure InitBtnClick(Sender: TObject);
  32 + procedure SelectFileBtnClick(Sender: TObject);
  33 + procedure FormCreate(Sender: TObject);
  34 + procedure StartBtnClick(Sender: TObject);
  35 + private
  36 +
  37 + public
  38 + procedure UpdateResult(
  39 + Msg: AnsiString;
  40 + StartTime: Single;
  41 + StopTime: Single;
  42 + TotalDuration: Single);
  43 + procedure UpdateProgress(StopTime: Single; TotalDuration: Single);
  44 + public
  45 + Vad: TSherpaOnnxVoiceActivityDetector;
  46 + OfflineRecognizer: TSherpaOnnxOfflineRecognizer;
  47 + end;
  48 +
  49 +var
  50 + Form1: TForm1;
  51 +
  52 +implementation
  53 +
  54 +uses
  55 + my_worker
  56 + {$IFDEF DARWIN}
  57 + ,MacOSAll
  58 + ,CocoaAll
  59 + {$ENDIF}
  60 + ;
  61 +{See https://wiki.lazarus.freepascal.org/Locating_the_macOS_application_resources_directory}
  62 +
  63 +{$IFDEF DARWIN}
  64 +{Note: The returned path contains a trailing /}
  65 +function GetResourcesPath(): AnsiString;
  66 +var
  67 + pathStr: shortstring;
  68 + status: Boolean = false;
  69 +begin
  70 + status := CFStringGetPascalString(CFStringRef(NSBundle.mainBundle.resourcePath), @pathStr, 255, CFStringGetSystemEncoding());
  71 +
  72 + if status = true then
  73 + Result := pathStr + PathDelim
  74 + else
  75 + raise Exception.Create('Error in GetResourcesPath()');
  76 +end;
  77 +{$ENDIF}
  78 +
  79 +function CreateVad(VadFilename: AnsiString): TSherpaOnnxVoiceActivityDetector;
  80 +var
  81 + Config: TSherpaOnnxVadModelConfig;
  82 +
  83 + SampleRate: Integer;
  84 + WindowSize: Integer;
  85 +begin
  86 + Initialize(Config);
  87 +
  88 + SampleRate := 16000; {Please don't change it unless you know the details}
  89 + WindowSize := 512; {Please don't change it unless you know the details}
  90 +
  91 + Config.SileroVad.Model := VadFilename;
  92 + Config.SileroVad.MinSpeechDuration := 0.5;
  93 + Config.SileroVad.MinSilenceDuration := 0.5;
  94 + Config.SileroVad.Threshold := 0.5;
  95 + Config.SileroVad.WindowSize := WindowSize;
  96 + Config.NumThreads:= 2;
  97 + Config.Debug:= True;
  98 + Config.Provider:= 'cpu';
  99 + Config.SampleRate := SampleRate;
  100 +
  101 + Result := TSherpaOnnxVoiceActivityDetector.Create(Config, 30);
  102 +end;
  103 +
  104 +function CreateOfflineRecognizerTransducer(
  105 + Tokens: AnsiString;
  106 + Encoder: AnsiString;
  107 + Decoder: AnsiString;
  108 + Joiner: AnsiString;
  109 + ModelType: AnsiString): TSherpaOnnxOfflineRecognizer;
  110 +var
  111 + Config: TSherpaOnnxOfflineRecognizerConfig;
  112 +begin
  113 + Initialize(Config);
  114 +
  115 + Config.ModelConfig.Transducer.Encoder := Encoder;
  116 + Config.ModelConfig.Transducer.Decoder := Decoder;
  117 + Config.ModelConfig.Transducer.Joiner := Joiner;
  118 +
  119 + Config.ModelConfig.ModelType := ModelType;
  120 + Config.ModelConfig.Tokens := Tokens;
  121 + Config.ModelConfig.Provider := 'cpu';
  122 + Config.ModelConfig.NumThreads := 2;
  123 + Config.ModelConfig.Debug := False;
  124 +
  125 + Result := TSherpaOnnxOfflineRecognizer.Create(Config);
  126 +end;
  127 +
  128 +function CreateOfflineRecognizerTeleSpeech(
  129 + Tokens: AnsiString;
  130 + TeleSpeech: AnsiString): TSherpaOnnxOfflineRecognizer;
  131 +var
  132 + Config: TSherpaOnnxOfflineRecognizerConfig;
  133 +begin
  134 + Initialize(Config);
  135 +
  136 + Config.ModelConfig.TeleSpeechCtc := TeleSpeech;
  137 +
  138 + Config.ModelConfig.Tokens := Tokens;
  139 + Config.ModelConfig.Provider := 'cpu';
  140 + Config.ModelConfig.NumThreads := 2;
  141 + Config.ModelConfig.Debug := False;
  142 +
  143 + Result := TSherpaOnnxOfflineRecognizer.Create(Config);
  144 +end;
  145 +
  146 +function CreateOfflineRecognizerParaformer(
  147 + Tokens: AnsiString;
  148 + Paraformer: AnsiString): TSherpaOnnxOfflineRecognizer;
  149 +var
  150 + Config: TSherpaOnnxOfflineRecognizerConfig;
  151 +begin
  152 + Initialize(Config);
  153 +
  154 + Config.ModelConfig.Paraformer.Model := Paraformer;
  155 +
  156 + Config.ModelConfig.Tokens := Tokens;
  157 + Config.ModelConfig.Provider := 'cpu';
  158 + Config.ModelConfig.NumThreads := 2;
  159 + Config.ModelConfig.Debug := False;
  160 +
  161 + Result := TSherpaOnnxOfflineRecognizer.Create(Config);
  162 +end;
  163 +
  164 +function CreateOfflineRecognizerSenseVoice(
  165 + Tokens: AnsiString;
  166 + SenseVoice: AnsiString): TSherpaOnnxOfflineRecognizer;
  167 +var
  168 + Config: TSherpaOnnxOfflineRecognizerConfig;
  169 +begin
  170 + Initialize(Config);
  171 +
  172 + Config.ModelConfig.SenseVoice.Model := SenseVoice;
  173 + Config.ModelConfig.SenseVoice.Language := 'auto';
  174 + Config.ModelConfig.SenseVoice.UseItn := True;
  175 + Config.ModelConfig.Tokens := Tokens;
  176 + Config.ModelConfig.Provider := 'cpu';
  177 + Config.ModelConfig.NumThreads := 2;
  178 + Config.ModelConfig.Debug := False;
  179 +
  180 + Result := TSherpaOnnxOfflineRecognizer.Create(Config);
  181 +end;
  182 +
  183 +function CreateOfflineRecognizerWhisper(
  184 + Tokens: AnsiString;
  185 + WhisperEncoder: AnsiString;
  186 + WhisperDecoder: AnsiString): TSherpaOnnxOfflineRecognizer;
  187 +var
  188 + Config: TSherpaOnnxOfflineRecognizerConfig;
  189 +begin
  190 + Initialize(Config);
  191 +
  192 + Config.ModelConfig.Whisper.Encoder := WhisperEncoder;
  193 + Config.ModelConfig.Whisper.Decoder := WhisperDecoder;
  194 + Config.ModelConfig.Tokens := Tokens;
  195 + Config.ModelConfig.Provider := 'cpu';
  196 + Config.ModelConfig.NumThreads := 2;
  197 + Config.ModelConfig.Debug := False;
  198 +
  199 + Result := TSherpaOnnxOfflineRecognizer.Create(Config);
  200 +end;
  201 +
  202 +{$R *.lfm}
  203 +
  204 +{ TForm1 }
  205 +
  206 +procedure TForm1.FormCreate(Sender: TObject);
  207 +begin
  208 + StartBtn.Enabled := False;
  209 + SelectFileDlg.Filter := 'All Files|*.wav';
  210 + FileNameEdt.Enabled := False;
  211 + SelectFileBtn.Enabled := False;
  212 + ResultMemo.Lines.Add('1. It supports only 1 channel, 16-bit, 16000Hz wav files');
  213 + ResultMemo.Lines.Add('2. There should be no Chinese characters in the file path.');
  214 +
  215 + ProgressBar.Position := 0;
  216 + ProgressLabel.Caption := '';
  217 +end;
  218 +
  219 +procedure TForm1.StartBtnClick(Sender: TObject);
  220 +begin
  221 + if StartBtn.Caption = 'Stop' then
  222 + begin
  223 + if (MyWorkerThread <> nil) and not MyWorkerThread.Finished then
  224 + MyWorkerThread.Terminate;
  225 +
  226 + StartBtn.Caption := 'Start';
  227 + Exit;
  228 + end;
  229 +
  230 + ResultMemo.Lines.Clear();
  231 + ResultMemo.Lines.Add('Start processing');
  232 +
  233 + ProgressBar.Position := 0;
  234 + ProgressLabel.Caption := Format('%d%%', [ProgressBar.Position]);
  235 +
  236 + MyWorkerThread := TMyWorkerThread.Create(False, FileNameEdt.Text);
  237 +
  238 + StartBtn.Caption := 'Stop';
  239 +end;
  240 +
  241 +procedure TForm1.SelectFileBtnClick(Sender: TObject);
  242 +begin
  243 + if SelectFileDlg.Execute then
  244 + begin
  245 + FileNameEdt.Text := SelectFileDlg.FileName;
  246 + end;
  247 +end;
  248 +
  249 +procedure TForm1.FileNameEdtChange(Sender: TObject);
  250 +begin
  251 + if FileExists(FileNameEdt.Text) then
  252 + StartBtn.Enabled := True
  253 + else
  254 + StartBtn.Enabled := False;
  255 +end;
  256 +
  257 +procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
  258 +begin
  259 + if (MyWorkerThread <> nil) and not MyWorkerThread.Finished then
  260 + begin
  261 + MyWorkerThread.Terminate;
  262 + MyWorkerThread.WaitFor;
  263 + end;
  264 + FreeAndNil(Vad);
  265 + FreeAndNil(OfflineRecognizer);
  266 +end;
  267 +
  268 +procedure TForm1.UpdateProgress(StopTime: Single; TotalDuration: Single);
  269 +var
  270 + Percent: Single;
  271 +begin
  272 + if (StopTime <> 0) and (TotalDuration <> 0) then
  273 + begin
  274 + Percent := StopTime / TotalDuration * 100;
  275 + ProgressBar.Position := Round(Percent);
  276 + ProgressLabel.Caption := Format('%d%%', [ProgressBar.Position]);
  277 + end;
  278 +end;
  279 +
  280 +procedure TForm1.UpdateResult(
  281 + Msg: AnsiString;
  282 + StartTime: Single;
  283 + StopTime: Single;
  284 + TotalDuration: Single);
  285 +var
  286 + NewResult: AnsiString;
  287 +begin
  288 + UpdateProgress(StopTime, TotalDuration);
  289 +
  290 + if (Msg = 'DONE!') or
  291 + (Msg = 'Cancelled!') or
  292 + EndsStr('16-bit encoded wave files', Msg) or
  293 + EndsStr('. Please select a new file', Msg) then
  294 + begin
  295 + Form1.StartBtn.Caption := 'Start';
  296 + NewResult := Msg;
  297 + end
  298 + else
  299 + begin
  300 + NewResult := Format('%.3f -- %.3f %s', [StartTime, StopTime, Msg]);
  301 + end;
  302 +
  303 + if Msg = 'DONE!' then
  304 + begin
  305 + ProgressBar.Position := 100;
  306 +
  307 + ProgressLabel.Caption := '100%';
  308 + end;
  309 +
  310 + Form1.ResultMemo.Lines.Add(NewResult);
  311 +end;
  312 +
  313 +procedure TForm1.InitBtnClick(Sender: TObject);
  314 +var
  315 + Msg: AnsiString;
  316 + ModelDir: AnsiString;
  317 + VadFilename: AnsiString;
  318 + Tokens: AnsiString;
  319 +
  320 + WhisperEncoder: AnsiString;
  321 + WhisperDecoder: AnsiString;
  322 +
  323 + SenseVoice: AnsiString;
  324 +
  325 + Paraformer: AnsiString;
  326 +
  327 + TeleSpeech: AnsiString;
  328 +
  329 + TransducerEncoder: AnsiString; // from icefall
  330 + TransducerDecoder: AnsiString;
  331 + TransducerJoiner: AnsiString;
  332 +
  333 + NeMoTransducerEncoder: AnsiString;
  334 + NeMoTransducerDecoder: AnsiString;
  335 + NeMoTransducerJoiner: AnsiString;
  336 +begin
  337 + {$IFDEF DARWIN}
  338 + ModelDir := GetResourcesPath;
  339 + {$ELSE}
  340 + ModelDir := './';
  341 + {$ENDIF}
  342 +
  343 + VadFilename := ModelDir + 'silero_vad.onnx';
  344 + Tokens := ModelDir + 'tokens.txt';
  345 +
  346 + {
  347 + Please refer to
  348 + https://k2-fsa.github.io/sherpa/onnx/pretrained_models/whisper/export-onnx.html#available-models
  349 + for a list of whisper models.
  350 +
  351 + In the code, we use the normalized filename whisper-encoder.onnx, whisper-decoder.onnx, and tokens.txt
  352 + You need to rename the existing model files.
  353 +
  354 + For instance, if you use sherpa-onnx-whisper-tiny.en, you have to do
  355 + mv tiny.en-tokens.txt tokens.txt
  356 +
  357 + mv tiny.en-encoder.onnx whisper-encoder.onnx
  358 + mv tiny.en-decoder.onnx whisper-decoder.onnx
  359 +
  360 + // or use the int8.onnx
  361 +
  362 + mv tiny.en-encoder.int8.onnx whisper-encoder.onnx
  363 + mv tiny.en-decoder.int8.onnx whisper-decoder.onnx
  364 + }
  365 + WhisperEncoder := ModelDir + 'whisper-encoder.onnx';
  366 + WhisperDecoder := ModelDir + 'whisper-decoder.onnx';
  367 +
  368 +
  369 + {
  370 + Please refer to
  371 + https://k2-fsa.github.io/sherpa/onnx/sense-voice/pretrained.html#pre-trained-models
  372 + to download models for SenseVoice.
  373 +
  374 + In the code, we use the normalized model name sense-voice.onnx. You have
  375 + to rename the downloaded model files.
  376 +
  377 + For example, you need to use
  378 +
  379 + mv model.onnx sense-voice.onnx
  380 +
  381 + // or use the int8.onnx
  382 + mv model.int8.onnx sense-voice.onnx
  383 + }
  384 +
  385 + SenseVoice := ModelDir + 'sense-voice.onnx';
  386 +
  387 + {
  388 + Please refer to
  389 + https://k2-fsa.github.io/sherpa/onnx/pretrained_models/offline-paraformer/index.html
  390 + to download paraformer models.
  391 +
  392 + Note that you have to rename model.onnx or model.int8.onnx to paraformer.onnx.
  393 + An example is given below for the rename:
  394 +
  395 + cp model.onnx paraformer.onnx
  396 +
  397 + // or use int8.onnx
  398 + cp model.int8.onnx paraformer.onnx
  399 + }
  400 + Paraformer := ModelDir + 'paraformer.onnx';
  401 +
  402 +
  403 + {
  404 + please refer to
  405 + https://k2-fsa.github.io/sherpa/onnx/pretrained_models/telespeech/models.html
  406 + to download TeleSpeech models.
  407 +
  408 + Note that you have to rename model files after downloading. The following
  409 + is an example
  410 +
  411 + mv model.onnx telespeech.onnx
  412 +
  413 + // or to use int8.onnx
  414 +
  415 + mv model.int8.onnx telespeech.onnx
  416 + }
  417 +
  418 + TeleSpeech := ModelDir + 'telespeech.onnx';
  419 +
  420 +
  421 + {
  422 + Please refer to
  423 + https://k2-fsa.github.io/sherpa/onnx/pretrained_models/index.html
  424 + to download an icefall offline transducer model. Note that you need to rename the
  425 + model files to transducer-encoder.onnx, transducer-decoder.onnx, and
  426 + transducer-joiner.onnx
  427 + }
  428 + TransducerEncoder := ModelDir + 'transducer-encoder.onnx';
  429 + TransducerDecoder := ModelDir + 'transducer-decoder.onnx';
  430 + TransducerJoiner := ModelDir + 'transducer-joiner.onnx';
  431 +
  432 + {
  433 + Please visit
  434 + https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
  435 + to donwload a NeMo transducer model.
  436 + }
  437 + NeMoTransducerEncoder := ModelDir + 'nemo-transducer-encoder.onnx';
  438 + NeMoTransducerDecoder := ModelDir + 'nemo-transducer-decoder.onnx';
  439 + NeMoTransducerJoiner := ModelDir + 'nemo-transducer-joiner.onnx';
  440 +
  441 + if not FileExists(VadFilename) then
  442 + begin
  443 + ShowMessage(VadFilename + ' does not exist! Please download it from' +
  444 + sLineBreak + 'https://github.com/k2-fsa/sherpa-onnx/tree/asr-models'
  445 + );
  446 + Exit;
  447 + end;
  448 +
  449 + Self.Vad := CreateVad(VadFilename);
  450 +
  451 + if not FileExists(Tokens) then
  452 + begin
  453 + ShowMessage(Tokens + ' not found. Please download a non-streaming ASR model first!');
  454 + Exit;
  455 + end;
  456 +
  457 + if FileExists(WhisperEncoder) and FileExists(WhisperDecoder) then
  458 + begin
  459 + OfflineRecognizer := CreateOfflineRecognizerWhisper(Tokens, WhisperEncoder, WhisperDecoder);
  460 + Msg := 'Whisper';
  461 + end
  462 + else if FileExists(SenseVoice) then
  463 + begin
  464 + OfflineRecognizer := CreateOfflineRecognizerSenseVoice(Tokens, SenseVoice);
  465 + Msg := 'SenseVoice';
  466 + end
  467 + else if FileExists(Paraformer) then
  468 + begin
  469 + OfflineRecognizer := CreateOfflineRecognizerParaformer(Tokens, Paraformer);
  470 + Msg := 'Paraformer';
  471 + end
  472 + else if FileExists(TeleSpeech) then
  473 + begin
  474 + OfflineRecognizer := CreateOfflineRecognizerTeleSpeech(Tokens, TeleSpeech);
  475 + Msg := 'TeleSpeech';
  476 + end
  477 + else if FileExists(TransducerEncoder) and FileExists(TransducerDecoder) and FileExists(TransducerJoiner) then
  478 + begin
  479 + OfflineRecognizer := CreateOfflineRecognizerTransducer(Tokens,
  480 + TransducerEncoder, TransducerDecoder, TransducerJoiner, 'transducer');
  481 + Msg := 'Zipformer transducer';
  482 + end
  483 + else if FileExists(NeMoTransducerEncoder) and FileExists(NeMoTransducerDecoder) and FileExists(NeMoTransducerJoiner) then
  484 + begin
  485 + OfflineRecognizer := CreateOfflineRecognizerTransducer(Tokens,
  486 + NeMoTransducerEncoder, NeMoTransducerDecoder, NeMoTransducerJoiner, 'nemo_transducer');
  487 + Msg := 'NeMo transducer';
  488 + end
  489 + else
  490 + begin
  491 + ShowMessage('Please download at least one non-streaming speech recognition model first.');
  492 + Exit;
  493 + end;
  494 +
  495 + MessageDlg('Congrat! The ' + Msg + ' model is initialized succesfully!', mtInformation, [mbOk], 0);
  496 + FileNameEdt.Enabled := True;
  497 + SelectFileBtn.Enabled := True;
  498 + InitBtn.Enabled := False;
  499 +end;
  500 +
  501 +end.
  502 +
@@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-nemo-fast-conformer-ctc-be-de-en-es-fr-hr-it-pl-ru-uk-20 @@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-nemo-fast-conformer-ctc-be-de-en-es-fr-hr-it-pl-ru-uk-20
31 fi 31 fi
32 32
33 fpc \ 33 fpc \
  34 + -dSHERPA_ONNX_USE_SHARED_LIBS \
34 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
35 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 36 -Fl$SHERPA_ONNX_DIR/build/install/lib \
36 ./nemo_ctc.pas 37 ./nemo_ctc.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-nemo-fast-conformer-transducer-be-de-en-es-fr-hr-it-pl-r @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-nemo-fast-conformer-transducer-be-de-en-es-fr-hr-it-pl-r
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./nemo_transducer.pas 38 ./nemo_transducer.pas
@@ -40,6 +40,7 @@ if [ ! -f ./itn_zh_number.fst ]; then @@ -40,6 +40,7 @@ if [ ! -f ./itn_zh_number.fst ]; then
40 fi 40 fi
41 41
42 fpc \ 42 fpc \
  43 + -dSHERPA_ONNX_USE_SHARED_LIBS \
43 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 44 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
44 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 45 -Fl$SHERPA_ONNX_DIR/build/install/lib \
45 ./paraformer_itn.pas 46 ./paraformer_itn.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-paraformer-zh-2023-09-14/tokens.txt ]; then @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-paraformer-zh-2023-09-14/tokens.txt ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./paraformer.pas 38 ./paraformer.pas
@@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt ]; the @@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt ]; the
31 fi 31 fi
32 32
33 fpc \ 33 fpc \
  34 + -dSHERPA_ONNX_USE_SHARED_LIBS \
34 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
35 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 36 -Fl$SHERPA_ONNX_DIR/build/install/lib \
36 ./sense_voice.pas 37 ./sense_voice.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-telespeech-ctc-int8-zh-2024-06-04/tokens.txt ]; then @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-telespeech-ctc-int8-zh-2024-06-04/tokens.txt ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./telespeech_ctc.pas 38 ./telespeech_ctc.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt ]; then @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./whisper.pas 38 ./whisper.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-zipformer-gigaspeech-2023-12-12/tokens.txt ]; then @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-zipformer-gigaspeech-2023-12-12/tokens.txt ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./zipformer_transducer.pas 38 ./zipformer_transducer.pas
@@ -28,6 +28,7 @@ if [ ! -f ./lei-jun-test.wav ]; then @@ -28,6 +28,7 @@ if [ ! -f ./lei-jun-test.wav ]; then
28 fi 28 fi
29 29
30 fpc \ 30 fpc \
  31 + -dSHERPA_ONNX_USE_SHARED_LIBS \
31 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 32 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
32 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 33 -Fl$SHERPA_ONNX_DIR/build/install/lib \
33 ./main.pas 34 ./main.pas
@@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-nemo-streaming-fast-conformer-transducer-en-80ms/tokens. @@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-nemo-streaming-fast-conformer-transducer-en-80ms/tokens.
31 fi 31 fi
32 32
33 fpc \ 33 fpc \
  34 + -dSHERPA_ONNX_USE_SHARED_LIBS \
34 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
35 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 36 -Fl$SHERPA_ONNX_DIR/build/install/lib \
36 ./nemo_transducer.pas 37 ./nemo_transducer.pas
@@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-streaming-paraformer-bilingual-zh-en/tokens.txt ]; then @@ -32,6 +32,7 @@ if [ ! -f ./sherpa-onnx-streaming-paraformer-bilingual-zh-en/tokens.txt ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./paraformer.pas 38 ./paraformer.pas
@@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18/tokens.txt ]; t @@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18/tokens.txt ]; t
31 fi 31 fi
32 32
33 fpc \ 33 fpc \
  34 + -dSHERPA_ONNX_USE_SHARED_LIBS \
34 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
35 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 36 -Fl$SHERPA_ONNX_DIR/build/install/lib \
36 ./zipformer_ctc_hlg.pas 37 ./zipformer_ctc_hlg.pas
@@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18/tokens.txt ]; t @@ -31,6 +31,7 @@ if [ ! -f ./sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18/tokens.txt ]; t
31 fi 31 fi
32 32
33 fpc \ 33 fpc \
  34 + -dSHERPA_ONNX_USE_SHARED_LIBS \
34 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
35 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 36 -Fl$SHERPA_ONNX_DIR/build/install/lib \
36 ./zipformer_ctc.pas 37 ./zipformer_ctc.pas
@@ -32,6 +32,7 @@ fi @@ -32,6 +32,7 @@ fi
32 32
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./zipformer_transducer.pas 38 ./zipformer_transducer.pas
@@ -38,6 +38,7 @@ if [ ! -f ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt ]; the @@ -38,6 +38,7 @@ if [ ! -f ./sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/tokens.txt ]; the
38 fi 38 fi
39 39
40 fpc \ 40 fpc \
  41 + -dSHERPA_ONNX_USE_SHARED_LIBS \
41 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 42 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
42 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 43 -Fl$SHERPA_ONNX_DIR/build/install/lib \
43 ./vad_with_sense_voice.pas 44 ./vad_with_sense_voice.pas
@@ -39,6 +39,7 @@ if [ ! -f ./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt ]; then @@ -39,6 +39,7 @@ if [ ! -f ./sherpa-onnx-whisper-tiny.en/tiny.en-tokens.txt ]; then
39 fi 39 fi
40 40
41 fpc \ 41 fpc \
  42 + -dSHERPA_ONNX_USE_SHARED_LIBS \
42 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 43 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
43 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 44 -Fl$SHERPA_ONNX_DIR/build/install/lib \
44 ./vad_with_whisper.pas 45 ./vad_with_whisper.pas
@@ -24,6 +24,7 @@ if [[ ! -f ../../build/install/lib/libsherpa-onnx-c-api.dylib && ! -f ../../bui @@ -24,6 +24,7 @@ if [[ ! -f ../../build/install/lib/libsherpa-onnx-c-api.dylib && ! -f ../../bui
24 fi 24 fi
25 25
26 fpc \ 26 fpc \
  27 + -dSHERPA_ONNX_USE_SHARED_LIBS \
27 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 28 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
28 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 29 -Fl$SHERPA_ONNX_DIR/build/install/lib \
29 ./circular_buffer.pas 30 ./circular_buffer.pas
@@ -32,6 +32,7 @@ if [ ! -f ./lei-jun-test.wav ]; then @@ -32,6 +32,7 @@ if [ ! -f ./lei-jun-test.wav ]; then
32 fi 32 fi
33 33
34 fpc \ 34 fpc \
  35 + -dSHERPA_ONNX_USE_SHARED_LIBS \
35 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \ 36 -Fu$SHERPA_ONNX_DIR/sherpa-onnx/pascal-api \
36 -Fl$SHERPA_ONNX_DIR/build/install/lib \ 37 -Fl$SHERPA_ONNX_DIR/build/install/lib \
37 ./remove_silence.pas 38 ./remove_silence.pas
@@ -71,7 +71,7 @@ def get_models(): @@ -71,7 +71,7 @@ def get_models():
71 Model( 71 Model(
72 model_name="sherpa-onnx-paraformer-zh-2023-09-14", 72 model_name="sherpa-onnx-paraformer-zh-2023-09-14",
73 idx=0, 73 idx=0,
74 - lang="zh", 74 + lang="zh_en",
75 short_name="paraformer", 75 short_name="paraformer",
76 rule_fsts="itn_zh_number.fst", 76 rule_fsts="itn_zh_number.fst",
77 cmd=""" 77 cmd="""
@@ -109,7 +109,7 @@ def get_models(): @@ -109,7 +109,7 @@ def get_models():
109 Model( 109 Model(
110 model_name="sherpa-onnx-paraformer-zh-small-2024-03-09", 110 model_name="sherpa-onnx-paraformer-zh-small-2024-03-09",
111 idx=14, 111 idx=14,
112 - lang="zh", 112 + lang="zh_en",
113 short_name="small_paraformer", 113 short_name="small_paraformer",
114 rule_fsts="itn_zh_number.fst", 114 rule_fsts="itn_zh_number.fst",
115 cmd=""" 115 cmd="""
  1 +#!/usr/bin/env bash
  2 +#
  3 +# It expects that there are 4 directories inside /tmp
  4 +#
  5 +# macos-x64
  6 +# macos-arm64
  7 +# linux-x64
  8 +# windows-x64
  9 +#
  10 +# Generated files are saved in /tmp/out/*.tar.bz2
  11 +
  12 +set -ex
  13 +
  14 +log() {
  15 + # This function is from espnet
  16 + local fname=${BASH_SOURCE[1]##*/}
  17 + echo -e "$(date '+%Y-%m-%d %H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*"
  18 +}
  19 +
  20 +SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  21 +
  22 +curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx
  23 +
  24 +os_array=(
  25 +linux-x64
  26 +macos-x64
  27 +macos-arm64
  28 +windows-x64
  29 +)
  30 +
  31 +for os in ${os_array[@]}; do
  32 + if [[ $os == macos-x64 || $os == macos-arm64 ]]; then
  33 + cp -v silero_vad.onnx /tmp/$os/Contents/Resources/
  34 + else
  35 + cp -v silero_vad.onnx /tmp/$os/
  36 + fi
  37 +done
  38 +
  39 +{% for model in model_list %}
  40 +model_name={{ model.model_name }}
  41 +lang={{ model.lang }}
  42 +short_name={{ model.short_name }}
  43 +
  44 +curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/${model_name}.tar.bz2
  45 +tar xvf ${model_name}.tar.bz2
  46 +rm ${model_name}.tar.bz2
  47 +
  48 +{{ model.cmd }}
  49 +
  50 +ls -lh $model_name
  51 +
  52 +for os in ${os_array[@]}; do
  53 + dst=sherpa-onnx-$SHERPA_ONNX_VERSION-generate-subtitles-$os-$short_name-$lang
  54 + src=/tmp/$os
  55 +
  56 + cp -a $src $dst
  57 + d=$dst
  58 +
  59 + if [[ $os == macos-x64 || $os == macos-arm64 ]]; then
  60 + mv $dst $dst.app
  61 +
  62 + dst=$dst.app
  63 + d=$dst/Contents/Resources
  64 + fi
  65 +
  66 + cp -v $model_name/*.onnx $d
  67 + cp -v $model_name/tokens.txt $d
  68 +
  69 + d=$dst
  70 +
  71 + tar cjvf $d.tar.bz2 $d
  72 +
  73 + ls -lh
  74 +
  75 + mkdir -p /tmp/out
  76 + mv $d.tar.bz2 /tmp/out
  77 + ls -lh /tmp/out
  78 +done
  79 +
  80 +rm -rf $model_name
  81 +{% endfor %}
  1 +#!/usr/bin/env python3
  2 +
  3 +import argparse
  4 +from dataclasses import dataclass
  5 +from typing import List, Optional
  6 +
  7 +import jinja2
  8 +
  9 +
  10 +def get_args():
  11 + parser = argparse.ArgumentParser()
  12 + parser.add_argument(
  13 + "--total",
  14 + type=int,
  15 + default=1,
  16 + help="Number of runners",
  17 + )
  18 + parser.add_argument(
  19 + "--index",
  20 + type=int,
  21 + default=0,
  22 + help="Index of the current runner",
  23 + )
  24 + return parser.parse_args()
  25 +
  26 +
  27 +@dataclass
  28 +class Model:
  29 + model_name: str
  30 + lang: str
  31 + short_name: str = ""
  32 + cmd: str = ""
  33 +
  34 +
  35 +def get_models():
  36 + models = [
  37 + Model(
  38 + model_name="sherpa-onnx-whisper-tiny.en",
  39 + lang="en",
  40 + short_name="whisper_tiny.en",
  41 + cmd="""
  42 + pushd $model_name
  43 + rm -fv tiny.en-encoder.onnx
  44 + rm -fv tiny.en-decoder.onnx
  45 +
  46 + mv -v tiny.en-encoder.int8.onnx whisper-encoder.onnx
  47 + mv -v tiny.en-decoder.int8.onnx whisper-decoder.onnx
  48 + mv -v tiny.en-tokens.txt tokens.txt
  49 +
  50 + popd
  51 + """,
  52 + ),
  53 + Model(
  54 + model_name="sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17",
  55 + lang="zh_en_ko_ja_yue",
  56 + short_name="sense_voice",
  57 + cmd="""
  58 + pushd $model_name
  59 + rm -fv model.onnx
  60 + mv -v model.int8.onnx sense-voice.onnx
  61 + popd
  62 + """,
  63 + ),
  64 + Model(
  65 + model_name="sherpa-onnx-paraformer-zh-2023-09-14",
  66 + lang="zh_en",
  67 + short_name="paraformer_2023_09_14",
  68 + cmd="""
  69 + pushd $model_name
  70 + rm -fv model.onnx
  71 + mv -v model.int8.onnx paraformer.onnx
  72 + popd
  73 + """,
  74 + ),
  75 + Model(
  76 + model_name="sherpa-onnx-paraformer-zh-small-2024-03-09",
  77 + lang="zh_en",
  78 + short_name="paraformer_small_2024_03_09",
  79 + cmd="""
  80 + pushd $model_name
  81 + rm -fv model.onnx
  82 + mv -v model.int8.onnx paraformer.onnx
  83 + popd
  84 + """,
  85 + ),
  86 + Model(
  87 + model_name="sherpa-onnx-zipformer-gigaspeech-2023-12-12",
  88 + lang="en",
  89 + short_name="zipformer_gigaspeech_2023_12_12",
  90 + cmd="""
  91 + pushd $model_name
  92 + mv encoder-epoch-30-avg-1.int8.onnx transducer-encoder.onnx
  93 + mv decoder-epoch-30-avg-1.onnx transducer-decoder.onnx
  94 + mv joiner-epoch-30-avg-1.int8.onnx transducer-joiner.onnx
  95 +
  96 + rm -fv encoder-epoch-30-avg-1.onnx
  97 + rm -fv decoder-epoch-30-avg-1.int8.onnx
  98 + rm -fv joiner-epoch-30-avg-1.onnx
  99 +
  100 + popd
  101 + """,
  102 + ),
  103 + Model(
  104 + model_name="icefall-asr-zipformer-wenetspeech-20230615",
  105 + lang="zh",
  106 + short_name="zipformer_wenetspeech",
  107 + cmd="""
  108 + pushd $model_name
  109 +
  110 + rm -rfv test_wavs
  111 + rm -fv README.md
  112 + mv -v data/lang_char/tokens.txt ./
  113 + rm -rfv data/lang_char
  114 +
  115 + mv -v exp/encoder-epoch-12-avg-4.int8.onnx ./
  116 + mv -v exp/decoder-epoch-12-avg-4.onnx ./
  117 + mv -v exp/joiner-epoch-12-avg-4.int8.onnx ./
  118 + rm -rfv exp
  119 +
  120 + mv -v encoder-epoch-12-avg-4.int8.onnx transducer-encoder.onnx
  121 + mv -v decoder-epoch-12-avg-4.onnx transducer-decoder.onnx
  122 + mv -v joiner-epoch-12-avg-4.int8.onnx transducer-joiner.onnx
  123 +
  124 + ls -lh
  125 +
  126 + popd
  127 + """,
  128 + ),
  129 + ]
  130 + return models
  131 +
  132 +
  133 +def main():
  134 + args = get_args()
  135 + index = args.index
  136 + total = args.total
  137 + assert 0 <= index < total, (index, total)
  138 +
  139 + all_model_list = get_models()
  140 +
  141 + num_models = len(all_model_list)
  142 +
  143 + num_per_runner = num_models // total
  144 + if num_per_runner <= 0:
  145 + raise ValueError(f"num_models: {num_models}, num_runners: {total}")
  146 +
  147 + start = index * num_per_runner
  148 + end = start + num_per_runner
  149 +
  150 + remaining = num_models - args.total * num_per_runner
  151 +
  152 + print(f"{index}/{total}: {start}-{end}/{num_models}")
  153 +
  154 + d = dict()
  155 + d["model_list"] = all_model_list[start:end]
  156 + if index < remaining:
  157 + s = args.total * num_per_runner + index
  158 + d["model_list"].append(all_model_list[s])
  159 + print(f"{s}/{num_models}")
  160 +
  161 + filename_list = [
  162 + "./build-generate-subtitles.sh",
  163 + ]
  164 + for filename in filename_list:
  165 + environment = jinja2.Environment()
  166 + with open(f"{filename}.in") as f:
  167 + s = f.read()
  168 + template = environment.from_string(s)
  169 +
  170 + s = template.render(**d)
  171 + with open(filename, "w") as f:
  172 + print(s, file=f)
  173 +
  174 +
  175 +if __name__ == "__main__":
  176 + main()
@@ -224,8 +224,6 @@ std::vector<float> ReadWaveImpl(std::istream &is, int32_t *sampling_rate, @@ -224,8 +224,6 @@ std::vector<float> ReadWaveImpl(std::istream &is, int32_t *sampling_rate,
224 // header.subchunk2_size contains the number of bytes in the data. 224 // header.subchunk2_size contains the number of bytes in the data.
225 // As we assume each sample contains two bytes, so it is divided by 2 here 225 // As we assume each sample contains two bytes, so it is divided by 2 here
226 std::vector<int16_t> samples(header.subchunk2_size / 2); 226 std::vector<int16_t> samples(header.subchunk2_size / 2);
227 - SHERPA_ONNX_LOGE("%d samples, bytes: %d", (int)samples.size(),  
228 - header.subchunk2_size);  
229 227
230 is.read(reinterpret_cast<char *>(samples.data()), header.subchunk2_size); 228 is.read(reinterpret_cast<char *>(samples.data()), header.subchunk2_size);
231 if (!is) { 229 if (!is) {
@@ -309,19 +309,50 @@ uses @@ -309,19 +309,50 @@ uses
309 SysUtils; 309 SysUtils;
310 310
311 const 311 const
312 - {See https://www.freepascal.org/docs-html/prog/progap7.html} 312 + {
  313 + See
  314 + - https://www.freepascal.org/docs-html/prog/progap7.html
  315 + - https://downloads.freepascal.org/fpc/docs-pdf/
  316 + - https://downloads.freepascal.org/fpc/docs-pdf/CinFreePascal.pdf
  317 + }
313 318
314 {$IFDEF WINDOWS} 319 {$IFDEF WINDOWS}
315 - SherpaOnnxLibName = 'sherpa-onnx-c-api.dll';  
316 - {$ENDIF}  
317 -  
318 - {$IFDEF DARWIN}  
319 - SherpaOnnxLibName = 'sherpa-onnx-c-api';  
320 - {$linklib sherpa-onnx-c-api}  
321 - {$ENDIF}  
322 -  
323 - {$IFDEF LINUX}  
324 - SherpaOnnxLibName = 'libsherpa-onnx-c-api.so'; 320 + { For windows, we always use dynamic link. See
  321 + https://forum.lazarus.freepascal.org/index.php/topic,15712.msg84781.html#msg84781
  322 + We need to rebuild the static lib for windows using Mingw or cygwin
  323 + }
  324 + SherpaOnnxLibName = 'sherpa-onnx-c-api.dll';
  325 + {$ELSE}
  326 + {$IFNDEF SHERPA_ONNX_USE_SHARED_LIBS}
  327 + {static link for linux and macos}
  328 + {$linklib sherpa-onnx-c-api}
  329 + {$linklib sherpa-onnx-core}
  330 + {$linklib kaldi-decoder-core}
  331 + {$linklib sherpa-onnx-kaldifst-core}
  332 + {$linklib sherpa-onnx-fstfar}
  333 + {$linklib sherpa-onnx-fst}
  334 + {$linklib kaldi-native-fbank-core}
  335 + {$linklib piper_phonemize}
  336 + {$linklib espeak-ng}
  337 + {$linklib ucd}
  338 + {$linklib onnxruntime}
  339 + {$linklib ssentencepiece_core}
  340 +
  341 + {$IFDEF LINUX}
  342 + {$linklib m}
  343 + {$LINKLIB stdc++}
  344 + {$LINKLIB gcc_s}
  345 + {$ENDIF}
  346 +
  347 + {$IFDEF DARWIN}
  348 + {$linklib c++}
  349 + {$ENDIF}
  350 + SherpaOnnxLibName = '';
  351 + {$ELSE}
  352 + {dynamic link for linux and macos}
  353 + SherpaOnnxLibName = 'sherpa-onnx-c-api';
  354 + {$linklib sherpa-onnx-c-api}
  355 + {$ENDIF}
325 {$ENDIF} 356 {$ENDIF}
326 357
327 type 358 type
@@ -621,10 +652,17 @@ var @@ -621,10 +652,17 @@ var
621 PWave: PSherpaOnnxWave; 652 PWave: PSherpaOnnxWave;
622 I: Integer; 653 I: Integer;
623 begin 654 begin
  655 + Result.Samples := nil;
  656 + Result.SampleRate := 0;
  657 +
624 PFilename := PAnsiChar(Filename); 658 PFilename := PAnsiChar(Filename);
  659 +
625 PWave := SherpaOnnxReadWaveWrapper(PFilename); 660 PWave := SherpaOnnxReadWaveWrapper(PFilename);
626 661
627 - Result.Samples := nil; 662 + if PWave = nil then
  663 + Exit;
  664 +
  665 +
628 SetLength(Result.Samples, PWave^.NumSamples); 666 SetLength(Result.Samples, PWave^.NumSamples);
629 667
630 Result.SampleRate := PWave^.SampleRate; 668 Result.SampleRate := PWave^.SampleRate;