diff --git a/.github/workflows/flutter.yaml b/.github/workflows/flutter.yaml new file mode 100644 index 000000000..86ca82602 --- /dev/null +++ b/.github/workflows/flutter.yaml @@ -0,0 +1,157 @@ +name: flutter + +on: + push: + branches: + - flutter + - flutter-sid-2 + tags: + - '*' + paths: + - '.github/workflows/flutter.yaml' + - 'CMakeLists.txt' + - 'cmake/**' + - 'sherpa-onnx/csrc/*' + - 'sherpa-onnx/c-api/*' + - 'sherpa-onnx/flutter/**' + pull_request: + branches: + - master + paths: + - '.github/workflows/flutter.yaml' + - 'CMakeLists.txt' + - 'cmake/**' + - 'sherpa-onnx/csrc/*' + - 'sherpa-onnx/c-api/*' + - 'sherpa-onnx/flutter/**' + + workflow_dispatch: + +concurrency: + group: flutter-${{ github.ref }} + cancel-in-progress: true + +jobs: + flutter: + name: flutter + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [macos-latest] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Flutter SDK + uses: flutter-actions/setup-flutter@v3 + with: + channel: stable + version: latest + + - name: ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ matrix.os }}-flutter + + - name: Display PWD + shell: bash + run: | + echo "pwd: $PWD" + ls -lh + + - name: Display machine info + shell: bash + run: | + uname -a + + - name: Display flutter info + shell: bash + run: | + which flutter + which dart + + flutter --version + dart --version + flutter doctor + + - 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 \ + -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' \ + -DSHERPA_ONNX_ENABLE_PORTAUDIO=OFF \ + -DSHERPA_ONNX_ENABLE_WEBSOCKET=OFF \ + -DSHERPA_ONNX_ENABLE_BINARY=ON \ + -DCMAKE_INSTALL_PREFIX=./install \ + .. + + - name: Build sherpa-onnx for macos + shell: bash + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + + cd build + make -j2 + make install + + rm -v ./install/lib/libcargs* + + - name: Copy libs + shell: bash + run: | + cp -v build/install/lib/lib* ./sherpa-onnx/flutter/macos/ + + echo "--------------------" + + ls -lh ./sherpa-onnx/flutter/macos/ + + - name: Download model files + shell: bash + run: | + cd sherpa-onnx/flutter + pushd example/assets + + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx + git clone https://github.com/csukuangfj/sr-data + + rm -rf sr-data/.git + popd + + + - name: Build flutter + shell: bash + run: | + d=$PWD + + pushd sherpa-onnx/flutter + dart pub get + + cd example + flutter build macos + + pushd build/macos/Build/Products/Release/ + tar cjfv sherpa_onnx.app.tar.bz2 ./sherpa_onnx.app + ls -lh + mv sherpa_onnx.app.tar.bz2 $d + popd + + popd + + ls -lh sherpa_onnx.app.tar.bz2 + + - uses: actions/upload-artifact@v4 + if: matrix.os == 'macos-latest' + with: + name: flutter-sherpa-onnx-app-macos + path: ./sherpa_onnx.app.tar.bz2 diff --git a/CMakeLists.txt b/CMakeLists.txt index a3e4ffef4..21ba4f66f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,7 @@ cmake_minimum_required(VERSION 3.13 FATAL_ERROR) + +set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14" CACHE STRING "Minimum OS X deployment version. Used only for macOS") + project(sherpa-onnx) set(SHERPA_ONNX_VERSION "1.9.25") diff --git a/sherpa-onnx/flutter/.gitignore b/sherpa-onnx/flutter/.gitignore new file mode 100644 index 000000000..e54732c88 --- /dev/null +++ b/sherpa-onnx/flutter/.gitignore @@ -0,0 +1,145 @@ +# Do not remove or rename entries in this file, only add new ones +# See https://github.com/flutter/flutter/issues/128635 for more context. + +# Miscellaneous +*.class +*.lock +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# Visual Studio Code related +.classpath +.project +.settings/ +.vscode/* + +# Flutter repo-specific +/bin/cache/ +/bin/internal/bootstrap.bat +/bin/internal/bootstrap.sh +/bin/mingit/ +/dev/benchmarks/mega_gallery/ +/dev/bots/.recipe_deps +/dev/bots/android_tools/ +/dev/devicelab/ABresults*.json +/dev/docs/doc/ +/dev/docs/api_docs.zip +/dev/docs/flutter.docs.zip +/dev/docs/lib/ +/dev/docs/pubspec.yaml +/dev/integration_tests/**/xcuserdata +/dev/integration_tests/**/Pods +/packages/flutter/coverage/ +version +analysis_benchmark.json + +# packages file containing multi-root paths +.packages.generated + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +**/generated_plugin_registrant.dart +.packages +.pub-preload-cache/ +.pub-cache/ +.pub/ +build/ +flutter_*.png +linked_*.ds +unlinked.ds +unlinked_spec.ds + +# Android related +**/android/**/gradle-wrapper.jar +.gradle/ +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java +**/android/key.properties +*.jks + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/.last_build_id +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/ephemeral +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# macOS +**/Flutter/ephemeral/ +**/Pods/ +**/macos/Flutter/GeneratedPluginRegistrant.swift +**/macos/Flutter/ephemeral +**/xcuserdata/ + +# Windows +**/windows/flutter/generated_plugin_registrant.cc +**/windows/flutter/generated_plugin_registrant.h +**/windows/flutter/generated_plugins.cmake + +# Linux +**/linux/flutter/generated_plugin_registrant.cc +**/linux/flutter/generated_plugin_registrant.h +**/linux/flutter/generated_plugins.cmake + +# Coverage +coverage/ + +# Symbols +app.*.symbols + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!/dev/ci/**/Gemfile.lock +!.vscode/settings.json + +## User settings +xcuserdata/ + +## Xcode 8 and earlier +*.xcscmblueprint +*.xccheckout diff --git a/sherpa-onnx/flutter/LICENSE b/sherpa-onnx/flutter/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/sherpa-onnx/flutter/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/sherpa-onnx/flutter/analysis_options.yaml b/sherpa-onnx/flutter/analysis_options.yaml new file mode 100644 index 000000000..a5744c1cf --- /dev/null +++ b/sherpa-onnx/flutter/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/sherpa-onnx/flutter/example/assets/README.md b/sherpa-onnx/flutter/example/assets/README.md new file mode 100644 index 000000000..cffaf536b --- /dev/null +++ b/sherpa-onnx/flutter/example/assets/README.md @@ -0,0 +1,12 @@ +# Introduction + +## Speaker identification + +```bash +# switch to this directory and run + +wget https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx +git clone https://github.com/csukuangfj/sr-data + +rm -rf sr-data/.git +``` diff --git a/sherpa-onnx/flutter/example/lib/main.dart b/sherpa-onnx/flutter/example/lib/main.dart new file mode 100644 index 000000000..317b91f9b --- /dev/null +++ b/sherpa-onnx/flutter/example/lib/main.dart @@ -0,0 +1,117 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'package:sherpa_onnx/sherpa_onnx.dart' as sherpa_onnx; +import 'package:flutter/material.dart'; +import "./speaker_identification_test.dart"; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + // This is the theme of your application. + // + // Try running your application with "flutter run". You'll see the + // application has a blue toolbar. Then, without quitting the app, try + // changing the primarySwatch below to Colors.green and then invoke + // "hot reload" (press "r" in the console where you ran "flutter run", + // or simply save your changes to "hot reload" in a Flutter IDE). + // Notice that the counter didn't reset back to zero; the application + // is not restarted. + primarySwatch: Colors.blue, + ), + home: const MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + const MyHomePage({Key? key, required this.title}) : super(key: key); + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + final String title; + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + int _counter = 0; + Future _incrementCounter() async { + if (_counter <= 10) { + sherpa_onnx.initBindings(); + await testSpeakerID(); + } + + setState(() { + // This call to setState tells the Flutter framework that something has + // changed in this State, which causes it to rerun the build method below + // so that the display can reflect the updated values. If we changed + // _counter without calling setState(), then the build method would not be + // called again, and so nothing would appear to happen. + _counter++; + }); + } + + @override + Widget build(BuildContext context) { + // This method is rerun every time setState is called, for instance as done + // by the _incrementCounter method above. + // + // The Flutter framework has been optimized to make rerunning build methods + // fast, so that you can just rebuild anything that needs updating rather + // than having to individually change instances of widgets. + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text(widget.title), + ), + body: Center( + // Center is a layout widget. It takes a single child and positions it + // in the middle of the parent. + child: Column( + // Column is also a layout widget. It takes a list of children and + // arranges them vertically. By default, it sizes itself to fit its + // children horizontally, and tries to be as tall as its parent. + // + // Invoke "debug painting" (press "p" in the console, choose the + // "Toggle Debug Paint" action from the Flutter Inspector in Android + // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) + // to see the wireframe for each widget. + // + // Column has various properties to control how it sizes itself and + // how it positions its children. Here we use mainAxisAlignment to + // center the children vertically; the main axis here is the vertical + // axis because Columns are vertical (the cross axis would be + // horizontal). + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text( + 'You have pushed the button this many times:', + ), + Text( + '$_counter', + style: Theme.of(context).textTheme.headlineSmall, + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: _incrementCounter, + tooltip: 'Increment', + child: const Icon(Icons.add), + ), // This trailing comma makes auto-formatting nicer for build methods. + ); + } +} diff --git a/sherpa-onnx/flutter/example/lib/speaker_identification_test.dart b/sherpa-onnx/flutter/example/lib/speaker_identification_test.dart new file mode 100644 index 000000000..535c0dd57 --- /dev/null +++ b/sherpa-onnx/flutter/example/lib/speaker_identification_test.dart @@ -0,0 +1,129 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'package:sherpa_onnx/sherpa_onnx.dart' as sherpa_onnx; +import 'dart:typed_data'; +import 'package:path/path.dart'; +import './utils.dart'; + +Float32List computeEmbedding( + {required sherpa_onnx.SpeakerEmbeddingExtractor extractor, + required String filename}) { + final stream = extractor.createStream(); + final waveData = sherpa_onnx.readWave(filename); + + stream.acceptWaveform( + samples: waveData.samples, sampleRate: waveData.sampleRate); + + stream.inputFinished(); + + final embedding = extractor.compute(stream); + + stream.free(); + + return embedding; +} + +Future testSpeakerID() async { + final src = + 'assets/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx'; + final modelPath = await copyAssetFile(src: src, dst: 'model.onnx'); + + final config = sherpa_onnx.SpeakerEmbeddingExtractorConfig(model: modelPath); + final extractor = sherpa_onnx.SpeakerEmbeddingExtractor(config: config); + + const _spk1Files = [ + 'assets/sr-data/enroll/fangjun-sr-1.wav', + 'assets/sr-data/enroll/fangjun-sr-2.wav', + 'assets/sr-data/enroll/fangjun-sr-3.wav', + ]; + final spk1Files = []; + for (final f in _spk1Files) { + spk1Files.add(await copyAssetFile(src: f, dst: basename(f))); + } + + final spk1Vec = []; + for (final f in spk1Files) { + spk1Vec.add(computeEmbedding(extractor: extractor, filename: f)); + } + + const _spk2Files = [ + 'assets/sr-data/enroll/leijun-sr-1.wav', + 'assets/sr-data/enroll/leijun-sr-2.wav', + ]; + final spk2Files = []; + for (final f in _spk2Files) { + spk2Files.add(await copyAssetFile(src: f, dst: basename(f))); + } + + final spk2Vec = []; + for (final f in spk2Files) { + spk2Vec.add(computeEmbedding(extractor: extractor, filename: f)); + } + + final manager = sherpa_onnx.SpeakerEmbeddingManager(extractor.dim); + assert(manager.numSpeakers == 0, '${manager.numSpeakers}'); + + bool ok = manager.addMulti(name: 'fangjun', embeddingList: spk1Vec); + assert(ok, "Failed to add fangjun"); + assert(manager.numSpeakers == 1, '${manager.numSpeakers}'); + + ok = manager.addMulti(name: 'leijun', embeddingList: spk2Vec); + assert(ok, "Failed to add leijun"); + assert(manager.numSpeakers == 2, '${manager.numSpeakers}'); + + bool found = manager.contains('fangjun'); + assert(found, 'Failed to find fangjun'); + + found = manager.contains('leijun'); + assert(found, 'Failed to find leijun'); + + print('---All speakers---'); + + print(manager.allSpeakerNames); + + print('------------'); + + const _testFiles = [ + 'assets/sr-data/test/fangjun-test-sr-1.wav', + 'assets/sr-data/test/leijun-test-sr-1.wav', + 'assets/sr-data/test/liudehua-test-sr-1.wav', + ]; + + final testFiles = []; + for (final f in _testFiles) { + testFiles.add(await copyAssetFile(src: f, dst: basename(f))); + } + + const threshold = 0.6; + + for (final f in testFiles) { + final embedding = computeEmbedding(extractor: extractor, filename: f); + + var name = manager.search(embedding: embedding, threshold: threshold); + if (name == '') { + name = ''; + } + print('${f}: ${name}'); + } + + ok = manager.verify( + name: 'fangjun', + embedding: computeEmbedding(extractor: extractor, filename: testFiles[0]), + threshold: threshold); + assert(ok, 'Failed to verify fangjun using ${testFiles[0]}'); + + ok = manager.remove('fangjun'); + assert(ok, 'Failed to remove fangjun'); + assert(manager.numSpeakers == 1, '${manager.numSpeakers}'); + + found = manager.contains('fangjun'); + assert(!found, 'Still found fangjun!'); + + ok = manager.verify( + name: 'fangjun', + embedding: computeEmbedding(extractor: extractor, filename: testFiles[0]), + threshold: threshold); + assert(!ok, '${testFiles[0]}'); + + manager.free(); + extractor.free(); +} diff --git a/sherpa-onnx/flutter/example/lib/utils.dart b/sherpa-onnx/flutter/example/lib/utils.dart new file mode 100644 index 000000000..b7417eb11 --- /dev/null +++ b/sherpa-onnx/flutter/example/lib/utils.dart @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:flutter/services.dart' show rootBundle; +import "dart:io"; + +// Copy the asset file from src to dst +Future copyAssetFile({required String src, required String dst}) async { + final Directory directory = await getApplicationDocumentsDirectory(); + final target = join(directory.path, dst); + + final data = await rootBundle.load(src); + final List bytes = + data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); + await File(target).writeAsBytes(bytes); + + return target; +} diff --git a/sherpa-onnx/flutter/example/macos/.gitignore b/sherpa-onnx/flutter/example/macos/.gitignore new file mode 100644 index 000000000..746adbb6b --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Debug.xcconfig b/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 000000000..4b81f9b2d --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Release.xcconfig b/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 000000000..5caa9d157 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/sherpa-onnx/flutter/example/macos/Podfile b/sherpa-onnx/flutter/example/macos/Podfile new file mode 100644 index 000000000..c795730db --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Podfile @@ -0,0 +1,43 @@ +platform :osx, '10.14' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\"" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_macos_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_macos_build_settings(target) + end +end diff --git a/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.pbxproj b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 000000000..da5c34d8d --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,801 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + AD18C81BD25EB64A10A74721 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3EEF159F4D7912B9311CB282 /* Pods_Runner.framework */; }; + F1F6B0C655533B7F45E75DA0 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA92A3C1CA5533C24C7C7468 /* Pods_RunnerTests.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 09EF98B2CF4F049F4C7B5BAA /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* sherpa_onnx.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = sherpa_onnx.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 3EEF159F4D7912B9311CB282 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A1236548122E91133BF39DA1 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + BA92A3C1CA5533C24C7C7468 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C9A014A0AF0A3CC243C5BA0C /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + CDC9FAA17691FA4BA5F49074 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + E3A16097032C820A141E3D0C /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + F7379309434F931B509C87FA /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F1F6B0C655533B7F45E75DA0 /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AD18C81BD25EB64A10A74721 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + 782733D97D5852B42F7DAD3B /* Pods */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* sherpa_onnx.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + 782733D97D5852B42F7DAD3B /* Pods */ = { + isa = PBXGroup; + children = ( + A1236548122E91133BF39DA1 /* Pods-Runner.debug.xcconfig */, + 09EF98B2CF4F049F4C7B5BAA /* Pods-Runner.release.xcconfig */, + CDC9FAA17691FA4BA5F49074 /* Pods-Runner.profile.xcconfig */, + E3A16097032C820A141E3D0C /* Pods-RunnerTests.debug.xcconfig */, + C9A014A0AF0A3CC243C5BA0C /* Pods-RunnerTests.release.xcconfig */, + F7379309434F931B509C87FA /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 3EEF159F4D7912B9311CB282 /* Pods_Runner.framework */, + BA92A3C1CA5533C24C7C7468 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + A6B10289F00794F0134DF87E /* [CP] Check Pods Manifest.lock */, + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 1CEDB7D27400A1C1B87B926C /* [CP] Check Pods Manifest.lock */, + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + C2CEDA50A000327A806944DD /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* sherpa_onnx.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 1CEDB7D27400A1C1B87B926C /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; + A6B10289F00794F0134DF87E /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + C2CEDA50A000327A806944DD /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = E3A16097032C820A141E3D0C /* Pods-RunnerTests.debug.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.k2fsa.sherpa.onnx.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sherpa_onnx.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sherpa_onnx"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = C9A014A0AF0A3CC243C5BA0C /* Pods-RunnerTests.release.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.k2fsa.sherpa.onnx.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sherpa_onnx.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sherpa_onnx"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = F7379309434F931B509C87FA /* Pods-RunnerTests.profile.xcconfig */; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.k2fsa.sherpa.onnx.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sherpa_onnx.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sherpa_onnx"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 000000000..33dea4279 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/contents.xcworkspacedata b/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..21a3cc14c --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner/AppDelegate.swift b/sherpa-onnx/flutter/example/macos/Runner/AppDelegate.swift new file mode 100644 index 000000000..d53ef6437 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/AppDelegate.swift @@ -0,0 +1,9 @@ +import Cocoa +import FlutterMacOS + +@NSApplicationMain +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } +} diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..a2ec33f19 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 000000000..82b6f9d9a Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 000000000..13b35eba5 Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 000000000..0a3f5fa40 Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 000000000..bdb57226d Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 000000000..f083318e0 Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 000000000..326c0e72c Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 000000000..2f1632cfd Binary files /dev/null and b/sherpa-onnx/flutter/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/sherpa-onnx/flutter/example/macos/Runner/Base.lproj/MainMenu.xib b/sherpa-onnx/flutter/example/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 000000000..80e867a4e --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner/Configs/AppInfo.xcconfig b/sherpa-onnx/flutter/example/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 000000000..04f791df1 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = sherpa_onnx + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.k2fsa.sherpa.onnx + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2024 com.k2fsa.sherpa.onnx. All rights reserved. diff --git a/sherpa-onnx/flutter/example/macos/Runner/Configs/Debug.xcconfig b/sherpa-onnx/flutter/example/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 000000000..36b0fd946 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/sherpa-onnx/flutter/example/macos/Runner/Configs/Release.xcconfig b/sherpa-onnx/flutter/example/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 000000000..dff4f4956 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/sherpa-onnx/flutter/example/macos/Runner/Configs/Warnings.xcconfig b/sherpa-onnx/flutter/example/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 000000000..42bcbf478 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/sherpa-onnx/flutter/example/macos/Runner/DebugProfile.entitlements b/sherpa-onnx/flutter/example/macos/Runner/DebugProfile.entitlements new file mode 100644 index 000000000..dddb8a30c --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/sherpa-onnx/flutter/example/macos/Runner/Info.plist b/sherpa-onnx/flutter/example/macos/Runner/Info.plist new file mode 100644 index 000000000..4789daa6a --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/sherpa-onnx/flutter/example/macos/Runner/MainFlutterWindow.swift b/sherpa-onnx/flutter/example/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 000000000..3cc05eb23 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/sherpa-onnx/flutter/example/macos/Runner/Release.entitlements b/sherpa-onnx/flutter/example/macos/Runner/Release.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/sherpa-onnx/flutter/example/macos/RunnerTests/RunnerTests.swift b/sherpa-onnx/flutter/example/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 000000000..61f3bd1fc --- /dev/null +++ b/sherpa-onnx/flutter/example/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/sherpa-onnx/flutter/example/pubspec.yaml b/sherpa-onnx/flutter/example/pubspec.yaml new file mode 100644 index 000000000..2db23c3d7 --- /dev/null +++ b/sherpa-onnx/flutter/example/pubspec.yaml @@ -0,0 +1,102 @@ +name: hello_sherpa_onnx +description: "Demonstrates how to use the sherpa_onnx ffi plugin." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: '>=3.4.0 <4.0.0' + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + + path_provider: ^2.1.3 + path: + + sherpa_onnx: + # When depending on this package from a real application you should use: + # sherpa_onnx: ^x.y.z + # See https://dart.dev/tools/pub/dependencies#version-constraints + # The example app is bundled with the plugin so we use a path dependency on + # the parent directory to use the current plugin's version. + path: ../ + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + cupertino_icons: ^1.0.6 + +dev_dependencies: + flutter_test: + sdk: flutter + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + assets: + - assets/ + - assets/sr-data/enroll/ + - assets/sr-data/test/ + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/assets-and-images/#from-packages + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/custom-fonts/#from-packages diff --git a/sherpa-onnx/flutter/lib/sherpa_onnx.dart b/sherpa-onnx/flutter/lib/sherpa_onnx.dart new file mode 100644 index 000000000..2985fb419 --- /dev/null +++ b/sherpa-onnx/flutter/lib/sherpa_onnx.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'dart:io'; +import 'dart:ffi'; + +import 'src/sherpa_onnx_bindings.dart'; +export 'src/speaker_identification.dart'; +export 'src/online_stream.dart'; +export 'src/wave_reader.dart'; + +final DynamicLibrary _dylib = () { + if (Platform.isIOS) { + throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); + } + if (Platform.isMacOS) { + return DynamicLibrary.open('libsherpa-onnx-c-api.dylib'); + } + if (Platform.isAndroid || Platform.isLinux) { + return DynamicLibrary.open('libsherpa-onnx-c-api.so'); + } + + if (Platform.isWindows) { + return DynamicLibrary.open('sherpa-onnx-c-api.dll'); + } + + throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}'); +}(); + +void initBindings() { + SherpaOnnxBindings.init(_dylib); +} diff --git a/sherpa-onnx/flutter/lib/src/online_stream.dart b/sherpa-onnx/flutter/lib/src/online_stream.dart new file mode 100644 index 000000000..c585ae9a5 --- /dev/null +++ b/sherpa-onnx/flutter/lib/src/online_stream.dart @@ -0,0 +1,41 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'dart:typed_data'; +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; +import "./sherpa_onnx_bindings.dart"; + +class OnlineStream { + /// The user has to call OnlineStream.free() to avoid memory leak. + OnlineStream({required this.ptr}); + + void free() { + SherpaOnnxBindings.destroyOnlineStream?.call(ptr); + ptr = nullptr; + } + + /// If you have List data, then you can use + /// Float32List.fromList(data) to convert data to Float32List + /// + /// See + /// https://api.flutter.dev/flutter/dart-core/List-class.html + /// and + /// https://api.flutter.dev/flutter/dart-typed_data/Float32List-class.html + void acceptWaveform({required Float32List samples, required int sampleRate}) { + final n = samples.length; + final Pointer p = calloc(n); + + final pList = p.asTypedList(n); + pList.setAll(0, samples); + + SherpaOnnxBindings.onlineStreamAcceptWaveform + ?.call(this.ptr, sampleRate, p, n); + + calloc.free(p); + } + + void inputFinished() { + SherpaOnnxBindings.onlineStreamInputFinished?.call(this.ptr); + } + + Pointer ptr; +} diff --git a/sherpa-onnx/flutter/lib/src/sherpa_onnx_bindings.dart b/sherpa-onnx/flutter/lib/src/sherpa_onnx_bindings.dart new file mode 100644 index 000000000..95869542c --- /dev/null +++ b/sherpa-onnx/flutter/lib/src/sherpa_onnx_bindings.dart @@ -0,0 +1,395 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; + +final class SherpaOnnxWave extends Struct { + external Pointer samples; + + @Int32() + external int sampleRate; + + @Int32() + external int numSamples; +} + +final class SherpaOnnxSpeakerEmbeddingExtractorConfig extends Struct { + external Pointer model; + + @Int32() + external int numThreads; + + @Int32() + external int debug; + + external Pointer provider; +} + +final class SherpaOnnxOnlineStream extends Opaque {} + +final class SherpaOnnxSpeakerEmbeddingExtractor extends Opaque {} + +final class SherpaOnnxSpeakerEmbeddingManager extends Opaque {} + +typedef SherpaOnnxCreateSpeakerEmbeddingManagerNative + = Pointer Function(Int32 dim); + +typedef SherpaOnnxCreateSpeakerEmbeddingManager + = Pointer Function(int dim); + +typedef SherpaOnnxDestroySpeakerEmbeddingManagerNative = Void Function( + Pointer); + +typedef SherpaOnnxDestroySpeakerEmbeddingManager = void Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerAddNative = Int32 Function( + Pointer, Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerAdd = int Function( + Pointer, Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerAddListFlattenedNative + = Int32 Function(Pointer, Pointer, + Pointer, Int32); + +typedef SherpaOnnxSpeakerEmbeddingManagerAddListFlattened = int Function( + Pointer, + Pointer, + Pointer, + int); + +typedef SherpaOnnxSpeakerEmbeddingManagerRemoveNative = Int32 Function( + Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerRemove = int Function( + Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerContainsNative = Int32 Function( + Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerContains = int Function( + Pointer, Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerSearchNative = Pointer Function( + Pointer, Pointer, Float); + +typedef SherpaOnnxSpeakerEmbeddingManagerSearch = Pointer Function( + Pointer, Pointer, double); + +typedef SherpaOnnxSpeakerEmbeddingManagerFreeSearchNative = Void Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerFreeSearch = void Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerNumSpeakersNative = Int32 Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerNumSpeakers = int Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerVerifyNative = Int32 Function( + Pointer, + Pointer, + Pointer, + Float); + +typedef SherpaOnnxSpeakerEmbeddingManagerVerify = int Function( + Pointer, + Pointer, + Pointer, + double); + +typedef SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakersNative + = Pointer> Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers + = SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakersNative; + +typedef SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakersNative = Void Function( + Pointer>); + +typedef SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers = void Function( + Pointer>); + +typedef SherpaOnnxCreateSpeakerEmbeddingExtractorNative + = Pointer Function( + Pointer); + +typedef SherpaOnnxCreateSpeakerEmbeddingExtractor + = SherpaOnnxCreateSpeakerEmbeddingExtractorNative; + +typedef SherpaOnnxDestroySpeakerEmbeddingExtractorNative = Void Function( + Pointer); + +typedef SherpaOnnxDestroySpeakerEmbeddingExtractor = void Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorDimNative = Int32 Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorDim = int Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorCreateStreamNative + = Pointer Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorCreateStream + = SherpaOnnxSpeakerEmbeddingExtractorCreateStreamNative; + +typedef DestroyOnlineStreamNative = Void Function( + Pointer); + +typedef DestroyOnlineStream = void Function(Pointer); + +typedef OnlineStreamAcceptWaveformNative = Void Function( + Pointer, + Int32 sample_rate, + Pointer, + Int32 n); + +typedef OnlineStreamAcceptWaveform = void Function( + Pointer, int sample_rate, Pointer, int n); + +typedef OnlineStreamInputFinishedNative = Void Function( + Pointer); + +typedef OnlineStreamInputFinished = void Function( + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorIsReadyNative = Int32 Function( + Pointer, + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorIsReady = int Function( + Pointer, + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorComputeEmbeddingNative + = Pointer Function(Pointer, + Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding + = SherpaOnnxSpeakerEmbeddingExtractorComputeEmbeddingNative; + +typedef SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbeddingNative = Void + Function(Pointer); + +typedef SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding = void Function( + Pointer); + +typedef SherpaOnnxReadWaveNative = Pointer Function( + Pointer); + +typedef SherpaOnnxReadWave = SherpaOnnxReadWaveNative; + +typedef SherpaOnnxFreeWaveNative = Void Function(Pointer); + +typedef SherpaOnnxFreeWave = void Function(Pointer); + +class SherpaOnnxBindings { + static SherpaOnnxCreateSpeakerEmbeddingExtractor? + createSpeakerEmbeddingExtractor; + + static SherpaOnnxDestroySpeakerEmbeddingExtractor? + destroySpeakerEmbeddingExtractor; + + static SherpaOnnxSpeakerEmbeddingExtractorDim? speakerEmbeddingExtractorDim; + + static SherpaOnnxSpeakerEmbeddingExtractorCreateStream? + speakerEmbeddingExtractorCreateStream; + + static SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding? + speakerEmbeddingExtractorComputeEmbedding; + + static SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding? + speakerEmbeddingExtractorDestroyEmbedding; + + static DestroyOnlineStream? destroyOnlineStream; + + static OnlineStreamAcceptWaveform? onlineStreamAcceptWaveform; + + static OnlineStreamInputFinished? onlineStreamInputFinished; + + static SherpaOnnxSpeakerEmbeddingExtractorIsReady? + speakerEmbeddingExtractorIsReady; + + static SherpaOnnxCreateSpeakerEmbeddingManager? createSpeakerEmbeddingManager; + + static SherpaOnnxDestroySpeakerEmbeddingManager? + destroySpeakerEmbeddingManager; + + static SherpaOnnxSpeakerEmbeddingManagerAdd? speakerEmbeddingManagerAdd; + + static SherpaOnnxSpeakerEmbeddingManagerAddListFlattened? + speakerEmbeddingManagerAddListFlattened; + + static SherpaOnnxSpeakerEmbeddingManagerRemove? speakerEmbeddingManagerRemove; + + static SherpaOnnxSpeakerEmbeddingManagerContains? + speakerEmbeddingManagerContains; + + static SherpaOnnxSpeakerEmbeddingManagerSearch? speakerEmbeddingManagerSearch; + + static SherpaOnnxSpeakerEmbeddingManagerFreeSearch? + speakerEmbeddingManagerFreeSearch; + + static SherpaOnnxSpeakerEmbeddingManagerNumSpeakers? + speakerEmbeddingManagerNumSpeakers; + + static SherpaOnnxSpeakerEmbeddingManagerVerify? speakerEmbeddingManagerVerify; + + static SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers? + speakerEmbeddingManagerGetAllSpeakers; + + static SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers? + speakerEmbeddingManagerFreeAllSpeakers; + + static SherpaOnnxReadWave? readWave; + + static SherpaOnnxFreeWave? freeWave; + + static void init(DynamicLibrary dynamicLibrary) { + createSpeakerEmbeddingExtractor ??= dynamicLibrary + .lookup>( + 'SherpaOnnxCreateSpeakerEmbeddingExtractor') + .asFunction(); + + destroySpeakerEmbeddingExtractor ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxDestroySpeakerEmbeddingExtractorNative>>( + 'SherpaOnnxDestroySpeakerEmbeddingExtractor') + .asFunction(); + + speakerEmbeddingExtractorDim ??= dynamicLibrary + .lookup>( + 'SherpaOnnxSpeakerEmbeddingExtractorDim') + .asFunction(); + + speakerEmbeddingExtractorCreateStream ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingExtractorCreateStreamNative>>( + 'SherpaOnnxSpeakerEmbeddingExtractorCreateStream') + .asFunction(); + + speakerEmbeddingExtractorComputeEmbedding ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingExtractorComputeEmbeddingNative>>( + 'SherpaOnnxSpeakerEmbeddingExtractorComputeEmbedding') + .asFunction(); + + speakerEmbeddingExtractorDestroyEmbedding ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbeddingNative>>( + 'SherpaOnnxSpeakerEmbeddingExtractorDestroyEmbedding') + .asFunction(); + + destroyOnlineStream ??= dynamicLibrary + .lookup>( + 'DestroyOnlineStream') + .asFunction(); + + onlineStreamAcceptWaveform ??= dynamicLibrary + .lookup>( + 'AcceptWaveform') + .asFunction(); + + onlineStreamInputFinished ??= dynamicLibrary + .lookup>( + 'InputFinished') + .asFunction(); + + speakerEmbeddingExtractorIsReady ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingExtractorIsReadyNative>>( + 'SherpaOnnxSpeakerEmbeddingExtractorIsReady') + .asFunction(); + + createSpeakerEmbeddingManager ??= dynamicLibrary + .lookup>( + 'SherpaOnnxCreateSpeakerEmbeddingManager') + .asFunction(); + + destroySpeakerEmbeddingManager ??= dynamicLibrary + .lookup>( + 'SherpaOnnxDestroySpeakerEmbeddingManager') + .asFunction(); + + speakerEmbeddingManagerAdd ??= dynamicLibrary + .lookup>( + 'SherpaOnnxSpeakerEmbeddingManagerAdd') + .asFunction(); + + speakerEmbeddingManagerAddListFlattened ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerAddListFlattenedNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerAddListFlattened') + .asFunction(); + + speakerEmbeddingManagerRemove ??= dynamicLibrary + .lookup>( + 'SherpaOnnxSpeakerEmbeddingManagerRemove') + .asFunction(); + + speakerEmbeddingManagerContains ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerContainsNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerContains') + .asFunction(); + + speakerEmbeddingManagerSearch ??= dynamicLibrary + .lookup>( + 'SherpaOnnxSpeakerEmbeddingManagerSearch') + .asFunction(); + + speakerEmbeddingManagerFreeSearch ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerFreeSearchNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerFreeSearch') + .asFunction(); + + speakerEmbeddingManagerNumSpeakers ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerNumSpeakersNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerNumSpeakers') + .asFunction(); + + speakerEmbeddingManagerVerify ??= dynamicLibrary + .lookup>( + 'SherpaOnnxSpeakerEmbeddingManagerVerify') + .asFunction(); + + speakerEmbeddingManagerGetAllSpeakers ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakersNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerGetAllSpeakers') + .asFunction(); + + speakerEmbeddingManagerFreeAllSpeakers ??= dynamicLibrary + .lookup< + NativeFunction< + SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakersNative>>( + 'SherpaOnnxSpeakerEmbeddingManagerFreeAllSpeakers') + .asFunction(); + + readWave ??= dynamicLibrary + .lookup>('SherpaOnnxReadWave') + .asFunction(); + + freeWave ??= dynamicLibrary + .lookup>('SherpaOnnxFreeWave') + .asFunction(); + } +} diff --git a/sherpa-onnx/flutter/lib/src/speaker_identification.dart b/sherpa-onnx/flutter/lib/src/speaker_identification.dart new file mode 100644 index 000000000..693ae4837 --- /dev/null +++ b/sherpa-onnx/flutter/lib/src/speaker_identification.dart @@ -0,0 +1,269 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'dart:ffi'; +import 'dart:typed_data'; +import 'package:ffi/ffi.dart'; +import "./sherpa_onnx_bindings.dart"; +import "./online_stream.dart"; + +class SpeakerEmbeddingExtractorConfig { + const SpeakerEmbeddingExtractorConfig( + {required this.model, + this.numThreads = 1, + this.debug = true, + this.provider = "cpu"}); + + @override + String toString() { + return "SpeakerEmbeddingExtractorConfig(model: $model, numThreads: $numThreads, debug: $debug, provider: $provider)"; + } + + final String model; + final int numThreads; + final bool debug; + final String provider; +} + +class SpeakerEmbeddingExtractor { + SpeakerEmbeddingExtractor._({required this.ptr, required this.dim}); + + /// The user is responsible to call the SpeakerEmbeddingExtractor.free() + /// method of the returned instance to avoid memory leak. + factory SpeakerEmbeddingExtractor( + {required SpeakerEmbeddingExtractorConfig config}) { + final c = calloc(); + + final modelPtr = config.model.toNativeUtf8(); + c.ref.model = modelPtr; + + c.ref.numThreads = config.numThreads; + c.ref.debug = config.debug ? 1 : 0; + + final providerPtr = config.provider.toNativeUtf8(); + c.ref.provider = providerPtr; + + final ptr = + SherpaOnnxBindings.createSpeakerEmbeddingExtractor?.call(c) ?? nullptr; + + calloc.free(providerPtr); + calloc.free(modelPtr); + calloc.free(c); + + final dim = SherpaOnnxBindings.speakerEmbeddingExtractorDim?.call(ptr) ?? 0; + + return SpeakerEmbeddingExtractor._(ptr: ptr, dim: dim); + } + + void free() { + SherpaOnnxBindings.destroySpeakerEmbeddingExtractor?.call(ptr); + ptr = nullptr; + } + + /// The user has to invoke stream.free() on the returned instance + /// to avoid memory leak + OnlineStream createStream() { + final p = + SherpaOnnxBindings.speakerEmbeddingExtractorCreateStream?.call(ptr) ?? + nullptr; + + return OnlineStream(ptr: p); + } + + bool isReady(OnlineStream stream) { + final int ready = SherpaOnnxBindings.speakerEmbeddingExtractorIsReady + ?.call(this.ptr, stream.ptr) ?? + 0; + return ready == 1; + } + + Float32List compute(OnlineStream stream) { + final Pointer embedding = SherpaOnnxBindings + .speakerEmbeddingExtractorComputeEmbedding + ?.call(this.ptr, stream.ptr) ?? + nullptr; + + if (embedding == nullptr) { + return Float32List(0); + } + + final embeddingList = embedding.asTypedList(this.dim); + final ans = Float32List(this.dim); + ans.setAll(0, embeddingList); + + SherpaOnnxBindings.speakerEmbeddingExtractorDestroyEmbedding + ?.call(embedding); + + return ans; + } + + Pointer ptr; + final int dim; +} + +class SpeakerEmbeddingManager { + SpeakerEmbeddingManager._({required this.ptr, required this.dim}); + + // The user has to use SpeakerEmbeddingManager.free() to avoid memory leak + factory SpeakerEmbeddingManager(int dim) { + final p = + SherpaOnnxBindings.createSpeakerEmbeddingManager?.call(dim) ?? nullptr; + return SpeakerEmbeddingManager._(ptr: p, dim: dim); + } + + void free() { + SherpaOnnxBindings.destroySpeakerEmbeddingManager?.call(this.ptr); + this.ptr = nullptr; + } + + /// Return true if added successfully; return false otherwise + bool add({required String name, required Float32List embedding}) { + assert(embedding.length == this.dim, "${embedding.length} vs ${this.dim}"); + + final Pointer namePtr = name.toNativeUtf8(); + final int n = embedding.length; + + final Pointer p = calloc(n); + final pList = p.asTypedList(n); + pList.setAll(0, embedding); + + final int ok = SherpaOnnxBindings.speakerEmbeddingManagerAdd + ?.call(this.ptr, namePtr, p) ?? + 0; + + calloc.free(p); + calloc.free(namePtr); + + return ok == 1; + } + + bool addMulti( + {required String name, required List embeddingList}) { + final Pointer namePtr = name.toNativeUtf8(); + final int n = embeddingList.length; + + final Pointer p = calloc(n * this.dim); + final pList = p.asTypedList(n * this.dim); + + int offset = 0; + for (final e in embeddingList) { + assert(e.length == this.dim, "${e.length} vs ${this.dim}"); + + pList.setAll(offset, e); + offset += this.dim; + } + + final int ok = SherpaOnnxBindings.speakerEmbeddingManagerAddListFlattened + ?.call(this.ptr, namePtr, p, n) ?? + 0; + + calloc.free(p); + calloc.free(namePtr); + + return ok == 1; + } + + bool contains(String name) { + final Pointer namePtr = name.toNativeUtf8(); + + final int found = SherpaOnnxBindings.speakerEmbeddingManagerContains + ?.call(this.ptr, namePtr) ?? + 0; + + calloc.free(namePtr); + + return found == 1; + } + + bool remove(String name) { + final Pointer namePtr = name.toNativeUtf8(); + + final int ok = SherpaOnnxBindings.speakerEmbeddingManagerRemove + ?.call(this.ptr, namePtr) ?? + 0; + + calloc.free(namePtr); + + return ok == 1; + } + + /// Return an empty string if no speaker is found + String search({required Float32List embedding, required double threshold}) { + assert(embedding.length == this.dim); + + final Pointer p = calloc(this.dim); + final pList = p.asTypedList(this.dim); + pList.setAll(0, embedding); + + final Pointer name = SherpaOnnxBindings.speakerEmbeddingManagerSearch + ?.call(this.ptr, p, threshold) ?? + nullptr; + + calloc.free(p); + + if (name == nullptr) { + return ''; + } + + final String ans = name.toDartString(); + + SherpaOnnxBindings.speakerEmbeddingManagerFreeSearch?.call(name); + + return ans; + } + + bool verify( + {required String name, + required Float32List embedding, + required double threshold}) { + assert(embedding.length == this.dim); + + final Pointer namePtr = name.toNativeUtf8(); + + final Pointer p = calloc(this.dim); + final pList = p.asTypedList(this.dim); + pList.setAll(0, embedding); + + final int ok = SherpaOnnxBindings.speakerEmbeddingManagerVerify + ?.call(this.ptr, namePtr, p, threshold) ?? + 0; + + calloc.free(p); + calloc.free(namePtr); + + return ok == 1; + } + + int get numSpeakers => + SherpaOnnxBindings.speakerEmbeddingManagerNumSpeakers?.call(this.ptr) ?? + 0; + + List get allSpeakerNames { + int n = this.numSpeakers; + if (n == 0) { + return []; + } + + final Pointer> names = SherpaOnnxBindings + .speakerEmbeddingManagerGetAllSpeakers + ?.call(this.ptr) ?? + nullptr; + + if (names == nullptr) { + return []; + } + + final ans = []; + + // see https://api.flutter.dev/flutter/dart-ffi/PointerPointer.html + for (int i = 0; i != n; ++i) { + String name = names[i].toDartString(); + ans.add(name); + } + + SherpaOnnxBindings.speakerEmbeddingManagerFreeAllSpeakers?.call(names); + + return ans; + } + + Pointer ptr; + final int dim; +} diff --git a/sherpa-onnx/flutter/lib/src/wave_reader.dart b/sherpa-onnx/flutter/lib/src/wave_reader.dart new file mode 100644 index 000000000..da8441086 --- /dev/null +++ b/sherpa-onnx/flutter/lib/src/wave_reader.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2024 Xiaomi Corporation +import 'dart:ffi'; +import 'dart:typed_data'; +import 'package:ffi/ffi.dart'; +import "./sherpa_onnx_bindings.dart"; + +class WaveData { + WaveData({required this.samples, required this.sampleRate}); + + /// normalized to [-1, 1] + Float32List samples; + int sampleRate; +} + +WaveData readWave(String filename) { + final Pointer str = filename.toNativeUtf8(); + Pointer wave = + SherpaOnnxBindings.readWave?.call(str) ?? nullptr; + calloc.free(str); + + if (wave == nullptr) { + return WaveData(samples: Float32List(0), sampleRate: 0); + } + + final samples = wave.ref.samples.asTypedList(wave.ref.numSamples); + + final newSamples = Float32List.fromList(samples); + int sampleRate = wave.ref.sampleRate; + SherpaOnnxBindings.freeWave?.call(wave); + + return WaveData(samples: newSamples, sampleRate: sampleRate); +} diff --git a/sherpa-onnx/flutter/macos/sherpa_onnx.podspec b/sherpa-onnx/flutter/macos/sherpa_onnx.podspec new file mode 100644 index 000000000..e5daf264e --- /dev/null +++ b/sherpa-onnx/flutter/macos/sherpa_onnx.podspec @@ -0,0 +1,27 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint hello.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'sherpa_onnx' + s.version = '0.0.1' + s.summary = 'sherpa-onnx Flutter FFI plugin project.' + s.description = <<-DESC +sherpa-onnx Flutter FFI plugin project. + DESC + s.homepage = 'https://github.com/k2-fsa/sherpa-onnx' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + + # This will ensure the source files in Classes/ are included in the native + # builds of apps using this FFI plugin. Podspec does not support relative + # paths, so Classes contains a forwarder C file that relatively imports + # `../src/*` so that the C sources can be shared among all target platforms. + s.source = { :path => '.' } + s.dependency 'FlutterMacOS' + s.vendored_libraries = '*.dylib' + + s.platform = :osx, '10.11' + s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' } + s.swift_version = '5.0' +end diff --git a/sherpa-onnx/flutter/notes.md b/sherpa-onnx/flutter/notes.md new file mode 100644 index 000000000..412bf23d0 --- /dev/null +++ b/sherpa-onnx/flutter/notes.md @@ -0,0 +1,42 @@ +# Usage + +## macOS + +1. Build required libraries + +```bash +git clone https://github.com/k2-fsa/sherpa-onnx +cd sherpa-onnx +mkdir build +cd build + +cmake -DCMAKE_INSTALL_PREFIX=./install -DBUILD_SHARED_LIBS=ON -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" .. +make install +cd ../sherpa-onnx/flutter/ +cp -v ../../build/install/lib/lib* ./macos/ +``` + +2. Test for speaker identification + +```bash +cd sherpa-onnx/sherpa-onnx/flutter/example +mkdir assets +``` + + +## Useful commands +``` +flutter pub publish --dry-run +flutter run -d macos +flutter run -d linux +flutter run -d windows + +flutter build macos + +flutter run --release -d macos + +# add platform to an existing project +flutter create --platforms=windows,macos,linux . + +dart analyze +``` diff --git a/sherpa-onnx/flutter/pubspec.yaml b/sherpa-onnx/flutter/pubspec.yaml new file mode 100644 index 000000000..e1ea6fb1d --- /dev/null +++ b/sherpa-onnx/flutter/pubspec.yaml @@ -0,0 +1,83 @@ +name: sherpa_onnx +description: > + Dart bindings for sherpa-onnx. +repository: https://github.com/k2-fsa/sherpa-onnx/tree/main/sherpa-onnx/flutter +topics: + - speech-to-text + - text-to-speech + - speaker-identification + - spoken-language-identification + - audio-tagging + - voice-activity-detection + +# remember to change the version in macos/sherpa_onnx.podspec +version: 0.0.1 +homepage: https://github.com/k2-fsa/sherpa-onnx + +environment: + sdk: '>=3.4.0 <4.0.0' + flutter: '>=3.3.0' + +dependencies: + ffi: ^2.1.0 + flutter: + sdk: flutter + plugin_platform_interface: ^2.0.2 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^3.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + # This section identifies this Flutter project as a plugin project. + # The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.) + # which should be registered in the plugin registry. This is required for + # using method channels. + # The Android 'package' specifies package in which the registered class is. + # This is required for using method channels on Android. + # The 'ffiPlugin' specifies that native code should be built and bundled. + # This is required for using `dart:ffi`. + # All these are used by the tooling to maintain consistency when + # adding or updating assets for this project. + # + # Please refer to README.md for a detailed explanation. + plugin: + platforms: + macos: + ffiPlugin: true + + # To add assets to your plugin package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your plugin package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages