Compare commits

..

221 Commits

Author SHA1 Message Date
Nickolay Shmyrev acadb5b4c2 Add optimization 2021-01-07 23:41:13 +01:00
Nickolay Shmyrev 2e1de6c3af No need for python 3.5 anymore 2021-01-07 23:20:54 +01:00
Nickolay Shmyrev 67de30908b Use openblas_clapack 2021-01-07 22:37:56 +01:00
Nickolay Shmyrev 9d398eff0e Remove armv6, too slow anyway. Build with new dockcross. 2021-01-06 16:26:23 +01:00
Nickolay Shmyrev 02b7312a00 Build with openblas-clapack to avoid fortran 2021-01-06 01:11:03 +01:00
Nickolay Shmyrev 08c35e84f3 Update demo with spk vector check 2020-12-23 22:21:12 +01:00
Nickolay Shmyrev b92a5c1fc7 Update wheels to openfst 1.8.0 2020-12-22 23:27:01 +01:00
Nickolay Shmyrev 8997a587c5 Fix warnings in preparation for openfst 1.8.0 2020-12-22 21:16:20 +01:00
Nickolay Shmyrev dc3d03d742 Make sure we have result field in json 2020-11-29 19:19:50 +01:00
Nickolay Shmyrev 84df40715c Add Filipino 2020-11-19 14:53:46 +01:00
Nickolay Shmyrev b639fb501a Package US model on bintray 2020-11-04 22:08:03 +01:00
Nickolay Shmyrev 746ff47757 Split long lines in subtitles 2020-11-03 15:13:16 +01:00
Nickolay Shmyrev 2d62db8118 Update link in readme 2020-10-31 10:03:25 +01:00
Nickolay Shmyrev 7a2adcd9ba Add nuget wraps 2020-10-26 15:57:40 +01:00
Nickolay Shmyrev 9ccf3ef0e8 Introduce CMVN in feature pipeline 2020-10-22 23:56:36 +02:00
Nickolay V. Shmyrev 0edab6d558 Merge pull request #259 from ThThoma/add-valid-word-check
add isWordRecognizable()
2020-10-22 15:53:04 +03:00
Athanasios Thoma 4b344f0cd8 rename 2020-10-22 14:09:50 +03:00
Athanasios Thoma 17ddc4d5ba add isWordRecognizable() 2020-10-21 10:00:39 +03:00
Nickolay Shmyrev 3e33860c47 Update to latest 0.3.15 changes 2020-10-20 23:50:39 +03:00
Nickolay Shmyrev 0269a10833 Critical ivector bugfix and version 0.3.15 2020-10-13 01:28:46 +02:00
Nickolay Shmyrev 7af3e9a334 Add srt example 2020-10-07 13:43:09 +02:00
Nickolay Shmyrev d666876be1 Revert compile flags 2020-10-05 01:24:32 +02:00
Nickolay Shmyrev 564fab7ec1 Update documentation 2020-10-05 00:16:15 +02:00
Nickolay Shmyrev 155c6c2a2a Don't crash with grammar and static graphs 2020-10-05 00:13:25 +02:00
Nickolay Shmyrev d43cbe9344 Add 0.3.14 2020-10-04 23:45:34 +02:00
Nickolay Shmyrev 57cc474c9f Build bigram language model from grammars 2020-10-04 23:42:50 +02:00
Nickolay Shmyrev 586603f8e1 Add Farsi 2020-10-03 12:42:54 +02:00
Nickolay Shmyrev d57887d22a Add Greek 2020-09-30 13:42:20 +02:00
Nickolay Shmyrev 6183bcfc5f Add Arabic model 2020-09-30 13:29:43 +02:00
Nickolay Shmyrev 65f6113b4d Add Catalan 2020-09-27 11:57:20 +02:00
Nickolay Shmyrev 8d88b89db1 Fix reserved identifier violation. Closes issue #226
Thanks to Markus Elfring
2020-09-23 21:16:34 +02:00
Nickolay Shmyrev 62885e8963 Update descriptions 2020-09-22 11:30:27 +02:00
qo6xup6 9fc094a5da Update kaldi_recognizer.h 2020-09-22 10:11:29 +08:00
Nickolay Shmyrev f97383c17f Update models location 2020-09-22 00:00:24 +02:00
Nickolay Shmyrev 4b892ec5e7 Bump version 2020-09-21 23:49:55 +02:00
Nickolay Shmyrev 41035485db Fix x-vectors, now they actually work. Requires new version spk-model-0.4 with whitening transform matrix 2020-09-21 23:31:30 +02:00
Nickolay Shmyrev 9696f4c917 Mention Dutch 2020-09-18 17:31:17 +02:00
Nickolay Shmyrev 55abf5f5ac Dynamic arch in pip module 2020-09-13 22:08:36 +02:00
Nickolay Shmyrev a1b2e41710 Mention we support Indian English 2020-09-09 23:28:55 +02:00
Nickolay Shmyrev dff4ab26e4 Library is now vosk_jni 2020-09-01 18:27:54 +02:00
Nickolay Shmyrev 83b6e1cdf7 Speech service for more flexible recognizer initialization
Publish repo on jcenter
2020-09-01 16:32:15 +02:00
Nickolay Shmyrev 38dbaa15ea Load JNI inside library itself 2020-09-01 12:44:44 +02:00
Nickolay Shmyrev 0e531b6061 Organize Makefile 2020-08-23 20:10:48 +02:00
Nickolay Shmyrev de94ef5537 Add speaker C demo 2020-08-14 11:33:41 +02:00
Nickolay Shmyrev 6ef9d13877 Add Italian 2020-08-03 01:31:30 +02:00
Nickolay Shmyrev 1c7b94757d Don't attempt to resize to empty matrix 2020-07-31 16:45:05 +02:00
Nickolay Shmyrev 83486e0bef Spk vector fix 2020-07-31 12:58:23 +02:00
Nickolay Shmyrev 9787e8a53f No .html in links 2020-07-21 10:15:27 +02:00
Nickolay Shmyrev f59d6685ad Fix confidences 2020-07-15 10:24:08 +02:00
Nickolay Shmyrev 8a986ef384 Require KALDI_MKL to be 1 2020-07-12 11:03:22 +02:00
Nickolay Shmyrev 78f9f55e14 Fixes description 2020-07-12 10:37:56 +02:00
Nickolay Shmyrev c2e006f664 Some probably helpful flags for npm on osx 2020-07-11 20:54:13 +02:00
Nickolay V. Shmyrev 4b8e9737a5 Update README.md 2020-07-08 01:38:03 +02:00
Nickolay Shmyrev 722b09eaa4 Ignore words missing in the vocabulary 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev f5b4f5a1f2 Added C test 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 4407d8da55 Another timestamp bugfix 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 73b73527cd Release memory when final result is received to reduce memory pressure. 2020-07-08 01:35:50 +02:00
Nickolay Shmyrev 4df0e3a741 Actually show the distance 2020-07-08 01:35:49 +02:00
He1nr1chK 1a771e0172 Added cosine distance function 2020-06-23 20:10:14 +02:00
Nickolay Shmyrev 4333c3c242 Build dockcross with python 3.8 2020-06-23 01:11:07 +02:00
Nickolay V. Shmyrev b831c9ad57 Merge pull request #151 from hviana/patch-1
Add support for speaker model in Android
2020-06-23 00:07:26 +03:00
Nickolay Shmyrev e5c08f7710 Allow to continue after final result. See for discussion
https://github.com/alphacep/vosk-api/issues/146
2020-06-22 23:04:09 +02:00
Henrique Emanoel Viana 51c2968595 fix 2020-06-22 18:01:42 -03:00
Henrique Emanoel Viana 5993376322 Add suport to SpkModel 2020-06-22 17:51:55 -03:00
Nickolay Shmyrev c4281622b9 Added node speaker demo 2020-06-22 21:45:50 +02:00
Nickolay Shmyrev 9d26014de2 Use wider beams by default to avoid accuracy confusion 2020-06-19 16:10:30 +02:00
Nickolay Shmyrev f6c115d215 Update to 0.3.9 and use our fork of openfst based on openfst 1.7.7 2020-06-16 19:13:57 +02:00
Nickolay Shmyrev 6bd102d778 Fixes timing issue #125 2020-06-15 02:04:02 +02:00
Nickolay Shmyrev d3d6af5712 Define os in a single place 2020-06-12 10:35:58 +02:00
Nickolay V. Shmyrev 876093446f Merge pull request #127 from nnkalita/master
added android build support on macOS
2020-06-12 11:32:27 +03:00
Nickolay Shmyrev 336f219f09 No Qr code for wechat anymore 2020-06-11 12:57:32 +02:00
Nickolay Shmyrev 584251cbdc Remove chinese-only 2020-06-11 09:18:34 +02:00
Nickolay Shmyrev a34995a788 Process audio in chunks for imporved accuracy 2020-06-11 01:06:11 +02:00
Nickolay Shmyrev 998e5da227 Update rules for joining wechat 2020-06-10 15:07:10 +02:00
Nickolay Shmyrev e04c15e367 Fix 2020-06-06 11:15:23 +02:00
Nickolay Shmyrev b81f69d407 Avoid overflow. See issue #128 2020-06-06 10:43:44 +02:00
Nickolay Shmyrev 0ac2064281 Few more words 2020-06-06 10:07:12 +02:00
Nickolay Shmyrev 1d00bd244e Multithreaded testing 2020-06-06 00:40:15 +02:00
Nickolay Shmyrev 8f5efc58c9 Disable ivector pipeline without ivectors 2020-06-05 19:34:04 +02:00
Nayan Kalita a0c5ae1b5e Update build-kaldi.sh
added android build from mac.
2020-06-05 20:10:28 +05:30
Nayan Kalita 99f48f9de1 Merge remote-tracking branch 'upstream/master' 2020-06-05 19:15:42 +05:30
Nayan Kalita 1948b23f32 Update build-kaldi.sh
Updated based feedback.
2020-06-05 18:03:01 +05:30
Nickolay Shmyrev c9eb572fc5 Move documentation to our website 2020-06-05 01:31:13 +02:00
Nickolay Shmyrev 7d9895ff81 Add API documentation in the header 2020-06-04 22:47:54 +02:00
Nickolay Shmyrev d507210ef8 Add npmignore and pure javascript package 2020-06-03 17:47:15 +02:00
Nickolay Shmyrev db0a3d23d5 Add repackages librispeech model 2020-06-03 17:24:28 +02:00
Nickolay Shmyrev f4f920f3cd Proper cross-compilation with setuptools 2020-06-02 00:36:16 +02:00
Nickolay Shmyrev 75993ea276 Update to 0.3.8 2020-06-01 00:55:28 +02:00
Nickolay Shmyrev ee9bacb092 Reset pipeline to save memory 2020-06-01 00:54:47 +02:00
Nickolay Shmyrev b1e775c67b Better speaker identification without silence frames 2020-05-31 23:46:42 +02:00
Nickolay Shmyrev d631e567aa Add README 2020-05-31 02:21:07 +02:00
Nickolay Shmyrev 9edf45be42 Sync version 2020-05-31 02:08:35 +02:00
Nickolay Shmyrev 8b4b3c646a Nodejs support 2020-05-31 02:07:01 +02:00
Nickolay Shmyrev 31bb0557d9 Add mkl support 2020-05-30 23:22:14 +02:00
Nickolay Shmyrev 4593183cf9 Create gen if doens't exist. Thanks to BMI24. 2020-05-25 00:32:42 +02:00
Nickolay Shmyrev fdc45f1187 Better link on wechat 2020-05-23 21:13:23 +02:00
Nickolay Shmyrev b3d3c6d12c Fix mistake, thanks to Shaheen 2020-05-23 01:12:31 +02:00
Nickolay Shmyrev f5f0794def Add logo 2020-05-22 15:24:57 +02:00
Nickolay Shmyrev 55664fcca0 Add wechat group 2020-05-22 09:56:54 +02:00
Nickolay Shmyrev afbf330f16 Make ivector extractor optional 2020-05-18 23:56:42 +02:00
Nickolay Shmyrev 25aadf61bc Fix travis 2020-05-09 17:36:55 +02:00
Nickolay Shmyrev be47056467 Updates for osx 2020-05-09 15:49:24 +03:00
Nickolay Shmyrev 8f623e0aea Get rid of broken cmake 2020-05-09 14:32:46 +02:00
Nickolay Shmyrev 78025435e4 Windows is fully supported now 2020-05-09 09:18:10 +02:00
Nickolay Shmyrev 910455802e Don't link to the library explicitely to allow relocations 2020-05-08 15:16:50 +03:00
Nickolay Shmyrev b12914955c Add x86 build 2020-05-08 11:33:25 +02:00
Nickolay Shmyrev dfe11eaf83 Linux build fix 2020-05-08 09:04:14 +02:00
Nickolay Shmyrev 37fbe1a52b OSX build 2020-05-08 09:55:15 +03:00
Nickolay Shmyrev af11bb2361 No need for external dependencies 2020-05-07 21:48:03 +02:00
Nickolay Shmyrev 8da8697c1e Add ffmpeg test 2020-05-07 21:07:17 +02:00
Nickolay V. Shmyrev 944dc87531 Update readme to mention aarch64 2020-05-05 00:55:29 +02:00
Nickolay Shmyrev 5c4dd4644e Update version 2020-05-03 20:52:43 +02:00
Nickolay Shmyrev 9bbd172cfd Some more links 2020-05-02 01:37:10 +02:00
Nickolay Shmyrev dbf9de77c3 Document model training and model structure 2020-05-02 01:11:25 +02:00
Nickolay Shmyrev 8b790cd162 Better android logging 2020-05-01 20:02:46 +02:00
Nickolay Shmyrev 80219066e9 Expose verbose level in the API 2020-05-01 19:02:57 +02:00
Nickolay Shmyrev 26fa5f098f Updated link to English model 2020-04-30 15:19:13 +02:00
Nickolay Shmyrev d75bb36131 Fix model download path 2020-04-30 11:04:35 +02:00
Nickolay Shmyrev 30c5e8ca79 Link to lm library for rescoring 2020-04-30 10:52:15 +02:00
Nickolay Shmyrev c00e36fab6 Rearrange models 2020-04-30 10:47:10 +02:00
Nickolay Shmyrev 80e60b9118 LM Rescoring 2020-04-28 22:17:34 +02:00
Nickolay Shmyrev e3a95a44bc Added Turkish model 2020-04-28 10:10:35 +02:00
Nickolay Shmyrev 86caf526f5 New model layout and model config file with beams for decoding 2020-04-28 01:06:41 +02:00
Nickolay Shmyrev e09f32b4b4 Properly stop listening so it can continue later 2020-04-27 09:00:32 +02:00
Nickolay Shmyrev 3803ab345d Proper reference couting of the models to avoid memory issus 2020-04-23 23:37:52 +02:00
Nickolay V. Shmyrev 889b43136f Update README.zh.md 2020-04-23 12:43:00 +02:00
John Baber-Lucero b517cf46af Fix some grammar/punctuation 2020-04-23 00:28:34 -04:00
Nickolay Shmyrev ffd810fe00 Fix threading bug 2020-04-22 22:15:45 +02:00
Nickolay V. Shmyrev a1a0ed70a1 Update README.zh.md 2020-04-22 18:29:01 +03:00
Nickolay Shmyrev 1554d9ede7 Added per-language readme 2020-04-22 13:21:36 +02:00
Nickolay Shmyrev 6f3190d83d Version 0.3.4 and arm wheels for python 3.6 2020-04-21 11:38:56 +02:00
Nickolay Shmyrev 3caaa32ec0 How to ask for the accuracy updates 2020-04-20 23:11:52 +02:00
Nickolay Shmyrev 3facf3ccf5 UI updates 2020-04-20 11:08:18 +03:00
Nickolay Shmyrev fad954e6e3 Full iOS project 2020-04-19 22:48:47 +03:00
Nickolay Shmyrev c4809cb618 Added Vietnamese model 2020-04-19 20:14:05 +02:00
Nickolay Shmyrev a241423baf Added iOS bits 2020-04-18 17:34:03 +03:00
Nickolay Shmyrev 1e9421dd38 Add a note about iOS 2020-04-18 15:41:51 +02:00
Nickolay Shmyrev b09ffda760 Fixes links and issue #59 2020-04-11 22:15:46 +02:00
Nickolay Shmyrev aeff663a7c Fix pocketsphinx references in Android sources 2020-04-09 21:50:38 +02:00
Nickolay Shmyrev fcd17fcd4c Added Russian model 0.9 2020-04-07 17:48:29 +02:00
Nickolay Shmyrev feffb2711d Repair travis build 2020-04-04 20:49:06 +02:00
Nickolay Shmyrev f76e5b592f kaldi-ru-0.8 2020-04-04 10:27:02 +02:00
Nickolay Shmyrev 71bdc900e3 C-only wrapper 2020-04-04 10:22:01 +02:00
Nickolay Shmyrev 96bbf5abc2 Add C API 2020-04-04 10:04:49 +02:00
Nickolay Shmyrev df9424a228 Introduce pure C api to deal with Windows runtime issues and make it easy to wrap in Swift 2020-04-04 00:35:56 +02:00
Nickolay Shmyrev 3310acaf54 Add lm to kaldi-android 2020-03-28 22:45:38 +01:00
Nickolay V. Shmyrev e8722d462d Merge pull request #54 from andremendesc/master
Fixes folder name instruction for python model on microphone test
2020-03-25 08:37:25 +03:00
André Mendes 14b2c13ed6 Fixes folder name instruction for python model on microphone test 2020-03-25 01:01:23 -03:00
Nickolay Shmyrev 19af324096 Small fix by Funny Jingl 2020-03-19 23:24:41 +01:00
Nickolay Shmyrev 0ca7b94e08 Add link on kaldi-ru-0.7 2020-03-19 20:14:41 +01:00
Nickolay Shmyrev 04ed310229 Move models list to doc 2020-03-15 22:39:57 +01:00
Nickolay Shmyrev 7ac33d521c Added information about models 2020-03-15 22:27:47 +01:00
Nickolay V. Shmyrev 08ada63da4 Added note about other projects 2020-03-15 02:48:49 +03:00
Nickolay Shmyrev cef3fd72fb Disable NEON fpu on ARMv6
Fixes issue #46
2020-03-10 00:24:57 +01:00
Nayan Kalita bca0b86e37 android build support on macOS 2020-03-06 20:57:56 +05:30
Nickolay V. Shmyrev bf973ff434 Merge pull request #43 from camillem/patch-1
Typo in folder name
2020-03-02 15:47:25 +03:00
camillem a172d60b20 Typo in folder name 2020-03-02 13:46:34 +01:00
Nickolay Shmyrev 060e4395c2 Fix repeating results issue #42
Thanks to Yondu Tsai
2020-03-02 13:41:27 +01:00
Nickolay Shmyrev 03f1417454 Added small readme 2020-03-01 09:12:09 +01:00
Nickolay Shmyrev 6b787a4d1e We actually need a bit newer cmake 2020-02-27 00:43:03 +01:00
Nickolay Shmyrev 095fac1de4 Small unittest 2020-02-25 21:45:27 +01:00
Nickolay V. Shmyrev 5ba9e353c7 Added contacts 2020-02-25 02:44:28 +03:00
Nickolay V. Shmyrev be117bfbb8 Update README.md 2020-02-25 02:39:14 +03:00
Nickolay V. Shmyrev c4f9bfe735 Update README.md 2020-02-24 17:50:39 +03:00
Nickolay Shmyrev cc96ef700f Fix mistake 2020-02-24 01:25:29 +01:00
Nickolay Shmyrev cb41d8c94b Added C# test 2020-02-24 00:25:15 +01:00
Nickolay Shmyrev 8913b93703 Fix message 2020-02-23 16:05:34 +00:00
Nickolay Shmyrev 174bf7b0ff Minor fixes 2020-02-23 15:06:06 +01:00
Nickolay Shmyrev 7e44844cd5 Added dockcross images for arm builds 2020-02-23 10:19:31 +01:00
Nickolay Shmyrev c0aa87af1b Build speaker model too 2020-02-21 09:53:00 +01:00
Nickolay Shmyrev f66f7a9290 Added microphone test 2020-02-21 00:08:50 +01:00
Nickolay Shmyrev 378fa3499a Downsample by default and also check wav file encoding in examples. Thanks to
dtreskunov. See for details

https://github.com/alphacep/vosk-api/pull/23
2020-02-18 11:45:50 +01:00
Nickolay Shmyrev 01eeec498d Fix memory access issues 2020-02-17 09:42:50 +00:00
Nickolay Shmyrev d422dfbddb Message update 2020-02-16 17:21:38 +01:00
Nickolay Shmyrev bd4a48d5a8 Added spkid to java 2020-02-16 17:12:54 +01:00
Nickolay Shmyrev aa91ccf68b Added speaker identification 2020-02-16 17:04:37 +01:00
Nickolay Shmyrev bda43565e1 Added the doc about langauge model recompilation with opengrm 2020-02-10 20:39:59 +01:00
Nickolay Shmyrev 8c9bae3ad1 Update version for Kaldi rebuild 2020-02-08 23:40:42 +01:00
Nickolay V. Shmyrev 87fc3bc073 Make structure more clear 2020-02-02 23:10:35 +03:00
Nickolay Shmyrev 9c101ffa86 Strip binary on release
Fixes issue #12.
2020-01-29 22:22:26 +01:00
Nickolay V. Shmyrev 5649d9e3c7 Merge pull request #22 from dtreskunov/issue-19
translate exceptions from C++ to Python
2020-01-29 23:12:41 +03:00
Denis Treskunov 5ee96b6d04 translate exceptions from C++ to Python
Wrap each API call in a try/catch.
See http://www.swig.org/Doc4.0/Python.html#Python_nn44
2020-01-28 14:12:53 -08:00
Nickolay V. Shmyrev 6a7854919e Clarify Pip install is sufficient. 2020-01-27 12:33:27 +03:00
Nickolay Shmyrev a6f6c0409b Demonstrate grammar compilation on the fly 2020-01-22 23:31:21 +01:00
Nickolay Shmyrev 41446c980c Use json library for convenience 2020-01-22 22:37:03 +01:00
Nickolay Shmyrev 7bed44a96e Automatically download model 2020-01-19 22:07:47 +01:00
Nickolay Shmyrev 3f7bd2f586 Added java example 2020-01-19 21:57:08 +01:00
Nickolay Shmyrev 2ba8466e0a Avoid hardcoded folders, fixes issue #14. Thanks to Bill Lambert. 2020-01-19 20:30:18 +01:00
Nickolay Shmyrev f80dcce5ed Clarify licences 2020-01-19 19:33:55 +01:00
Nickolay Shmyrev f4aed3e9a4 Added note about runnign the code 2020-01-18 00:28:35 +01:00
Nickolay Shmyrev 5c4ef66a08 Update README 2020-01-18 00:20:19 +01:00
Nickolay Shmyrev 29d2564efd Let it be 3.4 2020-01-12 13:16:59 +01:00
Nickolay Shmyrev 380fa9c7c8 Added a warning to download the model 2020-01-11 20:24:34 +01:00
Nickolay Shmyrev e55c6e09f8 Simplify swig task 2020-01-11 08:14:32 +01:00
Nickolay Shmyrev 355b58447a No need to link with python library 2020-01-10 19:57:41 +00:00
Nickolay Shmyrev fe35675eaa Added basic travis 2020-01-10 20:01:48 +01:00
Nickolay Shmyrev ae9db8652a Update gradle plugin to properly report about missing local properties.
Fix issue #8
2020-01-03 20:24:47 +01:00
Nickolay Shmyrev ac3e52596c Remove premature exit 2020-01-03 20:20:51 +01:00
Nickolay V. Shmyrev 17bffb6739 Update README.md 2020-01-03 09:58:08 +03:00
Nickolay V. Shmyrev 8839771794 Update README.md 2020-01-03 02:06:28 +03:00
Nickolay V. Shmyrev 95ee23521b Update README.md 2020-01-03 01:35:57 +03:00
Nickolay Shmyrev 38672ad1ca Update to current state 2020-01-02 21:53:07 +01:00
Nickolay Shmyrev 79cee1cab6 Update to use shared sources 2020-01-02 21:51:25 +01:00
Nickolay Shmyrev 3aece57b6e Kaldi doesn't use logarc 2020-01-02 20:48:08 +01:00
Nickolay Shmyrev 78e66149f8 Imported Python bindings and Node bindings 2020-01-02 20:46:14 +01:00
Nickolay Shmyrev 6805077934 Moved android things to a folder in preparation for merge with python bindings 2020-01-02 20:41:39 +01:00
Nickolay Shmyrev 688178ba5f -O3 implies tree vectorization 2020-01-02 19:59:17 +01:00
Nickolay Shmyrev cc13917903 Reuse symbol table from the grammar instead of separate file. 2019-12-25 23:54:53 +01:00
Nickolay Shmyrev 65ebfb0dac Update for disambig in lookahead 2019-11-25 23:29:05 +01:00
Nickolay Shmyrev 3954d89329 Use Atom architecture for emulator instead of SandyBridge 2019-11-13 20:45:05 +01:00
Nickolay Shmyrev 41ebb41bd8 Add x86 plugin 2019-11-12 00:05:15 +01:00
Nickolay Shmyrev 545800454b Update for arm64 2019-11-03 00:20:03 +01:00
Nickolay V. Shmyrev edad7eba9e Added link to XNNPack 2019-10-09 14:59:40 +03:00
Nickolay Shmyrev bb8188afe6 More compact ngram fsts 2019-09-23 01:38:43 +02:00
Nickolay Shmyrev 305961e8dc Update for lookahead model 2019-09-20 22:39:39 +02:00
Nickolay Shmyrev 06972ec3ad Simplify AcceptWaveform API 2019-09-11 18:55:24 +02:00
Nickolay Shmyrev 345dfde6fb Optimization for speed test 2019-09-10 21:50:18 +02:00
Nickolay Shmyrev 1326d3820f Unified build script without docker 2019-09-09 18:19:30 +02:00
Nickolay Shmyrev 9437f88ce2 Add readme 2019-09-05 13:00:23 +02:00
Nickolay Shmyrev 67b5814108 Allow model path specification 2019-09-05 12:59:23 +02:00
Nickolay Shmyrev 5a49c26d9d Initial import 2019-09-03 19:45:19 +02:00
271 changed files with 2912 additions and 29477 deletions
+31 -38
View File
@@ -1,25 +1,22 @@
# Built application files
*.apk
*.ap_
# Java class files
*.class
# Object files
*.o
# Temp files
nohup.out
# Gradle files
.gradle/
build/
gradlew
gradlew.bat
gradle
local.properties
gradle.properties
# Android
android/build
android/lib/build
android/model-en/build
android/model-en/src/main/assets/model-en-us
android/repo
*.apk
*.ap_
# Local configuration file (sdk path, etc)
local.properties
# Cmake
.cxx
@@ -30,8 +27,12 @@ wheelhouse
__pycache__
*.egg-info
python/dist
python/build
python/vosk/*.so
python/vosk/*.cc
python/vosk/*.c
python/vosk/*.h
python/vosk/*.i
python/vosk/vosk.py
python/vosk/vosk_wrap.cpp
python/test/db
python/test/hyp
python/test/model
@@ -40,32 +41,24 @@ python/test/result.txt
python/test/wav.scp
# Java
*.class
java/lib/model
java/demo/model
java/lib/build
java/demo/build
*.so
java/org
java/*.cc
java/model-spk/
java/model/
# CSharp
*.dll
*.so
*.dylib
*.nupkg
csharp/demo/model
csharp/demo/test.wav
csharp/demo/bin
csharp/demo/obj
csharp/gen
csharp/*.exe
csharp/*.c
csharp/model/
csharp/test.wav
Vosk.dll
# Node
nodejs/demo/model
nodejs/demo/model-spk
nodejs/demo/test.wav
nodejs/vosk_wrap.cc
nodejs/example/model
nodejs/example/test.wav
nodejs/node_modules
nodejs/package-lock.json
# C
c/test_vosk
c/test_vosk_speaker
c/oprofile_data
c/model
c/test.wav
nodejs/build
+2 -1
View File
@@ -7,10 +7,11 @@ matrix:
services:
- docker
env: DOCKER_IMAGE=alphacep/kaldi-manylinux:latest
PLAT=manylinux2010_x86_64
install:
- docker pull $DOCKER_IMAGE
script:
- docker run --rm -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/travis/build-wheels.sh
- docker run --rm -e PLAT=$PLAT -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/travis/build-wheels.sh
- ls wheelhouse/
-21
View File
@@ -1,21 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(vosk-api CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(vosk
src/language_model.cc
src/model.cc
src/recognizer.cc
src/spk_model.cc
src/vosk_api.cc
src/postprocessor.cc
)
find_package(kaldi REQUIRED)
target_link_libraries(vosk PUBLIC kaldi-base kaldi-online2 kaldi-rnnlm fstngram)
include(GNUInstallDirs)
install(TARGETS vosk DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(FILES src/vosk_api.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
-27
View File
@@ -1,27 +0,0 @@
# Vosk Speech Recognition Toolkit
Vosk is an offline open source speech recognition toolkit. It enables
speech recognition for 20+ languages and dialects - English, Indian
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino,
Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish.
More to come.
Vosk models are small (50 Mb) but provide continuous large vocabulary
transcription, zero-latency response with streaming API, reconfigurable
vocabulary and speaker identification.
Speech recognition bindings implemented for various programming languages
like Python, Java, Node.JS, C#, C++, Rust, Go and others.
Vosk supplies speech recognition for chatbots, smart home appliances,
virtual assistants. It can also create subtitles for movies,
transcription for lectures and interviews.
Vosk scales from small devices like Raspberry Pi or Android smartphone to
big clusters.
# Documentation
For installation instructions, examples and documentation visit [Vosk
Website](https://alphacephei.com/vosk).
+18 -14
View File
@@ -1,21 +1,25 @@
<!-- WEHUB_ZH_README -->
> [!NOTE]
> 本文档由 WeHub 基于上游 README 翻译整理,属于社区翻译,非官方中文文档。
> [English](./README.en.md) · [原始项目](https://github.com/alphacep/vosk-api) · [上游 README](https://github.com/alphacep/vosk-api/blob/HEAD/README.md)
> 原作者、版权与许可证归属以原始项目及本仓库 LICENSE 文件为准。
# About
# Vosk Speech Recognition Toolkit
Vosk is an offline open source speech recognition toolkit. It enables
speech recognition models for 17 languages and dialects - English, Indian
English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish,
Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino.
Vosk 是一款离线开源语音识别工具包。它支持 20 多种语言及方言的语音识别——英语、印度英语、德语、法语、西班牙语、葡萄牙语、中文、俄语、土耳其语、越南语、意大利语、荷兰语、加泰罗尼亚语、阿拉伯语、希腊语、波斯语、菲律宾语、乌克兰语、哈萨克语、瑞典语、日语、世界语、印地语、捷克语、波兰语。更多语言即将推出。
Vosk models are small (50 Mb) but provide continuous large vocabulary
transcription, zero-latency response with streaming API, reconfigurable
vocabulary and speaker identification.
Vosk 模型体积小(50 Mb),但可提供连续大词汇量转写、通过流式 API(streaming API)实现零延迟响应、可重新配置的词汇表以及说话人识别。
Speech recognition bindings implemented for various programming languages
like Python, Java, Node.JS, C#, C++ and others.
已为 Python、Java、Node.JS、C#、C++、Rust、Go 等多种编程语言实现语音识别绑定。
Vosk supplies speech recognition for chatbots, smart home appliances,
virtual assistants. It can also create subtitles for movies,
transcription for lectures and interviews.
Vosk 为聊天机器人、智能家居设备、虚拟助手提供语音识别,还可为电影生成字幕,为讲座和访谈提供转写。
Vosk scales from small devices like Raspberry Pi or Android smartphone to
big clusters.
Vosk 的部署规模可从小型设备(如 Raspberry Pi 或 Android 智能手机)扩展到大型集群。
# Documentation
# 文档
有关安装说明、示例和文档,请访问 [Vosk 网站](https://alphacephei.com/vosk).
For installation instructions, examples and documentation visit [Vosk
Website](https://alphacephei.com/vosk).
-7
View File
@@ -1,7 +0,0 @@
# WeHub 来源说明
- 原始项目:`alphacep/vosk-api`
- 原始仓库:https://github.com/alphacep/vosk-api
- 导入方式:上游默认分支的最新快照
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
+69
View File
@@ -0,0 +1,69 @@
# Vosk CMake File
cmake_minimum_required(VERSION 3.4.1)
if ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(OPENBLAS_ARCH "armv7")
set(KALDI_SUFFIX "arm_32")
elseif ("x${ANDROID_ABI}" STREQUAL "xarm64-v8a")
set(OPENBLAS_ARCH "armv8")
set(KALDI_SUFFIX "arm_64")
elseif ("x${ANDROID_ABI}" STREQUAL "xx86")
set(OPENBLAS_ARCH "atom")
set(KALDI_SUFFIX "x86")
else ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(OPENBLAS_ARCH "atom")
set(KALDI_SUFFIX "x86_64")
endif ("x${ANDROID_ABI}" STREQUAL "xarmeabi-v7a")
set(KALDI_ROOT "${PROJECT_SOURCE_DIR}/build/kaldi_${KALDI_SUFFIX}/kaldi")
set(LIB_ROOT "${PROJECT_SOURCE_DIR}/build/kaldi_${KALDI_SUFFIX}/local")
set(API_SOURCES
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.cc"
"${PROJECT_SOURCE_DIR}/../src/kaldi_recognizer.h"
"${PROJECT_SOURCE_DIR}/../src/language_model.cc"
"${PROJECT_SOURCE_DIR}/../src/language_model.h"
"${PROJECT_SOURCE_DIR}/../src/model.cc"
"${PROJECT_SOURCE_DIR}/../src/model.h"
"${PROJECT_SOURCE_DIR}/../src/spk_model.cc"
"${PROJECT_SOURCE_DIR}/../src/spk_model.h"
"${PROJECT_SOURCE_DIR}/../src/vosk_api.cc"
"${PROJECT_SOURCE_DIR}/../src/vosk_api.h"
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -DFST_NO_DYNAMIC_LINKING")
add_library( vosk_jni SHARED
build/generated-src/cpp/vosk_wrap.cc
${API_SOURCES}
)
include_directories("${PROJECT_SOURCE_DIR}/../src" "build/kaldi_${KALDI_SUFFIX}/kaldi/src" "build/kaldi_${KALDI_SUFFIX}/local/include")
target_link_libraries( vosk_jni
${KALDI_ROOT}/src/online2/kaldi-online2.a
${KALDI_ROOT}/src/decoder/kaldi-decoder.a
${KALDI_ROOT}/src/ivector/kaldi-ivector.a
${KALDI_ROOT}/src/gmm/kaldi-gmm.a
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a
${KALDI_ROOT}/src/tree/kaldi-tree.a
${KALDI_ROOT}/src/feat/kaldi-feat.a
${KALDI_ROOT}/src/lat/kaldi-lat.a
${KALDI_ROOT}/src/lm/kaldi-lm.a
${KALDI_ROOT}/src/hmm/kaldi-hmm.a
${KALDI_ROOT}/src/transform/kaldi-transform.a
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a
${KALDI_ROOT}/src/matrix/kaldi-matrix.a
${KALDI_ROOT}/src/fstext/kaldi-fstext.a
${KALDI_ROOT}/src/util/kaldi-util.a
${KALDI_ROOT}/src/base/kaldi-base.a
${LIB_ROOT}/lib/libfst.a
${LIB_ROOT}/lib/libfstngram.a
${LIB_ROOT}/lib/libopenblas_${OPENBLAS_ARCH}-r0.3.7.a
${LIB_ROOT}/lib/libclapack.a
${LIB_ROOT}/lib/liblapack.a
${LIB_ROOT}/lib/libblas.a
${LIB_ROOT}/lib/libf2c.a
log
)
+141
View File
@@ -0,0 +1,141 @@
#!/bin/bash
# Copyright 2019 Alpha Cephei Inc.
#
# 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.
if [ "x$ANDROID_SDK_HOME" == "x" ]; then
echo "ANDROID_SDK_HOME environment variable is undefined, define it with local.properties or with export"
exit 1
fi
if [ ! -d "$ANDROID_SDK_HOME" ]; then
echo "ANDROID_SDK_HOME ($ANDROID_SDK_HOME) is missing. Make sure you have sdk installed"
exit 1
fi
if [ ! -d "$ANDROID_SDK_HOME/ndk-bundle" ]; then
echo "$ANDROID_SDK_HOME/ndk-bundle is missing. Make sure you have ndk installed within sdk"
exit 1
fi
set -x
OS_NAME=`echo $(uname -s) | tr '[:upper:]' '[:lower:]'`
ANDROID_NDK_HOME=$ANDROID_SDK_HOME/ndk-bundle
ANDROID_TOOLCHAIN_PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64
WORKDIR_X86=`pwd`/build/kaldi_x86
WORKDIR_X86_64=`pwd`/build/kaldi_x86_64
WORKDIR_ARM32=`pwd`/build/kaldi_arm_32
WORKDIR_ARM64=`pwd`/build/kaldi_arm_64
PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64/bin
OPENFST_VERSION=1.6.7
mkdir -p $WORKDIR_ARM64/local/lib $WORKDIR_ARM32/local/lib $WORKDIR_X86_64/local/lib $WORKDIR_X86/local/lib
# Build standalone CLAPACK since gfortran is missing
cd build
git clone https://github.com/simonlynen/android_libs
cd android_libs/lapack
sed -i.bak -e 's/APP_STL := gnustl_static/APP_STL := c++_static/g' jni/Application.mk && \
sed -i.bak -e 's/android-10/android-21/g' project.properties && \
sed -i.bak -e 's/APP_ABI := armeabi armeabi-v7a/APP_ABI := armeabi-v7a arm64-v8a x86_64 x86/g' jni/Application.mk && \
sed -i.bak -e 's/LOCAL_MODULE:= testlapack/#LOCAL_MODULE:= testlapack/g' jni/Android.mk && \
sed -i.bak -e 's/LOCAL_SRC_FILES:= testclapack.cpp/#LOCAL_SRC_FILES:= testclapack.cpp/g' jni/Android.mk && \
sed -i.bak -e 's/LOCAL_STATIC_LIBRARIES := lapack/#LOCAL_STATIC_LIBRARIES := lapack/g' jni/Android.mk && \
sed -i.bak -e 's/include $(BUILD_SHARED_LIBRARY)/#include $(BUILD_SHARED_LIBRARY)/g' jni/Android.mk && \
${ANDROID_NDK_HOME}/ndk-build && \
cp obj/local/armeabi-v7a/*.a ${WORKDIR_ARM32}/local/lib && \
cp obj/local/arm64-v8a/*.a ${WORKDIR_ARM64}/local/lib
cp obj/local/x86_64/*.a ${WORKDIR_X86_64}/local/lib
cp obj/local/x86/*.a ${WORKDIR_X86}/local/lib
# Architecture-specific part
for arch in arm32 arm64 x86_64 x86; do
#for arch in x86_64; do
case $arch in
arm32)
BLAS_ARCH=ARMV7
WORKDIR=$WORKDIR_ARM32
HOST=arm-linux-androideabi
AR=arm-linux-androideabi-ar
CC=armv7a-linux-androideabi21-clang
CXX=armv7a-linux-androideabi21-clang++
ARCHFLAGS="-mfloat-abi=softfp -mfpu=neon"
;;
arm64)
BLAS_ARCH=ARMV8
WORKDIR=$WORKDIR_ARM64
HOST=aarch64-linux-android
AR=aarch64-linux-android-ar
CC=aarch64-linux-android21-clang
CXX=aarch64-linux-android21-clang++
ARCHFLAGS=""
;;
x86_64)
BLAS_ARCH=ATOM
WORKDIR=$WORKDIR_X86_64
HOST=x86_64-linux-android
AR=x86_64-linux-android-ar
CC=x86_64-linux-android21-clang
CXX=x86_64-linux-android21-clang++
ARCHFLAGS=""
;;
x86)
BLAS_ARCH=ATOM
WORKDIR=$WORKDIR_X86
HOST=i686-linux-android
AR=i686-linux-android-ar
CC=i686-linux-android21-clang
CXX=i686-linux-android21-clang++
ARCHFLAGS=""
;;
esac
# openblas first
cd $WORKDIR
git clone -b v0.3.7 --single-branch https://github.com/xianyi/OpenBLAS
make -C OpenBLAS TARGET=$BLAS_ARCH ONLY_CBLAS=1 AR=$AR CC=$CC HOSTCC=gcc ARM_SOFTFP_ABI=1 USE_THREAD=0 NUM_THREADS=1 -j4
make -C OpenBLAS install PREFIX=$WORKDIR/local
# tools directory --> we'll only compile OpenFST
cd $WORKDIR
git clone https://github.com/alphacep/openfst
cd openfst
autoreconf -i
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --prefix=${WORKDIR}/local \
--enable-shared --enable-static --with-pic --disable-bin \
--enable-lookahead-fsts --enable-ngram-fsts --host=$HOST --build=x86-linux-gnu
make -j 8
make install
# Kaldi itself
cd $WORKDIR
git clone -b android-mix --single-branch https://github.com/alphacep/kaldi
cd $WORKDIR/kaldi/src
if [ "`uname`" == "Darwin" ]; then
sed -i.bak -e 's/libfst.dylib/libfst.a/' configure
fi
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
--mathlib=OPENBLAS --shared \
--android-incdir=${ANDROID_TOOLCHAIN_PATH}/sysroot/usr/include \
--host=$HOST --openblas-root=${WORKDIR}/local \
--fst-root=${WORKDIR}/local --fst-version=${OPENFST_VERSION}
make -j 8 depend
make -j 8 online2 lm
done
+92 -35
View File
@@ -1,53 +1,110 @@
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.13.0'
classpath 'com.vanniktech:gradle-maven-publish-plugin:0.34.0'
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
plugins {
id "com.jfrog.bintray" version "1.8.5"
}
def archiveName = "vosk-android"
def libVersion = "0.3.16"
allprojects {
version = '0.3.75'
repositories {
google()
jcenter()
}
}
subprojects {
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'com.android.library'
apply plugin: 'com.vanniktech.maven.publish'
repositories {
google()
mavenCentral()
android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 6
versionName = libVersion
archivesBaseName = archiveName
externalNativeBuild {
cmake {
arguments "-DCMAKE_VERBOSE_MAKEFILE=ON", "-DANDROID_ARM_NEON=TRUE", "-DCMAKE_CXX_FLAGS_RELEASE=-O3"
}
}
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86_64', 'x86'
}
}
mavenPublishing {
publishToMavenCentral()
signAllPublications()
sourceSets {
main {
java.srcDirs = ['src/main/java', 'build/generated-src']
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
mavenPublishing {
pom {
url = 'http://www.alphacephei.com.com/vosk/'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'com.alphacephei'
name = 'Alpha Cephei Inc'
email = 'contact@alphacephei.com'
}
}
scm {
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
url = 'https://github.com/alphacep/vosk-api/'
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
pkg {
repo = 'vosk'
name = 'vosk-android'
userOrg = "alphacep"
licenses = ['Apache2.0']
websiteUrl = 'https://github.com/alphacep/vosk-api'
issueTrackerUrl = 'https://github.com/alphacep/vosk-api/issues'
vcsUrl = 'https://github.com/alphacep/vosk-api'
version {
name = libVersion
vcsTag = libVersion
}
}
publications = ['aar']
}
publishing {
publications {
aar(MavenPublication) {
groupId 'com.alphacep'
artifactId archiveName
version libVersion
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
}
}
}
task swig {
doLast {
mkdir 'build/generated-src/java'
mkdir 'build/generated-src/cpp'
exec {
commandLine 'swig',
"-c++",
"-java", "-package", "org.kaldi",
"-outdir", "build/generated-src/java", "-o", "build/generated-src/cpp/vosk_wrap.cc",
"../src/vosk.i"
}
}
}
task kaldi(type: Exec) {
commandLine './build-kaldi.sh'
environment ANDROID_SDK_HOME: android.getSdkDirectory()
}
preBuild.dependsOn kaldi, swig
-140
View File
@@ -1,140 +0,0 @@
#!/bin/bash
# Copyright 2019-2021 Alpha Cephei Inc.
#
# 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.
if [ "x$ANDROID_NDK_HOME" == "x" ]; then
echo "ANDROID_NDK_HOME environment variable is undefined, define it with local.properties or with export"
exit 1
fi
if [ ! -d "$ANDROID_NDK_HOME" ]; then
echo "ANDROID_NDK_HOME ($ANDROID_NDK_HOME) is missing. Make sure you have ndk installed"
exit 1
fi
set -x
OS_NAME=`echo $(uname -s) | tr '[:upper:]' '[:lower:]'`
ANDROID_TOOLCHAIN_PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/${OS_NAME}-x86_64
WORKDIR_BASE=`pwd`/build
PATH=$ANDROID_TOOLCHAIN_PATH/bin:$PATH
OPENFST_VERSION=1.8.0
for arch in armeabi-v7a arm64-v8a x86_64 x86; do
WORKDIR=${WORKDIR_BASE}/kaldi_${arch}
case $arch in
armeabi-v7a)
BLAS_ARCH=ARMV7
HOST=arm-linux-androideabi
AR=llvm-ar
RANLIB=llvm-ranlib
CC=armv7a-linux-androideabi21-clang
CXX=armv7a-linux-androideabi21-clang++
ARCHFLAGS="-mfloat-abi=softfp -mfpu=neon"
PAGESIZE_LDFLAGS=""
;;
arm64-v8a)
BLAS_ARCH=ARMV8
HOST=aarch64-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=aarch64-linux-android21-clang
CXX=aarch64-linux-android21-clang++
ARCHFLAGS=""
# Ensure compatibility with 16KiB page size devices
PAGESIZE_LDFLAGS="-Wl,-z,common-page-size=4096 -Wl,-z,max-page-size=16384"
;;
x86_64)
BLAS_ARCH=ATOM
HOST=x86_64-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=x86_64-linux-android21-clang
CXX=x86_64-linux-android21-clang++
ARCHFLAGS=""
PAGESIZE_LDFLAGS=""
;;
x86)
BLAS_ARCH=ATOM
HOST=i686-linux-android
AR=llvm-ar
RANLIB=llvm-ranlib
CC=i686-linux-android21-clang
CXX=i686-linux-android21-clang++
ARCHFLAGS=""
PAGESIZE_LDFLAGS=""
;;
esac
mkdir -p $WORKDIR/local/lib
# openblas first
cd $WORKDIR
git clone -b v0.3.20 --single-branch https://github.com/xianyi/OpenBLAS
make -C OpenBLAS TARGET=$BLAS_ARCH ONLY_CBLAS=1 AR=$AR CC=$CC HOSTCC=gcc ARM_SOFTFP_ABI=1 USE_THREAD=0 NUM_THREADS=1 -j 8
make -C OpenBLAS install PREFIX=$WORKDIR/local
# CLAPACK
cd $WORKDIR
git clone -b v3.2.1 --single-branch https://github.com/alphacep/clapack
mkdir -p clapack/BUILD && cd clapack/BUILD
cmake -DCMAKE_C_FLAGS="$ARCHFLAGS" -DCMAKE_C_COMPILER_TARGET=$HOST \
-DCMAKE_C_COMPILER=$CC -DCMAKE_SYSTEM_NAME=Generic -DCMAKE_AR=$ANDROID_TOOLCHAIN_PATH/bin/$AR \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DCMAKE_CROSSCOMPILING=True ..
make -j 8 -C F2CLIBS/libf2c
make -j 8 -C BLAS/SRC
make -j 8 -C SRC
find . -name "*.a" | xargs cp -t $WORKDIR/local/lib
# tools directory --> we'll only compile OpenFST
cd $WORKDIR
git clone https://github.com/alphacep/openfst
cd openfst
autoreconf -i
CXX=$CXX CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --prefix=${WORKDIR}/local \
--enable-shared --enable-static --with-pic --disable-bin \
--enable-lookahead-fsts --enable-ngram-fsts --host=$HOST --build=x86-linux-gnu
make -j 8
make install
# Kaldi itself
cd $WORKDIR
git clone -b vosk-android --single-branch https://github.com/alphacep/kaldi
cd $WORKDIR/kaldi/src
CXX=$CXX AR=$AR RANLIB=$RANLIB CXXFLAGS="$ARCHFLAGS -O3 -DFST_NO_DYNAMIC_LINKING" ./configure --use-cuda=no \
--mathlib=OPENBLAS_CLAPACK --shared \
--android-incdir=${ANDROID_TOOLCHAIN_PATH}/sysroot/usr/include \
--host=$HOST --openblas-root=${WORKDIR}/local \
--fst-root=${WORKDIR}/local --fst-version=${OPENFST_VERSION}
make -j 8 depend
cd $WORKDIR/kaldi/src
make -j 8 online2 rnnlm
# Vosk-api
cd $WORKDIR
mkdir -p $WORKDIR/vosk
make -j 8 -C ${WORKDIR_BASE}/../../../src \
OUTDIR=$WORKDIR/vosk \
KALDI_ROOT=${WORKDIR}/kaldi \
OPENFST_ROOT=${WORKDIR}/local \
OPENBLAS_ROOT=${WORKDIR}/local \
CXX=$CXX \
EXTRA_LDFLAGS="-llog -static-libstdc++ -Wl,-soname,libvosk.so ${PAGESIZE_LDFLAGS}"
cp $WORKDIR/vosk/libvosk.so $WORKDIR/../../src/main/jniLibs/$arch/libvosk.so
done
-39
View File
@@ -1,39 +0,0 @@
def archiveName = "vosk-android"
def pomName = "Vosk Android"
def pomDescription = "Vosk speech recognition library for Android"
android {
namespace 'org.vosk'
compileSdkVersion 36
defaultConfig {
minSdkVersion 21
targetSdkVersion 36
versionCode 10
versionName = version
archivesBaseName = archiveName
ndkVersion = "28.2.13676358"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
task buildVosk(type: Exec) {
commandLine './build-vosk.sh'
environment ANDROID_NDK_HOME: android.getNdkDirectory()
}
dependencies {
api 'net.java.dev.jna:jna:5.18.1@aar'
}
//preBuild.dependsOn buildVosk
mavenPublishing {
coordinates("com.alphacephei", archiveName, version)
pom {
name = pomName
description = pomDescription
}
}
-3
View File
@@ -1,3 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest>
</manifest>
@@ -1,82 +0,0 @@
package org.vosk;
import com.sun.jna.Native;
import com.sun.jna.Library;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class LibVosk {
static {
Native.register(LibVosk.class, "vosk");
}
public static native void vosk_set_log_level(int level);
public static native Pointer vosk_model_new(String path);
public static native void vosk_model_free(Pointer model);
public static native Pointer vosk_spk_model_new(String path);
public static native void vosk_spk_model_free(Pointer model);
public static native Pointer vosk_recognizer_new(Model model, float sample_rate);
public static native Pointer vosk_recognizer_new_spk(Pointer model, float sample_rate, Pointer spk_model);
public static native Pointer vosk_recognizer_new_grm(Pointer model, float sample_rate, String grammar);
public static native void vosk_recognizer_set_max_alternatives(Pointer recognizer, int max_alternatives);
public static native void vosk_recognizer_set_words(Pointer recognizer, boolean words);
public static native void vosk_recognizer_set_partial_words(Pointer recognizer, boolean partial_words);
public static native void vosk_recognizer_set_spk_model(Pointer recognizer, Pointer spk_model);
public static native boolean vosk_recognizer_accept_waveform(Pointer recognizer, byte[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_s(Pointer recognizer, short[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_f(Pointer recognizer, float[] data, int len);
public static native String vosk_recognizer_result(Pointer recognizer);
public static native String vosk_recognizer_final_result(Pointer recognizer);
public static native String vosk_recognizer_partial_result(Pointer recognizer);
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
public static native void vosk_recognizer_reset(Pointer recognizer);
public static native void vosk_recognizer_set_endpointer_mode(Pointer recognizer, int mode);
public static native void vosk_recognizer_set_endpointer_delays(Pointer recognizer, float t_start_max, float t_end, float t_max);
public static native void vosk_recognizer_free(Pointer recognizer);
public static native Pointer vosk_text_processor_new(String verbalizer, String tagger);
public static native void vosk_text_processor_free(Pointer processor);
public static native String vosk_text_processor_itn(Pointer processor, String input);
/**
* Set log level for Kaldi messages.
*
* @param loglevel the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greater than 0 - more verbose mode
*/
public static void setLogLevel(LogLevel loglevel) {
vosk_set_log_level(loglevel.getValue());
}
}
@@ -1,17 +0,0 @@
package org.vosk;
public enum LogLevel {
WARNINGS(-1), // Print warning and errors
INFO(0), // Print info, along with warning and error messages, but no debug
DEBUG(1); // Print debug info
private final int value;
LogLevel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
@@ -1,22 +0,0 @@
package org.vosk;
import java.io.IOException;
import com.sun.jna.PointerType;
public class Model extends PointerType implements AutoCloseable {
public Model() {
}
public Model(String path) throws IOException {
super(LibVosk.vosk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a model");
}
}
@Override
public void close() {
LibVosk.vosk_model_free(this.getPointer());
}
}
@@ -1,275 +0,0 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
public class Recognizer extends PointerType implements AutoCloseable {
/**
* Creates the recognizer object.
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate) throws IOException {
super(LibVosk.vosk_recognizer_new(model, sampleRate));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with speaker recognition.
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spkModel speaker model for speaker identification
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with the phrase list.
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Configures recognizer to output n-best results.
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param maxAlternatives - maximum alternatives to return from recognition results
*/
public void setMaxAlternatives(int maxAlternatives) {
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
}
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
public void setWords(boolean words) {
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
}
/**
* Like above return words and confidences in partial results.
*
* @param partial_words - boolean value
*/
public void setPartialWords(boolean partial_words) {
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
}
/**
* Adds speaker model to already initialized recognizer.
*
* Can add speaker recognition model to already created recognizer.
* Helps to initialize speaker recognition for grammar-based recognizer.
*
* @param spkModel Speaker recognition model
*/
public void setSpeakerModel(SpeakerModel spkModel) {
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
}
/**
* Accept and process new chunk of voice data.
*
* @param data - audio data in PCM 16-bit mono format
* @param len - length of the audio data
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occurred
*/
public boolean acceptWaveForm(byte[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
}
public boolean acceptWaveForm(short[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_s(this.getPointer(), data, len);
}
public boolean acceptWaveForm(float[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
}
/**
* Returns speech recognition result
*
* @return the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
*
* If word times enabled returns word time, see also #setWordTimes().
*/
public String getResult() {
return LibVosk.vosk_recognizer_result(this.getPointer());
}
/**
* Returns partial speech recognition.
*
* @return partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
public String getPartialResult() {
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
}
/**
* Returns speech recognition result. Same as result, but doesn't wait for silence.
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @return speech result in JSON format.
*/
public String getFinalResult() {
return LibVosk.vosk_recognizer_final_result(this.getPointer());
}
/**
* Reconfigures recognizer to use grammar.
*
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* @see #Recognizer(Model, float, String)
*/
public void setGrammar(String grammar) {
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
}
/**
* Resets the recognizer.
* Resets current results so the recognition can continue from scratch.
*/
public void reset() {
LibVosk.vosk_recognizer_reset(this.getPointer());
}
/**
* Endpointer delay mode
*/
public class EndpointerMode {
public static final int DEFAULT = 0;
public static final int SHORT = 1;
public static final int LONG = 2;
public static final int VERY_LONG = 3;
}
/**
* Configures endpointer mode for recognizer
*/
public void setEndpointerMode(int mode) {
LibVosk.vosk_recognizer_set_endpointer_mode(this.getPointer(), mode);
}
/**
* Set endpointer delays
*
* @param t_start_max timeout for stopping recognition in case of initial silence (usually around 5.0)
* @param t_end timeout for stopping recognition in milliseconds after we recognized something (usually around 0.5 - 1.0)
* @param t_max timeout for forcing utterance end in milliseconds (usually around 20-30)
**/
public void setEndpointerDelays(float t_start_max, float t_end, float t_max) {
LibVosk.vosk_recognizer_set_endpointer_delays(this.getPointer(), t_start_max, t_end, t_max);
}
/**
* Releases recognizer object.
* Underlying model is also unreferenced and if needed, released.
*/
@Override
public void close() {
LibVosk.vosk_recognizer_free(this.getPointer());
}
}
@@ -1,40 +0,0 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
/**
* Helps to initialize speaker recognition for grammar-based recognizer.
*/
public class SpeakerModel extends PointerType implements AutoCloseable {
public SpeakerModel() {
}
/**
* Loads speaker model data from the file.
*
* The path must contain:
* - a config file: mfcc.conf
* - kaldi nnet: final.ext.raw
* - mean.vec
* - transform.mat
*
* @param path the path of the model on the filesystem
* @throws IOException if the model could not be created
*
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
*/
public SpeakerModel(String path) throws IOException {
super(LibVosk.vosk_spk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a speaker model");
}
}
@Override
public void close() {
LibVosk.vosk_spk_model_free(this.getPointer());
}
}
@@ -1,21 +0,0 @@
package org.vosk;
import com.sun.jna.PointerType;
public class TextProcessor extends PointerType implements AutoCloseable {
public TextProcessor() {
}
public TextProcessor(String verbalizer, String tagger) {
super(LibVosk.vosk_text_processor_new(verbalizer, tagger));
}
@Override
public void close() {
LibVosk.vosk_text_processor_free(this.getPointer());
}
public String itn(String input) {
return LibVosk.vosk_text_processor_itn(this.getPointer(), input);
}
}
@@ -1,316 +0,0 @@
// Copyright 2019 Alpha Cephei Inc.
//
// 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.
package org.vosk.android;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Handler;
import android.os.Looper;
import android.annotation.SuppressLint;
import org.vosk.Recognizer;
import java.io.IOException;
/**
* Service that records audio in a thread, passes it to a recognizer and emits
* recognition results. Recognition events are passed to a client using
* {@link RecognitionListener}
*/
public class SpeechService {
private final Recognizer recognizer;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.2f;
private final int bufferSize;
private final AudioRecord recorder;
private RecognizerThread recognizerThread;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
/**
* Creates speech service. Service holds the AudioRecord object, so you
* need to call {@link #shutdown()} in order to properly finalize it.
*
* @throws IOException thrown if audio recorder can not be created for some reason.
*/
@SuppressLint("MissingPermission")
public SpeechService(Recognizer recognizer, float sampleRate) throws IOException {
this.recognizer = recognizer;
this.sampleRate = (int) sampleRate;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
recorder = new AudioRecord(
AudioSource.VOICE_RECOGNITION, this.sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
recorder.release();
throw new IOException(
"Failed to initialize recorder. Microphone might be already in use.");
}
}
/**
* Creates speech service with a caller-supplied {@link AudioRecord}.
* <p>
* Use this when you need to control the audio input device - for example,
* to pin recording to the built-in microphone when an external USB device
* without a microphone is present:
* <pre>
* AudioRecord recorder = new AudioRecord.Builder()
* .setAudioSource(MediaRecorder.AudioSource.VOICE_RECOGNITION)
* .setAudioFormat(format)
* .build();
* if (Build.VERSION.SDK_INT >= 28) {
* AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
* for (AudioDeviceInfo d : am.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
* if (d.getType() == AudioDeviceInfo.TYPE_BUILTIN_MIC) {
* recorder.setPreferredDevice(d);
* break;
* }
* }
* }
* SpeechService service = new SpeechService(recognizer, 16000f, recorder);
* </pre>
* <p>
* The caller retains ownership of {@code recorder}: if this constructor
* throws, the recorder is <em>not</em> released. Call
* {@link AudioRecord#release()} yourself in that case.
*
* @param recognizer the Vosk recognizer
* @param sampleRate sample rate in Hz; must match {@code recorder}'s configuration
* @param recorder a fully-initialised {@link AudioRecord}
* @throws IOException if {@code recorder} is in STATE_UNINITIALIZED
*/
public SpeechService(Recognizer recognizer, float sampleRate, AudioRecord recorder)
throws IOException {
this.recognizer = recognizer;
this.sampleRate = (int) sampleRate;
this.recorder = recorder;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
throw new IOException(
"Failed to initialize recorder. Microphone might be already in use.");
}
}
/**
* Starts recognition. Does nothing if recognition is active.
*
* @return true if recognition was actually started
*/
public boolean startListening(RecognitionListener listener) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(listener);
recognizerThread.start();
return true;
}
/**
* Starts recognition. After specified timeout listening stops and the
* endOfSpeech signals about that. Does nothing if recognition is active.
* <p>
* timeout - timeout in milliseconds to listen.
*
* @return true if recognition was actually started
*/
public boolean startListening(RecognitionListener listener, int timeout) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(listener, timeout);
recognizerThread.start();
return true;
}
private boolean stopRecognizerThread() {
if (null == recognizerThread)
return false;
try {
recognizerThread.interrupt();
recognizerThread.join();
} catch (InterruptedException e) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
recognizerThread = null;
return true;
}
/**
* Stops recognition. Listener should receive final result if there is
* any. Does nothing if recognition is not active.
*
* @return true if recognition was actually stopped
*/
public boolean stop() {
return stopRecognizerThread();
}
/**
* Cancel recognition. Do not post any new events, simply cancel processing.
* Does nothing if recognition is not active.
*
* @return true if recognition was actually stopped
*/
public boolean cancel() {
if (recognizerThread != null) {
recognizerThread.setPause(true);
}
return stopRecognizerThread();
}
/**
* Returns the audio session ID of the underlying {@link AudioRecord}.
* <p>
* The session ID can be used to attach audio effects such as
* {@link android.media.audiofx.NoiseSuppressor} to the recording session.
*
* @return audio session ID, or {@link AudioRecord#ERROR} if unavailable
*/
public int getAudioSessionId() {
return recorder.getAudioSessionId();
}
/**
* Shutdown the recognizer and release the recorder
*/
public void shutdown() {
recorder.release();
}
public void setPause(boolean paused) {
if (recognizerThread != null) {
recognizerThread.setPause(paused);
}
}
/**
* Resets recognizer in a thread, starts recognition over again
*/
public void reset() {
if (recognizerThread != null) {
recognizerThread.reset();
}
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private final int timeoutSamples;
private final static int NO_TIMEOUT = -1;
private volatile boolean paused = false;
private volatile boolean reset = false;
RecognitionListener listener;
public RecognizerThread(RecognitionListener listener, int timeout) {
this.listener = listener;
if (timeout != NO_TIMEOUT)
this.timeoutSamples = timeout * sampleRate / 1000;
else
this.timeoutSamples = NO_TIMEOUT;
this.remainingSamples = this.timeoutSamples;
}
public RecognizerThread(RecognitionListener listener) {
this(listener, NO_TIMEOUT);
}
/**
* When we are paused, don't process audio by the recognizer and don't emit
* any listener results
*
* @param paused the status of pause
*/
public void setPause(boolean paused) {
this.paused = paused;
}
/**
* Set reset state to signal reset of the recognizer and start over
*/
public void reset() {
this.reset = true;
}
@Override
public void run() {
recorder.startRecording();
if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) {
recorder.stop();
IOException ioe = new IOException(
"Failed to start recording. Microphone might be already in use.");
mainHandler.post(() -> listener.onError(ioe));
}
short[] buffer = new short[bufferSize];
while (!interrupted()
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
int nread = recorder.read(buffer, 0, buffer.length);
if (paused) {
continue;
}
if (reset) {
recognizer.reset();
reset = false;
}
if (nread < 0)
throw new RuntimeException("error reading audio buffer");
if (recognizer.acceptWaveForm(buffer, nread)) {
final String result = recognizer.getResult();
mainHandler.post(() -> listener.onResult(result));
} else {
final String partialResult = recognizer.getPartialResult();
mainHandler.post(() -> listener.onPartialResult(partialResult));
}
if (timeoutSamples != NO_TIMEOUT) {
remainingSamples = remainingSamples - nread;
}
}
recorder.stop();
if (!paused) {
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(() -> listener.onTimeout());
} else {
final String finalResult = recognizer.getFinalResult();
mainHandler.post(() -> listener.onFinalResult(finalResult));
}
}
}
}
}
@@ -1,165 +0,0 @@
// Copyright 2019 Alpha Cephei Inc.
//
// 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.
package org.vosk.android;
import android.os.Handler;
import android.os.Looper;
import org.vosk.Recognizer;
import java.io.IOException;
import java.io.InputStream;
/**
* Service that recognizes stream audio in a thread, passes it to a recognizer and emits
* recognition results. Recognition events are passed to a client using
* {@link RecognitionListener}
*/
public class SpeechStreamService {
private final Recognizer recognizer;
private final InputStream inputStream;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.2f;
private final int bufferSize;
private Thread recognizerThread;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
/**
* Creates speech service.
**/
public SpeechStreamService(Recognizer recognizer, InputStream inputStream, float sampleRate) {
this.recognizer = recognizer;
this.sampleRate = (int) sampleRate;
this.inputStream = inputStream;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS * 2);
}
/**
* Starts recognition. Does nothing if recognition is active.
*
* @return true if recognition was actually started
*/
public boolean start(RecognitionListener listener) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(listener);
recognizerThread.start();
return true;
}
/**
* Starts recognition. After specified timeout listening stops and the
* endOfSpeech signals about that. Does nothing if recognition is active.
* <p>
* timeout - timeout in milliseconds to listen.
*
* @return true if recognition was actually started
*/
public boolean start(RecognitionListener listener, int timeout) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(listener, timeout);
recognizerThread.start();
return true;
}
/**
* Stops recognition. All listeners should receive final result if there is
* any. Does nothing if recognition is not active.
*
* @return true if recognition was actually stopped
*/
public boolean stop() {
if (null == recognizerThread)
return false;
try {
recognizerThread.interrupt();
recognizerThread.join();
} catch (InterruptedException e) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
recognizerThread = null;
return true;
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private final int timeoutSamples;
private final static int NO_TIMEOUT = -1;
RecognitionListener listener;
public RecognizerThread(RecognitionListener listener, int timeout) {
this.listener = listener;
if (timeout != NO_TIMEOUT)
this.timeoutSamples = timeout * sampleRate / 1000;
else
this.timeoutSamples = NO_TIMEOUT;
this.remainingSamples = this.timeoutSamples;
}
public RecognizerThread(RecognitionListener listener) {
this(listener, NO_TIMEOUT);
}
@Override
public void run() {
byte[] buffer = new byte[bufferSize];
while (!interrupted()
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
try {
int nread = inputStream.read(buffer, 0, buffer.length);
if (nread < 0) {
break;
} else {
boolean isSilence = recognizer.acceptWaveForm(buffer, nread);
if (isSilence) {
final String result = recognizer.getResult();
mainHandler.post(() -> listener.onResult(result));
} else {
final String partialResult = recognizer.getPartialResult();
mainHandler.post(() -> listener.onPartialResult(partialResult));
}
}
if (timeoutSamples != NO_TIMEOUT) {
remainingSamples = remainingSamples - nread;
}
} catch (IOException e) {
mainHandler.post(() -> listener.onError(e));
}
}
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(() -> listener.onTimeout());
} else {
final String finalResult = recognizer.getFinalResult();
mainHandler.post(() -> listener.onFinalResult(finalResult));
}
}
}
}
@@ -1,150 +0,0 @@
// Copyright 2019 Alpha Cephei Inc.
//
// 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.
package org.vosk.android;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import org.vosk.Model;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
/**
* Provides utility methods to sync model files to external storage to allow
* C++ code access them. Relies on file named "uuid" to track updates.
*/
public class StorageService {
protected static final String TAG = StorageService.class.getSimpleName();
public interface Callback<R> {
void onComplete(R result);
}
public static void unpack(Context context, String sourcePath, final String targetPath, final Callback<Model> completeCallback, final Callback<IOException> errorCallback) {
Executor executor = Executors.newSingleThreadExecutor(); // change according to your requirements
Handler handler = new Handler(Looper.getMainLooper());
executor.execute(() -> {
try {
final String outputPath = sync(context, sourcePath, targetPath);
Model model = new Model(outputPath);
handler.post(() -> completeCallback.onComplete(model));
} catch (final IOException e) {
handler.post(() -> errorCallback.onComplete(e));
}
});
}
public static String sync(Context context, String sourcePath, String targetPath) throws IOException {
AssetManager assetManager = context.getAssets();
File externalFilesDir = context.getExternalFilesDir(null);
if (externalFilesDir == null) {
throw new IOException("cannot get external files dir, "
+ "external storage state is " + Environment.getExternalStorageState());
}
File targetDir = new File(externalFilesDir, targetPath);
String resultPath = new File(targetDir, sourcePath).getAbsolutePath();
String sourceUUID = readLine(assetManager.open(sourcePath + "/uuid"));
try {
String targetUUID = readLine(new FileInputStream(new File(targetDir, sourcePath + "/uuid")));
if (targetUUID.equals(sourceUUID)) return resultPath;
} catch (FileNotFoundException e) {
// ignore
}
deleteContents(targetDir);
copyAssets(assetManager, sourcePath, targetDir);
// Copy uuid
copyFile(assetManager, sourcePath + "/uuid", targetDir);
return resultPath;
}
private static String readLine(InputStream is) throws IOException {
return new BufferedReader(new InputStreamReader(is)).readLine();
}
private static boolean deleteContents(File dir) {
File[] files = dir.listFiles();
boolean success = true;
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
success &= deleteContents(file);
}
if (!file.delete()) {
success = false;
}
}
}
return success;
}
private static void copyAssets(AssetManager assetManager, String path, File outPath) throws IOException {
String[] assets = assetManager.list(path);
if (assets == null) {
return;
}
if (assets.length == 0) {
if (!path.endsWith("uuid"))
copyFile(assetManager, path, outPath);
} else {
File dir = new File(outPath, path);
if (!dir.exists()) {
Log.v(TAG, "Making directory " + dir.getAbsolutePath());
if (!dir.mkdirs()) {
Log.v(TAG, "Failed to create directory " + dir.getAbsolutePath());
}
}
for (String asset : assets) {
copyAssets(assetManager, path + "/" + asset, outPath);
}
}
}
private static void copyFile(AssetManager assetManager, String fileName, File outPath) throws IOException {
InputStream in;
Log.v(TAG, "Copy " + fileName + " to " + outPath);
in = assetManager.open(fileName);
OutputStream out = new FileOutputStream(outPath + "/" + fileName);
byte[] buffer = new byte[4000];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
in.close();
out.close();
}
}
+60 -32
View File
@@ -1,43 +1,71 @@
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
plugins {
id "com.jfrog.bintray"
}
def archiveName = "vosk-model-en"
def pomName = "Vosk English Model"
def pomDescription = "Small English model for Android"
def libVersion = "0.3.16"
allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
android {
namespace "org.vosk"
compileSdkVersion 36
compileSdkVersion 29
defaultConfig {
minSdkVersion 21
targetSdkVersion 36
versionCode 10
versionName = version
targetSdkVersion 29
versionCode 6
versionName = libVersion
archivesBaseName = archiveName
}
buildFeatures {
buildConfig = false
}
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
bintray {
user = properties.getProperty("bintray.user")
key = properties.getProperty("bintray.apikey")
pkg {
repo = 'vosk'
name = 'vosk-model-en'
userOrg = "alphacep"
licenses = ['Apache2.0']
websiteUrl = 'https://github.com/alphacep/vosk-api'
issueTrackerUrl = 'https://github.com/alphacep/vosk-api/issues'
vcsUrl = 'https://github.com/alphacep/vosk-api'
version {
name = libVersion
vcsTag = libVersion
}
}
sourceSets {
main {
assets.srcDirs += "$buildDir/generated/assets"
publications = ['aar']
}
publishing {
publications {
aar(MavenPublication) {
groupId 'com.alphacep'
artifactId archiveName
version libVersion
artifact("$buildDir/outputs/aar/$archiveName-release.aar")
}
}
}
tasks.register('genUUID') {
def uuid = UUID.randomUUID().toString()
def odir = file("$buildDir/generated/assets/model-en-us")
def ofile = file("$odir/uuid")
doLast {
mkdir odir
ofile.text = uuid
}
}
preBuild.dependsOn(genUUID)
mavenPublishing {
coordinates("com.alphacephei", archiveName, version)
pom {
name = pomName
description = pomDescription
}
}
@@ -1,2 +1,3 @@
<manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.kaldi.model.en">
</manifest>
@@ -0,0 +1,2 @@
US English model for android
@@ -0,0 +1 @@
0.3.16
+1 -1
View File
@@ -1 +1 @@
include ':lib', ':model-en'
include 'model-en'
+3
View File
@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.kaldi">
</manifest>
+262
View File
@@ -0,0 +1,262 @@
// Copyright 2019 Alpha Cephei Inc.
//
// 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.
package org.kaldi;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import android.content.Context;
import android.content.res.AssetManager;
import android.os.Environment;
import android.util.Log;
/**
* Provides utility methods to keep asset files to external storage to allow
* further JNI code access assets from a filesystem.
*
* There must be special file {@value #ASSET_LIST_NAME} among the application
* assets containing relative paths of assets to synchronize. If the
* corresponding path does not exist on the external storage it is copied. If
* the path exists checksums are compared and the asset is copied only if there
* is a mismatch. Checksum is stored in a separate asset with the name that
* consists of the original name and a suffix that depends on the checksum
* algorithm (e.g. MD5). Checksum files are copied along with the corresponding
* asset files.
*
* @author Alexander Solovets
*/
public class Assets {
protected static final String TAG = Assets.class.getSimpleName();
public static final String ASSET_LIST_NAME = "assets.lst";
public static final String SYNC_DIR = "sync";
public static final String HASH_EXT = ".md5";
private final AssetManager assetManager;
private final File externalDir;
/**
* Creates new instance for asset synchronization
*
* @param context
* application context
*
* @throws IOException
* if the directory does not exist
*
* @see android.content.Context#getExternalFilesDir
* @see android.os.Environment#getExternalStorageState
*/
public Assets(Context context) throws IOException {
File appDir = context.getExternalFilesDir(null);
if (null == appDir)
throw new IOException("cannot get external files dir, "
+ "external storage state is " + Environment.getExternalStorageState());
externalDir = new File(appDir, SYNC_DIR);
assetManager = context.getAssets();
}
/**
* Creates new instance with specified destination for assets
*
* @param context
* application context to retrieve the assets
* @param path
* path to sync the files
*/
public Assets(Context context, String dest) {
externalDir = new File(dest);
assetManager = context.getAssets();
}
/**
* Returns destination path on external storage where assets are copied.
*
* @return path to application directory or null if it does not exists
*/
public File getExternalDir() {
return externalDir;
}
/**
* Returns the map of asset paths to the files checksums.
*
* @return path to the root of resources directory on external storage
* @throws IOException
* if an I/O error occurs or "assets.lst" is missing
*/
public Map<String, String> getItems() throws IOException {
Map<String, String> items = new HashMap<String, String>();
for (String path : readLines(openAsset(ASSET_LIST_NAME))) {
Reader reader = new InputStreamReader(openAsset(path + HASH_EXT));
items.put(path, new BufferedReader(reader).readLine());
}
return items;
}
/**
* Returns path to hash mappings for the previously copied files. This
* method can be used to find out assets which must be updated.
*/
public Map<String, String> getExternalItems() {
try {
Map<String, String> items = new HashMap<String, String>();
File assetFile = new File(externalDir, ASSET_LIST_NAME);
for (String line : readLines(new FileInputStream(assetFile))) {
String[] fields = line.split(" ");
items.put(fields[0], fields[1]);
}
return items;
} catch (IOException e) {
return Collections.emptyMap();
}
}
/**
* In case you want to create more smart sync implementation, this method
* returns the list of items which must be synchronized.
*/
public Collection<String> getItemsToCopy(String path) throws IOException {
Collection<String> items = new ArrayList<String>();
Queue<String> queue = new ArrayDeque<String>();
queue.offer(path);
while (!queue.isEmpty()) {
path = queue.poll();
String[] list = assetManager.list(path);
for (String nested : list)
queue.offer(nested);
if (list.length == 0)
items.add(path);
}
return items;
}
private List<String> readLines(InputStream source) throws IOException {
List<String> lines = new ArrayList<String>();
BufferedReader br = new BufferedReader(new InputStreamReader(source));
String line;
while (null != (line = br.readLine()))
lines.add(line);
return lines;
}
private InputStream openAsset(String asset) throws IOException {
return assetManager.open(new File(SYNC_DIR, asset).getPath());
}
/**
* Saves the list of synchronized items. The list is stored as a two-column
* space-separated list of items in a text file. The file is located at the
* root of synchronization directory in the external storage.
*
* @param items
* the items
* @throws IOException
* if an I/O error occurs
*/
public void updateItemList(Map<String, String> items) throws IOException {
File assetListFile = new File(externalDir, ASSET_LIST_NAME);
PrintWriter pw = new PrintWriter(new FileOutputStream(assetListFile));
for (Map.Entry<String, String> entry : items.entrySet())
pw.format("%s %s\n", entry.getKey(), entry.getValue());
pw.close();
}
/**
* Copies raw asset resource to external storage of the device.
*
* @param path
* path of the asset to copy
* @throws IOException
* if an I/O error occurs
*/
public File copy(String asset) throws IOException {
InputStream source = openAsset(asset);
File destinationFile = new File(externalDir, asset);
destinationFile.getParentFile().mkdirs();
OutputStream destination = new FileOutputStream(destinationFile);
byte[] buffer = new byte[1024];
int nread;
while ((nread = source.read(buffer)) != -1) {
if (nread == 0) {
nread = source.read();
if (nread < 0)
break;
destination.write(nread);
continue;
}
destination.write(buffer, 0, nread);
}
destination.close();
return destinationFile;
}
/**
* Performs the sync of assets in the application and on the external
* storage
*
* @return The folder on external storage with data
* @throws IOException
*/
public File syncAssets() throws IOException {
Collection<String> newItems = new ArrayList<String>();
Collection<String> unusedItems = new ArrayList<String>();
Map<String, String> items = getItems();
Map<String, String> externalItems = getExternalItems();
for (String path : items.keySet()) {
if (!items.get(path).equals(externalItems.get(path))
|| !(new File(externalDir, path).exists()))
newItems.add(path);
}
unusedItems.addAll(externalItems.keySet());
unusedItems.removeAll(items.keySet());
for (String path : newItems) {
File file = copy(path);
}
for (String path : unusedItems) {
File file = new File(externalDir, path);
file.delete();
}
updateItemList(items);
return externalDir;
}
}
@@ -12,35 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package org.vosk.android;
package org.kaldi;
/**
* Interface to receive recognition results
*/
/** Interface to receive recognition results */
public interface RecognitionListener {
/**
* Called when partial recognition result is available.
*/
void onPartialResult(String hypothesis);
public void onPartialResult(String hypothesis);
/**
* Called after silence occured.
* Called after the recognition is ended.
*/
void onResult(String hypothesis);
/**
* Called after stream end.
*/
void onFinalResult(String hypothesis);
public void onResult(String hypothesis);
/**
* Called when an error occurs.
*/
void onError(Exception exception);
public void onError(Exception exception);
/**
* Called after timeout expired
*/
void onTimeout();
public void onTimeout();
}
@@ -0,0 +1,286 @@
// Copyright 2019 Alpha Cephei Inc.
//
// 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.
package org.kaldi;
import static java.lang.String.format;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
/**
* Service that records audio in a thread, passes it to a recognizer and emits
* recognition results. Recognition events are passed to a client using
* {@link RecognitionListener}
*
*/
public class SpeechService {
protected static final String TAG = SpeechService.class.getSimpleName();
private final KaldiRecognizer recognizer;
private final int sampleRate;
private final static float BUFFER_SIZE_SECONDS = 0.4f;
private int bufferSize;
private final AudioRecord recorder;
private Thread recognizerThread;
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private final Collection<RecognitionListener> listeners = new HashSet<RecognitionListener>();
/**
* Creates speech service. Service holds the AudioRecord object, so you
* need to call {@link release} in order to properly finalize it.
*
* @throws IOException thrown if audio recorder can not be created for some reason.
*/
public SpeechService(KaldiRecognizer recognizer, float sampleRate) throws IOException {
this.recognizer = recognizer;
this.sampleRate = (int)sampleRate;
bufferSize = Math.round(this.sampleRate * BUFFER_SIZE_SECONDS);
recorder = new AudioRecord(
AudioSource.VOICE_RECOGNITION, this.sampleRate,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSize * 2);
if (recorder.getState() == AudioRecord.STATE_UNINITIALIZED) {
recorder.release();
throw new IOException(
"Failed to initialize recorder. Microphone might be already in use.");
}
}
/**
* Adds listener.
*/
public void addListener(RecognitionListener listener) {
synchronized (listeners) {
listeners.add(listener);
}
}
/**
* Removes listener.
*/
public void removeListener(RecognitionListener listener) {
synchronized (listeners) {
listeners.remove(listener);
}
}
/**
* Starts recognition. Does nothing if recognition is active.
*
* @return true if recognition was actually started
*/
public boolean startListening() {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread();
recognizerThread.start();
return true;
}
/**
* Starts recognition. After specified timeout listening stops and the
* endOfSpeech signals about that. Does nothing if recognition is active.
*
* @timeout - timeout in milliseconds to listen.
*
* @return true if recognition was actually started
*/
public boolean startListening(int timeout) {
if (null != recognizerThread)
return false;
recognizerThread = new RecognizerThread(timeout);
recognizerThread.start();
return true;
}
private boolean stopRecognizerThread() {
if (null == recognizerThread)
return false;
try {
recognizerThread.interrupt();
recognizerThread.join();
} catch (InterruptedException e) {
// Restore the interrupted status.
Thread.currentThread().interrupt();
}
recognizerThread = null;
return true;
}
/**
* Stops recognition. All listeners should receive final result if there is
* any. Does nothing if recognition is not active.
*
* @return true if recognition was actually stopped
*/
public boolean stop() {
boolean result = stopRecognizerThread();
if (result) {
mainHandler.post(new ResultEvent(recognizer.Result(), true));
}
return result;
}
/**
* Cancels recognition. Listeners do not receive final result. Does nothing
* if recognition is not active.
*
* @return true if recognition was actually canceled
*/
public boolean cancel() {
boolean result = stopRecognizerThread();
recognizer.Result(); // Reset recognizer state
return result;
}
/**
* Shutdown the recognizer and release the recorder
*/
public void shutdown() {
recorder.release();
}
private final class RecognizerThread extends Thread {
private int remainingSamples;
private int timeoutSamples;
private final static int NO_TIMEOUT = -1;
public RecognizerThread(int timeout) {
if (timeout != NO_TIMEOUT)
this.timeoutSamples = timeout * sampleRate / 1000;
else
this.timeoutSamples = NO_TIMEOUT;
this.remainingSamples = this.timeoutSamples;
}
public RecognizerThread() {
this(NO_TIMEOUT);
}
@Override
public void run() {
recorder.startRecording();
if (recorder.getRecordingState() == AudioRecord.RECORDSTATE_STOPPED) {
recorder.stop();
IOException ioe = new IOException(
"Failed to start recording. Microphone might be already in use.");
mainHandler.post(new OnErrorEvent(ioe));
return;
}
short[] buffer = new short[bufferSize];
while (!interrupted()
&& ((timeoutSamples == NO_TIMEOUT) || (remainingSamples > 0))) {
int nread = recorder.read(buffer, 0, buffer.length);
if (nread < 0) {
throw new RuntimeException("error reading audio buffer");
} else {
boolean isFinal = recognizer.AcceptWaveform(buffer, nread);
if (isFinal) {
mainHandler.post(new ResultEvent(recognizer.Result(), true));
} else {
mainHandler.post(new ResultEvent(recognizer.PartialResult(), false));
}
}
if (timeoutSamples != NO_TIMEOUT) {
remainingSamples = remainingSamples - nread;
}
}
recorder.stop();
// Remove all pending notifications.
mainHandler.removeCallbacksAndMessages(null);
// If we met timeout signal that speech ended
if (timeoutSamples != NO_TIMEOUT && remainingSamples <= 0) {
mainHandler.post(new TimeoutEvent());
}
}
}
private abstract class RecognitionEvent implements Runnable {
public void run() {
RecognitionListener[] emptyArray = new RecognitionListener[0];
for (RecognitionListener listener : listeners.toArray(emptyArray))
execute(listener);
}
protected abstract void execute(RecognitionListener listener);
}
private class ResultEvent extends RecognitionEvent {
protected final String hypothesis;
private final boolean finalResult;
ResultEvent(String hypothesis, boolean finalResult) {
this.hypothesis = hypothesis;
this.finalResult = finalResult;
}
@Override
protected void execute(RecognitionListener listener) {
if (finalResult)
listener.onResult(hypothesis);
else
listener.onPartialResult(hypothesis);
}
}
private class OnErrorEvent extends RecognitionEvent {
private final Exception exception;
OnErrorEvent(Exception exception) {
this.exception = exception;
}
@Override
protected void execute(RecognitionListener listener) {
listener.onError(exception);
}
}
private class TimeoutEvent extends RecognitionEvent {
@Override
protected void execute(RecognitionListener listener) {
listener.onTimeout();
}
}
}
+44 -7
View File
@@ -1,16 +1,53 @@
CFLAGS=-I../src
LDFLAGS=-L../src -lvosk -ldl -lpthread -Wl,-rpath,../src
KALDI_ROOT=$(HOME)/travis/kaldi
VOSK_SOURCES= \
../src/kaldi_recognizer.cc \
../src/language_model.cc \
../src/model.cc \
../src/spk_model.cc \
../src/vosk_api.cc
CFLAGS=-g -O2 -DFST_NO_DYNAMIC_LINKING -I../src -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include
LIBS= \
$(KALDI_ROOT)/src/online2/kaldi-online2.a \
$(KALDI_ROOT)/src/decoder/kaldi-decoder.a \
$(KALDI_ROOT)/src/ivector/kaldi-ivector.a \
$(KALDI_ROOT)/src/gmm/kaldi-gmm.a \
$(KALDI_ROOT)/src/nnet3/kaldi-nnet3.a \
$(KALDI_ROOT)/src/tree/kaldi-tree.a \
$(KALDI_ROOT)/src/feat/kaldi-feat.a \
$(KALDI_ROOT)/src/lat/kaldi-lat.a \
$(KALDI_ROOT)/src/lm/kaldi-lm.a \
$(KALDI_ROOT)/src/hmm/kaldi-hmm.a \
$(KALDI_ROOT)/src/transform/kaldi-transform.a \
$(KALDI_ROOT)/src/cudamatrix/kaldi-cudamatrix.a \
$(KALDI_ROOT)/src/matrix/kaldi-matrix.a \
$(KALDI_ROOT)/src/fstext/kaldi-fstext.a \
$(KALDI_ROOT)/src/util/kaldi-util.a \
$(KALDI_ROOT)/src/base/kaldi-base.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libopenblas.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/liblapack.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libblas.a \
$(KALDI_ROOT)/tools/OpenBLAS/install/lib/libf2c.a \
$(KALDI_ROOT)/tools/openfst/lib/libfst.a \
$(KALDI_ROOT)/tools/openfst/lib/libfstngram.a
all: test_vosk test_vosk_speaker
test_vosk: test_vosk.o
gcc $^ -o $@ $(LDFLAGS)
test_vosk: test_vosk.o libvosk.a
g++ $^ -o $@ $(LIBS) -lpthread
test_vosk_speaker: test_vosk_speaker.o
gcc $^ -o $@ $(LDFLAGS)
test_vosk_speaker: test_vosk_speaker.o libvosk.a
g++ $^ -o $@ $(LIBS) -lpthread
libvosk.a: $(VOSK_SOURCES:.cc=.o)
ar rcs $@ $^
%.o: %.c
gcc $(CFLAGS) -c -o $@ $<
g++ $(CFLAGS) -c -o $@ $<
%.o: %.cc
g++ -std=c++17 $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o *.a test_vosk test_vosk_speaker
+1 -1
View File
@@ -8,7 +8,7 @@ int main() {
VoskModel *model = vosk_model_new("model");
VoskSpkModel *spk_model = vosk_spk_model_new("spk-model");
VoskRecognizer *recognizer = vosk_recognizer_new_spk(model, 16000.0, spk_model);
VoskRecognizer *recognizer = vosk_recognizer_new_spk(model, spk_model, 16000.0);
wavin = fopen("test.wav", "rb");
fseek(wavin, 44, SEEK_SET);
+68
View File
@@ -0,0 +1,68 @@
KALDI_ROOT ?= $(HOME)/kaldi
CFLAGS := -std=c++17 -g -O2 -DPIC -fPIC -Wno-unused-function
CPPFLAGS := -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include -I../src -DFST_NO_DYNAMIC_LINKING
KALDI_LIBS = \
${KALDI_ROOT}/src/online2/kaldi-online2.a \
${KALDI_ROOT}/src/decoder/kaldi-decoder.a \
${KALDI_ROOT}/src/ivector/kaldi-ivector.a \
${KALDI_ROOT}/src/gmm/kaldi-gmm.a \
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
${KALDI_ROOT}/src/matrix/kaldi-matrix.a \
${KALDI_ROOT}/src/fstext/kaldi-fstext.a \
${KALDI_ROOT}/src/util/kaldi-util.a \
${KALDI_ROOT}/src/base/kaldi-base.a \
${KALDI_ROOT}/tools/openfst/lib/libfst.a \
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a
# On Linux
MATH_LIBS = \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libopenblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/liblapack.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libf2c.a
# On OSX
# MATH_LIBS = -framework Accelerate
all: test.exe
test.exe: libkaldiwrap.so test.cs
mcs -out:Vosk.dll -target:library gen/*.cs
mcs test.cs -r:Vosk.dll -out:test.exe
VOSK_SOURCES = \
vosk_wrap.c \
../src/kaldi_recognizer.cc \
../src/language_model.cc \
../src/model.cc \
../src/spk_model.cc \
../src/vosk_api.cc
VOSK_HEADERS = \
../src/kaldi_recognizer.h \
../src/language_model.h \
../src/model.h \
../src/vosk_api.h \
../src/spk_model.h
libkaldiwrap.so: $(VOSK_SOURCES) $(VOSK_HEADERS)
$(CXX) -fpermissive $(CFLAGS) $(CPPFLAGS) -shared -o $@ $(VOSK_SOURCES) $(KALDI_LIBS) $(MATH_LIBS)
vosk_wrap.c: ../src/vosk.i
mkdir -p gen
swig -csharp -DSWIG_CSHARP_NO_EXCEPTION_HELPER -dllimport "libkaldiwrap" \
-namespace "Kaldi" -outdir gen -o vosk_wrap.c ../src/vosk.i
run: test.exe
mono test.exe
clean:
$(RM) *.so vosk_wrap.c *.o gen/*.cs test.exe *.dll
-12
View File
@@ -1,12 +0,0 @@
This is a nuget-based wrapper for libvosk library
See demo folder for example how to use the library. You can simply run
"dotnet run" to run the demo. Make sure you unpacked the model and the
test file.
See the nuget folder for the sources of the wrapper. Run build.sh to
build nuget package.
Note we only support win64 and linux64 for now. No support for win32
since it is a little bit painful to load the libraries depending on
architecture. In theory we can add OSX some time or even Android.
-83
View File
@@ -1,83 +0,0 @@
using System;
using System.IO;
using Vosk;
public class VoskDemo
{
public static void DemoBytes(Model model)
{
// Demo byte buffer
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetMaxAlternatives(0);
rec.SetWords(true);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void DemoFloats(Model model)
{
// Demo float array
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetEndpointerMode(EndpointerMode.LONG);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
float[] fbuffer = new float[bytesRead / 2];
for (int i = 0, n = 0; i < fbuffer.Length; i++, n+=2) {
fbuffer[i] = BitConverter.ToInt16(buffer, n);
}
if (rec.AcceptWaveform(fbuffer, fbuffer.Length)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void DemoSpeaker(Model model)
{
// Output speakers
SpkModel spkModel = new SpkModel("model-spk");
VoskRecognizer rec = new VoskRecognizer(model, 16000.0f);
rec.SetSpkModel(spkModel);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
public static void Main()
{
// You can set to -1 to disable logging messages
Vosk.Vosk.SetLogLevel(0);
Model model = new Model("model");
DemoBytes(model);
DemoFloats(model);
DemoSpeaker(model);
}
}
-17
View File
@@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>VoskDemo</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<RestoreSources>$(RestoreSources);../nuget</RestoreSources>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vosk" Version="0.3.75" />
</ItemGroup>
</Project>
-17
View File
@@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackageId>Vosk</PackageId>
<Version>0.3.75</Version>
<authors>Alpha Cephei Inc</authors>
<owners>Alpha Cephei Inc</owners>
</PropertyGroup>
<Target Name="CopyFiles" AfterTargets="Build">
<Copy SourceFiles="bin/Release/net8.0/Vosk.dll" DestinationFolder="lib/net8.0" />
</Target>
</Project>
+4 -9
View File
@@ -2,14 +2,13 @@
<package>
<metadata>
<id>Vosk</id>
<version>0.3.75</version>
<version>0.3.16</version>
<authors>Alpha Cephei Inc</authors>
<owners>Alpha Cephei Inc</owners>
<license type="expression">Apache-2.0</license>
<projectUrl>https://alphacephei.com/vosk/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<title>Vosk Speech Recognition Toolkit</title>
<description>Vosk is an offline open source speech recognition toolkit. It enables speech recognition models for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech. More to come.
<description>Vosk is an offline open source speech recognition toolkit. It enables speech recognition models for 16 languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi.
Vosk models are small (50 Mb) but provide continuous large vocabulary transcription, zero-latency response with streaming API, reconfigurable vocabulary and speaker identification.
@@ -19,14 +18,10 @@ Vosk supplies speech recognition for chatbots, smart home appliances, virtual as
Vosk scales from small devices like Raspberry Pi or Android smartphone to big clusters.</description>
<releaseNotes>See for details https://github.com/alphacep/vosk-api/releases</releaseNotes>
<repository type="git" url="https://github.com/alphacep/vosk-api.git" branch="master"/>
<copyright>Copyright 2020-2050 Alpha Cephei Inc</copyright>
<copyright>Copyright 2020 Alpha Cephei Inc</copyright>
<tags>speech recognition voice stt asr speech-to-text ai offline privacy</tags>
<dependencies>
<group targetFramework="net8.0"/>
<group targetFramework=".NETStandard2.0"/>
</dependencies>
</metadata>
<files>
<file src="**" exclude="bin/**;obj/**;build.sh;src/*.cs;*.nupkg;**/.keep-me" />
</files>
</package>
-2
View File
@@ -1,2 +0,0 @@
rm -rf bin lib obj
/home/shmyrev/local/dotnet/dotnet pack Vosk.csproj -p:NuspecFile=Vosk.nuspec -o .
-11
View File
@@ -1,11 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\linux-x64\*.so" Condition="'$([MSBuild]::IsOsPlatform(Linux))'" />
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\win-x64\*.dll" Condition="'$([MSBuild]::IsOsPlatform(Windows))'" />
<NativeLibs Include="$(MSBuildThisFileDirectory)\lib\osx-universal\*.dylib" Condition="'$([MSBuild]::IsOsPlatform(OSX))'" />
<None Include="@(NativeLibs)">
<Link>%(FileName)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,9 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Content Include="$(MSBuildThisFileDirectory)lib/**/**">
<Link>%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>false</Visible>
</Content>
</ItemGroup>
</Project>
-55
View File
@@ -1,55 +0,0 @@
using System;
namespace Vosk
{
public class BatchModel : global::System.IDisposable
{
private global::System.Runtime.InteropServices.HandleRef handle;
internal BatchModel(global::System.IntPtr cPtr)
{
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(BatchModel obj)
{
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
}
~BatchModel()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
global::System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
lock (this)
{
if (handle.Handle != global::System.IntPtr.Zero)
{
VoskPINVOKE.delete_BatchModel(handle);
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
}
}
}
public BatchModel(string model_path) : this(VoskPINVOKE.new_BatchModel(model_path))
{
}
public void WaitForCompletion()
{
if (handle.Handle != global::System.IntPtr.Zero)
{
VoskPINVOKE.wait_BatchModel(handle);
}
}
}
}
-41
View File
@@ -1,41 +0,0 @@
namespace Vosk {
public class Model : global::System.IDisposable {
private global::System.Runtime.InteropServices.HandleRef handle;
internal Model(global::System.IntPtr cPtr) {
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(Model obj) {
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
}
~Model() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
global::System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
lock(this) {
if (handle.Handle != global::System.IntPtr.Zero) {
VoskPINVOKE.delete_Model(handle);
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
}
}
}
public Model(string model_path) : this(VoskPINVOKE.new_Model(model_path)) {
}
public int FindWord(string word) {
return VoskPINVOKE.Model_vosk_model_find_word(handle, word);
}
}
}
-37
View File
@@ -1,37 +0,0 @@
namespace Vosk {
public class SpkModel : global::System.IDisposable {
private global::System.Runtime.InteropServices.HandleRef handle;
internal SpkModel(global::System.IntPtr cPtr) {
handle = new global::System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SpkModel obj) {
return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.handle;
}
~SpkModel() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
global::System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
lock(this) {
if (handle.Handle != global::System.IntPtr.Zero) {
VoskPINVOKE.delete_SpkModel(handle);
handle = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero);
}
}
}
public SpkModel(string model_path) : this(VoskPINVOKE.new_SpkModel(model_path)) {
}
}
}
-17
View File
@@ -1,17 +0,0 @@
namespace Vosk {
public class Vosk {
public static void SetLogLevel(int level) {
VoskPINVOKE.SetLogLevel(level);
}
public static void GpuInit() {
VoskPINVOKE.GpuInit();
}
public static void GpuThreadInit() {
VoskPINVOKE.GpuThreadInit();
}
}
}
-88
View File
@@ -1,88 +0,0 @@
using System;
namespace Vosk
{
public class VoskBatchRecognizer : System.IDisposable
{
private System.Runtime.InteropServices.HandleRef handle;
internal VoskBatchRecognizer(System.IntPtr cPtr)
{
handle = new System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static System.Runtime.InteropServices.HandleRef getCPtr(VoskBatchRecognizer obj)
{
return (obj == null) ? new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero) : obj.handle;
}
~VoskBatchRecognizer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
lock (this)
{
if (handle.Handle != System.IntPtr.Zero)
{
VoskPINVOKE.delete_VoskBatchRecognizer(handle);
handle = new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero);
}
}
}
public VoskBatchRecognizer(BatchModel model, float sample_rate) : this(VoskPINVOKE.new_VoskBatchRecognizer(BatchModel.getCPtr(model), sample_rate))
{
}
public bool AcceptWaveform(byte[] data, int len)
{
return VoskPINVOKE.VoskBatchRecognizer_AcceptWaveform(handle, data, len);
}
private static string PtrToStringUTF8(System.IntPtr ptr)
{
int len = 0;
while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
len++;
byte[] array = new byte[len];
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
return System.Text.Encoding.UTF8.GetString(array);
}
public string FrontResult()
{
return PtrToStringUTF8(VoskPINVOKE.VoskBatchRecognizer_FrontResult(handle));
}
public string Result()
{
string result = PtrToStringUTF8(VoskPINVOKE.VoskBatchRecognizer_FrontResult(handle));
VoskPINVOKE.VoskBatchRecognizer_Pop(handle);
return result;
}
public int GetNumPendingChunks()
{
return VoskPINVOKE.VoskBatchRecognizer_GetPendingChunks(handle);
}
public void FinishStream()
{
VoskPINVOKE.VoskBatchRecognizer_FinishStream(handle);
}
public void SetNLSML(bool nlsml)
{
VoskPINVOKE.VoskBatchRecognizer_SetNLSML(handle, Convert.ToInt32(nlsml));
}
}
}
-118
View File
@@ -1,118 +0,0 @@
namespace Vosk {
class VoskPINVOKE {
static VoskPINVOKE() {
}
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_new")]
public static extern global::System.IntPtr new_Model(string jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_free")]
public static extern void delete_Model(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_model_find_word")]
public static extern int Model_vosk_model_find_word(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_spk_model_new")]
public static extern global::System.IntPtr new_SpkModel(string jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_spk_model_free")]
public static extern void delete_SpkModel(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new")]
public static extern global::System.IntPtr new_VoskRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new_spk")]
public static extern global::System.IntPtr new_VoskRecognizerSpk(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, global::System.Runtime.InteropServices.HandleRef jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_new_grm")]
public static extern global::System.IntPtr new_VoskRecognizerGrm(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, string jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_free")]
public static extern void delete_VoskRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_max_alternatives")]
public static extern void VoskRecognizer_SetMaxAlternatives(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_words")]
public static extern void VoskRecognizer_SetWords(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_partial_words")]
public static extern void VoskRecognizer_SetPartialWords(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_spk_model")]
public static extern void VoskRecognizer_SetSpkModel(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_accept_waveform")]
public static extern bool VoskRecognizer_AcceptWaveform(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]byte[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_accept_waveform_s")]
public static extern bool VoskRecognizer_AcceptWaveformShort(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]short[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_accept_waveform_f")]
public static extern bool VoskRecognizer_AcceptWaveformFloat(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)]float[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_result")]
public static extern global::System.IntPtr VoskRecognizer_Result(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_partial_result")]
public static extern global::System.IntPtr VoskRecognizer_PartialResult(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_final_result")]
public static extern global::System.IntPtr VoskRecognizer_FinalResult(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_reset")]
public static extern void VoskRecognizer_Reset(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_endpointer_mode")]
public static extern void VoskRecognizer_SetEndpointerMode(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_recognizer_set_endpointer_delays")]
public static extern void VoskRecognizer_SetEndpointerDelays(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, float jarg3, float jarg4);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_set_log_level")]
public static extern void SetLogLevel(int jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_gpu_init")]
public static extern void GpuInit();
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint="vosk_gpu_thread_init")]
public static extern void GpuThreadInit();
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_new")]
public static extern global::System.IntPtr new_BatchModel(string jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_free")]
public static extern void delete_BatchModel(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_model_wait")]
public static extern void wait_BatchModel(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_new")]
public static extern global::System.IntPtr new_VoskBatchRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_free")]
public static extern void delete_VoskBatchRecognizer(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_accept_waveform")]
public static extern bool VoskBatchRecognizer_AcceptWaveform(global::System.Runtime.InteropServices.HandleRef jarg1, [global::System.Runtime.InteropServices.In, global::System.Runtime.InteropServices.MarshalAs(global::System.Runtime.InteropServices.UnmanagedType.LPArray)] byte[] jarg2, int jarg3);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_set_nlsml")]
public static extern void VoskBatchRecognizer_SetNLSML(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_finish_stream")]
public static extern void VoskBatchRecognizer_FinishStream(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_front_result")]
public static extern global::System.IntPtr VoskBatchRecognizer_FrontResult(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_pop")]
public static extern void VoskBatchRecognizer_Pop(global::System.Runtime.InteropServices.HandleRef jarg1);
[global::System.Runtime.InteropServices.DllImport("libvosk", EntryPoint = "vosk_batch_recognizer_get_pending_chunks")]
public static extern int VoskBatchRecognizer_GetPendingChunks(global::System.Runtime.InteropServices.HandleRef jarg1);
}
}
-111
View File
@@ -1,111 +0,0 @@
namespace Vosk {
public enum EndpointerMode {
DEFAULT = 0,
SHORT = 1,
LONG = 2,
VERY_LONG = 3
}
public class VoskRecognizer : System.IDisposable {
private System.Runtime.InteropServices.HandleRef handle;
internal VoskRecognizer(System.IntPtr cPtr) {
handle = new System.Runtime.InteropServices.HandleRef(this, cPtr);
}
internal static System.Runtime.InteropServices.HandleRef getCPtr(VoskRecognizer obj) {
return (obj == null) ? new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero) : obj.handle;
}
~VoskRecognizer() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
lock(this) {
if (handle.Handle != System.IntPtr.Zero) {
VoskPINVOKE.delete_VoskRecognizer(handle);
handle = new System.Runtime.InteropServices.HandleRef(null, System.IntPtr.Zero);
}
}
}
public VoskRecognizer(Model model, float sample_rate) : this(VoskPINVOKE.new_VoskRecognizer(Model.getCPtr(model), sample_rate)) {
}
public VoskRecognizer(Model model, float sample_rate, SpkModel spk_model) : this(VoskPINVOKE.new_VoskRecognizerSpk(Model.getCPtr(model), sample_rate, SpkModel.getCPtr(spk_model))) {
}
public VoskRecognizer(Model model, float sample_rate, string grammar) : this(VoskPINVOKE.new_VoskRecognizerGrm(Model.getCPtr(model), sample_rate, grammar)) {
}
public void SetMaxAlternatives(int max_alternatives) {
VoskPINVOKE.VoskRecognizer_SetMaxAlternatives(handle, max_alternatives);
}
public void SetWords(bool words) {
VoskPINVOKE.VoskRecognizer_SetWords(handle, words ? 1 : 0);
}
public void SetPartialWords(bool partial_words) {
VoskPINVOKE.VoskRecognizer_SetPartialWords(handle, partial_words ? 1 : 0);
}
public void SetSpkModel(SpkModel spk_model) {
VoskPINVOKE.VoskRecognizer_SetSpkModel(handle, SpkModel.getCPtr(spk_model));
}
public bool AcceptWaveform(byte[] data, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveform(handle, data, len);
}
public bool AcceptWaveform(short[] sdata, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveformShort(handle, sdata, len);
}
public bool AcceptWaveform(float[] fdata, int len) {
return VoskPINVOKE.VoskRecognizer_AcceptWaveformFloat(handle, fdata, len);
}
private static string PtrToStringUTF8(System.IntPtr ptr) {
int len = 0;
while (System.Runtime.InteropServices.Marshal.ReadByte(ptr, len) != 0)
len++;
byte[] array = new byte[len];
System.Runtime.InteropServices.Marshal.Copy(ptr, array, 0, len);
return System.Text.Encoding.UTF8.GetString(array);
}
public string Result() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_Result(handle));
}
public string PartialResult() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_PartialResult(handle));
}
public string FinalResult() {
return PtrToStringUTF8(VoskPINVOKE.VoskRecognizer_FinalResult(handle));
}
public void Reset() {
VoskPINVOKE.VoskRecognizer_Reset(handle);
}
public void SetEndpointerMode(EndpointerMode mode) {
VoskPINVOKE.VoskRecognizer_SetEndpointerMode(handle, (int) mode);
}
public void SetEndpointerDelays(float t_start_max, float t_end, float t_max) {
VoskPINVOKE.VoskRecognizer_SetEndpointerDelays(handle, t_start_max, t_end, t_max);
}
}
}
+47
View File
@@ -0,0 +1,47 @@
using System;
using System.IO;
using Kaldi;
public class Test
{
public static void Main()
{
Vosk.SetLogLevel(0);
Model model = new Model("model");
KaldiRecognizer rec = new KaldiRecognizer(model, 16000.0f);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
if (rec.AcceptWaveform(buffer, bytesRead)) {
Console.WriteLine(rec.Result());
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
rec = new KaldiRecognizer(model, 16000.0f);
using(Stream source = File.OpenRead("test.wav")) {
byte[] buffer = new byte[4096];
int bytesRead;
while((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
float[] fbuffer = new float[bytesRead / 2];
for (int i = 0, n = 0; i < fbuffer.Length; i++, n+=2) {
fbuffer[i] = (short)(buffer[n] | buffer[n+1] << 8);
}
if (rec.AcceptWaveform(fbuffer, fbuffer.Length)) {
Console.WriteLine(rec.Result());
GC.Collect();
} else {
Console.WriteLine(rec.PartialResult());
}
}
}
Console.WriteLine(rec.FinalResult());
}
}
+1
View File
@@ -0,0 +1 @@
See https://alphacephei.com/vosk/accuracy
+1
View File
@@ -0,0 +1 @@
See https://alphacephei.com/vosk/adaptation
+1
View File
@@ -0,0 +1 @@
See https://alphacephei.com/vosk/models
-176
View File
@@ -1,176 +0,0 @@
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
-1
View File
@@ -1 +0,0 @@
See example subfolder for instructions how to use the module
-99
View File
@@ -1,99 +0,0 @@
package vosk
// #cgo CPPFLAGS: -I ${SRCDIR}/../src
// #cgo !windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -ldl -lpthread
// #cgo windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -lpthread
// #include <stdlib.h>
// #include <vosk_api.h>
import "C"
import "unsafe"
// VoskBatchModel contains a reference to the C VoskBatchModel
type VoskBatchModel struct {
model *C.struct_VoskBatchModel
}
// NewBatchModel creates a new VoskBatchModel instance
func NewBatchModel(modelPath string) (*VoskBatchModel, error) {
cmodelPath := C.CString(modelPath)
defer C.free(unsafe.Pointer(cmodelPath))
internal := C.vosk_batch_model_new(cmodelPath)
model := &VoskBatchModel{model: internal}
return model, nil
}
func (m *VoskBatchModel) Free() {
C.vosk_batch_model_free(m.model)
}
func (m *VoskBatchModel) Wait() {
C.vosk_batch_model_wait(m.model);
}
func freeBatchModel(model *VoskBatchModel) {
C.vosk_batch_model_free(model.model)
}
// VoskBatchRecognizer contains a reference to the C VoskBatchRecognizer
type VoskBatchRecognizer struct {
rec *C.struct_VoskBatchRecognizer
}
func freeBatchRecognizer(recognizer *VoskBatchRecognizer) {
C.vosk_batch_recognizer_free(recognizer.rec)
}
func (r *VoskBatchRecognizer) Free() {
C.vosk_batch_recognizer_free(r.rec)
}
// NewBatchRecognizer creates a new VoskBatchRecognizer instance
func NewBatchRecognizer(model *VoskBatchModel, sampleRate float64) (*VoskBatchRecognizer, error) {
internal := C.vosk_batch_recognizer_new(model.model, C.float(sampleRate))
rec := &VoskBatchRecognizer{rec: internal}
return rec, nil
}
// AcceptWaveform accepts and processes a new chunk of the voice data.
func (r *VoskBatchRecognizer) AcceptWaveform(buffer []byte) {
cbuf := C.CBytes(buffer)
defer C.free(cbuf)
C.vosk_batch_recognizer_accept_waveform(r.rec, (*C.char)(cbuf), C.int(len(buffer)))
}
/** Set NLSML output
* @param nlsml - boolean value
*/
//void vosk_batch_recognizer_set_nlsml(VoskBatchRecognizer *recognizer, int nlsml);
func (r *VoskBatchRecognizer) SetNlsml(nlsml int) {
C.vosk_batch_recognizer_set_nlsml(r.rec, C.int(nlsml))
}
/** Closes the stream */
//void vosk_batch_recognizer_finish_stream(VoskBatchRecognizer *recognizer);
func (r *VoskBatchRecognizer) FinishStream() {
C.vosk_batch_recognizer_finish_stream(r.rec)
}
/** Return results */
//const char *vosk_batch_recognizer_front_result(VoskBatchRecognizer *recognizer);
func (r *VoskBatchRecognizer) FrontResult() string {
return C.GoString(C.vosk_batch_recognizer_front_result(r.rec))
}
/** Release and free first retrieved result */
//void vosk_batch_recognizer_pop(VoskBatchRecognizer *recognizer);
func (r *VoskBatchRecognizer) Pop() {
C.vosk_batch_recognizer_pop(r.rec)
}
/** Get amount of pending chunks for more intelligent waiting */
//int vosk_batch_recognizer_get_pending_chunks(VoskBatchRecognizer *recognizer);
func (r *VoskBatchRecognizer) GetPendingChunks() int {
i := C.vosk_batch_recognizer_get_pending_chunks(r.rec)
return int(i)
}
-5
View File
@@ -1,5 +0,0 @@
This example expects a `s16le` converted audio file and converts it to text in a
manner that imitates the Python example of [test_gpu_batch.py](../python/example/test_gpu_batch.py).
Note that the `libvosk.so` must be in the library path. This was successfully tested on
Ubuntu 24.04 with Go 1.18, gcc-11, NVIDIA driver 570.172.08.
-54
View File
@@ -1,54 +0,0 @@
package main
import (
"flag"
"fmt"
"io"
"log"
"os"
vosk "github.com/alphacep/vosk-api/go"
)
func main() {
var filename string
flag.StringVar(&filename, "f", "", "file to transcribe")
flag.Parse()
vosk.GPUInit()
model, err := vosk.NewBatchModel("model")
if err != nil {
log.Fatal(err)
}
rec, err := vosk.NewBatchRecognizer(model, 16000.0)
if err != nil {
log.Fatal(err)
}
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, 8000)
for {
if _, err := file.Read(buf); err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
rec.AcceptWaveform(buf)
model.Wait()
if rec.FrontResult() != "" {
fmt.Println(rec.FrontResult())
rec.Pop()
}
}
// Is this needed? rec.FinishStream()
}
-7
View File
@@ -1,7 +0,0 @@
// Go bindings for Vosk speech recognition toolkit. Vosk is an offline
// open source speech to text API for Android, iOS, Raspberry Pi and
// servers. It enables speech recognition models for 18 languages and
// dialects - English, Indian English, German, French, Spanish, Portuguese,
// Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic,
// Greek, Farsi, Filipino, Ukrainian.
package vosk
-31
View File
@@ -1,31 +0,0 @@
To try this package do the following steps:
On Linux (we download library and set LD_LIBRARY_PATH)
```
git clone https://github.com/alphacep/vosk-api
cd vosk-api/go/example
wget https://github.com/alphacep/vosk-api/releases/download/v0.3.45/vosk-linux-x86_64-0.3.45.zip
unzip vosk-linux-x86_64-0.3.45.zip
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
unzip vosk-model-small-en-us-0.15.zip
mv vosk-model-small-en-us-0.15 model
cp ../../python/example/test.wav .
VOSK_PATH=`pwd`/vosk-linux-x86_64-0.3.45 LD_LIBRARY_PATH=$VOSK_PATH CGO_CPPFLAGS="-I $VOSK_PATH" CGO_LDFLAGS="-L $VOSK_PATH" go run . -f test.wav
```
for Windows (we place DLLs in current folder where linker finds them):
```
git clone https://github.com/alphacep/vosk-api
cd vosk-api/go/example
wget https://github.com/alphacep/vosk-api/releases/download/v0.3.45/vosk-linux-x86_64-0.3.45.zip
unzip vosk-linux-x86_64-0.3.45.zip
cp vosk-linux-x86_64-0.3.45/*.dll .
cp vosk-linux-x86_64-0.3.45/*.h .
wget https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip
unzip vosk-model-small-en-us-0.15.zip
mv vosk-model-small-en-us-0.15 model
cp ../../python/example/test.wav .
VOSK_PATH=`pwd` LD_LIBRARY_PATH=$VOSK_PATH CGO_CPPFLAGS="-I $VOSK_PATH" CGO_LDFLAGS="-L $VOSK_PATH -lvosk -lpthread -dl" go run . -f test.wav
```
-2
View File
@@ -1,2 +0,0 @@
// Example package for Vosk Go bindings.
package main
-63
View File
@@ -1,63 +0,0 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"log"
"os"
vosk "github.com/alphacep/vosk-api/go"
)
func main() {
var filename string
flag.StringVar(&filename, "f", "", "file to transcribe")
flag.Parse()
vosk.GPUInit()
model, err := vosk.NewModel("model")
if err != nil {
log.Fatal(err)
}
// we can check if word is in the vocabulary
// fmt.Println(model.FindWord("air"))
sampleRate := 16000.0
rec, err := vosk.NewRecognizer(model, sampleRate)
if err != nil {
log.Fatal(err)
}
rec.SetWords(1)
file, err := os.Open(filename)
if err != nil {
panic(err)
}
defer file.Close()
buf := make([]byte, 4096)
for {
_, err := file.Read(buf)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
if rec.AcceptWaveform(buf) != 0 {
fmt.Println(rec.Result())
}
}
// Unmarshal example for final result
var jres map[string]interface{}
json.Unmarshal([]byte(rec.FinalResult()), &jres)
fmt.Println(jres["text"])
}
-7
View File
@@ -1,7 +0,0 @@
module github.com/alphacep/vosk-api/go
go 1.16
replace (
github.com/alphacep/vosk-api/go => ./
)
-180
View File
@@ -1,180 +0,0 @@
package vosk
// #cgo CPPFLAGS: -I ${SRCDIR}/../src
// #cgo !windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -ldl -lpthread
// #cgo windows LDFLAGS: -L ${SRCDIR}/../src -lvosk -lpthread
// #include <stdlib.h>
// #include <vosk_api.h>
import "C"
import "unsafe"
// VoskModel contains a reference to the C VoskModel
type VoskModel struct {
model *C.struct_VoskModel
}
// NewModel creates a new VoskModel instance
func NewModel(modelPath string) (*VoskModel, error) {
cmodelPath := C.CString(modelPath)
defer C.free(unsafe.Pointer(cmodelPath))
internal := C.vosk_model_new(cmodelPath)
model := &VoskModel{model: internal}
return model, nil
}
func (m *VoskModel) Free() {
C.vosk_model_free(m.model)
}
func freeModel(model *VoskModel) {
C.vosk_model_free(model.model)
}
// FindWord checks if a word can be recognized by the model.
// Returns the word symbol if the word exists inside the model or
// -1 otherwise.
func (m *VoskModel) FindWord(word string) int {
cstr := C.CString(word)
defer C.free(unsafe.Pointer(cstr))
i := C.vosk_model_find_word(m.model, cstr)
return int(i)
}
// VoskSpkModel contains a reference to the C VoskSpkModel
type VoskSpkModel struct {
spkModel *C.struct_VoskSpkModel
}
// NewSpkModel creates a new VoskSpkModel instance
func NewSpkModel(spkModelPath string) (*VoskSpkModel, error) {
cspkModelPath := C.CString(spkModelPath)
defer C.free(unsafe.Pointer(cspkModelPath))
internal := C.vosk_spk_model_new(cspkModelPath)
spkModel := &VoskSpkModel{spkModel: internal}
return spkModel, nil
}
func freeSpkModel(model *VoskSpkModel) {
C.vosk_spk_model_free(model.spkModel)
}
func(s *VoskSpkModel) Free() {
C.vosk_spk_model_free(s.spkModel)
}
// VoskRecognizer contains a reference to the C VoskRecognizer
type VoskRecognizer struct {
rec *C.struct_VoskRecognizer
}
func freeRecognizer(recognizer *VoskRecognizer) {
C.vosk_recognizer_free(recognizer.rec)
}
func (r *VoskRecognizer) Free() {
C.vosk_recognizer_free(r.rec)
}
// NewRecognizer creates a new VoskRecognizer instance
func NewRecognizer(model *VoskModel, sampleRate float64) (*VoskRecognizer, error) {
internal := C.vosk_recognizer_new(model.model, C.float(sampleRate))
rec := &VoskRecognizer{rec: internal}
return rec, nil
}
// NewRecognizerSpk creates a new VoskRecognizer instance with a speaker model.
func NewRecognizerSpk(model *VoskModel, sampleRate float64, spkModel *VoskSpkModel) (*VoskRecognizer, error) {
internal := C.vosk_recognizer_new_spk(model.model, C.float(sampleRate), spkModel.spkModel)
rec := &VoskRecognizer{rec: internal}
return rec, nil
}
// NewRecognizerGrm creates a new VoskRecognizer instance with the phrase list.
func NewRecognizerGrm(model *VoskModel, sampleRate float64, grammar string) (*VoskRecognizer, error) {
cgrammar := C.CString(grammar)
defer C.free(unsafe.Pointer(cgrammar))
internal := C.vosk_recognizer_new_grm(model.model, C.float(sampleRate), cgrammar)
rec := &VoskRecognizer{rec: internal}
return rec, nil
}
// SetSpkModel adds a speaker model to an already initialized recognizer.
func (r *VoskRecognizer) SetSpkModel(spkModel *VoskSpkModel) {
C.vosk_recognizer_set_spk_model(r.rec, spkModel.spkModel)
}
// SetGrm sets which phrases to recognize on an already initialized recognizer.
func (r *VoskRecognizer) SetGrm(grammar string) {
cgrammar := C.CString(grammar)
defer C.free(unsafe.Pointer(cgrammar))
C.vosk_recognizer_set_grm(r.rec, cgrammar)
}
// SetMaxAlternatives configures the recognizer to output n-best results.
func (r *VoskRecognizer) SetMaxAlternatives(maxAlternatives int) {
C.vosk_recognizer_set_max_alternatives(r.rec, C.int(maxAlternatives))
}
// SetWords enables words with times in the ouput.
func (r *VoskRecognizer) SetWords(words int) {
C.vosk_recognizer_set_words(r.rec, C.int(words))
}
// SetPartialWords enables words with times in the partial ouput.
func (r *VoskRecognizer) SetPartialWords(words int) {
C.vosk_recognizer_set_partial_words(r.rec, C.int(words))
}
// SetEndpointerDelays sets the recognition timeouts, where startMax
// is the timeout for stopping recognition in case of initial silence
// (usually around 5), end is the timeout for stopping recognition
// in milliseconds after we recognized something (usually around 0.5-1.0),
// and max is the timeout for forcing utterance end in milliseconds
// (usually around 20-30).
func (r *VoskRecognizer) SetEndpointerDelays(startMax, end, max float64) {
C.vosk_recognizer_set_endpointer_delays(r.rec, C.float(startMax), C.float(end), C.float(max))
}
// AcceptWaveform accepts and processes a new chunk of the voice data.
func (r *VoskRecognizer) AcceptWaveform(buffer []byte) int {
cbuf := C.CBytes(buffer)
defer C.free(cbuf)
i := C.vosk_recognizer_accept_waveform(r.rec, (*C.char)(cbuf), C.int(len(buffer)))
return int(i)
}
// Result returns a speech recognition result.
func (r *VoskRecognizer) Result() string {
return C.GoString(C.vosk_recognizer_result(r.rec))
}
// PartialResult returns a partial speech recognition result.
func (r *VoskRecognizer) PartialResult() string {
return C.GoString(C.vosk_recognizer_partial_result(r.rec))
}
// FinalResult returns a speech recognition result. Same as result, but doesn't wait
// for silence.
func (r *VoskRecognizer) FinalResult() string {
return C.GoString(C.vosk_recognizer_final_result(r.rec))
}
// Reset resets the recognizer.
func (r *VoskRecognizer) Reset() {
C.vosk_recognizer_reset(r.rec)
}
// SetLogLevel sets the log level for Kaldi messages.
func SetLogLevel(logLevel int) {
C.vosk_set_log_level(C.int(logLevel))
}
// GPUInit automatically selects a CUDA device and allows multithreading.
func GPUInit() {
C.vosk_gpu_init()
}
// GPUThreadInit inits CUDA device in a multi-threaded environment.
func GPUThreadInit() {
C.vosk_gpu_thread_init()
}
+20 -33
View File
@@ -13,12 +13,11 @@
92375229240C550B00DD6076 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92375228240C550B00DD6076 /* Assets.xcassets */; };
9237522C240C550B00DD6076 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9237522A240C550B00DD6076 /* LaunchScreen.storyboard */; };
92375234240C558900DD6076 /* Vosk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92375233240C558900DD6076 /* Vosk.swift */; };
9237523C240C642000DD6076 /* libkaldiwrap.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9237523A240C642000DD6076 /* libkaldiwrap.a */; };
92375244240C6DAF00DD6076 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92375243240C6DAF00DD6076 /* Accelerate.framework */; };
92375246240C6DC900DD6076 /* libstdc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 92375245240C6DC900DD6076 /* libstdc++.tbd */; };
92375274240C6F1E00DD6076 /* 10001-90210-01803.wav in Resources */ = {isa = PBXBuildFile; fileRef = 92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */; };
925527A9273C492C00FFD9CC /* libvosk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 925527A8273C492C00FFD9CC /* libvosk.a */; };
92833003273C466E00058B52 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 92833002273C466E00058B52 /* libc++.tbd */; };
92BACED125BE125A00B5CC93 /* vosk-model-small-en-us-0.15 in Resources */ = {isa = PBXBuildFile; fileRef = 928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */; };
92D6B8D325BDFEAC007FF08D /* VoskModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92D6B8D225BDFEAC007FF08D /* VoskModel.swift */; };
92D86BD5253F823F0040D53F /* vosk-model-small-en-us-0.4 in Resources */ = {isa = PBXBuildFile; fileRef = 92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */; };
92D86BD6253F823F0040D53F /* vosk-model-spk-0.4 in Resources */ = {isa = PBXBuildFile; fileRef = 92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */; };
/* End PBXBuildFile section */
@@ -31,14 +30,13 @@
9237522B240C550B00DD6076 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
9237522D240C550B00DD6076 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
92375233240C558900DD6076 /* Vosk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vosk.swift; sourceTree = "<group>"; };
9237523A240C642000DD6076 /* libkaldiwrap.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libkaldiwrap.a; sourceTree = "<group>"; };
92375243240C6DAF00DD6076 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; };
92375245240C6DC900DD6076 /* libstdc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libstdc++.tbd"; path = "usr/lib/libstdc++.tbd"; sourceTree = SDKROOT; };
92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = "10001-90210-01803.wav"; sourceTree = "<group>"; };
925527A8273C492C00FFD9CC /* libvosk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libvosk.a; sourceTree = "<group>"; };
92833002273C466E00058B52 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "vosk-model-small-en-us-0.15"; path = "/Users/shmyrev/Documents/IOS/VoskApiTest/VoskApiTest/Vosk/vosk-model-small-en-us-0.15"; sourceTree = "<absolute>"; };
92AA22AD244CDD1200DA464B /* vosk_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vosk_api.h; sourceTree = "<group>"; };
92AA22AE244CDD5200DA464B /* bridging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bridging.h; sourceTree = "<group>"; };
92D6B8D225BDFEAC007FF08D /* VoskModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoskModel.swift; sourceTree = "<group>"; };
92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vosk-model-small-en-us-0.4"; sourceTree = "<group>"; };
92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "vosk-model-spk-0.4"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -47,9 +45,9 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
92833003273C466E00058B52 /* libc++.tbd in Frameworks */,
92375246240C6DC900DD6076 /* libstdc++.tbd in Frameworks */,
92375244240C6DAF00DD6076 /* Accelerate.framework in Frameworks */,
925527A9273C492C00FFD9CC /* libvosk.a in Frameworks */,
9237523C240C642000DD6076 /* libkaldiwrap.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -85,7 +83,6 @@
9237522A240C550B00DD6076 /* LaunchScreen.storyboard */,
9237522D240C550B00DD6076 /* Info.plist */,
92375233240C558900DD6076 /* Vosk.swift */,
92D6B8D225BDFEAC007FF08D /* VoskModel.swift */,
);
path = VoskApiTest;
sourceTree = "<group>";
@@ -93,11 +90,11 @@
92375239240C642000DD6076 /* Vosk */ = {
isa = PBXGroup;
children = (
92D86BD3253F823E0040D53F /* vosk-model-small-en-us-0.4 */,
92D86BD4253F823F0040D53F /* vosk-model-spk-0.4 */,
928CC50C25BE124400490481 /* vosk-model-small-en-us-0.15 */,
925527A8273C492C00FFD9CC /* libvosk.a */,
92AA22AD244CDD1200DA464B /* vosk_api.h */,
92375256240C6E3D00DD6076 /* 10001-90210-01803.wav */,
92AA22AD244CDD1200DA464B /* vosk_api.h */,
9237523A240C642000DD6076 /* libkaldiwrap.a */,
);
name = Vosk;
path = VoskApiTest/Vosk;
@@ -106,7 +103,7 @@
92375242240C6DAF00DD6076 /* Frameworks */ = {
isa = PBXGroup;
children = (
92833002273C466E00058B52 /* libc++.tbd */,
92375245240C6DC900DD6076 /* libstdc++.tbd */,
92375243240C6DAF00DD6076 /* Accelerate.framework */,
);
name = Frameworks;
@@ -145,7 +142,7 @@
9237521D240C550B00DD6076 = {
CreatedOnToolsVersion = 8.3.2;
LastSwiftMigration = 0920;
ProvisioningStyle = Manual;
ProvisioningStyle = Automatic;
};
};
};
@@ -172,12 +169,12 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
92BACED125BE125A00B5CC93 /* vosk-model-small-en-us-0.15 in Resources */,
92375274240C6F1E00DD6076 /* 10001-90210-01803.wav in Resources */,
9237522C240C550B00DD6076 /* LaunchScreen.storyboard in Resources */,
92375229240C550B00DD6076 /* Assets.xcassets in Resources */,
92D86BD6253F823F0040D53F /* vosk-model-spk-0.4 in Resources */,
92375227240C550B00DD6076 /* Main.storyboard in Resources */,
92D86BD5253F823F0040D53F /* vosk-model-small-en-us-0.4 in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -190,7 +187,6 @@
files = (
92375224240C550B00DD6076 /* ViewController.swift in Sources */,
92375222240C550B00DD6076 /* AppDelegate.swift in Sources */,
92D6B8D325BDFEAC007FF08D /* VoskModel.swift in Sources */,
92375234240C558900DD6076 /* Vosk.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -223,6 +219,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -244,7 +241,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -281,6 +278,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -302,7 +300,7 @@
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
@@ -317,7 +315,6 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.3;
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = bridging.h;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -332,10 +329,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
INFOPLIST_FILE = VoskApiTest/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
@@ -344,13 +338,11 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.alphacephei.VoskApiTest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_INSTALL_OBJC_HEADER = YES;
SWIFT_OBJC_BRIDGING_HEADER = VoskApiTest/bridging.h;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
@@ -359,10 +351,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = "";
ENABLE_BITCODE = NO;
ENABLE_BITCODE = YES;
INFOPLIST_FILE = VoskApiTest/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
@@ -371,12 +360,10 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.alphacephei.VoskApiTest;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_INSTALL_OBJC_HEADER = YES;
SWIFT_OBJC_BRIDGING_HEADER = VoskApiTest/bridging.h;
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
@@ -1,6 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:../VoskApiTest/Vosk/vosk-model-small-en-us-0.4">
</FileRef>
<FileRef
location = "group:../VoskApiTest/Vosk/vosk-model-spk-0.4">
</FileRef>
<FileRef
location = "self:">
</FileRef>
+13 -42
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="bdW-KL-Y8Z">
<device id="retina5_5" orientation="portrait">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
@@ -10,52 +10,23 @@
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="nEc-89-Iqu">
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="bdW-KL-Y8Z" customClass="ViewController" customModule="VoskApiTest" customModuleProvider="target" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Hyr-Dz-4mU"/>
<viewControllerLayoutGuide type="bottom" id="w4A-5X-uBu"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="m5v-US-bvR">
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="IaT-no-U3i" userLabel="Microphone">
<rect key="frame" x="124" y="34" width="157" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Recognize Microphone"/>
<connections>
<action selector="runRecognizeMicrohpone:" destination="bdW-KL-Y8Z" eventType="touchUpInside" id="hGB-lz-N2B"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GC5-nT-FQR" userLabel="File">
<rect key="frame" x="90" y="84" width="221" height="41"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Recognize File"/>
<connections>
<action selector="runRecognizeFile:" destination="bdW-KL-Y8Z" eventType="touchUpInside" id="xp5-Yi-rnN"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" fixedFrame="YES" text="Results here" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="w4X-cu-USq">
<rect key="frame" x="11" y="112" width="383" height="569"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="VoskApiTest" customModuleProvider="target" sceneMemberID="viewController">
<textView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" id="CtX-mx-X98">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
<connections>
<outlet property="mainText" destination="w4X-cu-USq" id="rZS-nz-Wql"/>
<outlet property="recognizeFile" destination="GC5-nT-FQR" id="dRe-tc-IA0"/>
<outlet property="recognizeMicrophone" destination="IaT-no-U3i" id="IuM-aa-pAP"/>
<outlet property="mainText" destination="CtX-mx-X98" id="oJy-5J-NKp"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="nWA-4D-pA6" userLabel="First Responder" sceneMemberID="firstResponder"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-17.39130434782609" y="-285.32608695652175"/>
<point key="canvasLocation" x="32.799999999999997" y="32.833583208395808"/>
</scene>
</scenes>
</document>
+16 -99
View File
@@ -3,113 +3,30 @@
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
// Copyright © 2020 Alpha Cephei. All rights reserved.
//
import UIKit
import AVFoundation
enum WorkMode {
case stopped
case microphone
case file
}
class ViewController: UIViewController {
var mode: WorkMode!
@IBOutlet weak var recognizeFile: UIButton!
@IBOutlet weak var mainText: UITextView!
@IBOutlet weak var recognizeMicrophone: UIButton!
var audioEngine : AVAudioEngine!
var processingQueue: DispatchQueue!
var model : VoskModel!
func setMode(mode: WorkMode) {
switch mode {
case .stopped:
self.recognizeFile.isEnabled = true
self.recognizeMicrophone.isEnabled = true
self.recognizeMicrophone.setTitle("Recognize Microphone",for: .normal)
case .microphone:
self.recognizeFile.isEnabled = false
self.recognizeMicrophone.isEnabled = true
self.recognizeMicrophone.setTitle("Stop Microphone",for: .normal)
self.mainText.text = ""
case .file:
self.recognizeFile.isEnabled = false
self.recognizeMicrophone.isEnabled = false
self.mainText.text = "Processing file..."
}
self.mode = mode
}
func startAudioEngine() {
do {
// Create a new audio engine.
audioEngine = AVAudioEngine()
let inputNode = audioEngine.inputNode
let formatInput = inputNode.inputFormat(forBus: 0)
let formatPcm = AVAudioFormat.init(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: formatInput.sampleRate, channels: 1, interleaved: true)
let recognizer = Vosk(model: model, sampleRate: Float(formatInput.sampleRate))
inputNode.installTap(onBus: 0,
bufferSize: UInt32(formatInput.sampleRate / 10),
format: formatPcm) { buffer, time in
self.processingQueue.async {
let res = recognizer.recognizeData(buffer: buffer)
DispatchQueue.main.async {
self.mainText.text = res + "\n" + self.mainText.text
}
}
}
// Start the stream of audio data.
audioEngine.prepare()
try audioEngine.start()
} catch {
print("Unable to start AVAudioEngine: \(error.localizedDescription)")
}
}
func stopAudioEngine() {
audioEngine.stop()
}
@IBAction func runRecognizeMicrohpone(_ sender: Any) {
if (mode == .stopped) {
setMode(mode: .microphone)
startAudioEngine()
} else {
stopAudioEngine()
setMode(mode: .stopped)
}
}
@IBAction func runRecognizeFile(_ sender: Any) {
setMode(mode: .file)
processingQueue.async {
let recognizer = Vosk(model: self.model, sampleRate: 16000.0)
let res = recognizer.recognizeFile()
DispatchQueue.main.async {
self.mainText.text = res
self.setMode(mode: .stopped)
}
}
}
@IBOutlet var mainText: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
setMode(mode: .stopped)
processingQueue = DispatchQueue(label: "recognizerQueue")
model = VoskModel()
}
DispatchQueue.global(qos: .userInitiated).async {
DispatchQueue.main.async {
self.mainText.text = "Processing file..."
}
let vosk = Vosk()
let res = vosk.recognizeFile()
DispatchQueue.main.async {
self.mainText.text = res
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
+21 -33
View File
@@ -3,52 +3,40 @@
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
// Copyright © 2020 Alpha Cephei. All rights reserved.
//
import Foundation
import AVFoundation
public final class Vosk {
var recognizer : OpaquePointer!
init(model: VoskModel, sampleRate: Float) {
recognizer = vosk_recognizer_new_spk(model.model, sampleRate, model.spkModel)
}
deinit {
vosk_recognizer_free(recognizer);
}
func recognizeFile() -> String {
var sres = ""
if let resourcePath = Bundle.main.resourcePath {
// Set to -1 to disable logs
vosk_set_log_level(0);
let modelPath = resourcePath + "/vosk-model-small-en-us-0.4"
let spkModelPath = resourcePath + "/vosk-model-spk-0.4"
let model = vosk_model_new(modelPath)
let spkModel = vosk_spk_model_new(spkModelPath)
let recognizer = vosk_recognizer_new_spk(model, spkModel, 16000.0)
let audioFile = URL(fileURLWithPath: resourcePath + "/10001-90210-01803.wav")
if let data = try? Data(contentsOf: audioFile) {
let _ = data.withUnsafeBytes {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(data.count))
}
let res = vosk_recognizer_final_result(recognizer);
sres = String(validatingUTF8: res!)!;
print(sres);
let _ = data.withUnsafeBytes {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(data.count))
}
let res = vosk_recognizer_final_result(recognizer);
sres = String(validatingUTF8: res!)!;
print(sres);
}
vosk_recognizer_free(recognizer)
vosk_model_free(model)
}
return sres
}
func recognizeData(buffer : AVAudioPCMBuffer) -> String {
let dataLen = Int(buffer.frameLength * 2)
let channels = UnsafeBufferPointer(start: buffer.int16ChannelData, count: 1)
let endOfSpeech = channels[0].withMemoryRebound(to: Int8.self, capacity: dataLen) {
vosk_recognizer_accept_waveform(recognizer, $0, Int32(dataLen))
}
let res = endOfSpeech == 1 ?vosk_recognizer_result(recognizer) :vosk_recognizer_partial_result(recognizer)
return String(validatingUTF8: res!)!;
}
}
+36 -117
View File
@@ -1,4 +1,4 @@
// Copyright 2020-2021 Alpha Cephei Inc.
// Copyright 2020 Alpha Cephei Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@ typedef struct VoskRecognizer VoskRecognizer;
/** Loads model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
@ @returns model object */
VoskModel *vosk_model_new(const char *model_path);
@@ -55,18 +55,10 @@ VoskModel *vosk_model_new(const char *model_path);
void vosk_model_free(VoskModel *model);
/** Check if a word can be recognized by the model
* @param word: the word
* @returns the word symbol if @param word exists inside the model
* or -1 otherwise.
* Reminding that word symbol 0 is for <epsilon> */
int vosk_model_find_word(VoskModel *model, const char *word);
/** Loads speaker model data from the file and returns the model object
*
* @param model_path: the path of the model on the filesystem
* @returns model object or NULL if problem occured */
* @returns model object */
VoskSpkModel *vosk_spk_model_new(const char *model_path);
@@ -79,13 +71,9 @@ void vosk_spk_model_free(VoskSpkModel *model);
/** Creates the recognizer object
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @returns recognizer object or NULL if problem occured */
* The recognizers process the speech and return text using shared model data
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
@@ -94,14 +82,10 @@ VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spk_model speaker model for speaker identification
* @returns recognizer object or NULL if problem occured */
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, VoskSpkModel *spk_model);
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, VoskSpkModel *spk_model, float sample_rate);
/** Creates the recognizer object with the phrase list
@@ -114,46 +98,42 @@ VoskRecognizer *vosk_recognizer_new_spk(VoskModel *model, float sample_rate, Vos
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param sample_rate The sample rate of the audio you going to feed into the recognizer
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
*
* @returns recognizer object or NULL if problem occured */
* @returns recognizer object */
VoskRecognizer *vosk_recognizer_new_grm(VoskModel *model, float sample_rate, const char *grammar);
/** Adds speaker model to already initialized recognizer
/** Accept voice data
*
* Can add speaker recognition model to already created recognizer. Helps to initialize
* speaker recognition for grammar-based recognizer.
* accept and process new chunk of voice data
*
* @param spk_model Speaker recognition model */
void vosk_recognizer_set_spk_model(VoskRecognizer *recognizer, VoskSpkModel *spk_model);
* @param data - audio data in PCM 16-bit mono format
* @param length - length of the audio data
* @returns true if silence is occured and you can retrieve a new utterance with result method */
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
/** Configures recognizer to output n-best results
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param max_alternatives - maximum alternatives to return from recognition results
*/
void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_alternatives);
/** Enables words with times in the output
/** Same as above but the version with the short data for language bindings where you have
* audio as array of shorts */
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
/** Same as above but the version with the float data for language bindings where you have
* audio as array of floats */
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
/** Returns speech recognition result
*
* @returns the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
@@ -176,54 +156,13 @@ void vosk_recognizer_set_max_alternatives(VoskRecognizer *recognizer, int max_al
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
void vosk_recognizer_set_words(VoskRecognizer *recognizer, int words);
/** Accept voice data
*
* accept and process new chunk of voice data
*
* @param data - audio data in PCM 16-bit mono format
* @param length - length of the audio data
* @returns 1 if silence is occured and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occured */
int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);
/** Same as above but the version with the short data for language bindings where you have
* audio as array of shorts */
int vosk_recognizer_accept_waveform_s(VoskRecognizer *recognizer, const short *data, int length);
/** Same as above but the version with the float data for language bindings where you have
* audio as array of floats */
int vosk_recognizer_accept_waveform_f(VoskRecognizer *recognizer, const float *data, int length);
/** Returns speech recognition result
*
* @returns the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also vosk_recognizer_set_alternatives().
*
* If word times enabled returns word time, see also vosk_recognizer_set_word_times().
*/
const char *vosk_recognizer_result(VoskRecognizer *recognizer);
@@ -235,7 +174,7 @@ const char *vosk_recognizer_result(VoskRecognizer *recognizer);
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
@@ -251,12 +190,6 @@ const char *vosk_recognizer_partial_result(VoskRecognizer *recognizer);
const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);
/** Resets the recognizer
*
* Resets current results so the recognition can continue from scratch */
void vosk_recognizer_reset(VoskRecognizer *recognizer);
/** Releases recognizer object
*
* Underlying model is also unreferenced and if needed released */
@@ -271,20 +204,6 @@ void vosk_recognizer_free(VoskRecognizer *recognizer);
*/
void vosk_set_log_level(int log_level);
/**
* Init, automatically select a CUDA device and allow multithreading.
* Must be called once from the main thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_init();
/**
* Init CUDA device in a multi-threaded environment.
* Must be called for each thread.
* Has no effect if HAVE_CUDA flag is not set.
*/
void vosk_gpu_thread_init();
#ifdef __cplusplus
}
#endif
-36
View File
@@ -1,36 +0,0 @@
//
// Vosk.swift
// VoskApiTest
//
// Created by Niсkolay Shmyrev on 01.03.20.
// Copyright © 2020-2021 Alpha Cephei. All rights reserved.
//
import Foundation
public final class VoskModel {
var model : OpaquePointer!
var spkModel : OpaquePointer!
init() {
// Set to -1 to disable logs
vosk_set_log_level(0);
if let resourcePath = Bundle.main.resourcePath {
let modelPath = resourcePath + "/vosk-model-small-en-us-0.15"
let spkModelPath = resourcePath + "/vosk-model-spk-0.4"
model = vosk_model_new(modelPath)
spkModel = vosk_spk_model_new(spkModelPath)
}
}
deinit {
vosk_model_free(model)
vosk_spk_model_free(spkModel)
}
}
+72
View File
@@ -0,0 +1,72 @@
KALDI_ROOT ?= $(HOME)/kaldi
CFLAGS := -g -O2 -DPIC -fPIC -Wno-unused-function -std=c++17
CPPFLAGS := -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -I$(KALDI_ROOT)/src -I$(KALDI_ROOT)/tools/openfst/include -I../src
KALDI_LIBS = \
${KALDI_ROOT}/src/online2/kaldi-online2.a \
${KALDI_ROOT}/src/decoder/kaldi-decoder.a \
${KALDI_ROOT}/src/ivector/kaldi-ivector.a \
${KALDI_ROOT}/src/gmm/kaldi-gmm.a \
${KALDI_ROOT}/src/nnet3/kaldi-nnet3.a \
${KALDI_ROOT}/src/tree/kaldi-tree.a \
${KALDI_ROOT}/src/feat/kaldi-feat.a \
${KALDI_ROOT}/src/lat/kaldi-lat.a \
${KALDI_ROOT}/src/lm/kaldi-lm.a \
${KALDI_ROOT}/src/hmm/kaldi-hmm.a \
${KALDI_ROOT}/src/transform/kaldi-transform.a \
${KALDI_ROOT}/src/cudamatrix/kaldi-cudamatrix.a \
${KALDI_ROOT}/src/matrix/kaldi-matrix.a \
${KALDI_ROOT}/src/fstext/kaldi-fstext.a \
${KALDI_ROOT}/src/util/kaldi-util.a \
${KALDI_ROOT}/src/base/kaldi-base.a \
${KALDI_ROOT}/tools/openfst/lib/libfst.a \
${KALDI_ROOT}/tools/openfst/lib/libfstngram.a \
# On Linux
MATH_LIBS = \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libopenblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/liblapack.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libblas.a \
${KALDI_ROOT}/tools/OpenBLAS/install/lib/libf2c.a
all: libvosk_jni.so
VOSK_SOURCES = \
vosk_wrap.cc \
../src/kaldi_recognizer.cc \
../src/kaldi_recognizer.h \
../src/language_model.cc \
../src/language_model.h \
../src/model.cc \
../src/model.h \
../src/spk_model.cc \
../src/spk_model.h \
../src/vosk_api.cc \
../src/vosk_api.h
libvosk_jni.so: $(VOSK_SOURCES)
$(CXX) -shared -o $@ $(CPPFLAGS) $(CFLAGS) $(VOSK_SOURCES) $(KALDI_LIBS) $(MATH_LIBS)
vosk_wrap.cc: ../src/vosk.i
mkdir -p org/kaldi
swig -c++ -I../src \
-java -package org.kaldi \
-outdir org/kaldi -o $@ $<
clean:
$(RM) *.so *_wrap.cc *_wrap.o test/*.class
$(RM) -r org model-en
model:
wget https://alphacephei.com/kaldi/models/vosk-model-small-en-us-0.3.zip
unzip vosk-model-small-en-us-0.3.zip && rm vosk-model-small-en-us-0.3.zip
mv vosk-model-small-en-us-0.3 model
model-spk:
wget https://alphacephei.com/kaldi/models/vosk-model-spk-0.3.zip
unzip vosk-model-spk-0.3.zip && rm vosk-model-spk-0.3.zip
mv vosk-model-spk-0.3 model-spk
run: model model-spk
javac test/*.java org/kaldi/*.java
java -Djava.library.path=. -cp . test.DecoderTest
+16 -4
View File
@@ -1,7 +1,19 @@
Java bindings for Vosk API using jnr-ffi
Java API sample
See demo project for details, build it with Gradle.
Doesn't work on Windows or Mac yet, help to prepare the packaged jars is welcome.
Download model and unpack as "model" folder in the demo project.
For now to try it:
Make sure you are using recent JDK and Gradle.
On Linux you can do
1. Build recent kaldi
1. `git clone https://github.com/alphacep/vosk-api`
1. `cd vosk-api/java`
1. `export KALDI_ROOT=<KALDI_ROOT>`
1. `export JAVA_HOME=<JAVA_HOME>`
1. `make`
1. `make run`
For details of the code you can check:
https://github.com/alphacep/vosk-api/blob/master/java/test/DecoderTest.java
-15
View File
@@ -1,15 +0,0 @@
plugins {
id 'application'
}
application {
mainClass = 'org.vosk.demo.DecoderDemo'
}
repositories {
mavenCentral()
}
dependencies {
implementation group: 'com.alphacephei', name: 'vosk', version: '0.3.75'
}
@@ -1,38 +0,0 @@
package org.vosk.demo;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.LibVosk;
import org.vosk.Model;
public class DecoderDemo {
public static void main(String[] argv) throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
}
}
-71
View File
@@ -1,71 +0,0 @@
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id 'java-library'
id 'maven-publish'
id 'com.vanniktech.maven.publish' version '0.18.0'
}
repositories {
mavenCentral()
}
archivesBaseName = 'vosk'
group = 'com.alphacephei'
version = '0.3.75'
mavenPublish {
group = 'com.alphacephei'
version = version
sonatypeHost = 's01'
}
dependencies {
api group: 'net.java.dev.jna', name: 'jna', version: '5.18.1'
testImplementation 'junit:junit:4.13'
}
publishing {
publications {
mavenJava(MavenPublication) {
artifactId = 'vosk'
from components.java
pom {
name = 'Vosk'
description = 'Speech recognition library'
url = 'http://www.alphacephei.com.com/vosk/'
licenses {
license {
name = 'The Apache License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id = 'alphacephei'
name = 'Alpha Cephei Inc'
email = 'contact@alphacephei.com'
}
}
scm {
connection = 'scm:git:git://github.com/alphacep/vosk-api.git'
url = 'https://github.com/alphacep/vosk-api/'
}
}
}
}
}
test {
dependsOn cleanTest
testLogging.showStandardStreams = true
}
java {
withSourcesJar()
withJavadocJar()
}
@@ -1,108 +0,0 @@
package org.vosk;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
public class LibVosk {
private static void unpackDll(File targetDir, String lib) throws IOException {
try (InputStream source = LibVosk.class.getResourceAsStream("/win32-x86-64/" + lib + ".dll")) {
Files.copy(source, new File(targetDir, lib + ".dll").toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
static {
if (Platform.isWindows()) {
// We have to unpack dependencies
try {
// To get a tmp folder we unpack small library and mark it for deletion
File tmpFile = Native.extractFromResourcePath("/win32-x86-64/empty", LibVosk.class.getClassLoader());
File tmpDir = tmpFile.getParentFile();
new File(tmpDir, tmpFile.getName() + ".x").createNewFile();
// Now unpack dependencies
unpackDll(tmpDir, "libwinpthread-1");
unpackDll(tmpDir, "libgcc_s_seh-1");
unpackDll(tmpDir, "libstdc++-6");
} catch (IOException e) {
// Nothing for now, it will fail on next step
} finally {
Native.register(LibVosk.class, "libvosk");
}
} else {
Native.register(LibVosk.class, "vosk");
}
}
public static native void vosk_set_log_level(int level);
public static native Pointer vosk_model_new(String path);
public static native void vosk_model_free(Pointer model);
public static native Pointer vosk_spk_model_new(String path);
public static native void vosk_spk_model_free(Pointer model);
public static native Pointer vosk_recognizer_new(Model model, float sample_rate);
public static native Pointer vosk_recognizer_new_spk(Pointer model, float sample_rate, Pointer spk_model);
public static native Pointer vosk_recognizer_new_grm(Pointer model, float sample_rate, String grammar);
public static native void vosk_recognizer_set_max_alternatives(Pointer recognizer, int max_alternatives);
public static native void vosk_recognizer_set_words(Pointer recognizer, boolean words);
public static native void vosk_recognizer_set_partial_words(Pointer recognizer, boolean partial_words);
public static native void vosk_recognizer_set_spk_model(Pointer recognizer, Pointer spk_model);
public static native boolean vosk_recognizer_accept_waveform(Pointer recognizer, byte[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_s(Pointer recognizer, short[] data, int len);
public static native boolean vosk_recognizer_accept_waveform_f(Pointer recognizer, float[] data, int len);
public static native String vosk_recognizer_result(Pointer recognizer);
public static native String vosk_recognizer_final_result(Pointer recognizer);
public static native String vosk_recognizer_partial_result(Pointer recognizer);
public static native void vosk_recognizer_set_grm(Pointer recognizer, String grammar);
public static native void vosk_recognizer_reset(Pointer recognizer);
public static native void vosk_recognizer_set_endpointer_mode(Pointer recognizer, int mode);
public static native void vosk_recognizer_set_endpointer_delays(Pointer recognizer, float t_start_max, float t_end, float t_max);
public static native void vosk_recognizer_free(Pointer recognizer);
public static native Pointer vosk_text_processor_new(String verbalizer, String tagger);
public static native void vosk_text_processor_free(Pointer processor);
public static native String vosk_text_processor_itn(Pointer processor, String input);
/**
* Set log level for Kaldi messages.
*
* @param loglevel the level
* 0 - default value to print info and error messages but no debug
* less than 0 - don't print info messages
* greater than 0 - more verbose mode
*/
public static void setLogLevel(LogLevel loglevel) {
vosk_set_log_level(loglevel.getValue());
}
}
@@ -1,17 +0,0 @@
package org.vosk;
public enum LogLevel {
WARNINGS(-1), // Print warning and errors
INFO(0), // Print info, along with warning and error messages, but no debug
DEBUG(1); // Print debug info
private final int value;
LogLevel(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
}
@@ -1,22 +0,0 @@
package org.vosk;
import java.io.IOException;
import com.sun.jna.PointerType;
public class Model extends PointerType implements AutoCloseable {
public Model() {
}
public Model(String path) throws IOException {
super(LibVosk.vosk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a model");
}
}
@Override
public void close() {
LibVosk.vosk_model_free(this.getPointer());
}
}
@@ -1,275 +0,0 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
public class Recognizer extends PointerType implements AutoCloseable {
/**
* Creates the recognizer object.
*
* The recognizers process the speech and return text using shared model data
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate) throws IOException {
super(LibVosk.vosk_recognizer_new(model, sampleRate));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with speaker recognition.
*
* With the speaker recognition mode the recognizer not just recognize
* text but also return speaker vectors one can use for speaker identification
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param spkModel speaker model for speaker identification
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, SpeakerModel spkModel) throws IOException {
super(LibVosk.vosk_recognizer_new_spk(model.getPointer(), sampleRate, spkModel.getPointer()));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Creates the recognizer object with the phrase list.
*
* Sometimes when you want to improve recognition accuracy and when you don't need
* to recognize large vocabulary you can specify a list of phrases to recognize. This
* will improve recognizer speed and accuracy but might return [unk] if user said
* something different.
*
* Only recognizers with lookahead models support this type of quick configuration.
* Precompiled HCLG graph models are not supported.
*
* @param model VoskModel containing static data for recognizer. Model can be
* shared across recognizers, even running in different threads.
* @param sampleRate The sample rate of the audio you are going to feed into the recognizer.
* Make sure this rate matches the audio content, it is a common
* issue causing accuracy problems.
* @param grammar The string with the list of phrases to recognize as JSON array of strings,
* for example "["one two three four five", "[unk]"]".
* @throws IOException if the recognizer could not be created
*/
public Recognizer(Model model, float sampleRate, String grammar) throws IOException {
super(LibVosk.vosk_recognizer_new_grm(model.getPointer(), sampleRate, grammar));
if (getPointer() == null) {
throw new IOException("Failed to create a recognizer");
}
}
/**
* Configures recognizer to output n-best results.
*
* <pre>
* {
* "alternatives": [
* { "text": "one two three four five", "confidence": 0.97 },
* { "text": "one two three for five", "confidence": 0.03 },
* ]
* }
* </pre>
*
* @param maxAlternatives - maximum alternatives to return from recognition results
*/
public void setMaxAlternatives(int maxAlternatives) {
LibVosk.vosk_recognizer_set_max_alternatives(this.getPointer(), maxAlternatives);
}
/** Enables words with times in the output
*
* <pre>
* "result" : [{
* "conf" : 1.000000,
* "end" : 1.110000,
* "start" : 0.870000,
* "word" : "what"
* }, {
* "conf" : 1.000000,
* "end" : 1.530000,
* "start" : 1.110000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 1.950000,
* "start" : 1.530000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.340000,
* "start" : 1.950000,
* "word" : "zero"
* }, {
* "conf" : 1.000000,
* "end" : 2.610000,
* "start" : 2.340000,
* "word" : "one"
* }],
* </pre>
*
* @param words - boolean value
*/
public void setWords(boolean words) {
LibVosk.vosk_recognizer_set_words(this.getPointer(), words);
}
/**
* Like above return words and confidences in partial results.
*
* @param partial_words - boolean value
*/
public void setPartialWords(boolean partial_words) {
LibVosk.vosk_recognizer_set_partial_words(this.getPointer(), partial_words);
}
/**
* Adds speaker model to already initialized recognizer.
*
* Can add speaker recognition model to already created recognizer.
* Helps to initialize speaker recognition for grammar-based recognizer.
*
* @param spkModel Speaker recognition model
*/
public void setSpeakerModel(SpeakerModel spkModel) {
LibVosk.vosk_recognizer_set_spk_model(this.getPointer(), spkModel.getPointer());
}
/**
* Accept and process new chunk of voice data.
*
* @param data - audio data in PCM 16-bit mono format
* @param len - length of the audio data
* @return 1 if silence is occurred and you can retrieve a new utterance with result method
* 0 if decoding continues
* -1 if exception occurred
*/
public boolean acceptWaveForm(byte[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform(this.getPointer(), data, len);
}
public boolean acceptWaveForm(short[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_s(this.getPointer(), data, len);
}
public boolean acceptWaveForm(float[] data, int len) {
return LibVosk.vosk_recognizer_accept_waveform_f(this.getPointer(), data, len);
}
/**
* Returns speech recognition result
*
* @return the result in JSON format which contains decoded line, decoded
* words, times in seconds and confidences. You can parse this result
* with any json parser
*
* <pre>
* {
* "text" : "what zero zero zero one"
* }
* </pre>
*
* If alternatives enabled it returns result with alternatives, see also #setMaxAlternatives().
*
* If word times enabled returns word time, see also #setWordTimes().
*/
public String getResult() {
return LibVosk.vosk_recognizer_result(this.getPointer());
}
/**
* Returns partial speech recognition.
*
* @return partial speech recognition text which is not yet finalized.
* result may change as recognizer process more data.
*
* <pre>
* {
* "partial" : "cyril one eight zero"
* }
* </pre>
*/
public String getPartialResult() {
return LibVosk.vosk_recognizer_partial_result(this.getPointer());
}
/**
* Returns speech recognition result. Same as result, but doesn't wait for silence.
* You usually call it in the end of the stream to get final bits of audio. It
* flushes the feature pipeline, so all remaining audio chunks got processed.
*
* @return speech result in JSON format.
*/
public String getFinalResult() {
return LibVosk.vosk_recognizer_final_result(this.getPointer());
}
/**
* Reconfigures recognizer to use grammar.
*
* @param grammar Set of phrases in JSON array of strings or "[]" to use default model graph.
* @see #Recognizer(Model, float, String)
*/
public void setGrammar(String grammar) {
LibVosk.vosk_recognizer_set_grm(this.getPointer(), grammar);
}
/**
* Resets the recognizer.
* Resets current results so the recognition can continue from scratch.
*/
public void reset() {
LibVosk.vosk_recognizer_reset(this.getPointer());
}
/**
* Endpointer delay mode
*/
public class EndpointerMode {
public static final int DEFAULT = 0;
public static final int SHORT = 1;
public static final int LONG = 2;
public static final int VERY_LONG = 3;
}
/**
* Configures endpointer mode for recognizer
*/
public void setEndpointerMode(int mode) {
LibVosk.vosk_recognizer_set_endpointer_mode(this.getPointer(), mode);
}
/**
* Set endpointer delays
*
* @param t_start_max timeout for stopping recognition in case of initial silence (usually around 5.0)
* @param t_end timeout for stopping recognition in milliseconds after we recognized something (usually around 0.5 - 1.0)
* @param t_max timeout for forcing utterance end in milliseconds (usually around 20-30)
**/
public void setEndpointerDelays(float t_start_max, float t_end, float t_max) {
LibVosk.vosk_recognizer_set_endpointer_delays(this.getPointer(), t_start_max, t_end, t_max);
}
/**
* Releases recognizer object.
* Underlying model is also unreferenced and if needed, released.
*/
@Override
public void close() {
LibVosk.vosk_recognizer_free(this.getPointer());
}
}
@@ -1,40 +0,0 @@
package org.vosk;
import com.sun.jna.PointerType;
import java.io.IOException;
/**
* Helps to initialize speaker recognition for grammar-based recognizer.
*/
public class SpeakerModel extends PointerType implements AutoCloseable {
public SpeakerModel() {
}
/**
* Loads speaker model data from the file.
*
* The path must contain:
* - a config file: mfcc.conf
* - kaldi nnet: final.ext.raw
* - mean.vec
* - transform.mat
*
* @param path the path of the model on the filesystem
* @throws IOException if the model could not be created
*
* @see <a href="http://kaldi-asr.org/doc/structkaldi_1_1MfccOptions.html">Kaldi MfccOptions</a>
* @see <a href="http://kaldi-asr.org/doc/classkaldi_1_1nnet3_1_1Nnet.html">Kaldi Nnet</a>
*/
public SpeakerModel(String path) throws IOException {
super(LibVosk.vosk_spk_model_new(path));
if (getPointer() == null) {
throw new IOException("Failed to create a speaker model");
}
}
@Override
public void close() {
LibVosk.vosk_spk_model_free(this.getPointer());
}
}
@@ -1 +0,0 @@
Mainly for work around JNA API
@@ -1,120 +0,0 @@
package org.vosk.test;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import org.junit.Test;
import org.junit.Assert;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
import org.vosk.LogLevel;
import org.vosk.Recognizer;
import org.vosk.Recognizer.EndpointerMode;
import org.vosk.LibVosk;
import org.vosk.Model;
import org.vosk.TextProcessor;
public class DecoderTest {
@Test
public void decoderTest() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
recognizer.setMaxAlternatives(10);
recognizer.setWords(true);
recognizer.setPartialWords(true);
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestShort() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000)) {
int nbytes;
byte[] b = new byte[4096];
short[] s = new short[2048];
while ((nbytes = ais.read(b)) >= 0) {
ByteBuffer.wrap(b).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(s);
if (recognizer.acceptWaveForm(s, nbytes / 2)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderTestGrammar() throws IOException, UnsupportedAudioFileException {
LibVosk.setLogLevel(LogLevel.DEBUG);
try (Model model = new Model("model");
InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream("../../python/example/test.wav")));
Recognizer recognizer = new Recognizer(model, 16000, "[\"one two three four five six seven eight nine zero oh\"]")) {
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (recognizer.acceptWaveForm(b, nbytes)) {
System.out.println(recognizer.getResult());
} else {
System.out.println(recognizer.getPartialResult());
}
}
System.out.println(recognizer.getFinalResult());
}
Assert.assertTrue(true);
}
@Test
public void decoderEndpointerDelays() throws IOException, UnsupportedAudioFileException {
try (Model model = new Model("model");
Recognizer recognizer = new Recognizer(model, 16000)) {
recognizer.setEndpointerMode(EndpointerMode.VERY_LONG);
recognizer.setEndpointerDelays(5.0f, 3.0f, 50.0f);
}
Assert.assertTrue(true);
}
@Test(expected = IOException.class)
public void decoderTestException() throws IOException {
Model model = new Model("model_missing");
}
@Test
public void testItn() throws IOException {
TextProcessor p = new TextProcessor("model/itn/en_itn_tagger.fst", "model/itn/en_itn_verbalizer.fst");
System.out.println(p.itn("as easy as one two three"));
}
}
+37
View File
@@ -0,0 +1,37 @@
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.URL;
import java.nio.*;
import org.kaldi.KaldiRecognizer;
import org.kaldi.Model;
import org.kaldi.SpkModel;
import org.kaldi.Vosk;
public class DecoderTest {
public static void main(String args[]) throws IOException {
Vosk.SetLogLevel(-10);
FileInputStream ais = new FileInputStream(new File("../python/example/test.wav"));
Model model = new Model("model");
SpkModel spkModel = new SpkModel("model-spk");
KaldiRecognizer rec = new KaldiRecognizer(model, spkModel, 16000.0f);
int nbytes;
byte[] b = new byte[4096];
while ((nbytes = ais.read(b)) >= 0) {
if (rec.AcceptWaveform(b)) {
System.out.println(rec.Result());
} else {
System.out.println(rec.PartialResult());
}
}
System.out.println(rec.FinalResult());
}
}
-3
View File
@@ -1,3 +0,0 @@
.gradle/
.idea/
build/
-1
View File
@@ -1 +0,0 @@
Doomsdayrs doomsdayrs@gmail.com
-8
View File
@@ -1,8 +0,0 @@
# Maintenance
To maintain this module, please ensure the following.
1. Kotlin version is kept up to date.
This will be found in the plugins block of the [build.gradle.kts](./build.gradle.kts).
Ensure both multiplatform and serialization have the same value.
2. Ensure dependencies are up to date
3. Ensure that the android min & target sdks are up to date.
-63
View File
@@ -1,63 +0,0 @@
# vosk-api-kotlin
The vosk-api wrapped using Kotlin Multiplatform.
## Usage
The following are ways to use this wrapper.
### JVM
For Java & Android targets.
```kotlin
dependencoes {
val voskVersion = "0.4.0-alpha0"
// Generic
implementation("com.alphacephei:vosk-api-kotlin:$voskVersion")
// Android
implementation("com.alphacephei:vosk-api-kotlin-android:$voskVersion")
}
```
## Building
To build this project, follow the following steps.
1. Install `libvosk`.
This can be done from [source][source install] (parent monorepo)
or [downloaded][download].
2. Download a [Vosk model](https://alphacephei.com/vosk/models) to use.
- It is suggested to use a small model to speed up tests.
3. Once both are downloaded and placed into a proper location (hopefully following UNIX specification).
Set the following environment variables:
- `VOSK_MODEL` to the path of the model.
- `VOSK_PATH` to the path of `libvosk`.
These are used by the various tests to operate.
4. Now that the required steps are complete, one can run `./gradlew build`.
## Kotlin/Native
Currently, the native target is disabled due to a lack of vosk-api packaging on platforms.
Further worsened by the fact that installing the vosk-api on Linux systems is a chore.
First, either install from [source][source install]
or [download][download] and install into the proper unix directories as expected in
[libvosk.def](./src/nativeInterop/cinterop/libvosk.def).
To enable development for Kotlin/Native, do either for the following.
- Add `NATIVE_EXPERIMENT=true` to your environment.
- Go into [build.gradle.kts](./build.gradle.kts) & find `enableNative` & set the right side to true.
Afterwards, when syncing the project, the native source sets will become available to work on.
It is suggested to run `cinteropLibvoskNative` to generate the Kotlin C bindings to work with.
## Future
- Possibly target Kotlin/JS
- Possibly target Kotlin/Objective-C (?)
[source install]: https://alphacephei.com/vosk/install
[download]: https://github.com/alphacep/vosk-api/releases/latest
-204
View File
@@ -1,204 +0,0 @@
import org.jetbrains.dokka.gradle.DokkaTask
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/*
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
*
* 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.
*/
plugins {
kotlin("multiplatform") version "2.0.0"
id("com.android.library")
`maven-publish`
id("org.jetbrains.dokka") version "1.9.20"
kotlin("plugin.serialization") version "2.0.0"
}
group = "com.alphacephei"
version = "0.3.75"
repositories {
google()
mavenCentral()
}
val dokkaOutputDir = "$buildDir/dokka"
tasks.getByName<DokkaTask>("dokkaHtml") {
outputDirectory.set(file(dokkaOutputDir))
}
val deleteDokkaOutputDir by tasks.register<Delete>("deleteDokkaOutputDirectory") {
delete(dokkaOutputDir)
}
val javadocJar = tasks.register<Jar>("javadocJar") {
dependsOn(deleteDokkaOutputDir, tasks.dokkaHtml)
archiveClassifier.set("javadoc")
from(dokkaOutputDir)
}
fun org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension.native(
configure: org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests.() -> Unit = {}
) {
when {
org.jetbrains.kotlin.konan.target.HostManager.hostIsMingw -> mingwX64("native")
org.jetbrains.kotlin.konan.target.HostManager.hostIsLinux -> linuxX64("native")
org.jetbrains.kotlin.konan.target.HostManager.hostIsMac -> if (org.jetbrains.kotlin.konan.target.HostManager.hostArch() == "arm64") {
macosArm64("native")
} else {
macosX64("native")
}
else -> error("Unsupported Host OS: ${org.jetbrains.kotlin.konan.target.HostManager.hostOs()}")
}.apply(configure)
}
kotlin {
jvm {
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_17)
}
testRuns["test"].executionTask.configure {
useJUnitPlatform()
environment("MODEL", "VOSK_MODEL")
//environment("MODEL", "/home/doomsdayrs/Downloads/vosk-model-small-en-us-0.15/")
environment("LIBRARY", "VOSK_PATH")
//environment("LIBRARY", "/usr/local/lib64/libvosk/libvosk.so")
environment("AUDIO", "$projectDir/../python/example/test.wav")
}
}
androidTarget {
publishAllLibraryVariants()
}
/**
* If native target should be enabled or not.
*
* Currently disabled as there is no proper packaging distribution currently.
*/
@Suppress("SimplifyBooleanWithConstants") // Ignore, the false is for overrides
val enableNative = System.getenv("NATIVE_EXPERIMENT") == "true" || false
if (enableNative)
native {
val main by compilations.getting
val libvosk by main.cinterops.creating
binaries {
sharedLib()
}
}
@OptIn(ExperimentalKotlinGradlePluginApi::class)
applyDefaultHierarchyTemplate {
withJvm()
withAndroidTarget()
if (enableNative)
withNative()
}
publishing {
publications {
withType<MavenPublication> {
artifact(javadocJar)
pom {
url.set("http://www.alphacephei.com.com/vosk/")
licenses {
license {
name.set("The Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}
developers {
developer {
id.set("com.alphacephei")
name.set("Alpha Cephei Inc")
email.set("contact@alphacephei.com")
}
}
scm {
connection.set("scm:git:git://github.com/alphacep/vosk-api.git")
url.set("https://github.com/alphacep/vosk-api/")
}
}
}
}
}
val jna_version = "5.14.0"
val coroutines_version = "1.7.3"
sourceSets {
val commonMain by getting {
dependencies {
api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0")
api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version")
}
}
val jvmMain by getting {
dependencies {
api("net.java.dev.jna:jna:$jna_version")
}
}
val jvmTest by getting
if (enableNative) {
val nativeMain by getting
}
val androidMain by getting {
dependsOn(jvmMain)
dependencies {
api("net.java.dev.jna:jna:$jna_version@aar")
}
}
val androidUnitTest by getting {
dependencies {
implementation("junit:junit:4.13.2")
}
}
}
}
android {
namespace = "com.alphacephei.library"
compileSdk = 34
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdk = 24
targetSdk = 34
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
publishing {
multipleVariants {
withSourcesJar()
withJavadocJar()
allVariants()
}
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
* Copyright 2020 Alpha Cephei Inc. & Doomsdayrs
*
* 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.
*/
pluginManagement {
repositories {
google()
gradlePluginPortal()
mavenCentral()
}
resolutionStrategy {
eachPlugin {
if (requested.id.namespace == "com.android") {
useModule("com.android.tools.build:gradle:8.3.0")
}
}
}
}
rootProject.name = "vosk-api-kotlin"
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.alphacephei.library">
<uses-permission android:name="android.permission.RECORD_AUDIO" />
</manifest>

Some files were not shown because too many files have changed in this diff Show More