Fangjun Kuang
Committed by GitHub

Add WearOS demo for audio tagging (#777)

正在显示 46 个修改的文件 包含 1114 行增加16 行删除
  1 +name: apk-audio-tagging-wearos
  2 +
  3 +on:
  4 + push:
  5 + tags:
  6 + - '*'
  7 +
  8 + workflow_dispatch:
  9 +
  10 +concurrency:
  11 + group: apk-audio-tagging-wearos-${{ github.ref }}
  12 + cancel-in-progress: true
  13 +
  14 +permissions:
  15 + contents: write
  16 +
  17 +jobs:
  18 + apk_audio_tagging_wearos:
  19 + if: github.repository_owner == 'csukuangfj' || github.repository_owner == 'k2-fsa'
  20 + runs-on: ${{ matrix.os }}
  21 + name: apk for WearOS ${{ matrix.index }}/${{ matrix.total }}
  22 + strategy:
  23 + fail-fast: false
  24 + matrix:
  25 + os: [ubuntu-latest]
  26 + total: ["1"]
  27 + index: ["0"]
  28 +
  29 + steps:
  30 + - uses: actions/checkout@v4
  31 + with:
  32 + fetch-depth: 0
  33 +
  34 + # https://github.com/actions/setup-java
  35 + - uses: actions/setup-java@v4
  36 + with:
  37 + distribution: 'temurin' # See 'Supported distributions' for available options
  38 + java-version: '21'
  39 +
  40 + - name: ccache
  41 + uses: hendrikmuhs/ccache-action@v1.2
  42 + with:
  43 + key: ${{ matrix.os }}-android
  44 +
  45 + - name: Display NDK HOME
  46 + shell: bash
  47 + run: |
  48 + echo "ANDROID_NDK_LATEST_HOME: ${ANDROID_NDK_LATEST_HOME}"
  49 + ls -lh ${ANDROID_NDK_LATEST_HOME}
  50 +
  51 + - name: Install Python dependencies
  52 + shell: bash
  53 + run: |
  54 + python3 -m pip install --upgrade pip jinja2
  55 +
  56 + - name: Setup build tool version variable
  57 + shell: bash
  58 + run: |
  59 + echo "---"
  60 + ls -lh /usr/local/lib/android/
  61 + echo "---"
  62 +
  63 + ls -lh /usr/local/lib/android/sdk
  64 + echo "---"
  65 +
  66 + ls -lh /usr/local/lib/android/sdk/build-tools
  67 + echo "---"
  68 +
  69 + BUILD_TOOL_VERSION=$(ls /usr/local/lib/android/sdk/build-tools/ | tail -n 1)
  70 + echo "BUILD_TOOL_VERSION=$BUILD_TOOL_VERSION" >> $GITHUB_ENV
  71 + echo "Last build tool version is: $BUILD_TOOL_VERSION"
  72 +
  73 + - name: Generate build script
  74 + shell: bash
  75 + run: |
  76 + cd scripts/apk
  77 +
  78 + total=${{ matrix.total }}
  79 + index=${{ matrix.index }}
  80 +
  81 + ./generate-audio-tagging-apk-script.py --total $total --index $index
  82 +
  83 + chmod +x build-apk-audio-tagging-wearos.sh
  84 + mv -v ./build-apk-audio-tagging-wearos.sh ../..
  85 +
  86 + - name: build APK
  87 + shell: bash
  88 + run: |
  89 + export CMAKE_CXX_COMPILER_LAUNCHER=ccache
  90 + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
  91 + cmake --version
  92 +
  93 + export ANDROID_NDK=$ANDROID_NDK_LATEST_HOME
  94 + ./build-apk-audio-tagging-wearos.sh
  95 +
  96 + - name: Display APK
  97 + shell: bash
  98 + run: |
  99 + ls -lh ./apks/
  100 + du -h -d1 .
  101 +
  102 + # https://github.com/marketplace/actions/sign-android-release
  103 + - uses: r0adkll/sign-android-release@v1
  104 + name: Sign app APK
  105 + with:
  106 + releaseDirectory: ./apks
  107 + signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
  108 + alias: ${{ secrets.ANDROID_SIGNING_KEY_ALIAS }}
  109 + keyStorePassword: ${{ secrets.ANDROID_SIGNING_KEY_STORE_PASSWORD }}
  110 + env:
  111 + BUILD_TOOLS_VERSION: ${{ env.BUILD_TOOL_VERSION }}
  112 +
  113 + - name: Display APK for audio tagging after signing
  114 + shell: bash
  115 + run: |
  116 + ls -lh ./apks/
  117 + du -h -d1 .
  118 +
  119 + - name: Rename APK for audio tagging after signing
  120 + shell: bash
  121 + run: |
  122 + cd apks
  123 + rm -fv signingKey.jks
  124 + rm -fv *.apk.idsig
  125 + rm -fv *-aligned.apk
  126 +
  127 + all_apks=$(ls -1 *-signed.apk)
  128 + echo "----"
  129 + echo $all_apks
  130 + echo "----"
  131 + for apk in ${all_apks[@]}; do
  132 + n=$(echo $apk | sed -e s/-signed//)
  133 + mv -v $apk $n
  134 + done
  135 +
  136 + cd ..
  137 +
  138 + ls -lh ./apks/
  139 + du -h -d1 .
  140 +
  141 + - name: Display APK after rename
  142 + shell: bash
  143 + run: |
  144 + ls -lh ./apks/
  145 + du -h -d1 .
  146 +
  147 + - name: Publish to huggingface
  148 + env:
  149 + HF_TOKEN: ${{ secrets.HF_TOKEN }}
  150 + uses: nick-fields/retry@v3
  151 + with:
  152 + max_attempts: 20
  153 + timeout_seconds: 200
  154 + shell: bash
  155 + command: |
  156 + git config --global user.email "csukuangfj@gmail.com"
  157 + git config --global user.name "Fangjun Kuang"
  158 +
  159 + rm -rf huggingface
  160 + export GIT_LFS_SKIP_SMUDGE=1
  161 +
  162 + git clone https://huggingface.co/csukuangfj/sherpa-onnx-apk huggingface
  163 + cd huggingface
  164 + git fetch
  165 + git pull
  166 + git merge -m "merge remote" --ff origin main
  167 +
  168 + mkdir -p audio-tagging-wearos
  169 + cp -v ../apks/*.apk ./audio-tagging-wearos/
  170 + git status
  171 + git lfs track "*.apk"
  172 + git add .
  173 + git commit -m "add more apks"
  174 + git push https://csukuangfj:$HF_TOKEN@huggingface.co/csukuangfj/sherpa-onnx-apk main
@@ -90,7 +90,7 @@ jobs: @@ -90,7 +90,7 @@ jobs:
90 export PATH=/c/hostedtoolcache/windows/Python/3.9.13/x64/bin:$PATH 90 export PATH=/c/hostedtoolcache/windows/Python/3.9.13/x64/bin:$PATH
91 export PATH=/c/hostedtoolcache/windows/Python/3.10.11/x64/bin:$PATH 91 export PATH=/c/hostedtoolcache/windows/Python/3.10.11/x64/bin:$PATH
92 export PATH=/c/hostedtoolcache/windows/Python/3.11.9/x64/bin:$PATH 92 export PATH=/c/hostedtoolcache/windows/Python/3.11.9/x64/bin:$PATH
93 - export PATH=/c/hostedtoolcache/windows/Python/3.12.2/x64/bin:$PATH 93 + export PATH=/c/hostedtoolcache/windows/Python/3.12.3/x64/bin:$PATH
94 94
95 which sherpa-onnx 95 which sherpa-onnx
96 sherpa-onnx --help 96 sherpa-onnx --help
@@ -68,7 +68,7 @@ jobs: @@ -68,7 +68,7 @@ jobs:
68 export PATH=/c/hostedtoolcache/windows/Python/3.9.13/x64/bin:$PATH 68 export PATH=/c/hostedtoolcache/windows/Python/3.9.13/x64/bin:$PATH
69 export PATH=/c/hostedtoolcache/windows/Python/3.10.11/x64/bin:$PATH 69 export PATH=/c/hostedtoolcache/windows/Python/3.10.11/x64/bin:$PATH
70 export PATH=/c/hostedtoolcache/windows/Python/3.11.9/x64/bin:$PATH 70 export PATH=/c/hostedtoolcache/windows/Python/3.11.9/x64/bin:$PATH
71 - export PATH=/c/hostedtoolcache/windows/Python/3.12.2/x64/bin:$PATH 71 + export PATH=/c/hostedtoolcache/windows/Python/3.12.3/x64/bin:$PATH
72 72
73 sherpa-onnx --help 73 sherpa-onnx --help
74 sherpa-onnx-keyword-spotter --help 74 sherpa-onnx-keyword-spotter --help
@@ -40,7 +40,7 @@ jobs: @@ -40,7 +40,7 @@ jobs:
40 ls -lh 40 ls -lh
41 echo "----------" 41 echo "----------"
42 42
43 - wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 43 + curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
44 tar xvf sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 44 tar xvf sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
45 rm sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 45 rm sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
46 46
@@ -26,3 +26,7 @@ for usage. @@ -26,3 +26,7 @@ for usage.
26 26
27 - [SherpaOnnxWebSocket](./SherpaOnnxWebSocket) It shows how to write a websocket 27 - [SherpaOnnxWebSocket](./SherpaOnnxWebSocket) It shows how to write a websocket
28 client for the Python streaming websocket server. 28 client for the Python streaming websocket server.
  29 +
  30 +- [SherpaOnnxAudioTagging](./SherpaOnnxAudioTagging) It shows how to use audio tagging.
  31 +
  32 +- [SherpaOnnxAudioTaggingWearOS](./SherpaOnnxAudioTagging) It shows how to use audio tagging on WearOS.
@@ -103,14 +103,14 @@ class AudioTagging( @@ -103,14 +103,14 @@ class AudioTagging(
103 // 103 //
104 // See also 104 // See also
105 // https://k2-fsa.github.io/sherpa/onnx/audio-tagging/ 105 // https://k2-fsa.github.io/sherpa/onnx/audio-tagging/
106 -fun getAudioTaggingConfig(type: Int): AudioTaggingConfig? { 106 +fun getAudioTaggingConfig(type: Int, numThreads: Int=1): AudioTaggingConfig? {
107 when (type) { 107 when (type) {
108 0 -> { 108 0 -> {
109 val modelDir = "sherpa-onnx-zipformer-small-audio-tagging-2024-04-15" 109 val modelDir = "sherpa-onnx-zipformer-small-audio-tagging-2024-04-15"
110 return AudioTaggingConfig( 110 return AudioTaggingConfig(
111 model = AudioTaggingModelConfig( 111 model = AudioTaggingModelConfig(
112 zipformer = OfflineZipformerAudioTaggingModelConfig(model = "$modelDir/model.int8.onnx"), 112 zipformer = OfflineZipformerAudioTaggingModelConfig(model = "$modelDir/model.int8.onnx"),
113 - numThreads = 1, 113 + numThreads = numThreads,
114 debug = true, 114 debug = true,
115 ), 115 ),
116 labels = "$modelDir/class_labels_indices.csv", 116 labels = "$modelDir/class_labels_indices.csv",
@@ -3,6 +3,7 @@ package com.k2fsa.sherpa.onnx.audio.tagging @@ -3,6 +3,7 @@ package com.k2fsa.sherpa.onnx.audio.tagging
3 import android.content.res.AssetManager 3 import android.content.res.AssetManager
4 import android.util.Log 4 import android.util.Log
5 import com.k2fsa.sherpa.onnx.AudioTagging 5 import com.k2fsa.sherpa.onnx.AudioTagging
  6 +import com.k2fsa.sherpa.onnx.audio.tagging.wear.os.presentation.TAG
6 import com.k2fsa.sherpa.onnx.getAudioTaggingConfig 7 import com.k2fsa.sherpa.onnx.getAudioTaggingConfig
7 8
8 object Tagger { 9 object Tagger {
@@ -11,14 +12,14 @@ object Tagger { @@ -11,14 +12,14 @@ object Tagger {
11 get() { 12 get() {
12 return _tagger!! 13 return _tagger!!
13 } 14 }
14 - fun initTagger(assetManager: AssetManager? = null) { 15 + fun initTagger(assetManager: AssetManager? = null, numThreads: Int = 1) {
15 synchronized(this) { 16 synchronized(this) {
16 if (_tagger != null) { 17 if (_tagger != null) {
17 return 18 return
18 } 19 }
19 20
20 Log.i(TAG, "Initializing audio tagger") 21 Log.i(TAG, "Initializing audio tagger")
21 - val config = getAudioTaggingConfig(type = 0)!! 22 + val config = getAudioTaggingConfig(type = 0, numThreads=numThreads)!!
22 _tagger = AudioTagging(assetManager, config) 23 _tagger = AudioTagging(assetManager, config)
23 } 24 }
24 } 25 }
1 <resources> 1 <resources>
2 - <string name="app_name">SherpaOnnxAudioTagging</string>  
3 -</resources>  
  2 + <string name="app_name">Audio Tagging</string>
  3 +</resources>
  1 +*.iml
  2 +.gradle
  3 +/local.properties
  4 +/.idea/caches
  5 +/.idea/libraries
  6 +/.idea/modules.xml
  7 +/.idea/workspace.xml
  8 +/.idea/navEditor.xml
  9 +/.idea/assetWizardSettings.xml
  10 +.DS_Store
  11 +/build
  12 +/captures
  13 +.externalNativeBuild
  14 +.cxx
  15 +local.properties
  1 +plugins {
  2 + id("com.android.application")
  3 + id("org.jetbrains.kotlin.android")
  4 +}
  5 +
  6 +android {
  7 + namespace = "com.k2fsa.sherpa.onnx.audio.tagging.wear.os"
  8 + compileSdk = 34
  9 +
  10 + defaultConfig {
  11 + applicationId = "com.k2fsa.sherpa.onnx.audio.tagging.wear.os"
  12 + minSdk = 26
  13 + targetSdk = 34
  14 + versionCode = 1
  15 + versionName = "1.0"
  16 + vectorDrawables {
  17 + useSupportLibrary = true
  18 + }
  19 +
  20 + }
  21 +
  22 + buildTypes {
  23 + release {
  24 + isMinifyEnabled = false
  25 + proguardFiles(
  26 + getDefaultProguardFile("proguard-android-optimize.txt"),
  27 + "proguard-rules.pro"
  28 + )
  29 + }
  30 + }
  31 + compileOptions {
  32 + sourceCompatibility = JavaVersion.VERSION_1_8
  33 + targetCompatibility = JavaVersion.VERSION_1_8
  34 + }
  35 + kotlinOptions {
  36 + jvmTarget = "1.8"
  37 + }
  38 + buildFeatures {
  39 + compose = true
  40 + }
  41 + composeOptions {
  42 + kotlinCompilerExtensionVersion = "1.5.1"
  43 + }
  44 + packaging {
  45 + resources {
  46 + excludes += "/META-INF/{AL2.0,LGPL2.1}"
  47 + }
  48 + }
  49 +}
  50 +
  51 +dependencies {
  52 +
  53 + implementation("com.google.android.gms:play-services-wearable:18.1.0")
  54 + implementation(platform("androidx.compose:compose-bom:2023.08.00"))
  55 + implementation("androidx.compose.ui:ui")
  56 + implementation("androidx.compose.ui:ui-tooling-preview")
  57 + implementation("androidx.wear.compose:compose-material:1.1.2")
  58 + implementation("androidx.wear.compose:compose-foundation:1.1.2")
  59 + implementation("androidx.activity:activity-compose:1.7.2")
  60 + implementation("androidx.core:core-splashscreen:1.0.1")
  61 + implementation("androidx.compose.material3:material3-android:1.2.1")
  62 + androidTestImplementation(platform("androidx.compose:compose-bom:2023.08.00"))
  63 + androidTestImplementation("androidx.compose.ui:ui-test-junit4")
  64 + debugImplementation("androidx.compose.ui:ui-tooling")
  65 + debugImplementation("androidx.compose.ui:ui-test-manifest")
  66 +}
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<lint>
  3 + <!-- Ignore the IconLocation for the Tile preview images -->
  4 + <issue id="IconLocation">
  5 + <ignore path="res/drawable/tile_preview.png" />
  6 + <ignore path="res/drawable-round/tile_preview.png" />
  7 + </issue>
  8 +</lint>
  1 +# Add project specific ProGuard rules here.
  2 +# You can control the set of applied configuration files using the
  3 +# proguardFiles setting in build.gradle.
  4 +#
  5 +# For more details, see
  6 +# http://developer.android.com/guide/developing/tools/proguard.html
  7 +
  8 +# If your project uses WebView with JS, uncomment the following
  9 +# and specify the fully qualified class name to the JavaScript interface
  10 +# class:
  11 +#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
  12 +# public *;
  13 +#}
  14 +
  15 +# Uncomment this to preserve the line number information for
  16 +# debugging stack traces.
  17 +#-keepattributes SourceFile,LineNumberTable
  18 +
  19 +# If you keep the line number information, uncomment this to
  20 +# hide the original source file name.
  21 +#-renamesourcefileattribute SourceFile
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  3 +
  4 + <uses-permission android:name="android.permission.WAKE_LOCK" />
  5 + <uses-permission android:name="android.permission.RECORD_AUDIO" />
  6 +
  7 + <uses-feature android:name="android.hardware.type.watch" />
  8 +
  9 + <application
  10 + android:allowBackup="true"
  11 + android:icon="@mipmap/ic_launcher"
  12 + android:label="@string/app_name"
  13 + android:supportsRtl="true"
  14 + android:theme="@android:style/Theme.DeviceDefault">
  15 + <uses-library
  16 + android:name="com.google.android.wearable"
  17 + android:required="true" />
  18 +
  19 + <!--
  20 + Set to true if your app is Standalone, that is, it does not require the handheld
  21 + app to run.
  22 + -->
  23 + <meta-data
  24 + android:name="com.google.android.wearable.standalone"
  25 + android:value="true" />
  26 +
  27 + <activity
  28 + android:name=".presentation.MainActivity"
  29 + android:exported="true"
  30 + android:taskAffinity=""
  31 + android:theme="@style/MainActivityTheme.Starting">
  32 + <intent-filter>
  33 + <action android:name="android.intent.action.MAIN" />
  34 +
  35 + <category android:name="android.intent.category.LAUNCHER" />
  36 + </intent-filter>
  37 + </activity>
  38 + </application>
  39 +
  40 +</manifest>
  1 +../../../../../../../../../../../../../../SherpaOnnxAudioTagging/app/src/main/java/com/k2fsa/sherpa/onnx/audio/tagging/AudioTagging.kt
  1 +package com.k2fsa.sherpa.onnx.audio.tagging.wear.os.presentation
  2 +
  3 +import android.Manifest
  4 +import android.app.Activity
  5 +import android.content.pm.PackageManager
  6 +import android.media.AudioFormat
  7 +import android.media.AudioRecord
  8 +import android.media.MediaRecorder
  9 +import android.util.Log
  10 +import androidx.compose.foundation.background
  11 +import androidx.compose.foundation.layout.Arrangement
  12 +import androidx.compose.foundation.layout.Box
  13 +import androidx.compose.foundation.layout.Column
  14 +import androidx.compose.foundation.layout.Row
  15 +import androidx.compose.foundation.layout.Spacer
  16 +import androidx.compose.foundation.layout.fillMaxSize
  17 +import androidx.compose.foundation.layout.fillMaxWidth
  18 +import androidx.compose.foundation.layout.height
  19 +import androidx.compose.material3.Slider
  20 +import androidx.compose.runtime.Composable
  21 +import androidx.compose.runtime.getValue
  22 +import androidx.compose.runtime.mutableStateOf
  23 +import androidx.compose.runtime.remember
  24 +import androidx.compose.runtime.setValue
  25 +import androidx.compose.ui.Alignment
  26 +import androidx.compose.ui.Modifier
  27 +import androidx.compose.ui.platform.LocalContext
  28 +import androidx.compose.ui.text.style.TextAlign
  29 +import androidx.compose.ui.unit.dp
  30 +import androidx.compose.ui.unit.sp
  31 +import androidx.core.app.ActivityCompat
  32 +import androidx.wear.compose.material.Button
  33 +import androidx.wear.compose.material.MaterialTheme
  34 +import androidx.wear.compose.material.Text
  35 +import com.k2fsa.sherpa.onnx.AudioEvent
  36 +import com.k2fsa.sherpa.onnx.audio.tagging.Tagger
  37 +import com.k2fsa.sherpa.onnx.audio.tagging.wear.os.presentation.theme.SherpaOnnxAudioTaggingWearOsTheme
  38 +import kotlin.concurrent.thread
  39 +
  40 +private var audioRecord: AudioRecord? = null
  41 +private val sampleRateInHz = 16000
  42 +
  43 +@Composable
  44 +fun HomeScreen() {
  45 + val activity = LocalContext.current as Activity
  46 + var threshold by remember { mutableStateOf<Float>(0.6F) }
  47 + var firstTime by remember { mutableStateOf(true) }
  48 + var isStarted by remember { mutableStateOf(false) }
  49 + var result by remember { mutableStateOf("") }
  50 + val onButtonClick: () -> Unit = {
  51 + firstTime = false
  52 +
  53 + isStarted = !isStarted
  54 + if (isStarted) {
  55 + result = ""
  56 + if (ActivityCompat.checkSelfPermission(
  57 + activity,
  58 + Manifest.permission.RECORD_AUDIO
  59 + ) != PackageManager.PERMISSION_GRANTED
  60 + ) {
  61 + Log.i(TAG, "Recording is not allowed")
  62 + } else {
  63 + val audioSource = MediaRecorder.AudioSource.MIC
  64 + val channelConfig = AudioFormat.CHANNEL_IN_MONO
  65 + val audioFormat = AudioFormat.ENCODING_PCM_16BIT
  66 + val numBytes =
  67 + AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
  68 +
  69 + audioRecord = AudioRecord(
  70 + audioSource,
  71 + sampleRateInHz,
  72 + AudioFormat.CHANNEL_IN_MONO,
  73 + AudioFormat.ENCODING_PCM_16BIT,
  74 + numBytes * 2 // a sample has two bytes as we are using 16-bit PCM
  75 + )
  76 +
  77 + thread(true) {
  78 + Log.i(TAG, "processing samples")
  79 + val interval = 0.1 // i.e., 100 ms
  80 + val bufferSize = (interval * sampleRateInHz).toInt() // in samples
  81 + val buffer = ShortArray(bufferSize)
  82 + val sampleList = ArrayList<FloatArray>()
  83 + audioRecord?.let {
  84 + it.startRecording()
  85 + while (isStarted) {
  86 + val ret = it.read(buffer, 0, buffer.size)
  87 + ret.let { n ->
  88 + val samples = FloatArray(n) { buffer[it] / 32768.0f }
  89 + sampleList.add(samples)
  90 + }
  91 + }
  92 + }
  93 + Log.i(TAG, "Stop recording")
  94 + Log.i(TAG, "Start recognition")
  95 + val samples = Flatten(sampleList)
  96 + val stream = Tagger.tagger.createStream()
  97 + stream.acceptWaveform(samples, sampleRateInHz)
  98 + val events = Tagger.tagger.compute(stream)
  99 + stream.release()
  100 +
  101 + var str: String = ""
  102 + for (e in events) {
  103 + if (e.prob > threshold) {
  104 + str += "%s (%.2f)\n".format(e.name, e.prob)
  105 + }
  106 + }
  107 + result = str
  108 + }
  109 + }
  110 + }
  111 + }
  112 +
  113 +
  114 + SherpaOnnxAudioTaggingWearOsTheme {
  115 + Box(
  116 + modifier = Modifier
  117 + .fillMaxSize()
  118 + .background(MaterialTheme.colors.background),
  119 + contentAlignment = Alignment.Center
  120 + ) {
  121 + Column(
  122 + horizontalAlignment = Alignment.CenterHorizontally
  123 + ) {
  124 + Spacer(modifier = Modifier.height(16.dp))
  125 + if (firstTime) {
  126 + ShowMessage()
  127 + }
  128 +
  129 + Spacer(modifier = Modifier.height(16.dp))
  130 + Text(
  131 + result,
  132 + fontSize = 12.sp,
  133 + )
  134 +
  135 + Text(
  136 + "Threshold " + String.format("%.1f", threshold),
  137 + fontSize = 12.sp
  138 + )
  139 + Slider(
  140 + value = threshold,
  141 + onValueChange = { threshold = it },
  142 + valueRange = 0.1F..1.0F,
  143 + modifier = Modifier.fillMaxWidth()
  144 + )
  145 + Button(
  146 + onClick = onButtonClick,
  147 + ) {
  148 + if (isStarted) {
  149 + Text("Stop")
  150 + } else {
  151 + Text("Start")
  152 + }
  153 + }
  154 + }
  155 + }
  156 + }
  157 +}
  158 +
  159 +@Composable
  160 +fun ShowMessage() {
  161 + val msg = "Audio tagging\nwith\nNext-gen Kaldi"
  162 + Text(
  163 + modifier = Modifier.fillMaxWidth(),
  164 + textAlign = TextAlign.Center,
  165 + color = MaterialTheme.colors.primary,
  166 + text = msg,
  167 + )
  168 +}
  169 +
  170 +@Composable
  171 +fun ViewRow(
  172 + modifier: Modifier = Modifier,
  173 + event: AudioEvent
  174 +) {
  175 + Row(
  176 + modifier = modifier,
  177 + horizontalArrangement = Arrangement.Center,
  178 + verticalAlignment = Alignment.CenterVertically,
  179 + ) {
  180 + Text(
  181 + text = event.name,
  182 + modifier = modifier.weight(1.0F),
  183 + )
  184 + Text(
  185 + text = "%.2f".format(event.prob),
  186 + modifier = modifier.weight(1.0F),
  187 + )
  188 + }
  189 +
  190 +}
  191 +
  192 +
  193 +fun Flatten(sampleList: ArrayList<FloatArray>): FloatArray {
  194 + var totalSamples = 0
  195 + for (a in sampleList) {
  196 + totalSamples += a.size
  197 + }
  198 + var i = 0
  199 + val samples = FloatArray(totalSamples)
  200 + for (a in sampleList) {
  201 + for (s in a) {
  202 + samples[i] = s
  203 + i += 1
  204 + }
  205 + }
  206 + Log.i(TAG, "$i, $totalSamples")
  207 +
  208 + return samples
  209 +}
  1 +/* While this template provides a good starting point for using Wear Compose, you can always
  2 + * take a look at https://github.com/android/wear-os-samples/tree/main/ComposeStarter and
  3 + * https://github.com/android/wear-os-samples/tree/main/ComposeAdvanced to find the most up to date
  4 + * changes to the libraries and their usages.
  5 + */
  6 +
  7 +package com.k2fsa.sherpa.onnx.audio.tagging.wear.os.presentation
  8 +
  9 +import android.Manifest
  10 +import android.content.pm.PackageManager
  11 +import android.os.Bundle
  12 +import android.util.Log
  13 +import android.view.WindowManager
  14 +import android.widget.Toast
  15 +import androidx.activity.ComponentActivity
  16 +import androidx.activity.compose.setContent
  17 +import androidx.compose.runtime.Composable
  18 +import androidx.core.app.ActivityCompat
  19 +import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
  20 +import com.k2fsa.sherpa.onnx.audio.tagging.Tagger
  21 +
  22 +const val TAG = "sherpa-onnx"
  23 +private const val REQUEST_RECORD_AUDIO_PERMISSION = 200
  24 +
  25 +class MainActivity : ComponentActivity() {
  26 + private val permissions: Array<String> = arrayOf(Manifest.permission.RECORD_AUDIO)
  27 + override fun onCreate(savedInstanceState: Bundle?) {
  28 + installSplashScreen()
  29 +
  30 + super.onCreate(savedInstanceState)
  31 +
  32 + // Keep the screen always on
  33 + // https://developer.android.com/develop/background-work/background-tasks/scheduling/wakelock
  34 + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
  35 +
  36 + setTheme(android.R.style.Theme_DeviceDefault)
  37 +
  38 + setContent {
  39 + WearApp()
  40 + }
  41 +
  42 + ActivityCompat.requestPermissions(this, permissions, REQUEST_RECORD_AUDIO_PERMISSION)
  43 + Tagger.initTagger(this.assets, numThreads = 2)
  44 + }
  45 +
  46 + @Suppress("DEPRECATION")
  47 + override fun onRequestPermissionsResult(
  48 + requestCode: Int,
  49 + permissions: Array<out String>,
  50 + grantResults: IntArray
  51 + ) {
  52 + super.onRequestPermissionsResult(requestCode, permissions, grantResults)
  53 + val permissionToRecordAccepted = if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
  54 + grantResults[0] == PackageManager.PERMISSION_GRANTED
  55 + } else {
  56 + false
  57 + }
  58 +
  59 + if (!permissionToRecordAccepted) {
  60 + Log.e(TAG, "Audio record is disallowed")
  61 + Toast.makeText(
  62 + this,
  63 + "This App needs access to the microphone",
  64 + Toast.LENGTH_SHORT
  65 + )
  66 + .show()
  67 + finish()
  68 + }
  69 + Log.i(TAG, "Audio record is permitted")
  70 + }
  71 +}
  72 +
  73 +@Composable
  74 +fun WearApp() {
  75 + HomeScreen()
  76 +}
  1 +../../../../../../../../../../../../../../SherpaOnnxAudioTagging/app/src/main/java/com/k2fsa/sherpa/onnx/audio/tagging/OfflineStream.kt
  1 +../../../../../../../../../../../../../../SherpaOnnxAudioTagging/app/src/main/java/com/k2fsa/sherpa/onnx/audio/tagging/Tagger.kt
  1 +package com.k2fsa.sherpa.onnx.audio.tagging.wear.os.presentation.theme
  2 +
  3 +import androidx.compose.runtime.Composable
  4 +import androidx.wear.compose.material.MaterialTheme
  5 +
  6 +@Composable
  7 +fun SherpaOnnxAudioTaggingWearOsTheme(
  8 + content: @Composable () -> Unit
  9 +) {
  10 + /**
  11 + * Empty theme to customize for your app.
  12 + * See: https://developer.android.com/jetpack/compose/designsystems/custom
  13 + */
  14 + MaterialTheme(
  15 + content = content
  16 + )
  17 +}
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +
  3 +<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  4 + <item
  5 + android:width="48dp"
  6 + android:height="48dp"
  7 + android:gravity="center">
  8 + <shape android:shape="oval">
  9 + <solid android:color="#FFFFFF" />
  10 + </shape>
  11 + </item>
  12 + <item
  13 + android:width="40dp"
  14 + android:height="40dp"
  15 + android:gravity="center">
  16 + <vector
  17 + android:width="24dp"
  18 + android:height="24dp"
  19 + android:tint="#000000"
  20 + android:viewportWidth="24"
  21 + android:viewportHeight="24">
  22 + <path
  23 + android:fillColor="#FF000000"
  24 + android:pathData="M17.6,11.48 L19.44,8.3a0.63,0.63 0,0 0,-1.09 -0.63l-1.88,3.24a11.43,11.43 0,0 0,-8.94 0L5.65,7.67a0.63,0.63 0,0 0,-1.09 0.63L6.4,11.48A10.81,10.81 0,0 0,1 20L23,20A10.81,10.81 0,0 0,17.6 11.48ZM7,17.25A1.25,1.25 0,1 1,8.25 16,1.25 1.25,0 0,1 7,17.25ZM17,17.25A1.25,1.25 0,1 1,18.25 16,1.25 1.25,0 0,1 17,17.25Z" />
  25 + </vector>
  26 + </item>
  27 +</layer-list>
  1 +<resources>
  2 + <string name="hello_world">From the Round world,\nHello, %1$s!</string>
  3 +</resources>
  1 +<resources>
  2 + <string name="app_name">AudioTagging</string>
  3 + <!--
  4 + This string is used for square devices and overridden by hello_world in
  5 + values-round/strings.xml for round devices.
  6 + -->
  7 + <string name="hello_world">From the Square world,\nHello, %1$s!</string>
  8 +</resources>
  1 +<resources>
  2 +
  3 + <style name="MainActivityTheme.Starting" parent="Theme.SplashScreen">
  4 + <item name="windowSplashScreenBackground">@android:color/black</item>
  5 + <item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
  6 + <item name="postSplashScreenTheme">@android:style/Theme.DeviceDefault</item>
  7 + </style>
  8 +</resources>
  1 +// Top-level build file where you can add configuration options common to all sub-projects/modules.
  2 +plugins {
  3 + id("com.android.application") version "8.2.0" apply false
  4 + id("org.jetbrains.kotlin.android") version "1.9.0" apply false
  5 +}
  1 +# Project-wide Gradle settings.
  2 +# IDE (e.g. Android Studio) users:
  3 +# Gradle settings configured through the IDE *will override*
  4 +# any settings specified in this file.
  5 +# For more details on how to configure your build environment visit
  6 +# http://www.gradle.org/docs/current/userguide/build_environment.html
  7 +# Specifies the JVM arguments used for the daemon process.
  8 +# The setting is particularly useful for tweaking memory settings.
  9 +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
  10 +# When configured, Gradle will run in incubating parallel mode.
  11 +# This option should only be used with decoupled projects. More details, visit
  12 +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
  13 +# org.gradle.parallel=true
  14 +# AndroidX package structure to make it clearer which packages are bundled with the
  15 +# Android operating system, and which are packaged with your app's APK
  16 +# https://developer.android.com/topic/libraries/support-library/androidx-rn
  17 +android.useAndroidX=true
  18 +# Kotlin code style for this project: "official" or "obsolete":
  19 +kotlin.code.style=official
  20 +# Enables namespacing of each library's R class so that its R class includes only the
  21 +# resources declared in the library itself and none from the library's dependencies,
  22 +# thereby reducing the size of the R class for that library
  23 +android.nonTransitiveRClass=true
  1 +#Tue Apr 16 20:57:10 CST 2024
  2 +distributionBase=GRADLE_USER_HOME
  3 +distributionPath=wrapper/dists
  4 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
  5 +zipStoreBase=GRADLE_USER_HOME
  6 +zipStorePath=wrapper/dists
  1 +#!/usr/bin/env sh
  2 +
  3 +#
  4 +# Copyright 2015 the original author or authors.
  5 +#
  6 +# Licensed under the Apache License, Version 2.0 (the "License");
  7 +# you may not use this file except in compliance with the License.
  8 +# You may obtain a copy of the License at
  9 +#
  10 +# https://www.apache.org/licenses/LICENSE-2.0
  11 +#
  12 +# Unless required by applicable law or agreed to in writing, software
  13 +# distributed under the License is distributed on an "AS IS" BASIS,
  14 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +# See the License for the specific language governing permissions and
  16 +# limitations under the License.
  17 +#
  18 +
  19 +##############################################################################
  20 +##
  21 +## Gradle start up script for UN*X
  22 +##
  23 +##############################################################################
  24 +
  25 +# Attempt to set APP_HOME
  26 +# Resolve links: $0 may be a link
  27 +PRG="$0"
  28 +# Need this for relative symlinks.
  29 +while [ -h "$PRG" ] ; do
  30 + ls=`ls -ld "$PRG"`
  31 + link=`expr "$ls" : '.*-> \(.*\)$'`
  32 + if expr "$link" : '/.*' > /dev/null; then
  33 + PRG="$link"
  34 + else
  35 + PRG=`dirname "$PRG"`"/$link"
  36 + fi
  37 +done
  38 +SAVED="`pwd`"
  39 +cd "`dirname \"$PRG\"`/" >/dev/null
  40 +APP_HOME="`pwd -P`"
  41 +cd "$SAVED" >/dev/null
  42 +
  43 +APP_NAME="Gradle"
  44 +APP_BASE_NAME=`basename "$0"`
  45 +
  46 +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
  47 +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
  48 +
  49 +# Use the maximum available, or set MAX_FD != -1 to use that value.
  50 +MAX_FD="maximum"
  51 +
  52 +warn () {
  53 + echo "$*"
  54 +}
  55 +
  56 +die () {
  57 + echo
  58 + echo "$*"
  59 + echo
  60 + exit 1
  61 +}
  62 +
  63 +# OS specific support (must be 'true' or 'false').
  64 +cygwin=false
  65 +msys=false
  66 +darwin=false
  67 +nonstop=false
  68 +case "`uname`" in
  69 + CYGWIN* )
  70 + cygwin=true
  71 + ;;
  72 + Darwin* )
  73 + darwin=true
  74 + ;;
  75 + MINGW* )
  76 + msys=true
  77 + ;;
  78 + NONSTOP* )
  79 + nonstop=true
  80 + ;;
  81 +esac
  82 +
  83 +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
  84 +
  85 +
  86 +# Determine the Java command to use to start the JVM.
  87 +if [ -n "$JAVA_HOME" ] ; then
  88 + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
  89 + # IBM's JDK on AIX uses strange locations for the executables
  90 + JAVACMD="$JAVA_HOME/jre/sh/java"
  91 + else
  92 + JAVACMD="$JAVA_HOME/bin/java"
  93 + fi
  94 + if [ ! -x "$JAVACMD" ] ; then
  95 + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
  96 +
  97 +Please set the JAVA_HOME variable in your environment to match the
  98 +location of your Java installation."
  99 + fi
  100 +else
  101 + JAVACMD="java"
  102 + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
  103 +
  104 +Please set the JAVA_HOME variable in your environment to match the
  105 +location of your Java installation."
  106 +fi
  107 +
  108 +# Increase the maximum file descriptors if we can.
  109 +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
  110 + MAX_FD_LIMIT=`ulimit -H -n`
  111 + if [ $? -eq 0 ] ; then
  112 + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
  113 + MAX_FD="$MAX_FD_LIMIT"
  114 + fi
  115 + ulimit -n $MAX_FD
  116 + if [ $? -ne 0 ] ; then
  117 + warn "Could not set maximum file descriptor limit: $MAX_FD"
  118 + fi
  119 + else
  120 + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
  121 + fi
  122 +fi
  123 +
  124 +# For Darwin, add options to specify how the application appears in the dock
  125 +if $darwin; then
  126 + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
  127 +fi
  128 +
  129 +# For Cygwin or MSYS, switch paths to Windows format before running java
  130 +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
  131 + APP_HOME=`cygpath --path --mixed "$APP_HOME"`
  132 + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
  133 +
  134 + JAVACMD=`cygpath --unix "$JAVACMD"`
  135 +
  136 + # We build the pattern for arguments to be converted via cygpath
  137 + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
  138 + SEP=""
  139 + for dir in $ROOTDIRSRAW ; do
  140 + ROOTDIRS="$ROOTDIRS$SEP$dir"
  141 + SEP="|"
  142 + done
  143 + OURCYGPATTERN="(^($ROOTDIRS))"
  144 + # Add a user-defined pattern to the cygpath arguments
  145 + if [ "$GRADLE_CYGPATTERN" != "" ] ; then
  146 + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
  147 + fi
  148 + # Now convert the arguments - kludge to limit ourselves to /bin/sh
  149 + i=0
  150 + for arg in "$@" ; do
  151 + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
  152 + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
  153 +
  154 + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
  155 + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
  156 + else
  157 + eval `echo args$i`="\"$arg\""
  158 + fi
  159 + i=`expr $i + 1`
  160 + done
  161 + case $i in
  162 + 0) set -- ;;
  163 + 1) set -- "$args0" ;;
  164 + 2) set -- "$args0" "$args1" ;;
  165 + 3) set -- "$args0" "$args1" "$args2" ;;
  166 + 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
  167 + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
  168 + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
  169 + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
  170 + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
  171 + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
  172 + esac
  173 +fi
  174 +
  175 +# Escape application args
  176 +save () {
  177 + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
  178 + echo " "
  179 +}
  180 +APP_ARGS=`save "$@"`
  181 +
  182 +# Collect all arguments for the java command, following the shell quoting and substitution rules
  183 +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
  184 +
  185 +exec "$JAVACMD" "$@"
  1 +@rem
  2 +@rem Copyright 2015 the original author or authors.
  3 +@rem
  4 +@rem Licensed under the Apache License, Version 2.0 (the "License");
  5 +@rem you may not use this file except in compliance with the License.
  6 +@rem You may obtain a copy of the License at
  7 +@rem
  8 +@rem https://www.apache.org/licenses/LICENSE-2.0
  9 +@rem
  10 +@rem Unless required by applicable law or agreed to in writing, software
  11 +@rem distributed under the License is distributed on an "AS IS" BASIS,
  12 +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 +@rem See the License for the specific language governing permissions and
  14 +@rem limitations under the License.
  15 +@rem
  16 +
  17 +@if "%DEBUG%" == "" @echo off
  18 +@rem ##########################################################################
  19 +@rem
  20 +@rem Gradle startup script for Windows
  21 +@rem
  22 +@rem ##########################################################################
  23 +
  24 +@rem Set local scope for the variables with windows NT shell
  25 +if "%OS%"=="Windows_NT" setlocal
  26 +
  27 +set DIRNAME=%~dp0
  28 +if "%DIRNAME%" == "" set DIRNAME=.
  29 +set APP_BASE_NAME=%~n0
  30 +set APP_HOME=%DIRNAME%
  31 +
  32 +@rem Resolve any "." and ".." in APP_HOME to make it shorter.
  33 +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
  34 +
  35 +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
  36 +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
  37 +
  38 +@rem Find java.exe
  39 +if defined JAVA_HOME goto findJavaFromJavaHome
  40 +
  41 +set JAVA_EXE=java.exe
  42 +%JAVA_EXE% -version >NUL 2>&1
  43 +if "%ERRORLEVEL%" == "0" goto execute
  44 +
  45 +echo.
  46 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
  47 +echo.
  48 +echo Please set the JAVA_HOME variable in your environment to match the
  49 +echo location of your Java installation.
  50 +
  51 +goto fail
  52 +
  53 +:findJavaFromJavaHome
  54 +set JAVA_HOME=%JAVA_HOME:"=%
  55 +set JAVA_EXE=%JAVA_HOME%/bin/java.exe
  56 +
  57 +if exist "%JAVA_EXE%" goto execute
  58 +
  59 +echo.
  60 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
  61 +echo.
  62 +echo Please set the JAVA_HOME variable in your environment to match the
  63 +echo location of your Java installation.
  64 +
  65 +goto fail
  66 +
  67 +:execute
  68 +@rem Setup the command line
  69 +
  70 +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
  71 +
  72 +
  73 +@rem Execute Gradle
  74 +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
  75 +
  76 +:end
  77 +@rem End local scope for the variables with windows NT shell
  78 +if "%ERRORLEVEL%"=="0" goto mainEnd
  79 +
  80 +:fail
  81 +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
  82 +rem the _cmd.exe /c_ return code!
  83 +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
  84 +exit /b 1
  85 +
  86 +:mainEnd
  87 +if "%OS%"=="Windows_NT" endlocal
  88 +
  89 +:omega
  1 +pluginManagement {
  2 + repositories {
  3 + google()
  4 + mavenCentral()
  5 + gradlePluginPortal()
  6 + }
  7 +}
  8 +dependencyResolutionManagement {
  9 + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
  10 + repositories {
  11 + google()
  12 + mavenCentral()
  13 + }
  14 +}
  15 +
  16 +rootProject.name = "SherpaOnnxAudioTaggingWearOs"
  17 +include(":app")
  18 +
@@ -183,7 +183,7 @@ we use [sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18](https://github.com @@ -183,7 +183,7 @@ we use [sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18](https://github.com
183 You can use the following command to run it: 183 You can use the following command to run it:
184 184
185 ```bash 185 ```bash
186 -wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18.tar.bz2 186 +wget -q https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18.tar.bz2
187 tar xvf sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18.tar.bz2 187 tar xvf sherpa-onnx-streaming-zipformer-ctc-small-2024-03-18.tar.bz2
188 node ./test-online-zipformer2-ctc-hlg.js 188 node ./test-online-zipformer2-ctc-hlg.js
189 ``` 189 ```
  1 +#!/usr/bin/env bash
  2 +#
  3 +# Auto generated! Please DO NOT EDIT!
  4 +
  5 +# Please set the environment variable ANDROID_NDK
  6 +# before running this script
  7 +
  8 +# Inside the $ANDROID_NDK directory, you can find a binary ndk-build
  9 +# and some other files like the file "build/cmake/android.toolchain.cmake"
  10 +
  11 +set -ex
  12 +
  13 +log() {
  14 + # This function is from espnet
  15 + local fname=${BASH_SOURCE[1]##*/}
  16 + echo -e "$(date '+%Y-%m-%d %H:%M:%S') (${fname}:${BASH_LINENO[0]}:${FUNCNAME[1]}) $*"
  17 +}
  18 +
  19 +SHERPA_ONNX_VERSION=$(grep "SHERPA_ONNX_VERSION" ./CMakeLists.txt | cut -d " " -f 2 | cut -d '"' -f 2)
  20 +
  21 +log "Building audio tagging WearOS APK for sherpa-onnx v${SHERPA_ONNX_VERSION}"
  22 +
  23 +log "====================arm64-v8a================="
  24 +./build-android-arm64-v8a.sh
  25 +log "====================armv7-eabi================"
  26 +./build-android-armv7-eabi.sh
  27 +log "====================x86-64===================="
  28 +./build-android-x86-64.sh
  29 +log "====================x86===================="
  30 +./build-android-x86.sh
  31 +
  32 +mkdir -p apks
  33 +
  34 +{% for model in model_list %}
  35 +pushd ./android/SherpaOnnxAudioTaggingWearOs/app/src/main/assets/
  36 +model_name={{ model.model_name }}
  37 +short_name={{ model.short_name }}
  38 +type={{ model.idx }}
  39 +
  40 +curl -SL -O https://github.com/k2-fsa/sherpa-onnx/releases/download/audio-tagging-models/${model_name}.tar.bz2
  41 +tar xvf ${model_name}.tar.bz2
  42 +rm -rfv $model_name/model.onnx
  43 +rm -rfv $model_name/test_wavs
  44 +rm -rf *.tar.bz2
  45 +ls -lh $model_name
  46 +
  47 +popd
  48 +# Now we are at the project root directory
  49 +
  50 +git checkout .
  51 +# Tagger.kt is a symlink file, so we use SherpaOnnxAudioTagging here instead of SherpaOnnxAudioTaggingWearOs
  52 +pushd android/SherpaOnnxAudioTagging/app/src/main/java/com/k2fsa/sherpa/onnx/audio/tagging/
  53 +sed -i.bak s/"type = 0/type = $type/" ./Tagger.kt
  54 +git diff
  55 +popd
  56 +
  57 +for arch in arm64-v8a armeabi-v7a x86_64 x86; do
  58 + log "------------------------------------------------------------"
  59 + log "build audio tagging apk for $arch"
  60 + log "------------------------------------------------------------"
  61 + src_arch=$arch
  62 + if [ $arch == "armeabi-v7a" ]; then
  63 + src_arch=armv7-eabi
  64 + elif [ $arch == "x86_64" ]; then
  65 + src_arch=x86-64
  66 + fi
  67 +
  68 + ls -lh ./build-android-$src_arch/install/lib/*.so
  69 +
  70 + cp -v ./build-android-$src_arch/install/lib/*.so ./android/SherpaOnnxAudioTaggingWearOs/app/src/main/jniLibs/$arch/
  71 +
  72 + pushd ./android/SherpaOnnxAudioTaggingWearOs
  73 + sed -i.bak s/2048/9012/g ./gradle.properties
  74 + git diff ./gradle.properties
  75 + ./gradlew assembleRelease
  76 + popd
  77 +
  78 + mv android/SherpaOnnxAudioTaggingWearOs/app/build/outputs/apk/release/app-release-unsigned.apk ./apks/sherpa-onnx-${SHERPA_ONNX_VERSION}-$arch-audio-tagging-$short_name-wearos.apk
  79 + ls -lh apks
  80 + rm -v ./android/SherpaOnnxAudioTaggingWearOs/app/src/main/jniLibs/$arch/*.so
  81 +done
  82 +
  83 +rm -rf ./android/SherpaOnnxAudioTaggingWearOs/app/src/main/assets/$model_name
  84 +{% endfor %}
  85 +
  86 +git checkout .
  87 +
  88 +ls -lh apks/
@@ -77,7 +77,10 @@ def main(): @@ -77,7 +77,10 @@ def main():
77 d["model_list"].append(all_model_list[s]) 77 d["model_list"].append(all_model_list[s])
78 print(f"{s}/{num_models}") 78 print(f"{s}/{num_models}")
79 79
80 - filename_list = ["./build-apk-audio-tagging.sh"] 80 + filename_list = [
  81 + "./build-apk-audio-tagging.sh",
  82 + "./build-apk-audio-tagging-wearos.sh",
  83 + ]
81 for filename in filename_list: 84 for filename in filename_list:
82 environment = jinja2.Environment() 85 environment = jinja2.Environment()
83 with open(f"{filename}.in") as f: 86 with open(f"{filename}.in") as f:
@@ -40,8 +40,8 @@ def process_linux(s): @@ -40,8 +40,8 @@ def process_linux(s):
40 "libpiper_phonemize.so.1", 40 "libpiper_phonemize.so.1",
41 "libsherpa-onnx-c-api.so", 41 "libsherpa-onnx-c-api.so",
42 "libsherpa-onnx-core.so", 42 "libsherpa-onnx-core.so",
43 - "libsherpa-onnx-fstfar.so.16",  
44 - "libsherpa-onnx-fst.so.16", 43 + "libsherpa-onnx-fstfar.so.7",
  44 + "libsherpa-onnx-fst.so.6",
45 "libsherpa-onnx-kaldifst-core.so", 45 "libsherpa-onnx-kaldifst-core.so",
46 "libucd.so", 46 "libucd.so",
47 ] 47 ]
@@ -69,8 +69,8 @@ def process_macos(s): @@ -69,8 +69,8 @@ def process_macos(s):
69 "libpiper_phonemize.1.dylib", 69 "libpiper_phonemize.1.dylib",
70 "libsherpa-onnx-c-api.dylib", 70 "libsherpa-onnx-c-api.dylib",
71 "libsherpa-onnx-core.dylib", 71 "libsherpa-onnx-core.dylib",
72 - "libsherpa-onnx-fstfar.16.dylib",  
73 - "libsherpa-onnx-fst.16.dylib", 72 + "libsherpa-onnx-fstfar.7.dylib",
  73 + "libsherpa-onnx-fst.6.dylib",
74 "libsherpa-onnx-kaldifst-core.dylib", 74 "libsherpa-onnx-kaldifst-core.dylib",
75 "libucd.dylib", 75 "libucd.dylib",
76 ] 76 ]
@@ -47,7 +47,7 @@ assets fangjun$ tree -L 1 @@ -47,7 +47,7 @@ assets fangjun$ tree -L 1
47 ## Paraformer 47 ## Paraformer
48 48
49 ``` 49 ```
50 -wget https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 50 +wget -q https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
51 tar xvf sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 51 tar xvf sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
52 rm sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2 52 rm sherpa-onnx-streaming-paraformer-bilingual-zh-en.tar.bz2
53 53